Search Unity

Parallax effect without without warping?

Discussion in 'Shaders' started by Warrior1424, May 15, 2018.

  1. Warrior1424

    Warrior1424

    Joined:
    Sep 30, 2010
    Posts:
    984
    I'm trying to create a "surface below a surface" effect.

    Currently I'm using the basic parallax offset with a constant depth, but it isn't ideal as it gets deeper near the view position and shallower farther away which creates an undesirable effect.



    However I can't just move the verts along their normals as it introduces a rendering order problem and unlike parallaxed textures will not repeat indefinitely at the bounds as it is restricted to the polygon it renders on.

    I tried changing the parallax depth based on camera depth but wasn't able to find out what the exact correlation it would be to make it work, if any.

    If a shader can be made that fakes a building interior, certainly this should also be possible.

    Any help would be greatly appreciated!
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,348
    Here's the trick to do what you want in one line:

    float2 uvOffset.xy = tangentSpaceViewDir.xy / max(tangentSpaceViewDir.z, 0.00001) * _OffsetDepth;

    The divide by z is the magic. Dividing a tangent space view vector by its z creates a vector with a constant depth (z) of 1.0, ie: a flat plane. Since we don't actually need the z, we just divide the view vector's xy values to get the xy offset at a depth of 1 unit, then scale it by the offset depth you want. The max() is just to prevent the rare case of a divide by zero. On a flat plane it should be impossible, but if you apply this to anything with a curve or normals that don't match the tri surface (ie: pretty much anything not perfectly flat) then you can get a zero.
     
    Last edited: May 15, 2018
  3. Warrior1424

    Warrior1424

    Joined:
    Sep 30, 2010
    Posts:
    984
    Oh wow that's really simple!

    Only problem is I can't find out how to get the tangent space viewdir.
    Initially I thought it was a built-in thing but that doesn't appear to be the case.
    I tried looking up how convert viewDir to tangent space but was unsuccessful (I still haven't fully grasped vectors and tangent/world/view/local spaces)
    Also I should have mentioned that this is a surface shader.
    Everything else works fine though cause plugging in viewDir makes the effect work, just obviously not in the correct orientation.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,348
    If you're using a Surface Shader and setting the o.Normal value in the surf function, then IN.viewDir is the view direction vector in tangent space. If you're not setting the o.Normal then it is the view direction in world space even though the documentation doesn't mention this.

    If you don't want or need a normal map, just use o.Normal = half(0,0,1); to get IN.viewDir to be in tangent space in a Surface Shader.
     
    unity_StMzt01iz5SGnw likes this.
  5. Warrior1424

    Warrior1424

    Joined:
    Sep 30, 2010
    Posts:
    984
    You're a life saver as always bgolus!
    Here's the code for anyone else stumbling across this in the future:
    Code (CSharp):
    1. o.Normal = half3(0.0, 0.0, 1.0);
    2. float2 uvOffset = IN.viewDir.xy / max(IN.viewDir.z, 0.00001) * 1.0;
    3. fixed4 c = tex2D (_MainTex, IN.uv_MainTex - uvOffset);
    4. o.Albedo = c.rgb;