Convert Shader to HD SRP

I am having some trouble converting my unlit (emissive) billboard shader to the HD Scriptable Render Pipeline.

The problem is with the new Camera Relative Rendering the HD SRP uses. See code below.

        //Legacy pipeline version:
        //output.pos = mul(UNITY_MATRIX_P, float4(UnityObjectToViewPos(input.center), 1.0f) + offset); //Place the vertex by moving it away from the center, rotate the billboard towards the camera.

        //HD SRP version, but it causes major rendering artifacts.
        output.pos.xyz = TransformObjectToWorld(input.center.xyz);
        output.pos = mul(UNITY_MATRIX_P, float4(output.pos.xyz, 1.0f) + offset); //Rotate billboard towards camera. Not sure how to convert this to SRP.
        output.pos.xyz = GetCameraRelativePositionWS(output.pos.xyz);
        output.pos = TransformWorldToHClip(output.pos.xyz);

I fixed it now. This is the correct working version:

        output.pos.xyz = TransformObjectToWorld(input.center.xyz + offset.xyz);
        output.pos.xyz = GetCameraRelativePositionWS(output.pos.xyz);
        output.pos = TransformWorldToHClip(output.pos.xyz);
4 Likes

In Unity 2018.2.0f2 the Camera Relative Rendering seems to be broken. Commenting out line 2 in the code will at least render the lights, but they will not face the camera…

This seems to be the correct code, but I am awaiting confirmation that it is future proof:

output.pos.xyz = TransformObjectToWorld(input.center.xyz);
output.pos.xyz = TransformWorldToView(output.pos.xyz) + offset.xyz;
output.pos = mul(UNITY_MATRIX_P, float4(output.pos.xyz, 1.0f));
2 Likes

This also works:

positionWS = TransformObjectToWorld(input.center.xyz);
output.pos.xyz = TransformWorldToView(positionWS) + offset.xyz;
output.pos = TransformWViewToHClip(output.pos.xyz);
2 Likes

Hi,

Here is how camera relative is implemented, this can help you.

We remove the translation part of the View Matrix on C# side
and we add it the the object transform on hlsl side.

The hlsl code that update the object transform is via the Macro UNITY_MATRIX_M

float4x4 ApplyCameraTranslationToMatrix(float4x4 modelMatrix)
{
// To handle camera relative rendering we substract the camera position in the model matrix
#if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0)
modelMatrix._m03_m13_m23 -= _WorldSpaceCameraPos;
#endif
return modelMatrix;
}

#define UNITY_MATRIX_M ApplyCameraTranslationToMatrix(GetRawUnityObjectToWorld())

So when using UNITY_MATRIX_M and UNITY_MATRIX_V you are all set. Note that the projection matrix have no impact.

in our case we use TransformObjectToWorld and TransformWorldToHClip for all our operation

float4x4 GetObjectToWorldMatrix()
{
return UNITY_MATRIX_M;
}

float3 TransformObjectToWorld(float3 positionOS)
{
return mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)).xyz;
}

See VertMesh.hlsl for correct use or camera relative rendering.

We transform like this:

// This return the camera relative position (if enable)
float3 positionRWS = TransformObjectToWorld(input.positionOS);
output.positionCS = TransformWorldToHClip(positionRWS);

So indeed the equivalent of the above code if you split View and Projection matrice is:

  • output.pos.xyz = TransformObjectToWorld(input.center.xyz);
  • output.pos.xyz = TransformWorldToView(output.pos.xyz);
  • output.pos = mul(UNITY_MATRIX_P, float4(output.pos.xyz, 1.0f));

now you can include your extra transformation inside it, as you do

4 Likes

Thanks for the clarification.

1 Like