Search Unity

Set textures for Terrain AddPass shader

Discussion in 'Shaders' started by hausmaus, Jan 4, 2017.

  1. hausmaus

    hausmaus

    Joined:
    Dec 9, 2011
    Posts:
    105
    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.

    Thanks for any insight,
    Adrian
     
    mgeorgedeveloper likes this.
  2. mgeorgedeveloper

    mgeorgedeveloper

    Joined:
    Jul 10, 2012
    Posts:
    326
    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.
     
  3. Arnklit

    Arnklit

    Joined:
    May 18, 2015
    Posts:
    48
    Bump! I'm having the exact same problem. The documentation is really lacking in this area.
     
  4. hausmaus

    hausmaus

    Joined:
    Dec 9, 2011
    Posts:
    105
    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.
     
  5. fox3fire

    fox3fire

    Joined:
    Aug 20, 2017
    Posts:
    3
    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.
     
  6. fox3fire

    fox3fire

    Joined:
    Aug 20, 2017
    Posts:
    3
    Wrong! I can still see an addpass in the frame debugger before my shader. It did not disappear but only got covered up.