Search Unity

meta pass & world space data

Discussion in 'Shaders' started by drago_, Jan 20, 2017.

  1. drago_

    drago_

    Joined:
    Jan 20, 2017
    Posts:
    1
    Hi,

    I'm making custom shader with dynamic light emission and encountered problems with meta pass not taking into account world space data, neither its own mesh nor data passed from a script.

    Here is very basic example.
    Create Unity built-in Standard shader and add emission to be taken from the object 'worldPos'
    Code (CSharp):
    1. Shader "Custom/Meta_Standard"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic ("Metallic", Range(0,1)) = 0.0
    9.      
    10.  
    11.         _Emission("Emission", float) = 1
    12.     }
    13.  
    14.     SubShader
    15.     {
    16.         Tags { "RenderType"="Opaque" }
    17.         LOD 200
    18.      
    19.         CGPROGRAM
    20.         // Physically based Standard lighting model, and enable shadows on all light types
    21.         #pragma surface surf Standard fullforwardshadows
    22.  
    23.         // Use shader model 3.0 target, to get nicer looking lighting
    24.         #pragma target 3.0
    25.  
    26.         sampler2D _MainTex;
    27.  
    28.         struct Input
    29.         {
    30.             float2 uv_MainTex;
    31.             float3 worldPos;
    32.         };
    33.  
    34.         half _Glossiness;
    35.         half _Metallic;
    36.         fixed4 _Color;
    37.         float _Emission;
    38.  
    39.         void surf (Input IN, inout SurfaceOutputStandard o)
    40.         {
    41.             // Albedo comes from a texture tinted by color
    42.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    43.             o.Albedo = c.rgb;
    44.             // Metallic and smoothness come from slider variables
    45.             o.Metallic = _Metallic;
    46.             o.Smoothness = _Glossiness;
    47.             o.Alpha = c.a;
    48.  
    49.  
    50.             o.Emission = IN.worldPos * _Emission;
    51.         }
    52.         ENDCG
    53.     }
    54.     FallBack "Diffuse"
    55. }
    56.  
    And the result is this:
    meta.png
    All spheres emit same color, even those that are in completely negative coordinates and must have 0 emission.


    Same result if writing custom meta pass. Everything here is calculated in light-map space.
    Code (CSharp):
    1.         Pass
    2.         {
    3.             Name "META"
    4.             Tags { "LightMode"="Meta" }
    5.  
    6.             CGPROGRAM
    7.             #pragma vertex vert
    8.             #pragma fragment frag
    9.  
    10.             #define UNITY_PASS_META
    11.             #include "UnityCG.cginc"
    12.             #include "UnityMetaPass.cginc"
    13.  
    14.  
    15.  
    16.             float _Emission;
    17.  
    18.             struct appdata
    19.             {
    20.                 float4 vertex : POSITION;
    21.                 float2 texcoord1 : TEXCOORD0;
    22.                 float2 texcoord2 : TEXCOORD1;
    23.             };
    24.  
    25.             struct v2f
    26.             {
    27.                 float4 vertex : SV_POSITION;
    28.                 float3 worldPos : TEXCOORD0;
    29.             };
    30.  
    31.             float4 MetaVertexPosition(float4 vertex, float2 uv1, float2 uv2, float4 lightmapST, float4 dynlightmapST)
    32.             {
    33.                 if (unity_MetaVertexControl.x)
    34.                 {
    35.                     vertex.xy = uv1 * lightmapST.xy + lightmapST.zw;
    36.                     // OpenGL right now needs to actually use incoming vertex position,
    37.                     // so use it in a very dummy way
    38.                     vertex.z = vertex.z > 0 ? 1.0e-4f : 0.0f;
    39.                 }
    40.                 if (unity_MetaVertexControl.y)
    41.                 {
    42.                     vertex.xy = uv2 * dynlightmapST.xy + dynlightmapST.zw;
    43.                     // OpenGL right now needs to actually use incoming vertex position,
    44.                     // so use it in a very dummy way
    45.                     vertex.z = vertex.z > 0 ? 1.0e-4f : 0.0f;
    46.                 }
    47.                 return vertex;
    48.             }
    49.          
    50.             v2f vert (appdata IN)
    51.             {
    52.                 v2f o;
    53.  
    54.                 float4 vertex = MetaVertexPosition(IN.vertex, IN.texcoord1.xy, IN.texcoord2.xy, unity_LightmapST, unity_DynamicLightmapST);
    55.                 o.vertex = UnityObjectToClipPos(vertex);
    56.              
    57.                 o.worldPos = mul(unity_ObjectToWorld, IN.vertex);
    58.                 //o.worldPos = mul(unity_ObjectToWorld, vertex);
    59.              
    60.                 return o;
    61.             }
    62.          
    63.             fixed4 frag (v2f i) : SV_Target
    64.             {
    65.                 fixed4 c = fixed4(i.worldPos, 1);
    66.  
    67.  
    68.  
    69.                 UnityMetaInput metaIN;
    70.  
    71.                 UNITY_INITIALIZE_OUTPUT(UnityMetaInput, metaIN);
    72.                 metaIN.Albedo = c.rgb;
    73.                 metaIN.Emission = c.rgb * _Emission;
    74.                 return UnityMetaFragment(metaIN);
    75.             }
    76.             ENDCG
    77.         }
    78.  
    Even if I first take vertex position from light-map space and then transforming it into world space (line 58), results are always wrong.


    Above example is very simple, beside mesh worldPos I have to find solution to work with non-mesh data inside meta pass, like camera world space position and other info that is passed from script.

    So, how do I supply meta pass with world space data?
     
  2. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    826
    Hm, your shader seems to do what you're telling it to do, but the range of the world position from 0 to 1 is quite small. I added a tiling size and let it tile just to see the effect everywhere. Here is the modified shader:
    Code (CSharp):
    1. Shader "Custom/Meta_Standard"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color", Color) = (1,1,1,1)
    6.         _MainTex("Albedo (RGB)", 2D) = "white" {}
    7.     _Glossiness("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic("Metallic", Range(0,1)) = 0.0
    9.  
    10.         _EmissionTiling("EmissionTiling", Range(0.1, 20)) = 10
    11.         _Emission("Emission", float) = 1
    12.     }
    13.  
    14.         SubShader
    15.     {
    16.         Tags{ "RenderType" = "Opaque" }
    17.         LOD 200
    18.  
    19.         CGPROGRAM
    20.         // Physically based Standard lighting model, and enable shadows on all light types
    21. #pragma surface surf Standard fullforwardshadows
    22.  
    23.         // Use shader model 3.0 target, to get nicer looking lighting
    24. #pragma target 3.0
    25.  
    26.         sampler2D _MainTex;
    27.  
    28.     struct Input
    29.     {
    30.         float2 uv_MainTex;
    31.         float3 worldPos;
    32.     };
    33.  
    34.     half _Glossiness;
    35.     half _Metallic;
    36.     fixed4 _Color;
    37.     fixed _Emission;
    38.     half _EmissionTiling;
    39.  
    40.     void surf(Input IN, inout SurfaceOutputStandard o)
    41.     {
    42.         // Albedo comes from a texture tinted by color
    43.         fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    44.         o.Albedo = c.rgb;
    45.         // Metallic and smoothness come from slider variables
    46.         o.Metallic = _Metallic;
    47.         o.Smoothness = _Glossiness;
    48.         o.Alpha = c.a;
    49.  
    50.  
    51.         o.Emission = frac(IN.worldPos / _EmissionTiling) * _Emission;
    52.     }
    53.     ENDCG
    54.     }
    55.         FallBack "Diffuse"
    56. }
    And that's the result:
    upload_2017-1-20_13-51-26.png


    As for your second question: You can set values of a shader by either providing a property block or directly set vectors: https://docs.unity3d.com/ScriptReference/Shader.SetGlobalVector.html