Make billboard shader only rotate on one axis.

Hello,

I got a billboard shader from Cg Programming/Unity/Billboards - Wikibooks, open books for an open world
I adjusted it a little to work with the default plane and with textures having an alpha channel:

Shader "Cg  shader for billboards" {
   Properties {
      _MainTex ("Billboard Image", 2D) = "white" {}
   }
   SubShader {

      Tags {"Queue"="Transparent" "RenderType"="Transparent"}
      Blend SrcAlpha OneMinusSrcAlpha

      Pass { 
         CGPROGRAM

         // compilation directives
         #pragma vertex vert  // tells that the code contains a vertex program in the given function (vert here).
         #pragma fragment frag // tells that the code contains a fragment program in the given function (frag here).

         // User-specified uniforms          
         uniform sampler2D _MainTex; // define variable in order to have access to the property.
         struct vertexInput {
            float4 vertex : POSITION; // position in local space
            float4 tex : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION; // position after being transformed into projection space
            float4 tex : TEXCOORD0;
         };
         vertexOutput vert(vertexInput input)
         {
            vertexOutput output;

             float4 camDir = mul(UNITY_MATRIX_P,
              mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
              - float4(input.vertex.x, input.vertex.z, 0.0, 0.0));

            output.pos = camDir;
            output.tex = input.tex;

            return output;
         }
         float4 frag(vertexOutput input) : COLOR
         {
            return tex2D(_MainTex, float2(input.tex.xy)); 
         }
         ENDCG
      }
   }
}

This shader rotates the billboard in all directions (on all axes). I’m new to shader programming (like you can see from the comments :slight_smile: ) 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.

1 Like

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?

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

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:

vertexOutput vert(vertexInput input)
         {
            vertexOutput output;

            float4x4 modelView = UNITY_MATRIX_MV;

            modelView[0][0] = 1;
            modelView[0][1] = 0;
            modelView[0][2] = 0;
     
            // uncomment for working spherical billboarding
            //modelView[1][0] = 0;
            //modelView[1][1] = 1;
            //modelView[1][2] = 0;

            modelView[2][0] = 0;
            modelView[2][1] = 0;
            modelView[2][2] = 1;

            float4 P = mul(modelView, input.vertex * float4(_ScaleX, _ScaleY, 1.0, 1.0));
          
            output.pos = mul(UNITY_MATRIX_P, P);

            // alternate method for spherical billboarding, working
            //output.pos = mul( UNITY_MATRIX_P,
            //mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
            //- float4(input.vertex.x, input.vertex.y, 0.0, 0.0)
            //* float4(_ScaleX, _ScaleY, 1.0, 1.0));

            output.color = input.color * _Color;
            output.tex = input.tex;

            return output;
         }
2 Likes