How to make an invisible part cast a shadow

Many people don’t seem to know that if you set a part’s material to force field and it’s transparency to -math.huge it becomes transparent while still casting shadows. Please note that this does not work with humanoids for some reason.

Here are some first person shadows I made with this method that also works with animations.
https://i.gyazo.com/f2a5e71f80b1dceeddb2178aa1b80a63.mp4

Source code for it: Enable shadows in first person. (Roblox) · GitHub

-- This is a local script since we only want it to run client sided
local RunService = game:GetService("RunService");

local Players = game:GetService("Players");
local Player = Players.LocalPlayer;

local Camera = workspace.CurrentCamera or workspace:WaitForChild("Camera");
local CharacterParts = {};
local Ignore = {["HumanoidRootPart"] = true}; -- Ignore these parts

local FAR = Vector3.new(1e6, 1e6, 1e6); -- Create a very far constant
Player.CharacterAdded:Connect(function(Character)
	for _, Part in ipairs(CharacterParts) do Part:Destroy(); end; -- Destroy all the parts inside the array
	table.clear(CharacterParts); -- Clear the array

	local function HandleCharacterChild(Child)
		if (Child:IsA("BasePart") and not Ignore[Child.Name]) then
			local Clone = Child:Clone();
			Clone:ClearAllChildren(); -- We don't care about the children
			Clone.Material = Enum.Material.ForceField; -- Set it's material to force field
			Clone.Transparency = -math.huge; -- Set the transparency to -inf
                        Clone.CanCollide = false; -- So it doesn't fling us
			Clone.Position = FAR; -- Initially place it very far

			Clone.Parent = workspace; -- Set it's parent to the workspace
			CharacterParts[#CharacterParts + 1] = Clone; -- Insert it to the table
		end
	end
	table.foreachi(Character:GetChildren(), HandleCharacterChild); -- If there are existing parts inside the character
	Character.ChildAdded:Connect(HandleCharacterChild); -- If any parts are added when for example the player is loading
end)


RunService.RenderStepped:Connect(function(DeltaTime:number)
	local Character = Player.Character;

	if (Character and Character:FindFirstChild("Head")) then -- Check if the character exists and the character's head exists since it can be destroyed and that can lead to errors
		local CameraZoomDistance = (Character.Head.Position - Camera.CFrame.Position).Magnitude; -- Get the zoom distance

		local IsInFirstPerson = CameraZoomDistance < 3; -- There might be a better way to check if the player is in first person

		for _, Part:BasePart in ipairs(CharacterParts) do -- Loop through the table where we inserted all the duplicate parts
			local CharacterPart = Character:FindFirstChild(Part.Name);

			if (CharacterPart) then -- If it finds a part with the same name inside the character then continue
				Part.CFrame = IsInFirstPerson and CharacterPart.CFrame or CFrame.new(FAR); -- Set its CFrame to that character's part with the same name or very far depending on if the player is in first person
			end
		end
	end
end)
70 Likes

This is extremely useful for those who like to make scary games for first person games. Can this also be utilized for VR Games for a more realistic look?

3 Likes

It really depends on how you’re going to utilize it. I don’t know much about VR Games do they use the default Roblox character? I thought they would use a viewmodel rig for the arms.

Wow, this is super helpful!

I’m going to link a few #help-and-feedback posts so they can find this page:

6 Likes

This is actually really cool, I might try this out sometime.

Note that you don’t need to put semicolons at the end of a line in Lua, it’s good practice for languages like Java, but your code will be much more readable without semicolons.

Damn, I remember some time ago I was developing a horror game in-roblox and ran into this issue. The cool thing is that I actually found a way around, which was exactly doing the -inf trick.

I don’t really understand why (maybe some release changed this or maybe it was just some mistake I had) the -inf trick only worked in-studio and not in-game, at least for me. Although, I’m glad to see that this trick finally works for everybody.

3 Likes

that was why I was asking, Im not sure, but i dont think they use the basic roblox rig.

1 Like

Not entirely sure why Roblox doesn’t do this automatically. It’d make sense for any parts with CastShadow enabled to cast a shadow.

Anyways, thanks for putting this info out there, I’ll be using it. :sunglasses:


Made some text with shadows.

5 Likes

You can use it for secrete cheat codes n stuff, thats actually smart

Worth noting that this does not function on any low-end mobile device as it renders the forcefield material as if it were smooth-plastic.

6 Likes

Bumping this for people who target mobile, you can also do this with regular smooth plastic parts but they must have a highlight parented to it.

6 Likes