Closesthit shader not working

Hi everyone!

I am new with Unity and I bumped into issues that I can not overcome.
I am working on a project where I have to use Ray Tracing in Unity to create a radar model. Shortly, my model has the following logic:
The behaviour of the radar is described in C# script MimoFmcwRadar.cs and Shader codes radarRayShader.raytrace, ClosestHitShader.shader and signalCalculationShader.compute. MimoFmcwRadar.cs: it is attached to a cylinder gameobject and describe the properties of a single MIMO FMCW Radar model, generates the transmit signal then process the receive signal then generate the pointcloud data.
radarRayShader.raytrace : Dispatches the rays with ray tracing. It dispatches as many rays parallel as many transmit antennas a MIMO FMCW Radar object has, and if it hits a target with target layer assigned to it then it saves the nearest distance to it in a buffer.
ClosestHitShader.shader: The ClosestHit interaction of the rays from ray tracing is described here then it is set-shader-passed to the radarRayShader.raytrace. Because .raytrace file doesn't recognize a closeshit shader, so after searching for solutions I found this solution.

This is the part in my MimoFmcwRadar.cs where I passed the shader:

private void CreateAccelerationStructure()
    {
        // Create a new acceleration structure
        accelerationStructure = new RayTracingAccelerationStructure();

     // Add the obstacle layer to the acceleration structure
     foreach (var renderer in cachedRenderers){
            // Prepare an array of flags for the submeshes
            RayTracingSubMeshFlags[] subMeshFlags = new     RayTracingSubMeshFlags[renderer.sharedMaterials.Length];
            for (int i = 0; i < subMeshFlags.Length; i++)
            {
                // Initialize as needed, assuming you want to include all sub-meshes without special handling
                subMeshFlags[i] = RayTracingSubMeshFlags.ClosestHitOnly;
            }

            accelerationStructure.AddInstance(renderer, subMeshFlags, true, false, 255, 0);
        }

        // Build the acceleration structure
        accelerationStructure.Build();
        // Assign the acceleration structure to the compute shader
         radarRayShader.SetAccelerationStructure("_AccelerationStructure", accelerationStructure);
         radarRayShader.SetShaderPass("ClosestHitPass");

         Debug.Log("Acceleration structure created with " + cachedRenderers.Count + " instances.");
    }

signalCalculationShader.compute: It is dispatched with as many threads as many receive antennas a MIMO FMCW Radar object has, and it gets the distance information from the raytracing shader through the CPU and simulates the receive signals by calculating the delay. Then this information is given back to the CPU and MimoFmcwRadar.cs.
I added an obstacleLayer to my MimoFmcwRadar object and accelerationstructure is created according to that and rays are also only recognize that layer as a target.

However, I created a Standard Surface Shader and placed my ClosestHitShader code in it (see attached file) and passed it with "radarRayShader.SetShaderPass("ClosestHitPass")", it seems like I only get "-1" back as a distance information from the traced rays.

I visualize the path of the rays with OnDrawGizmos() so I am sure that it interacts with my target (see screenshot).

9871119--1422852--upload_2024-6-4_0-35-31.png

Can you please help me find where my code went wrong?

An extra question: In ValidateSetUp() I log the Radar position and Renderer position and it always logs (0.0, 0.0, 0.0) for both, but in the scene I clearly moved them elsewhere before running it... Can somebody help me solve this as well?

Thank you very much in advance.

PS.: I couldn't upload my radarRayShader.raytrace file:

RWTexture2D<float4> RenderTarget;
RWStructuredBuffer<float> _DistanceBuffer;

struct RayPayload
{
    float distance;
};

int _NumTxAntennas;
float _MaxRange;
float _Spacing;
float _txHeight;
float3 _RayOrigin;
float3 _RayDirection;
uint _LayerMask;
RaytracingAccelerationStructure _AccelerationStructure;

#pragma max_recursion_depth 1

[shader("raygeneration")]
void RayGenShader()
{
    uint txIndex = DispatchRaysIndex().x;
    RayPayload payload;
    payload.distance = -1.0f;

    float startX = -(float)(_NumTxAntennas - 1) * _Spacing / 2.0f;

    float3 txPosition = _RayOrigin + float3(_txHeight, 0, startX + txIndex * _Spacing);
    float3 rxPosition = _RayOrigin + float3(0, 0, startX + txIndex * _Spacing);

    RayDesc ray;
    ray.Origin = txPosition;
    ray.Direction = _RayDirection;
    ray.TMin = 0;
    ray.TMax = _MaxRange;

    TraceRay(_AccelerationStructure, RAY_FLAG_FORCE_OPAQUE, _LayerMask, 0, 1, 0, ray, payload);

    // Write the distance to the buffer
    _DistanceBuffer[txIndex] = (payload.distance >= 0) ? payload.distance : -1.0f;
}

[shader("miss")]
void MissShader(inout RayPayload payload)
{
    payload.distance = -1.0f;
}

and my signalCalculationShader.compute file:

#pragma kernel  SignalCalculationShader

RWStructuredBuffer<float> _DistanceBuffer;
RWStructuredBuffer<float> _ReceivedSignals;
RWStructuredBuffer<float> _ChirpSignal;
float _Bandwidth;
float _ChirpDuration;
float _SamplingRate;
float _StartFrequency;
int _NumTxAntennas;
int _NumRxAntennas;
int _ChirpSignalLength;

[numthreads(1, 1, 1)]
void SignalCalculationShader(uint3 dispatchThreadId : SV_DispatchThreadID)
{
    int rxIndex = dispatchThreadId.x;

    if (rxIndex >= _NumRxAntennas)
    {
        return;
    }

    float distance = _DistanceBuffer[rxIndex];

    if (distance >= 0)
    {
        float delay = distance / 3e8f;
        float chirpRate = _Bandwidth/_ChirpDuration;

        for (int i = 0; i < _ChirpSignalLength; i++)
        {
            float t = delay + (float)i / _SamplingRate;  // Current time including delay
            float frequency = _StartFrequency + chirpRate * t;
        // Simulated received signal at sample i
            int bufferIndex = rxIndex * _ChirpSignalLength + i;
            _ReceivedSignals[bufferIndex] = sin(2.0*3.14159265359*frequency*t);
        }
    }
}

9871119--1422846--MimoFmCwRadar.cs (13.6 KB)
9871119--1422849--ClosestHitShader.shader (650 Bytes)

Try subMeshFlags[i] = RayTracingSubMeshFlags.Enabled | RayTracingSubMeshFlags.ClosestHitOnly;

https://docs.unity3d.com/ScriptReference/Experimental.Rendering.RayTracingSubMeshFlags.html

Hi!
Thank you, but after changing this it still gives me only "-1" for the distance. Another strange thing I noticed was that

using UnityEngine.Experimental.Rendering;

is not even used in my C# script:

9872448--1423221--upload_2024-6-4_15-25-0.png

Use PIX https://devblogs.microsoft.com/pix/download/ to inspect the acceleration structure. You can print the instance count before building accelerationStructure using accelerationStructure.GetInstanceCount() just to make sure it's not empty.

I printed tje instance count before building the accelerationStructure with:

Debug.Log("Acceleration structure created with " + accelerationStructure.GetInstanceCount() + " instances.");

and this is the message on the console:
Acceleration structure created with 1 instances.
UnityEngine.Debug:Log (object)
MimoFmcwRadar:CreateAccelerationStructure () (at Assets/MimoFmcwRadar.cs:159)
MimoFmcwRadar:Start () (at Assets/MimoFmcwRadar.cs:62)

which should be correct since I have one cube as a target on my scene.

Do you think that the error is with my acceleration structure? Isn't it in the way I pass ClosestHit to my Ray Tracing Shader, because using UnityEngine.Experimental.Rendering; is not even used in my code.

Thank you again in advance!

Edit:
Yesterday night after I added the following header parts to my ray tracing shader code:

#pragma shader_stage(raygeneration)
#pragma shader_stage(miss)
#pragma shader_stage(closesthit)

Unity started to recognize my closesthit shader as well and running the project gave me back results to the distance. The strange thing (and I don't have any idea what just happened) is that now even after I commented out the header parts I can run the project... As a result of the distances of the traced ray it always gives me a few same sets of the four values doesn't matter if I move my radar object from my target or if there is no targets in the rays way.
The ray origin is also wrong and it changes every time I start the project again, while I haven't change it in my code.
Overall, it feels like the GPU generates some values and give them back as a result and doesn't run my code.
9874167--1423650--upload_2024-6-5_12-56-29.png
I have 4 ray origins, that's why the DistanceBuffer[0]- DistanceBuffer[3], but when I give back the ray properties only two appears with very random values.

Does anyone has an idea what could have happened and can give me advice how to overcome this?

#pragma shader_stage is not something that Unity recognizes, so those line don't have any effect. There are some defines that you can use similar to this: SHADER_STAGE_VERTEX, SHADER_STAGE_FRAGMENT, ... and SHADER_STAGE_RAY_TRACING. To specify that you have ray tracing code you just type #pragma raytracing somename. It looks like your closest hit shader is invoked since you get some values other than -1 so you'll have to debug you shader code.