Skip to main content
Returning transpose.
Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

This isn't as hard as it might seem.

We can simplify two of your arguments to one:

float3 viewDirection = target - source;

Then our strategy will be to cross the vertical axis and view direction to get a vector perpendicular to both (the right/sideways direction).

Next, we cross this with our vertical axis to complete the basis.

A rotation matrix is just a unit vector in each basis direction, so we can assign our vectors directly to the rows/columns of our matrix.

float3x3 AxisBillboard(float3 upAxis, float3 viewDirection) {
    float3 rightAxis = normalize(cross(upAxis, viewDirection));
    float3 forwardAxis = cross(rightAxis, upAxis);

    float3x3 result;
    result[0].xyz = rightAxis;
    result[1].xyz = upAxis;
    result[2].xyz = forwardAxis; 

    return transpose(result);
}

Some details can differ depending on the handedness of your coordinate system, or the multiplication convention you use (Matrix * vector or vector * Matrix), but this will get you within a sign flip or a transpose of the desired result.

This isn't as hard as it might seem.

We can simplify two of your arguments to one:

float3 viewDirection = target - source;

Then our strategy will be to cross the vertical axis and view direction to get a vector perpendicular to both (the right/sideways direction).

Next, we cross this with our vertical axis to complete the basis.

A rotation matrix is just a unit vector in each basis direction, so we can assign our vectors directly to the rows/columns of our matrix.

float3x3 AxisBillboard(float3 upAxis, float3 viewDirection) {
    float3 rightAxis = normalize(cross(upAxis, viewDirection));
    float3 forwardAxis = cross(rightAxis, upAxis);

    float3x3 result;
    result[0].xyz = rightAxis;
    result[1].xyz = upAxis;
    result[2].xyz = forwardAxis;
}

Some details can differ depending on the handedness of your coordinate system, or the multiplication convention you use (Matrix * vector or vector * Matrix), but this will get you within a sign flip or a transpose of the desired result.

This isn't as hard as it might seem.

We can simplify two of your arguments to one:

float3 viewDirection = target - source;

Then our strategy will be to cross the vertical axis and view direction to get a vector perpendicular to both (the right/sideways direction).

Next, we cross this with our vertical axis to complete the basis.

A rotation matrix is just a unit vector in each basis direction, so we can assign our vectors directly to the rows/columns of our matrix.

float3x3 AxisBillboard(float3 upAxis, float3 viewDirection) {
    float3 rightAxis = normalize(cross(upAxis, viewDirection));
    float3 forwardAxis = cross(rightAxis, upAxis);

    float3x3 result;
    result[0].xyz = rightAxis;
    result[1].xyz = upAxis;
    result[2].xyz = forwardAxis; 

    return transpose(result);
}
Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

This isn't as hard as it might seem.

We can simplify two of your arguments to one:

float3 viewDirection = target - source;

Then our strategy will be to cross the vertical axis and view direction to get a vector perpendicular to both (the right/sideways direction).

Next, we cross this with our vertical axis to complete the basis.

A rotation matrix is just a unit vector in each basis direction, so we can assign our vectors directly to the rows/columns of our matrix.

float3x3 AxisBillboard(float3 upAxis, float3 viewDirection) {
    float3 rightAxis = normalize(cross(upAxis, viewDirection));
    float3 forwardAxis = cross(rightAxis, upAxis);

    float3x3 result;
    result[0].xyz = rightAxis;
    result[1].xyz = upAxis;
    result[2].xyz = forwardAxis;
}

Some details can differ depending on the handedness of your coordinate system, or the multiplication convention you use (Matrix * vector or vector * Matrix), but this will get you within a sign flip or a transpose of the desired result.