I’m working on simulating player’s view field. The area(pixels) can’t be seen will be rendered in Monochrome.
So I add a point light on the player’s head, those pixels which are in shadow must also in Monochrome.
I saw the terrain component use standard material, so I use a custom material/shader instead, which I copy from the unity “Hidden/TerrainEngine/Splatmap/Lightmap-FirstPass”, this is a surface shader.
Then I found it’s hard to find a place to get the information of the cube light map.
Am I doing in the right way or Is it possible to find a solution to achieve my goal?
Surface Shaders are a way to interface with Unity’s built in lighting system, and generally hide a lot of the more complex parts of the shader from the author. More over, they often intentionally prevent access to those parts. There’s also the problem of Unity’s lighting system being done in multiple passes, where the first “base” pass is always lit by ambient lighting and the brightest directional light, and additional passes will be the other point, spot, or directional lights in the scene. Each pass has no knowledge of other lights in the scene, apart from that base pass which can have additional knowledge of non-shadowing per vertex lights (either lights set to be non-important, or additional lights past the max Per Pixel Light count).
This poses several problems for what you’re doing. The TLDR is you likely don’t want to use a Surface Shader for this, assuming you don’t want the terrain to be lit by other lights in the scene and only your “view” light. You probably want to use a vertex fragment shader and render out your own depth map, or potentially copy the main view’s camera depth texture and reuse that.
Here would be the basic steps:
Copy camera depth texture from main camera view using a command buffer.
Pass camera’s projection matrix and that depth texture to a custom shader.
Have that custom shader draw everything outside of that projection frustum in greyscale, and test against the depth texture inside the frustum.
Obviously there’s a lot of complexity there, but if you look around the forum there are examples of doing similar things for stuff like showing view cones or custom shadowed projectors.
If in a shader then, to continue my comments from above, you can find out if the pixel being rendered is in the shadow of the light being rendered by the current pass, but there’s not really a way to know if the light being rendered is the one you want, and any object outside of the radius of that light won’t even get rendered with that light. You can make the point light be the only light in the scene, or use layers to make it so the light only affects the one object, and you can increase the range of the light to ensure it hits all of the objects you care about. However be warned that the shadows from point lights are really bad and get significantly worse if they have a large radius.
Thank you, bgolus.
Since I’m new to unity and I spent my whole day on your reply things, now I’ve got clear about what you said.
I want to get my things done in shader and my first problem is, I can’t find a place to start.
I tried to do things with Camera.SetReplacementShader to get the entry to hack, but I still can’t find the place to handle shadow.(I got ONLY ONE point light in scene).
Would you please give me some more guide step?( Since I’m experienced in game engine but a newbie to Unity, maybe I need to know more about ways to use unity)
Thank you again!
ps.
in fact, I want a shader to only render the shadow to a render target.
I don’t know how to write it.
I guess I can’t do that in a surface shader.
Should I write a Forward base pass ? I don’t think so ,since I need point light shadow, it is not handled in base pass.
Should I write a Forward add pass? I think so, but I don’t know how to find the place to handle shadow.
Should I write a Forward shadowcaster pass? I’m still working on figuring it out.
I honestly don’t know if replacement shaders allow for shadows of any kind, maybe just the main directional light. I don’t use replacement shaders at all so I can’t say for sure.
Assuming they do, I think you still need a Forward Base pass, even if it just renders black. I’ve never tried to write a lit shader that only has a Forward Add pass.
And yes, you’ll need a shadowcaster pass of some kind, but as long as you’re not doing anything special in the vertex shader you can just rely on a fallback for that, which is how most shaders handle their shadowcaster pass.
As for how to get the shadow, you can look at this page: https://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html
Technically that only shows you how to have a forward base pass with shadows, but the forward add pass is almost identical apart from the lightmode, using #pragma multi_compile_fwdadd, and removing stuff for the ambient.
Catlike Coding has some more in depth tutorials on this kind of thing, going pretty deep into how Unity’s lighting system works. See the Multiple Lights segment in particular. http://catlikecoding.com/unity/tutorials/
However it’s possible that replacement shaders don’t support shadowing. In that case you’ll have to render out the shadow maps manually.