Search Unity

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:
    43
    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
    Rotecks likes this.
  2. zachduer

    zachduer

    Joined:
    Nov 7, 2016
    Posts:
    2
    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:
    2
    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.
unityunity