<p>I decided to use R16B16G16A16_FLOAT format instead to avoid problems as I'm working on hobby/academic code and it isn't fully fledged game/graphics engine.</p>
<p>I solves my problem. FYI, I've also tried using R8B8G8A8_SNORM instead of *_UNORM, but I failed to get correct results with that. Maybe it was due to other factors, so I don't fully blame format.</p>

CC BY-SA 4.0
2020-08-20T10:28:34.280Z
SNORM (-1 to 1) and UNORM (0 to 1) are by definition clamped (normalised). See also https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-data-conversion
PaulHK
CC BY-SA 4.0
2020-08-20T11:08:45.183Z
@PaulHK Thank you. I've already read about UNORM/SNORM formats and realized my mistake. Therefore, I tried to use it for storing normals. But as I said - it's academic project so I decided to use FP16 to avoid problems and get better image quality.
DirectX_Programmer
CC BY-SA 4.0
2020-08-19T13:01:41.497Z
2020-08-19T13:01:41.497Z
DirectX_Programmer
<p>I am working on ray/path-tracer using DXR and I'm starting with simple AO. In first pass, I am storing normal value and RayTCurrent():</p>
<pre><code>[shader(&quot;closesthit&quot;)]
void ClosestHit(inout RayPayload payload, in Attributes attrib)
{
    // Calculate triangle normal code - unrelated, so I deleted it
    
    // Store RayTCurrent value in payload
    payload.normalWithDepth = float4(triangleNormal, RayTCurrent());
}

[shader(&quot;raygeneration&quot;)]
void RayGen()
{  
    RayDesc ray = { origin, 1e-4f, rayDir, 1e+38f};
    RayPayload payload;
    payload.worldPos = float4(0, 0, 0, 0);
    payload.normalWithDepth = float4(0, 0, 0, 0);
    
    TraceRay(SceneBVH, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload);

    // Simply storing returned payload in RWTexture&lt;float4&gt;
    RTOutputNormal[DispatchRaysIndex().xy] = payload.normalWithDepth;
}
</code></pre>
<p>In AO pass I am using this information to calculate world space position of given pixel (i.e. transform from ndc to world space coordinate):</p>
<pre><code>[shader(&quot;raygeneration&quot;)]
void RayGenAO()
{
    float2 pixelCenter = (float2) LaunchIndex / (float2) LaunchDimensions + float2(0.5f / (float) LaunchDimensions.x, 0.5f / (float) LaunchDimensions.y);
    float4 normalAndDepth = NormalTextureInput.SampleLevel(g_sampler, pixelCenter, 0);

    // normalAndDepth.w is clamped to 1.0f, therefore information about distance to hit point is lost
}
</code></pre>
<p><a href="https://i.sstatic.net/hIh5R.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/hIh5R.png" alt="enter image description here" /></a></p>
<p>You can see, that above code results in correct AO results (1 spp noise with no filtering or accumulation) for happy buddha model. However, any AO can be seen when camera is extremely close (max 1 unit from object). In other cases I am getting completely white, flat model. The problem is that texture is clamping value in first pass to 1, so I am losing information about real distance between ray origin and ray hit.</p>
<p>Here is a hlsl code for AO generation. I don't think that any problem exists in there, apart from not enough information from texture. <strong>Therefore, below code can be ignored:</strong></p>
<pre><code>[shader(&quot;raygeneration&quot;)]
void RayGen()
{
    uint2 LaunchIndex = DispatchRaysIndex().xy;
    uint2 LaunchDimensions = DispatchRaysDimensions().xy;

    // Figure out pixel world space position (using length of a primary ray found in previous pass)
    float3 primaryRayOrigin, primaryRayDirection; 
    GenerateCameraRay(LaunchIndex, primaryRayOrigin, primaryRayDirection);
    
    float2 pixelCenter = (float2) LaunchIndex / (float2) LaunchDimensions + float2(0.5f / (float) LaunchDimensions.x, 0.5f / (float) LaunchDimensions.y);
    float4 normalAndDepth = NormalTextureInput.SampleLevel(g_sampler, pixelCenter, 0);
    float3 pixelWorldSpacePosition = primaryRayOrigin + (primaryRayDirection * normalAndDepth.w);

    //RTOutput[LaunchIndex] = float4(normalAndDepth.w, normalAndDepth.w, normalAndDepth.w, 1.0f);
    //return;
    
    if (normalAndDepth.w == 0.0f)
    {
        // Terminate if primary ray didn't hit anything
        RTOutput[LaunchIndex] = float4(0.0f, 0.2f, 0.4f, 1.0f);
        return;
    }
    
    uint seed = initRand(LaunchIndex.x + LaunchIndex.y * LaunchDimensions.x, g_cubeCB.frameCount);
    float3 worldDir = getCosHemisphereSample(seed.x, normalAndDepth.xyz);
    
    RayDesc aoRay;
    RayPayload payload;
    float3 aoSampleDirection = worldDir;
    float ao = 0.0f;

    aoRay.Origin = pixelWorldSpacePosition;
    aoRay.TMin = g_aoCB.minT;
    aoRay.TMax = g_aoCB.aoRadius; //&lt; Set max ray length to AO radius for early termination
    aoRay.Direction = aoSampleDirection;
    
    payload.T = g_aoCB.aoRadius; //&lt; Set T to &quot;maximum&quot;, to produce no occlusion in case ray doesn't hit anything (miss shader won't modify this value)

    // Trace the ray
    TraceRay(SceneBVH, RAY_FLAG_NONE, 0xFF, 0, 1, 0, aoRay, payload);
    ao = payload.T / g_aoCB.aoRadius;
    
    RTOutput[LaunchIndex.xy] = float4(ao, ao, ao, 1.0f); //&lt; Replace all cached AO with current result
}

    [shader(&quot;miss&quot;)]
    void Miss(inout RayPayload payload : SV_RayPayload)
    {
        // Empty
    }
    
    [shader(&quot;closesthit&quot;)]
    void ClosestHit(inout RayPayload payload, in Attributes attrib)
    {
        payload.T = RayTCurrent();
    }
</code></pre>

<raytracing><texture><hlsl><directx12>
Texture value clamped to 1
DirectX_Programmer
# Texture value clamped to 1

(Asked by: username_0 on 2020-08-13)

I am working on ray/path-tracer using DXR and I'm starting with simple AO. In first pass, I am storing normal value and RayTCurrent():

```
[shader("closesthit")]
void ClosestHit(inout RayPayload payload, in Attributes attrib)
{
    // Calculate triangle normal code - unrelated, so I deleted it
    
    // Store RayTCurrent value in payload
    payload.normalWithDepth = float4(triangleNormal, RayTCurrent());
}

[shader("raygeneration")]
void RayGen()
{  
    RayDesc ray = { origin, 1e-4f, rayDir, 1e+38f};
    RayPayload payload;
    payload.worldPos = float4(0, 0, 0, 0);
    payload.normalWithDepth = float4(0, 0, 0, 0);
    
    TraceRay(SceneBVH, RAY_FLAG_NONE, 0xFF, 0, 1, 0, ray, payload);

    // Simply storing returned payload in RWTexture<float4>
    RTOutputNormal[DispatchRaysIndex().xy] = payload.normalWithDepth;
}

```

In AO pass I am using this information to calculate world space position of given pixel (i.e. transform from ndc to world space coordinate):

```
[shader("raygeneration")]
void RayGenAO()
{
    float2 pixelCenter = (float2) LaunchIndex / (float2) LaunchDimensions + float2(0.5f / (float) LaunchDimensions.x, 0.5f / (float) LaunchDimensions.y);
    float4 normalAndDepth = NormalTextureInput.SampleLevel(g_sampler, pixelCenter, 0);

    // normalAndDepth.w is clamped to 1.0f, therefore information about distance to hit point is lost
}

```

[![enter image description here](https://i.sstatic.net/hIh5R.png)](https://i.sstatic.net/hIh5R.png)

You can see, that above code results in correct AO results (1 spp noise with no filtering or accumulation) for happy buddha model. However, any AO can be seen when camera is extremely close (max 1 unit from object). In other cases I am getting completely white, flat model. The problem is that texture is clamping value in first pass to 1, so I am losing information about real distance between ray origin and ray hit.

Here is a hlsl code for AO generation. I don't think that any problem exists in there, apart from not enough information from texture. **Therefore, below code can be ignored:**

```
[shader("raygeneration")]
void RayGen()
{
    uint2 LaunchIndex = DispatchRaysIndex().xy;
    uint2 LaunchDimensions = DispatchRaysDimensions().xy;

    // Figure out pixel world space position (using length of a primary ray found in previous pass)
    float3 primaryRayOrigin, primaryRayDirection; 
    GenerateCameraRay(LaunchIndex, primaryRayOrigin, primaryRayDirection);
    
    float2 pixelCenter = (float2) LaunchIndex / (float2) LaunchDimensions + float2(0.5f / (float) LaunchDimensions.x, 0.5f / (float) LaunchDimensions.y);
    float4 normalAndDepth = NormalTextureInput.SampleLevel(g_sampler, pixelCenter, 0);
    float3 pixelWorldSpacePosition = primaryRayOrigin + (primaryRayDirection * normalAndDepth.w);

    //RTOutput[LaunchIndex] = float4(normalAndDepth.w, normalAndDepth.w, normalAndDepth.w, 1.0f);
    //return;
    
    if (normalAndDepth.w == 0.0f)
    {
        // Terminate if primary ray didn't hit anything
        RTOutput[LaunchIndex] = float4(0.0f, 0.2f, 0.4f, 1.0f);
        return;
    }
    
    uint seed = initRand(LaunchIndex.x + LaunchIndex.y * LaunchDimensions.x, g_cubeCB.frameCount);
    float3 worldDir = getCosHemisphereSample(seed.x, normalAndDepth.xyz);
    
    RayDesc aoRay;
    RayPayload payload;
    float3 aoSampleDirection = worldDir;
    float ao = 0.0f;

    aoRay.Origin = pixelWorldSpacePosition;
    aoRay.TMin = g_aoCB.minT;
    aoRay.TMax = g_aoCB.aoRadius; //< Set max ray length to AO radius for early termination
    aoRay.Direction = aoSampleDirection;
    
    payload.T = g_aoCB.aoRadius; //< Set T to "maximum", to produce no occlusion in case ray doesn't hit anything (miss shader won't modify this value)

    // Trace the ray
    TraceRay(SceneBVH, RAY_FLAG_NONE, 0xFF, 0, 1, 0, aoRay, payload);
    ao = payload.T / g_aoCB.aoRadius;
    
    RTOutput[LaunchIndex.xy] = float4(ao, ao, ao, 1.0f); //< Replace all cached AO with current result
}

    [shader("miss")]
    void Miss(inout RayPayload payload : SV_RayPayload)
    {
        // Empty
    }
    
    [shader("closesthit")]
    void ClosestHit(inout RayPayload payload, in Attributes attrib)
    {
        payload.T = RayTCurrent();
    }

```

**Tags:** raytracing, texture, hlsl, directx12


---

## 1 answers

### Answer by username_0 on 2020-08-19. Score: 0 | Accepted answer

I decided to use R16B16G16A16\_FLOAT format instead to avoid problems as I'm working on hobby/academic code and it isn't fully fledged game/graphics engine.

I solves my problem. FYI, I've also tried using R8B8G8A8\_SNORM instead of \*\_UNORM, but I failed to get correct results with that. Maybe it was due to other factors, so I don't fully blame format.

> **Comments:**
> **username_1**: SNORM (-1 to 1) and UNORM (0 to 1) are by definition clamped (normalised). See also https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-data-conversion  
> **username_0**: @username_1 Thank you. I've already read about UNORM/SNORM formats and realized my mistake. Therefore, I tried to use it for storing normals. But as I said - it's academic project so I decided to use FP16 to avoid problems and get better image quality.  

---

