Search Unity

How to setup normals on triplanar

Discussion in 'Shaders' started by stationx, Dec 11, 2015.

  1. stationx

    stationx

    Joined:
    Jul 9, 2012
    Posts:
    251
    hello!
    I am having a hard time to setup combined normals on a triplanar shader.
    I have been able to reconstruct normals with RG and BA channels. Also setting up correct UV to make sure that the texture is correct wrapped.
    Now this causes that normals are flipped. I am super confused how to fix this. Anyone can shine some light on it?
     
  2. boundingbox

    boundingbox

    Joined:
    Mar 31, 2013
    Posts:
    30
    You need to pass in special tangents and binormals for your triplanar maps. This took me a while to figure out.

    In the vertex shader:

    Code (csharp):
    1.  
    2. fixed3 worldTangentXZ = float3( 1.0, 0.0, 0.0 );
    3. fixed3 worldTangentY = float3( 1.0, 0.0, 0.0 );
    4.  
    5. // don't try to figure out tangents on flat surfaces
    6. if( abs( worldNormal.y ) != 1 ){
    7.      worldTangentXZ = normalize( cross( worldNormal, float3( 0.0, -1.0, 0.0 ) ) );
    8. }
    9. if( abs( worldNormal.z ) != 1 ){    
    10.      worldTangentY = normalize( cross( worldNormal, float3( 0.0, 0.0, -1.0 ) ) );
    11. }
    12.          
    13. o.tSpaceXZ = float4(worldTangentXZ.xyz, 0.0);
    14. o.tSpaceY = float4(worldTangentY.xyz, 0.0);
    15. o.bSpaceXZ = float4( normalize( cross( v.normal.xyz, worldTangentXZ.xyz ) ), 0.0);
    16. o.bSpaceY = float4( normalize( cross( v.normal.xyz, worldTangentY.xyz ) ), 0.0);
    17.  
    In the pixel shader:

    Code (csharp):
    1.  
    2. // make some mildly random uv coords
    3. float2 worldUVx = worldPos.zy * _Tiling.xy * 1.17;
    4. float2 worldUVy = worldPos.xz * _Tiling.xy * 1.37;
    5. float2 worldUVz = worldPos.xy * _Tiling.xy;
    6.  
    7. // sample normal maps
    8. half4 worldNormalX= UnpackNormal( tex2D(_BumpTex,worldUVx) );
    9. half4 worldNormalY= UnpackNormal( tex2D(_BumpTex,worldUVy) );
    10. half4 worldNormalZ= UnpackNormal( tex2D(_BumpTex,worldUVz) );
    11.  
    12. // flip x on opposite side of mapping
    13. worldNormalX.x *= ( step( worldNormal.x, 0 ) * 2 - 1 );
    14. worldNormalY.x *= ( step( worldNormal.y, 0 ) * 2 - 1 );
    15. worldNormalZ.x *= -( step( worldNormal.z, 0 ) * 2 - 1 );
    16.  
    17. // the vertex normal that unity always passes in
    18. float3 vertWorldNormal = float3( IN.tSpace0.z, IN.tSpace1.z, IN.tSpace2.z );
    19.  
    20. // convert normals to world space
    21. worldNormalX = ( worldNormalX.x * IN.tSpaceXZ.xyz ) + ( worldNormalX.y * IN.bSpaceXZ.xyz ) + ( worldNormalX.z * vertWorldNormal );
    22. worldNormalY = ( worldNormalY.x * IN.tSpaceY.xyz ) + ( worldNormalY.y * IN.bSpaceY.xyz ) + ( worldNormalY.z * vertWorldNormal );
    23. worldNormalZ = ( worldNormalZ.x * IN.tSpaceXZ.xyz ) + ( worldNormalZ.y * IN.bSpaceXZ.xyz ) + ( worldNormalZ.z * vertWorldNormal );
    24.  
    now you should have 3 normal maps facing the correct direcection.