Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Triplanar Shader Working With Floating Origin?

Discussion in 'Shaders' started by melgeorgiou, Apr 14, 2021.

  1. melgeorgiou

    melgeorgiou

    Joined:
    Nov 3, 2012
    Posts:
    770
    Hi everyone,

    Firstly, I have limited experience with shaders, lol. However, I've been experimenting with a basic triplanar surface shader ( based on the github example by @bgolus ) to play nice with a modified "FloatingOrigin" script.

    There are two issues I'm trying to solve:
    1) I want to use the shader inside moving objects ( for example inside a vehicle ). The triplanar shader's UVs currently keep moving along with the vehicle as I move around which is obviously not great.
    2) I'm pretty sure that whenever the FloatingOrigin script updates ( by moving the scene so the camera is at the origin ), it is causing yet another offset in the shader as well.

    Dynamic Origin Global Vector

    My initial thoughts on fixing the issue was making a global float named "_DynamicOrigin" that is updated every time the floating origin script updates (stored internally as doubles for extra precision and then applied into the shader as a float4 ).

    My thinking is I could potentially use this to help with the offsets somehow. The relevant code for that, looks like this:

    Code (CSharp):
    1.             // Calculate the difference
    2.             originDistanceX -= cameraPosition.x;
    3.             originDistanceY -= cameraPosition.y;
    4.             originDistanceZ -= cameraPosition.z;
    5.  
    6.             // Update the global shader keyword ( _DynamicOrigin )
    7.             shaderV4.x = (float)originDistanceX;
    8.             shaderV4.y = (float)originDistanceY;
    9.             shaderV4.z = (float)originDistanceZ;
    10.             Shader.SetGlobalVector( _DynamicOriginShaderGlobalVectorName_ID, shaderV4 );

    And here's the current shader:


    Code (CSharp):
    1. Shader "Custom/Triplanar Tests (Basic)" {
    2.     Properties {
    3.  
    4.         _Color ("Color", Color) = (1,1,1,1)
    5.         [NoScaleOffset] _MainTex ("Albedo (RGB)", 2D) = "white" {}
    6.         _TriplanarScale("Triplanar Scale", float ) = 1
    7.  
    8.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    9.         _Metallic ("Metallic", Range(0,1)) = 0.0
    10.     }
    11.  
    12.     SubShader {
    13.  
    14.         Tags {
    15.             "RenderType"="Opaque"
    16.         }
    17.         LOD 200
    18.  
    19.         CGPROGRAM
    20.  
    21.         // Physically based Standard lighting model, and enable shadows on all light types
    22.         #pragma surface surf Standard  fullforwardshadows vertex:vert
    23.  
    24.         // Use shader model 3.0 target, to get nicer looking lighting
    25.         #pragma target 3.0
    26.  
    27.         // flip UVs horizontally to correct for back side projection
    28.         #define TRIPLANAR_CORRECT_PROJECTED_U
    29.  
    30.         // offset UVs to prevent obvious mirroring
    31.         //#define TRIPLANAR_UV_OFFSET
    32.  
    33.         // Apply Dynamic Origin Offsets
    34.         #define USE_DYNAMIC_ORIGIN
    35.  
    36.         sampler2D _MainTex;
    37.         float4 _MainTex_ST;
    38.         float _TriplanarScale;
    39.  
    40.  
    41.         half _Glossiness;
    42.         half _Metallic;
    43.         fixed4 _Color;
    44.  
    45.         // GLOBAL VECTOR4 Set by FloatingOrigin.cs
    46.         float4 _DynamicOrigin;  
    47.  
    48.  
    49.         struct Input {
    50.  
    51.             float3 position;
    52.             float3 worldPos;
    53.             float3 worldNormal;
    54.             INTERNAL_DATA
    55.  
    56.         };
    57.  
    58.         // ========================================================================
    59.         //    VERTEX FUNCTION
    60.         // ========================================================================
    61.  
    62.         void vert ( inout appdata_full v, out Input o ){
    63.  
    64.             UNITY_INITIALIZE_OUTPUT(Input,o);
    65.  
    66.         }
    67.  
    68.  
    69.         // ========================================================================
    70.         //    SURFACE FUNCTION
    71.         // ========================================================================
    72.  
    73.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    74.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    75.         // #pragma instancing_options assumeuniformscaling
    76.         UNITY_INSTANCING_BUFFER_START(Props)
    77.             // put more per-instance properties here
    78.         UNITY_INSTANCING_BUFFER_END(Props)
    79.  
    80.         void surf (Input IN, inout SurfaceOutputStandard o) {
    81.  
    82.             // BUGFIX: Work around bug where IN.worldNormal is always (0,0,0)!
    83.             IN.worldNormal = WorldNormalVector( IN, o.Normal );
    84.  
    85.             // Calculate triplanar blend
    86.             half3 triblend = saturate( pow( IN.worldNormal, 4 ));
    87.             triblend /= max( dot( triblend, half3(1,1,1) ), 0.0001);
    88.  
    89.             // Calculate Triplanar UVs
    90.             #if defined( USE_DYNAMIC_ORIGIN )
    91.  
    92.                 // ISSUES HERE: Not sure how to apply the _DynamicOrigin correctly ...
    93.                 float2 uvX = (IN.worldPos.zy * _TriplanarScale) - _DynamicOrigin.zy;
    94.                 float2 uvY = (IN.worldPos.xz * _TriplanarScale) - _DynamicOrigin.xz;
    95.                 float2 uvZ = (IN.worldPos.xy * _TriplanarScale) - _DynamicOrigin.xy;
    96.          
    97.             #else
    98.              
    99.                 float2 uvX = IN.worldPos.zy * _TriplanarScale;
    100.                 float2 uvY = IN.worldPos.xz * _TriplanarScale;
    101.                 float2 uvZ = IN.worldPos.xy * _TriplanarScale;
    102.  
    103.             #endif
    104.  
    105.          
    106.             // offset UVs to prevent obvious mirroring
    107.             #if defined(TRIPLANAR_UV_OFFSET)
    108.                 uvY += 0.33;
    109.                 uvZ += 0.67;
    110.             #endif
    111.  
    112.             // minor optimization of sign(). prevents return value of 0
    113.             half3 axisSign = IN.worldNormal < 0 ? -1 : 1;
    114.          
    115.             // flip UVs horizontally to correct for back side projection
    116.             #if defined(TRIPLANAR_CORRECT_PROJECTED_U)
    117.                 uvX.x *= axisSign.x;
    118.                 uvY.x *= axisSign.y;
    119.                 uvZ.x *= -axisSign.z;
    120.             #endif
    121.  
    122.  
    123.             // Albedo textures
    124.             fixed4 colX = tex2D(_MainTex, uvX);
    125.             fixed4 colY = tex2D(_MainTex, uvY);
    126.             fixed4 colZ = tex2D(_MainTex, uvZ);
    127.             fixed4 c = colX * triblend.x + colY * triblend.y + colZ * triblend.z;
    128.  
    129.  
    130.             // Standard Lighting
    131.             o.Albedo = c.rgb;
    132.             o.Metallic = _Metallic;
    133.             o.Smoothness = _Glossiness;
    134.             o.Alpha = c.a;
    135.          
    136.         }
    137.         ENDCG
    138.     }
    139.     FallBack "Diffuse"
    140. }
    141.  

    If anyone has any ideas on how to solve / improve this that would be great! :)

    Thanks!
     
  2. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    For moving objects, you need to use local vertex positions instead of world positions to calculate the UVs.
     
  3. melgeorgiou

    melgeorgiou

    Joined:
    Nov 3, 2012
    Posts:
    770
    Hi @KokkuHub ,

    Does that rule out triplanar for moving objects?
     
  4. melgeorgiou

    melgeorgiou

    Joined:
    Nov 3, 2012
    Posts:
    770
    UPDATE: My bad, just found some examples for local-space triplanar shaders and this seems to solve the entire problem, lol. Thanks! :)