1
\$\begingroup\$

I'm trying to make a custom GPU particle solution on Unity to fullfill some needs on my project, using compute shaders and custom shader + Graphics.DrawProceduralNow() to draw them.

While I managed to make the system, I'm struggling making the particles cylindrical billboards and align them to their velocity axis as I'm not really used to work with matrices.

I achieved to make both effect working individually (using usefull ressources on the forum) but I can't manage to combine the two rotations without obtaining wrong results

enter image description here enter image description here

v2f vert(uint id : SV_VertexID, uint inst : SV_InstanceID)
{
    v2f o;

    //Vertex position
    float3 q = quad[id];

    float3 newPos = q * particles[inst].size * _SizeMul;


    //PARTICLE DIRECTION

    float3 particleDirection = normalize(particles[inst].velocity);

    float3x3 rotMatrix;

    float3 xaxis = cross(float3(0,0,1), particleDirection);
    xaxis = normalize(xaxis);

    float3 zaxis = cross(xaxis, particleDirection);
    zaxis = normalize(zaxis);

    //Matrix for particle direction
    rotMatrix[0].xyz = float3(xaxis.x, particleDirection.x, zaxis.x);
    rotMatrix[1].xyz = float3(xaxis.y, particleDirection.y, zaxis.y);
    rotMatrix[2].xyz = float3(xaxis.z, particleDirection.z, zaxis.z);

    newPos = mul(rotMatrix, newPos);




    //CYLINDRICAL BILLBOARDING

    // Distance between the camera and the center
    float3 dist = _WorldSpaceCameraPos - particles[inst].position;

    // With atan the tree inverts when the camera has the same z position
    float angle = atan2(dist.x, dist.z);

    float cosinus = cos(angle);
    float sinus = sin(angle);

    // Matrix for billboarding
    rotMatrix[0].xyz = float3(cosinus, 0, sinus);
    rotMatrix[1].xyz = float3(0, 1, 0);
    rotMatrix[2].xyz = float3(- sinus, 0, cosinus);

    newPos = mul(rotMatrix, newPos);



    newPos += particles[inst].position;

    o.pos = mul(UNITY_MATRIX_VP, float4(newPos.xyz,1));

    o.uv = q + 0.5f;

    o.col = particles[inst].alive * particles[inst].color;

    return o;

}

Another way to say it is i would like Y to point toward the velocity direction and then rotate the quad around it's new Y axis to make the billboard point at best toward camera.

Any help would be much appreciated and any other approach for cylindrical billboarding that would work once quad is aligned to velocity vector would be welcomed too. Have a good day!

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Finally got it right ! Got it by trying to learn more about those matrices. I needed to use the direction vector between particle position and camera as a forward vector

Here's the code for those who need it.

float3 q = quad[id];

float3 newPos = q * particles[inst].size * _SizeMul;

float3 particleDirection = normalize(particles[inst].velocity);

float3 cameraDir = normalize(particles[inst].position - _WorldSpaceCameraPos);


float3x3 rotMatrix;

float3 xaxis = cross(cameraDir, particleDirection);
xaxis = normalize(xaxis);

float3 zaxis = cross(xaxis, particleDirection);
zaxis = normalize(zaxis);


rotMatrix[0].xyz = float3(xaxis.x, particleDirection.x, zaxis.x);
rotMatrix[1].xyz = float3(xaxis.y, particleDirection.y, zaxis.y);
rotMatrix[2].xyz = float3(xaxis.z, particleDirection.z, zaxis.z);

newPos = mul(rotMatrix, newPos);      

newPos += particles[inst].position;

o.pos = mul(UNITY_MATRIX_VP, float4(newPos.xyz,1));

o.uv = q + 0.5f;

o.col = particles[inst].alive * particles[inst].color;

return o;
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .