Control camera collision for zoom

I have a hallway with pillars down the sides and some pipes near the ceiling. When a player turns, the camera often clips through the pillars and pipes, and the resulting effect is unappealing. I’d like to find a way to have the camera use something like a camera-only collision group in these particular sections so that I can set some invisible parts to help manage the camera zoom ( DevCameraOcclusionMode=Zoom). Figuring out how to set up a “camera-only collision group” that works with invisible parts has me stumped at the moment.

Does this sound like a scripting problem (or is there a non-script solution–e.g. collision groups work with current camera and invis parts)? If it’s something to be done with scripts, is it something that can be run in parallel with existing camera scripts?

My initial dive into this suggests that I may need to customize the camera zoom code (maybe with some specialized raycasting) to account for the invisible manager parts. Does that sound about right or is there a more lightweight solution someone can think of for this problem?

Thanks for your thoughts! -Astr0

When you hit play, your character automatically spawns with a PlayerModule under their PlayerScripts (for mine, it’s game > Players > treebee63 > PlayerScripts > PlayerModule). You can copy and paste it under StarterPlayer > StarterPlayerScripts to overwrite the default one.

Inside CameraModule > ZoomController > Popper is this function:

local function canOcclude(part)
	-- Occluders must be:
	-- 1. Opaque
	-- 2. Interactable
	-- 3. Not in the same assembly as the subject

	return
		getTotalTransparency(part) < 0.25 and
		part.CanCollide and
		subjectRoot ~= (part:GetRootPart() or part) and
		not part:IsA("TrussPart")
end

You might be able to append to it to check for collision groups.

4 Likes

Thanks!

Got it working by adding a check for LocalTransparencyModifier of parts (that I edited)… may try to do it with tags instead or with collision groups as you suggested (I found that Popper code and was close to something workable when I noticed your reply. TY!).

Not a fan of having to customize these Roblox scripts, so still open to other ideas. Although, this approach is workable, so I’ll run with it until something less intrusive comes to light.


Here’s what I’m trying: The canOcclude function of the camera Popper script was edited to include a check for LocalTransparencyModifier == 1. I named the template Part being used for this HiddenPart, and I set CanCollide to false. I then added a “Hidden” tag, via the command bar, with game:GetService("CollectionService"):AddTag(workspace.HiddenPart, "Hidden"). If I then duplicate the hidden Part, the tag gets duplicated with it.

The edited canOcclude function
local function canOcclude(part)
	-- Occluders must be:
	-- 1. Opaque
	-- 2. Interactable
	-- 3. Not in the same assembly as the subject

	return part.LocalTransparencyModifier >= 1 or
		(getTotalTransparency(part) < 0.25 and
		part.CanCollide and
		subjectRoot ~= (part:GetRootPart() or part) and
		not part:IsA("TrussPart"))
end

From a LocalScript I’m checking for parts with Tags and setting their LocalTransparencyModifier. Altogether, this let’s me have semi-transparent, colored pieces in the scene that I can use to control how the camera behaves (pops in/out during zoom) in places I care about. When the game is run, these pieces are made invisible on the client and won’t collide with the player, but they will still affect the camera.

LocalScript to check Tags
local CollectionService = game:GetService("CollectionService")
local TAG_NAME = "Hidden"
 
local partAddedSignal = CollectionService:GetInstanceAddedSignal(TAG_NAME)
local partRemovedSignal = CollectionService:GetInstanceRemovedSignal(TAG_NAME)
 
local function onTagAdded(part)
	part.LocalTransparencyModifier = 1
end
 
local function onTagRemoved(part)
	if part ~= nil then
		part.LocalTransparencyModifier = 0
	end
end
 
for _,inst in pairs(CollectionService:GetTagged(TAG_NAME)) do
	onTagAdded(inst)
end
partAddedSignal:Connect(onTagAdded)
partRemovedSignal:Connect(onTagRemoved)

Please let me know if you foresee problems with this approach or have other advice. Thanks!

I’ve never tested with LocalTransparencyModifier for parts not parented to the character, so I don’t know how it will behave with the camera interacting with it in the long run. It is worth noting that that specific property is hidden in the object browser, so it’s probably not intended to be widely used.

Hey, if it works, then there’s no point in going back and redoing it.

I would recommend the if statement to become part.LocalTransparencyModifier >= 1 as just a precautionary thing. I think transparency does not clamp at 1.

1 Like

Yeah, I don’t really want to edit the camera script or use LocalTransparencyModifier, for the reason you mentioned. Using that hidden property with a CanCollide=false part does the trick, though. Changing the collision group keeps the part from ever getting passed to the canOcclude function, and I haven’t figured out where to modify things to keep my parts from being treated as invisible when going that route. The choice to exclude parts in other collision grps is maybe being handled in the blacklist part of the script or the whitelist part of the raycast, or maybe outside the script. I don’t know. Something to dig into more if this first approach fails in the future. :smiley:

1 Like

How do you override the canOcclude ? Did you recreate all of structure of CameraScript?

Yes, I just duplicated the whole PlayerModule into StarterPlayerScripts and made changes to the copy. Maybe someone knows of a less brute-force way to do that.

1 Like

Video:
robloxapp-20200811-1200189.wmv (2.2 MB)

Here’s the test file I was playing with if anyone wants it.
CustCameraZoom v0.01.rbxl (128.8 KB)

The LocalScript inside StarterPlayerScripts and edits to the Popper module (as outlined above) are the only differences from standard camera behavior.

[I only use models that I make and haven’t installed any plugins (beyond the defaults). Maybe someone can confirm that file is clean.]

What’s the easiest way to duplicate? I mean those scripts are only visible in runtime.

Copy them while running (nav to and Ctrl+C script(s) after hitting play) then stop game and paste where you want them.

1 Like