Search Unity

Question How to get color from another object in Shader Graph?

Discussion in 'Shader Graph' started by Ferdi7, Apr 30, 2021.

  1. Ferdi7

    Ferdi7

    Joined:
    Mar 12, 2013
    Posts:
    9
    I'm trying to get my objects, in this case a grass billboard, to get its color from the terrain it sits on. Like this Stylized Grass Shader.


    I've no clue how to even approach this in Shader Graph. Do I use the blend node? Replace colors? How do I get the terrain texture color in the first place? In C# I could probably raycast down and get the color of the object, but with Shader graph I don't even know where to start. It doesn't necessarily have to be from a terrain object, as long as I can get the color of any object underneath it.
     
    danielaquestions likes this.
  2. Domarius

    Domarius

    Joined:
    Jan 5, 2013
    Posts:
    103
    Sorry for necro posting but I stumbled across this question and found it interesting. I wonder if my answer will benefit anyone else.

    With what I've learned so far about GPU programming, your first step would be to capture a low resolution colour map of your terrain, the texture for this could be fairly low resolution, you'd have to experiment, but since you get bilinear filtering for free, it comes with its own blending between colours. This will be uploaded to the GPU. In Unity terms, I believe this means giving the grass material an extra texture channel for the shader to reference, and you would assign this texture to that channel.

    Then you would need to give each grass mesh a UV in that texture (so convert its actual world position into a UV coordinate that is relative to the appropriate location inside that colour map texture), and you would pack that UV info in with the vertex data. Each vert in the mesh would get a copy of the same UV coordinates but this is the trick I was taught to do this sort of thing. This means the shader can reference this info, it can be unique per mesh, and still be done in a single draw pass for all the meshes. Someone with more experience here let me know if there is a better way.

    Now you can write a fragment shader that, after the colour is applied to the pixel in the usual way (getting the usual UV info from the verts for the actual grass texture colour), the colour is tinted further by using the "special" UV info we packed in to the vertex buffer which tells the shader what UV to reference in the colour map, and apply this colour to the existing pixel colour.

    I don't know how to translate those concepts into the shader graph, but that is the rough idea for the actual shader programming as I understand it.

    Also you'd need some way to segment this open world off into giant cells - so each cell would have its own colour map, and any grass within that cell has a UV into that colour map. Essentially each cell would have it's own Unity material and each cell's grass would be a new render pass.

    Definitely not a trivial task though.
     
    OwenvP, DevDunk and Adrien_Triangles like this.
  3. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,307
    I am not 100% sure I understood this part, but it is not necessary to modify UV. Shader just need to know how to map it's position to color of that splat map or whatever you sample. Also grass is not rendered everywhere all the time, so if you use dedicated texture you probably don't need more than one - just one to render grass around player. Then in simple case you could set it as global shader parameter plus some data like size and offset in world space, then in grass shader you take node Position (world) and use it's xz to calculate pixel on that global texture.

    However it's not trivial task anyway.