Search Unity

Cubemap reflection per-vertex instead of per-object

Discussion in 'Shaders' started by D43DB33F, Feb 18, 2018.

  1. D43DB33F

    D43DB33F

    Joined:
    Apr 6, 2017
    Posts:
    43
    Hi ! I am currently writing a water shader that animates tiles of water of different shapes. This shader provides reflections using the built-in stuff that comes with Unity, as described in the following tutorial : https://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html at the chapter "Cubemap Reflection".

    It seems like the orientation of the object is taken into account when computing the reflections. However, it seems like that orientation is common to all the vertices of an object. In other words, it seems to be using the upwards direction of the object for all vertices instead of their normals.

    This is causing a problem in my case, because it causes the transition between two objects having different rotations to be clearly visible, despite the transition of vertex normals being rather seameless when using the same rotation :

    upload_2018-2-18_5-32-52.png


    As you can see on the picture above, the vertical (90 degrees) water tile is darker than the curved one right below it. And the 45 degree water tile is half way dark.

    So my question is : is there a way to make unity compute reflections using vertex normals instead of using the object's upwards direction for all vertices ? Or do I have to roll my own cubemap reflection code ?

    Thanks !
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    The documentation for Surface Shaders is somewhat incomplete at this point. Also the worldRefl is quite finicky and will seemingly break if you don't use it exactly right.
    See: https://docs.unity3d.com/Manual/SL-SurfaceShaders.html

    However, you probably don't even need to do your own reflections. Unity's Standard shading model handles this for you. If you create a new Surface Shader from the project view Unity will give you a shader using the standard shading model that you can build upon.
     
  3. D43DB33F

    D43DB33F

    Joined:
    Apr 6, 2017
    Posts:
    43
    Well I did create a surface shader from the editor, on top of which I added a vertex shader. My surface shader is very close to what the tutorial says :

    Code (CSharp):
    1.        void SSMain(Input IN, inout SurfaceOutputStandardSpecular o)
    2.        {
    3.            o.Albedo = _Color.rgb;
    4.            o.Alpha = _Color.a;
    5.            o.Smoothness = _Glossiness;
    6.            o.Specular = _Specular;
    7.            o.Emission = texCUBE(_Cube, IN.worldRefl).rgb * _ReflectionIntensity;
    8.        }
    Maybe that I should assign o.Normal with the normal previously computed in my vertex shader ?

    Because all my meshes, regardless of the shape created in the vertex shader, as just planes in the C# side. The shape is only created on the fly, in the vertex shader. Maybe that I should also update the tagents in my vertex shader and not just the vertex and normals ? I'm not sure what tangents are tough.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    When using the standard shading model you shouldn't need to calculate your own reflections at all. Reflections are built into the standard shading model by default. As long as your scene's lighting has been properly baked (either manually or automatically) Unity should automatically provide a reflection probe that matches the skybox. Set the gloss and specular high enough and you should get nice reflections.
     
  5. D43DB33F

    D43DB33F

    Joined:
    Apr 6, 2017
    Posts:
    43
    Well I am getting nice reflections already. I'm not trying to compute them myself, I wouldn't know how to do hehehe... But what I don't understand is why, in the image below, the curved water tile, whose perimeter is red, does not progressively gets darker as the vertex normals go from vertical to horizontal :

    upload_2018-2-18_23-54-2.png

    On this picture : the arrows represent some of the vertex normals. I would expect the water to look progressively darker and darker as you go from the green normals to the red normals. There should be a smooth transition between horizontal and vertical water "brightness" if I may call it like this.

    But in my case, it seems like the reflections are taking the object's Y direction instead of the vertex normal, which would explain why all that curved water tile has the same "brightness" at all vertexes.

    I'm not familiar with baking yet. Could this be related ? Since my game world is going to be dynamically created from a file, I'll have to perform the baking manually and at run-time, assuming it is possible.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    Are you sure your vertex normals are correct? If you disable your emission reflections, does the lighting act like what you expect or is that also wrong?
     
  7. D43DB33F

    D43DB33F

    Joined:
    Apr 6, 2017
    Posts:
    43
    Yes and no. They are correct once the vertex shader has executed, but the ones stored in the mesh are pointing upwards regardless of the shape of the mesh. I tried to make them point into another direction instead, just to make sure that the normals didn't need to be updated in both places (i.e in the mesh and in the shader), but I'm getting the same visual result, so I suppose they don't need to be updated into the mesh itself.

    I also tried to remove the cubemap reflection by commenting the o.Emission assignment in the surface shader, but I'm getting the same result, minus the reflections of course.
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,339
    If you're getting the same result, minus reflections, it means for sure you aren't setting the vertex normals properly.
     
    D43DB33F and AcidArrow like this.
  9. D43DB33F

    D43DB33F

    Joined:
    Apr 6, 2017
    Posts:
    43
    Man you're a life saver ! I'll add your name to the credits of my game :p

    It was indeed my normals that were partially wrong. I was using the "plane water shape" code to compute the normals for all shapes, so it was working correctly for all plane water tiles, but not for other shapes.

    I first tried to debug normals by trying to store them as colors, but since this is a surface shader instead of a regular vertex + fragment shader, I guess there was something missing somewhere and it didn't want to let me compile. So instead I assigned the normals to the vertex position for some of the vertices and I could see what was wrong.

    Thanks again for the help. Now I can get back to the actual content of my game and stop working on that water which I've been working on for many weeks.

    EDIT : The result

    upload_2018-2-21_23-35-50.png
    :
     
    Last edited: Feb 21, 2018