A clean way of rendering view models that don't interfere with post processing
What can't you do?
I am having trouble rendering my view models so that lighting and shadows from the scene is properly rendered, it doesn't cause weird artefacts, and post processing and UI from my main camera still appear.
How would you like it to work?
Some sort of proven and defined workflow for doing this.
My goal is;
- Render the view model, with shadows and lighting from the world, and a different FOV then the main first person camera
- Be able to apply the same post processing effects of the first person camera onto the view model
What have you tried?
I've tried a couple different strategies.
As a note; the FOV from the View Model camera and the First Person Camera are different. This is required.
Current Method - View Model First
View Model Camera Priority = 1 Render Tags = viewmodel, light Clear Flags = All Post Processing = None
First Person Camera Priority = 2 Render Exclude Tags = viewmodel Clear Flags = Stencil Post Processing = Set
Result This looks mostly correct, however my view model is not effected by shadows cast from objects in the scene
Method 2 - View Model First + World
View Model Camera Priority = 1 Render Tags = viewmodel, light, world Clear Flags = All Post Processing = None ZNear = Very Close
First Person Camera Priority = 2 Render Exclude Tags = viewmodel Clear Flags = Stencil Post Processing = Set
Result
The view model is affected by shadows in the world.
Problems Visual artefacts occur when you are close to world objects, you sometimes see a mirror of them
https://github.com/user-attachments/assets/e6e0b2a6-b464-46bf-860e-6a1d852fa1b9
Clearly this is due to the differences of FOV. And decreasing the View Model Camera ZNear helps hide it but it never goes away completely. And worse case it cuts off the end of the gun (view model.)
Method 3 - World First, then View Model
View Model Camera Priority = 2 Render Tags = viewmodel, light, world Clear Flags = Stencil Post Processing = None ZNear = Very Close
First Person Camera Priority = 1 Render Exclude Tags = viewmodel Clear Flags = All Post Processing = Set
In this method if world is set on the View Model camera then the artefacts are very noticeable. Additionally since post processing is done on the first person camera, I have to move any screen space post process effects to the view model camera to also have them be performed on the view model.
Some post processing effects no longer work on the First Person Camera as well, such as FilmGrain, Pixelate, Color Grading and Color Adjustments, which I think is weird but not a blocker.
Methods I haven't tried but thought about
Render Targets?
I've considered doing something where in a render target I render out the view model and the world.
- Create a render target
- Before the first person camera applies post processing:
- Use the View Model Camera rendering to the render target
- Render the world and lights
- Render the view model
- Create a stencil of just the view model that was rendered (??)
- When rendering the First person Camera:
- After (or before) rendering everything in the scene
- Blit (?) the render target onto the First Person Camera framebuffer
- Should only copy over from the render target where the view model stencil is set
- First person camera continues on like normal and does post processing
I've struggled with figuring out how to do this with the S&Box rendering pipeline so I haven't been able to implement it, and i'm also unsure if this is even a sane way of doing this.
Invisible shadow casing models
I create invisible geometry/models that block light, putting them where i'd expect shadows to be cast.
Seems tedious and prone to break if I then go and change the visible geometry.
Have the world be invisible but still render shadows
I have no idea how you can tell a specific camera when it's rendering to only cast shadows for specific objects, like a Map Instance, but not actually render the geometry.
Or perhaps a tag set that I could say "cast shadows for things with these tags (and don't actually render color)"
Additional context
Perhaps i'm just looking at this wrong and someone has already solved this.
I don't know if this is a design issue or what but the way I do my FPV weapon is just enable overlay under the advanced rendering bool of the model renderer for the weapon. This deals with the problem of getting up close to geometry in FPV, so your weapon doesn't clip, but it looks like you have some kind of transformation system where if you get close he pulls the weapon up. I would still enable it in this case to be sure, especially if I'm rendering out a TPV model (see caveat below).
Then I make sure that the overlay bool is only active for the owner, so nobody else can see it through walls.
My FPV/TPV weapons are essentially the same because I use a muzzle system that is attached to the tip of the weapon model. This is why I need a special case for disabling overlay for other clients. I need the FPV and TPV views the same (or at the very least extremely accurate replication), so it's like a physical player controller like Arma or something - simply because my FPV and TPV weapons should be the same thing. However, your case is even easier if you have seperate FPV and TPV systems.
From what I can see there are no rendering issues really, by doing it my way above. But it fits my game, I don't know if it will fit yours.
I don't believe separating FPV/TPV weapons is the right way to be doing things anymore. I think you can build a reliable controller and weapons system that can work in a much less convoluted way.
It may or may not answer your question but I read your extremely lengthy post and thought, this seems super complicated! I'm personally not sure why you are fiddling with FOV like that, it's not too clear in your post.
@chickenhair101 Thanks for the input. I fiddle with the FOV to help simulate the weapon being closer to the camera when the player is aiming down sights or pulling a scope up to their eye. I've found it looks better than just translating the view model closer to the camera.