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

Make billboard shader only rotate on one axis.

Discussion in 'Shaders' started by McGravity, Aug 23, 2016.

  1. McGravity

    McGravity

    Joined:
    Nov 2, 2013
    Posts:
    60
    Hello,

    I got a billboard shader from https://en.wikibooks.org/wiki/Cg_Programming/Unity/Billboards
    I adjusted it a little to work with the default plane and with textures having an alpha channel:

    Code (CSharp):
    1. Shader "Cg  shader for billboards" {
    2.    Properties {
    3.       _MainTex ("Billboard Image", 2D) = "white" {}
    4.    }
    5.    SubShader {
    6.  
    7.       Tags {"Queue"="Transparent" "RenderType"="Transparent"}
    8.       Blend SrcAlpha OneMinusSrcAlpha
    9.  
    10.       Pass {
    11.          CGPROGRAM
    12.  
    13.          // compilation directives
    14.          #pragma vertex vert  // tells that the code contains a vertex program in the given function (vert here).
    15.          #pragma fragment frag // tells that the code contains a fragment program in the given function (frag here).
    16.  
    17.          // User-specified uniforms          
    18.          uniform sampler2D _MainTex; // define variable in order to have access to the property.
    19.          struct vertexInput {
    20.             float4 vertex : POSITION; // position in local space
    21.             float4 tex : TEXCOORD0;
    22.          };
    23.          struct vertexOutput {
    24.             float4 pos : SV_POSITION; // position after being transformed into projection space
    25.             float4 tex : TEXCOORD0;
    26.          };
    27.          vertexOutput vert(vertexInput input)
    28.          {
    29.             vertexOutput output;
    30.  
    31.              float4 camDir = mul(UNITY_MATRIX_P,
    32.               mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
    33.               - float4(input.vertex.x, input.vertex.z, 0.0, 0.0));
    34.  
    35.             output.pos = camDir;
    36.             output.tex = input.tex;
    37.  
    38.             return output;
    39.          }
    40.          float4 frag(vertexOutput input) : COLOR
    41.          {
    42.             return tex2D(_MainTex, float2(input.tex.xy));
    43.          }
    44.          ENDCG
    45.       }
    46.    }
    47. }
    This shader rotates the billboard in all directions (on all axes). I'm new to shader programming (like you can see from the comments :) ) and don't know how to achive a rotation only on one axis. I'd like to have it only rotate on the global axis going up (y). Can you help me out?

    PS: I have seen this question a lot in the forums/answers but never with a solution.
     
    Last edited: Nov 17, 2016
    CGDever likes this.
  2. zachduer

    zachduer

    Joined:
    Nov 7, 2016
    Posts:
    9
    I also have this same exact question, arising from the same exact place as the OP. Does anyone know the matrix math to accomplish it?
     
  3. zachduer

    zachduer

    Joined:
    Nov 7, 2016
    Posts:
    9
    I do always attempt to solve my own problems, and I took a long hard shot at this one, but I'm still not sure what I'm doing wrong.

    This website
    http://www.geeks3d.com/20140807/billboarding-vertex-shader-glsl/
    shows how to do cylindrical billboarding. I attempted to copy it into HLSL. The spherical billboarding works perfectly! But the cylindrical billboarding squashes the mesh on one axis instead of preventing it from rotating.

    I'm wondering if I missed something in the conversion from GLSL to HLSL, since HLSL's * operator means something different than in GLSL, and I read somewhere HLSL matrices are row major, while in GLSL are column major, but I don't know if that affects what I'm doing or how to fix that in this circumstance.

    The relevant part of the code looks like this:
    Code (CSharp):
    1.  
    2. vertexOutput vert(vertexInput input)
    3.          {
    4.             vertexOutput output;
    5.  
    6.             float4x4 modelView = UNITY_MATRIX_MV;
    7.  
    8.             modelView[0][0] = 1;
    9.             modelView[0][1] = 0;
    10.             modelView[0][2] = 0;
    11.      
    12.             // uncomment for working spherical billboarding
    13.             //modelView[1][0] = 0;
    14.             //modelView[1][1] = 1;
    15.             //modelView[1][2] = 0;
    16.  
    17.             modelView[2][0] = 0;
    18.             modelView[2][1] = 0;
    19.             modelView[2][2] = 1;
    20.  
    21.             float4 P = mul(modelView, input.vertex * float4(_ScaleX, _ScaleY, 1.0, 1.0));
    22.          
    23.             output.pos = mul(UNITY_MATRIX_P, P);
    24.  
    25.             // alternate method for spherical billboarding, working
    26.             //output.pos = mul( UNITY_MATRIX_P,
    27.             //mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
    28.             //- float4(input.vertex.x, input.vertex.y, 0.0, 0.0)
    29.             //* float4(_ScaleX, _ScaleY, 1.0, 1.0));
    30.  
    31.             output.color = input.color * _Color;
    32.             output.tex = input.tex;
    33.  
    34.             return output;
    35.          }
     
    StaffanEk and McGravity like this.