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

Standard Surface Shader - Billboard

Discussion in 'Shaders' started by Ladder14, Jan 17, 2018.

  1. Ladder14

    Ladder14

    Joined:
    Nov 8, 2016
    Posts:
    6
    Hello, in shaders I do not really care. I wanted to transfer the Billboard code from the Unlit shader to the standard shader. But he stopped watching the camera. In Unlit, everything is fine. Help to understand what the problem is. Added the tag "DisableBatching" = "True" - did not help (

    GIF.gif

    Code (csharp):
    1.  
    2. Shader "TestShader/Billboard" {
    3.         Properties {
    4.                 _Color ("Color", Color) = (1,1,1,1)
    5.                 _MainTex ("Albedo (RGB)", 2D) = "white" {}
    6.                 _Glossiness ("Smoothness", Range(0,1)) = 0.5
    7.                 _Metallic ("Metallic", Range(0,1)) = 0.0
    8.         }
    9.         SubShader {
    10.                 Tags { "RenderType"="Opaque" }
    11.                 LOD 200
    12.              
    13.                 CGPROGRAM
    14.                 // Physically based Standard lighting model, and enable shadows on all light types
    15.                 #pragma surface surf Standard fullforwardshadows
    16.                 #pragma vertex vert
    17.                 // Use shader model 3.0 target, to get nicer looking lighting
    18.                 #pragma target 3.0
    19.                 #include "UnityCG.cginc"
    20.                 sampler2D _MainTex;
    21.  
    22.                 struct Input {
    23.                         float2 uv_MainTex;
    24.                 };
    25.  
    26.                 struct v2f
    27.                 {
    28.                         float4 pos : SV_POSITION;
    29.                         float2 uv : TEXCOORD0;
    30.                 };
    31.  
    32.                 half _Glossiness;
    33.                 half _Metallic;
    34.                 fixed4 _Color;
    35.                 float4 vv;
    36.  
    37.  
    38.                 void surf (Input IN, inout SurfaceOutputStandard o) {
    39.                         // Albedo comes from a texture tinted by color
    40.                         fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    41.                         o.Albedo = c.rgb;
    42.                         // Metallic and smoothness come from slider variables
    43.                         o.Metallic = _Metallic;
    44.                         o.Smoothness = _Glossiness;
    45.                         o.Alpha = c.a;
    46.                 }
    47.  
    48.  
    49.  
    50.                 v2f vert(inout appdata_full v) {
    51.  
    52.                         v2f o;
    53.                         float4 ori = mul(UNITY_MATRIX_MV, float4(0, 0, 0, 0));
    54.                         float4 vt = v.vertex;
    55.                         vt.y = vt.z;
    56.                         vt.z = 0;
    57.                         vt.xyz += ori.xyz;//result is vt.z==ori.z ,so the distance to camera keeped ,and screen size keeped
    58.                         o.pos = mul(UNITY_MATRIX_P, vt);
    59.                         v.vertex = o.pos;
    60.                         //o.uv = v.uv;
    61.                         return o;
    62.  
    63.                 }
    64.  
    65.  
    66.                 ENDCG
    67.         }
    68.         FallBack "Diffuse"
    69. }
    70.  
     
    Last edited: Jan 17, 2018
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    The vert function of a Surface Shader isn't like the vert function of a vertex & fragment shader.

    In a vertex & fragment shader the vertex function is outputting the final clip space position. In a Surface Shader the vertex function is used to modify the object space mesh data before it gets transformed into clip space.

    You're also mixing #pragma lines from a Surface Shader and a vertex & fragment shader. You can't define a vertex function using #pragma vertex vert in a Surface Shader, you need to define it in the #pragma surface line.

    See the Surface Shader examples page for an example of a properly setup vertex function. Look for "Normal Extrusion with Vertex Modifier".
    https://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html

    The short version is you want your #pragma surface line to look like this:
    #pragma surface surf Standard vertex:vert fullforwardshadows

    Then you should be able to copy this vert function into your shader and have it work (it's the first thing that comes up from a google search for "unity billboard surface shader").
    https://gist.github.com/renaudbedard/7a90ec4a5a7359712202
     
    Destriarch likes this.
  3. Ladder14

    Ladder14

    Joined:
    Nov 8, 2016
    Posts:
    6
    bgolus many Thanks!

    Already something like that.

    GIF2.gif

    Code (CSharp):
    1. Shader "TestShader/Billboard" {
    2.     Properties {
    3.         _Color ("Color", Color) = (1,1,1,1)
    4.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    5.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    6.         _Metallic ("Metallic", Range(0,1)) = 0.0
    7.     }
    8.     SubShader {
    9.         Tags { "RenderType"="Opaque" "DisableBatching"="True" }
    10.         LOD 200
    11.        
    12.         CGPROGRAM
    13.         // Physically based Standard lighting model, and enable shadows on all light types
    14.         #pragma surface surf Standard fullforwardshadows vertex:vert
    15.    
    16.  
    17.         // Use shader model 3.0 target, to get nicer looking lighting
    18.  
    19.         sampler2D _MainTex;
    20.  
    21.         struct Input {
    22.             float2 uv_MainTex;
    23.             float3 customColor;
    24.         };
    25.  
    26.  
    27.  
    28.         half _Glossiness;
    29.         half _Metallic;
    30.         fixed4 _Color;
    31.  
    32.  
    33.  
    34.         void surf (Input IN, inout SurfaceOutputStandard o) {
    35.             // Albedo comes from a texture tinted by color
    36.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    37.             o.Albedo = c.rgb;
    38.             // Metallic and smoothness come from slider variables
    39.             o.Metallic = _Metallic;
    40.             o.Smoothness = _Glossiness;
    41.             o.Alpha = c.a;
    42.         }
    43.  
    44.  
    45.         void vert(inout appdata_full v, out Input o)
    46.         //void vert(inout appdata_full v)
    47.         {
    48.             UNITY_INITIALIZE_OUTPUT(Input, o);
    49.  
    50.             // get the camera basis vectors
    51.             float3 forward = -normalize(UNITY_MATRIX_V._m20_m21_m22);
    52.             float3 up = float3(0, 1, 0); //normalize(UNITY_MATRIX_V._m10_m11_m12);
    53.             float3 right = normalize(UNITY_MATRIX_V._m00_m01_m02);
    54.  
    55.             // rotate to face camera
    56.             float4x4 rotationMatrix = float4x4(right, 0,
    57.                 up, 0,
    58.                 forward, 0,
    59.                 0, 0, 0, 1);
    60.  
    61.             //float offset = _Object2World._m22 / 2;
    62.             float offset = 0;
    63.             v.vertex = mul(v.vertex + float4(0, offset, 0, 0), rotationMatrix) + float4(0, -offset, 0, 0);
    64.             v.normal = mul(v.normal, rotationMatrix);
    65.         }
    66.         ENDCG
    67.     }
    68.     FallBack "Diffuse"
    69. }

     
  4. Ladder14

    Ladder14

    Joined:
    Nov 8, 2016
    Posts:
    6
    Please help, I can not deal with the shader :(
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Your shader works for me as I would expect, assuming the mesh in use is the default quad, the game object's rotation is zeroed out in world space, and your view isn't upside down.

    However that billboard code is specifically for vertically aligned quads so they only rotate around world Y which is a little different than your original shader's billboard code which would have aligned to the camera regardless of the view. If you change your shader on line 52 from the up = float3(0, 1, 0) to the commented out line after it, ie:
    float3 up = normalize(UNITY_MATRIX_V._m10_m11_m12);

    That should make it face the camera regardless of the orientation of the camera. However it doesn't fix the issue of the object needing to have no rotation to work. That takes a bit more work.

    Code (CSharp):
    1. Shader "TestShader/Billboard" {
    2.     Properties {
    3.         _Color ("Color", Color) = (1,1,1,1)
    4.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    5.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    6.         _Metallic ("Metallic", Range(0,1)) = 0.0
    7.     }
    8.     SubShader {
    9.         Tags { "Queue"="Transparent" "RenderType"="Transparent" "DisableBatching"="True" }
    10.         LOD 200
    11.    
    12.         CGPROGRAM
    13.         #pragma surface surf Standard fullforwardshadows vertex:vert alpha:fade
    14.  
    15.         sampler2D _MainTex;
    16.         struct Input {
    17.             float2 uv_MainTex;
    18.         };
    19.         half _Glossiness;
    20.         half _Metallic;
    21.         fixed4 _Color;
    22.  
    23.         void vert(inout appdata_full v, out Input o)
    24.         {
    25.             UNITY_INITIALIZE_OUTPUT(Input, o);
    26.  
    27.             // apply object scale
    28.             v.vertex.xy *= float2(length(unity_ObjectToWorld._m00_m10_m20), length(unity_ObjectToWorld._m01_m11_m21));
    29.  
    30.             // get the camera basis vectors
    31.             float3 forward = -normalize(UNITY_MATRIX_V._m20_m21_m22);
    32.             float3 up = normalize(UNITY_MATRIX_V._m10_m11_m12);
    33.             float3 right = normalize(UNITY_MATRIX_V._m00_m01_m02);
    34.  
    35.             // rotate to face camera
    36.             float4x4 rotationMatrix = float4x4(right, 0,
    37.                 up, 0,
    38.                 forward, 0,
    39.                 0, 0, 0, 1);
    40.             v.vertex = mul(v.vertex, rotationMatrix);
    41.             v.normal = mul(v.normal, rotationMatrix);
    42.  
    43.             // undo object to world transform surface shader will apply
    44.             v.vertex.xyz = mul((float3x3)unity_WorldToObject, v.vertex.xyz);
    45.             v.normal = mul(v.normal, (float3x3)unity_ObjectToWorld);
    46.         }
    47.  
    48.         void surf (Input IN, inout SurfaceOutputStandard o) {
    49.             // Albedo comes from a texture tinted by color
    50.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    51.             o.Albedo = c.rgb;
    52.             // Metallic and smoothness come from slider variables
    53.             o.Metallic = _Metallic;
    54.             o.Smoothness = _Glossiness;
    55.             o.Alpha = c.a;
    56.         }
    57.         ENDCG
    58.     }
    59.     FallBack "Transparent/VertexLit"
    60. }
     
  6. Ladder14

    Ladder14

    Joined:
    Nov 8, 2016
    Posts:
    6
    bgolus Thank you very much, with your help everything worked!

    GIF3.gif
     
    AntohaRDNS likes this.
  7. StevenGerrard

    StevenGerrard

    Joined:
    Jun 1, 2015
    Posts:
    97
    this is great.
    recommend use billboard to sectional replace particle system ( it is too heavy when your game is performance critical )
     
  8. Destriarch

    Destriarch

    Joined:
    Feb 18, 2020
    Posts:
    4
    Thanks for this, I spent AGES looking for a billboard surface shader tutorial and still didn't find the one linked above.