Rotate billboard in geometry-shader

Started by
1 comment, last by Juliean 9 years, 11 months ago

Hello,

is it possible to rotate a camera-oriented billboard that is created in a geometry-shader around the look-axis by a certain angle, given that the angle input is only a floating value, not an entire rotation matrix? I'm using this for a particle-cloud-renderer. This is the shader-body I'm using, its written in my own shader language, the code uses HLSL-instrincts though, so I hope everbody is able to understand it (the geometryShader-main is the interesting part though):


 vertexShader
{
    in
    {
        float vPosition;
        float3 vTranslation;
        float scale;
        float rotation;
        float type;
    }
    
    out
    {
        float4 vPosition;
        float scale;
        float rotation;
        float type;
    }
    
    main
    {
        out.vPosition.xyz = in.vTranslation;
        out.scale = in.scale;
        out.rotation = in.rotation;
        out.type = in.type;
    }
}

geometryShader
{
    input Stage
    {
        matrix mViewProj;
        float3 vCameraPos;
        float3 vCameraUp;
    }
    
    out
    {
        float4 vPosition;
        float2 vTexture;
    }
    
    primitives
    {
        in: point[1];
        out: triangle[4];
    }
    
    main
    {    
        // choose texture from atlas
        float2 vIndex = float2(fmod(in[0].type, 4.0f), floor(in[0].type / 4.0f));
        float2 texCoord[4];
        float texSize = 0.25f;
        float4 vTexCoords = float4(vIndex.x * texSize, vIndex.y * texSize, (vIndex.x + 1) * texSize, (vIndex.y + 1) * texSize);
        texCoord[0] = float2(vTexCoords.x, vTexCoords.w);
        texCoord[1] = float2(vTexCoords.z, vTexCoords.w);
        texCoord[2] = float2(vTexCoords.x, vTexCoords.y);
        texCoord[3] = float2(vTexCoords.z, vTexCoords.y);

        // create orientation vectors
        float3 vPlaneNormal = normalize(in[0].vPosition.xyz - vCameraPos);
        float3 vRight = normalize(cross(vPlaneNormal, vCameraUp));
        float3 vUp = normalize(cross(vRight, vPlaneNormal));
        
        vRight *= in[0].scale;
        vRight *= 0.5f;
    
        vUp *= in[0].scale;
        vUp *= 0.5f;
        
        // TODO: use in[0].angle to rotate the quad around vPlaneNormal
        
        // setup vertices
        float3 vVerts[4];
        vVerts[0] = in[0].vPosition.xyz - vRight - vUp; // Get bottom left vertex
        vVerts[1] = in[0].vPosition.xyz + vRight - vUp; // Get bottom right vertex
        vVerts[2] = in[0].vPosition.xyz - vRight + vUp; // Get top left vertex
        vVerts[3] = in[0].vPosition.xyz + vRight + vUp; // Get top right vertex
        
        for(int i = 0; i < 4; i++)
        {
            out.vPosition = mul(float4(vVerts[i], 1.0f), mViewProj);
                
            out.vTexture = texCoord[i];
            Append();
        }
    }
}

I figured that I could use trigonometric functions to add a certain amount of the right and up-vector to achieve the rotation, however I'm kind of stuck in the execution. Can somebody help me on this? Any drawing, explanation, or preferably pseudo-code would be quite nice.

Advertisement
vRight and vUp are orthogonal and of the same length, so you can use the 2D rotation, locally that is:


float s, c;
sincos(in[0].rotation, s, c); 
float3 vUpNew    = c * vRight - s * vUp;
float3 vRightNew = s * vRight + c * vUp;
Use these new values for the subsequent point expansion.

PS: Haven't checked this, but that should be the gist of it.

PPS: Small check. Not actually billboards, but the rotation works.

Works like a charm, thanks!

This topic is closed to new replies.

Advertisement