function Invisicam.Update(a)if not Character then return end if not HumanoidRootPart then local a=Character:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")if a and a.Torso then HumanoidRootPart=a.Torso else HumanoidRootPart=Character:FindFirstChild("\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")if not HumanoidRootPart then return end end local k k=HumanoidRootPart.AncestryChanged:connect(function(a,V)if a==HumanoidRootPart and not V then HumanoidRootPart=nil if k and k.Connected then k:Disconnect()k=nil end end end)end if not TorsoPart then CheckTorsoReference()if not TorsoPart then return end end local k={}BehaviorFunction(k)local V={}local l={Character}local function n(a)V[a]=true if not SavedHits[a]then SavedHits[a]=a.LocalTransparencyModifier end end local C local T=0 local L={}local i={}local N=TARGET_TRANSPARENCY local B=TARGET_TRANSPARENCY if USE_STACKING_TRANSPARENCY then local a=HeadPart and HeadPart.CFrame.p or k[1]local V=TorsoPart and TorsoPart.CFrame.p or k[2]C=Camera:GetPartsObscuringTarget({a,V},l)for a=1,#C,1 do local k=C[a]T=T+1 L[k]=true for a,k in pairs(k:GetChildren())do if k:IsA("\068\101\099\097\108")or k:IsA("\084\101\120\116\117\114\101")then T=T+1 break end end end if T>0 then N=math.pow(.5*TARGET_TRANSPARENCY+(.5*TARGET_TRANSPARENCY)/T,1/T)B=math.pow(.5*TARGET_TRANSPARENCY_PERIPHERAL+(.5*TARGET_TRANSPARENCY_PERIPHERAL)/T,1/T)end end C=Camera:GetPartsObscuringTarget(k,l)local s={}for a=1,#C,1 do local k=C[a]s[k]=L[k]and N or B if k.Transparency<s[k]then n(k)end for a,V in pairs(k:GetChildren())do if V:IsA("\068\101\099\097\108")or V:IsA("\084\101\120\116\117\114\101")then if V.Transparency<s[k]then s[V]=s[k]n(V)end end end end for a,k in pairs(SavedHits)do if V[a]then a.LocalTransparencyModifier=a.Transparency<1 and(s[a]-a.Transparency)/(1.0-a.Transparency)or 0 else a.LocalTransparencyModifier=k SavedHits[a]=nil end end end function Invisicam.SetMode(k,a)AssertTypes(a,"\110\117\109\098\101\114")for k,V in pairs(MODE)do if V==a then Mode=a BehaviorFunction=Behaviors[Mode]return end end error("\073\110\118\097\108\105\100 \109\111\100\101 \110\117\109\098\101\114")end function Invisicam.SetCustomBehavior(k,a)AssertTypes(a,"\102\117\110\099\116\105\111\110")Behaviors[MODE.CUSTOM]=a if Mode==MODE.CUSTOM then BehaviorFunction=a end end function Invisicam.GetObscuredParts(a)return SavedHits end
-- Update. Called every frame after the camera movement step
function Invisicam:Update()
	-- Bail if there is no Character
	if not Character then
		return
	end

	-- Make sure we still have a HumanoidRootPart
	if not HumanoidRootPart then
		local humanoid = Character:FindFirstChildOfClass("Humanoid")
		if humanoid and humanoid.Torso then
			HumanoidRootPart = humanoid.Torso
		else
			-- Not set up with Humanoid? Try and see if there's one in the Character at all:
			HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
			if not HumanoidRootPart then
				-- Bail out, since we're relying on HumanoidRootPart existing
				return
			end
		end
		local ancestryChangedConn
		ancestryChangedConn = HumanoidRootPart.AncestryChanged:connect(function(child, parent)
			if child == HumanoidRootPart and not parent then
				HumanoidRootPart = nil
				if ancestryChangedConn and ancestryChangedConn.Connected then
					ancestryChangedConn:Disconnect()
					ancestryChangedConn = nil
				end
			end
		end)
	end

	if not TorsoPart then
		CheckTorsoReference()
		if not TorsoPart then
			-- Bail out, since we're relying on Torso existing, should never happen since we fall back to using HumanoidRootPart as torso
			return
		end
	end

	-- Make a list of world points to raycast to
	local castPoints = {}
	BehaviorFunction(castPoints)

	-- Cast to get a list of objects between the camera and the cast points
	local currentHits = {}
	local ignoreList = { Character }
	local function add(hit)
		currentHits[hit] = true
		if not SavedHits[hit] then
			SavedHits[hit] = hit.LocalTransparencyModifier
		end
	end

	local hitParts
	local hitPartCount = 0

	-- Hash table to treat head-ray-hit parts differently than the rest of the hit parts hit by other rays
	-- head/torso ray hit parts will be more transparent than peripheral parts when USE_STACKING_TRANSPARENCY is enabled
	local headTorsoRayHitParts = {}
	local partIsTouchingCamera = {}

	local perPartTransparencyHeadTorsoHits = TARGET_TRANSPARENCY
	local perPartTransparencyOtherHits = TARGET_TRANSPARENCY

	if USE_STACKING_TRANSPARENCY then
		-- This first call uses head and torso rays to find out how many parts are stacked up
		-- for the purpose of calculating required per-part transparency
		local headPoint = HeadPart and HeadPart.CFrame.p or castPoints[1]
		local torsoPoint = TorsoPart and TorsoPart.CFrame.p or castPoints[2]
		hitParts = Camera:GetPartsObscuringTarget({ headPoint, torsoPoint }, ignoreList)

		-- Count how many things the sample rays passed through, including decals. This should only
		-- count decals facing the camera, but GetPartsObscuringTarget does not return surface normals,
		-- so my compromise for now is to just let any decal increase the part count by 1. Only one
		-- decal per part will be considered.
		for i = 1, #hitParts do
			local hitPart = hitParts[i]
			hitPartCount = hitPartCount + 1 -- count the part itself
			headTorsoRayHitParts[hitPart] = true
			for _, child in pairs(hitPart:GetChildren()) do
				if child:IsA("Decal") or child:IsA("Texture") then
					hitPartCount = hitPartCount + 1 -- count first decal hit, then break
					break
				end
			end
		end

		if hitPartCount > 0 then
			perPartTransparencyHeadTorsoHits =
				math.pow(((0.5 * TARGET_TRANSPARENCY) + (0.5 * TARGET_TRANSPARENCY / hitPartCount)), 1 / hitPartCount)
			perPartTransparencyOtherHits = math.pow(
				((0.5 * TARGET_TRANSPARENCY_PERIPHERAL) + (0.5 * TARGET_TRANSPARENCY_PERIPHERAL / hitPartCount)),
				1 / hitPartCount
			)
		end
	end

	-- Now get all the parts hit by all the rays
	hitParts = Camera:GetPartsObscuringTarget(castPoints, ignoreList)

	local partTargetTransparency = {}

	-- Include decals and textures
	for i = 1, #hitParts do
		local hitPart = hitParts[i]

		partTargetTransparency[hitPart] = headTorsoRayHitParts[hitPart] and perPartTransparencyHeadTorsoHits
			or perPartTransparencyOtherHits

		-- If the part is not already as transparent or more transparent than what invisicam requires, add it to the list of
		-- parts to be modified by invisicam
		if hitPart.Transparency < partTargetTransparency[hitPart] then
			add(hitPart)
		end

		-- Check all decals and textures on the part
		for _, child in pairs(hitPart:GetChildren()) do
			if child:IsA("Decal") or child:IsA("Texture") then
				if child.Transparency < partTargetTransparency[hitPart] then
					partTargetTransparency[child] = partTargetTransparency[hitPart]
					add(child)
				end
			end
		end
	end

	-- Invisibilize objects that are in the way, restore those that aren't anymore
	for hitPart, originalLTM in pairs(SavedHits) do
		if currentHits[hitPart] then
			-- LocalTransparencyModifier gets whatever value is required to print the part's total transparency to equal perPartTransparency
			hitPart.LocalTransparencyModifier = (hitPart.Transparency < 1)
					and ((partTargetTransparency[hitPart] - hitPart.Transparency) / (1.0 - hitPart.Transparency))
				or 0
		else -- Restore original pre-invisicam value of LTM
			hitPart.LocalTransparencyModifier = originalLTM
			SavedHits[hitPart] = nil
		end
	end
end

function Invisicam:SetMode(newMode)
	AssertTypes(newMode, "number")
	for modeName, modeNum in pairs(MODE) do
		if modeNum == newMode then
			Mode = newMode
			BehaviorFunction = Behaviors[Mode]
			return
		end
	end
	error("Invalid mode number")
end

function Invisicam:SetCustomBehavior(func)
	AssertTypes(func, "function")
	Behaviors[MODE.CUSTOM] = func
	if Mode == MODE.CUSTOM then
		BehaviorFunction = func
	end
end

function Invisicam:GetObscuredParts()
	return SavedHits
end
