I have written a simple custom PBR shader for Unity’s terrain that accepts some additional driver textures to allow things like height-based blending and roughness control.
This approach uses a script to create SplatPrototypes for the normal Terrain Editor to use, and then assigns ProceduralMaterial-derived textures to the custom shader. For that reason, it assumes script access to the material which is being drawn.
How do I access the properties of the AddPass shader? I am using the same shader dependency setup as Unity’s included terrain shaders. It seems like they must be doing some kind of MaterialPropertyBlock swap under the hood between passes since I assume they are reusing samplers and texture IDs between passes. So if I want to assign _Splat4, the fifth texture, that’s really _Splat0 of the AddPass, but I don’t know how to write to that without also writing to the FirstPass.
Did you manage to resolve this yet? (Please say yes.)
I have a similar problem.
I’m starting with Unity 5.5’s terrain shader, and want to add simple height based blending to it.
So it starts simple enough - just add new height map texture properties to both the First Pass and Add Pass shaders.
But of course, the Add Pass properties are not visible in the custom material I created, because you only assign the First Pass shader to the custom material, and the Add Pass is hidden magic accessed from Unity’s terrain system deep under the hood somewhere.
I thought that maybe moving the Add Pass shader path away from “Hidden/…” would make those properties surface, but no.
Please someone from Unity - tell us how we can add custom properties to First Pass AND Add Pass, and then access those properties from the editor (material properties) or script. Any approach is fine… anything that works.
Hi gentlemen, sorry to miss your questions, I didn’t get any email from the forums.
I never did find a way to do this using a normal AddPass. My current shader draws 8 layers in one shot (you need to reuse samplers with UNITY_DECLARE_TEX2D_NOSAMPLER for this, 8-way PBR uses 24 textures + 2 control maps) and has a stub AddPass shader that just clip()s out immediately. I get the control maps out of the terrainData object and assign them as normal textures in my custom material instead of letting the background material property write do it. I also wrote a lot of edge/seam healing tools and other things to make working with large, segmented terrains bearable.
Ultimately, it wound up being so much code and so many systems that I actually made a ~1hr YouTube video as a tutorial for myself so I could remember how it worked. I just watched it again after being away from the project for a long time and I’m not sure why I thought this was better than just going straight custom. But it is possible to do everything you need in a single material, just with quite a lot of work and a graphically/logically stable but very cumbersome result.
Documentation is currently the worst it’s been since I started using Unity, and with the much-discussed increase in price, that is disappointing to say the least.
IMO the terrain engine must added some code to the currently attached surface shader so that there will always be a line like Dependency “AddPassShader” = “THE DEFAULT ONE”. However, if you write this line by yourself, it will check whether it’s valid. If it’s not, Unity will still add this line. But if it is valid, then it will use that. In my case, I was doing some procedural virtual texture on unity terrain, so I have to change the terrain material on the fly. I tried both vertex/fragment shader and surface shader and it seems this mechanism only works when I’m using surface shaders. I wanted the simple surface shader with all the shadows and lightings done for me, so I’m sticking with surface shader. I found a way around which is not so efficient. I created a dummy surface shader to be the “AddPassShader”(it seems only a surface shader will work). In that shader, I used decals:blend instead of decals:add and set the ouput color and alpha to zero, which basically render nothing to the screen. This solution works but it will create at least one extra draw call as I understand it. Considering there are tons of triangles in a terrain, this solution is not good at all. Maybe I switch to the vertex/fragment shader solution in the future.