<p>Edit: I've pinpointed the problem. If I change:</p>
<pre><code>local_colour *= (rayPayload.color.r*mask.r + rayPayload.color.g*mask.g + rayPayload.color.b*mask.b);
</code></pre>
<p>into</p>
<pre><code>local_colour += (rayPayload.color.r*mask.r + rayPayload.color.g*mask.g + rayPayload.color.b*mask.b);
</code></pre>
<p>... then I get caustics, but not vibrant colour. Any path tracing experts care to enlighten me as to what I'm doing wrong? :)</p>
<p>The problem:</p>
<p>My code to do path tracing is:</p>
<pre><code>float trace_path2(out vec3 final_pos, const int steps, const vec3 origin, const vec3 direction, const float hue, float eta)
{
    const RayPayload r = rayPayload;

    vec3 hitPos = vec3(0.0);

    float ret_colour = 0;

    vec3 o = origin;
    vec3 d = direction;

    int count = 0;

    
    float energy = 100.0;

    float local_colour = energy;


    float total = 0;

    for(int i = 0; i &lt; steps; i++)
    {
        const float tmin = 0.001;
        const float tmax = 10000.0;
        traceRayEXT(topLevelAS, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, o.xyz, tmin, d.xyz, tmax, 0);

        const vec3 mask = hsv2rgb(vec3(hue, 1.0, 1.0));

        total += mask.r;
        total += mask.g;
        total += mask.b;

        local_colour *= (rayPayload.color.r*mask.r + rayPayload.color.g*mask.g + rayPayload.color.b*mask.b);

        if(rayPayload.distance == -1)
            break;

        hitPos = o + d * rayPayload.distance;

        if(rayPayload.color.r == 1.0 &amp;&amp; rayPayload.color.g == 1.0 &amp;&amp; rayPayload.color.b == 1.0)
            ret_colour += local_colour;


        vec3 o_reflect = hitPos + rayPayload.normal * 0.01;
        vec3 d_reflect = reflect(d, rayPayload.normal);

        vec3 temp_o = o_reflect;
        vec3 temp_d = d_reflect;

        if(rayPayload.reflector &lt; 1.0) // if less than fully reflective, do scattering
        {
            vec3 o_scatter = hitPos + rayPayload.normal * 0.01;
            vec3 d_scatter = cosWeightedRandomHemisphereDirection(rayPayload.normal, prng_state);

            temp_o = mix(temp_o, o_scatter, 1.0 - rayPayload.reflector);
            temp_d = mix(temp_d, d_scatter, 1.0 - rayPayload.reflector);
        }

        return rayPayload.opacity;

        if(rayPayload.opacity &lt; 1.0) // if partially transparent, do refraction
        {
            vec3 o_transparent = vec3(0.0);
            vec3 d_transparent = vec3(0.0);

            // Incoming
            if(dot(d, rayPayload.normal) &lt;= 0.0)
            {
                o_transparent = hitPos.xyz - rayPayload.normal * 0.01f;
                d_transparent = refract(d, rayPayload.normal, eta);
            }
            else // Outgoing
            {
                vec3 temp_dir = refract(d, -rayPayload.normal, 1.0 / eta);

                if(temp_dir != vec3(0.0))
                {
                    o_transparent = hitPos.xyz + rayPayload.normal * 0.01f;
                    d_transparent = temp_dir;
                }
                else
                {
                    // total internal reflection
                    o_transparent = hitPos.xyz - rayPayload.normal * 0.01f;
                    d_transparent = reflect(d, -rayPayload.normal);
                }
            }

            temp_o = mix(temp_o, o_transparent, 1.0 - rayPayload.opacity);
            temp_d = mix(temp_d, d_transparent, 1.0 - rayPayload.opacity);
        }
            
        o = temp_o;
        d = normalize(temp_d);
        
    }

    final_pos = hitPos;
    rayPayload = r;
    return ret_colour / total;
}
</code></pre>
<p>When I make the statement <code>return rayPayload.opacity;</code> it returns the following image, which is what I expect:</p>
<p><a href="https://i.sstatic.net/3JVtR.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/3JVtR.png" alt="enter image description here" /></a></p>
<p>However, if you comment out that return statement, the if statement on the next line is never run, even though it's obviously not 1.0 in some parts of the image. It's the strangest problem.</p>
<p>The full code is at: <a href="https://github.com/sjhalayka/cornell_box_textured" rel="nofollow noreferrer">https://github.com/sjhalayka/cornell_box_textured</a></p>
<p>Basically, I have reflection caustics working, but I cannot get refraction caustics to work yet (in the new version 2.0 of my path tracer).</p>
<p>Any big errors that I'm not seeing here?</p>
<p>Thanks for your time.</p>

CC BY-SA 4.0
2023-09-21T07:17:30.287Z
Can't dive into your code (though it seems you found the problem anyway). But regarding the question posted as a title: Vulkan with glsl on most cards supports `debugPrintfEXT` (see [LunarG paper about it](https://www.lunarg.com/wp-content/uploads/2021/08/Using-Debug-Printf-02August2021.pdf)). You have to be careful to limit the output - I print only when pressing a key and only for the center pixel. This limits the output to something I can actually read through and analyze. Also, depending on the bug checkout [NVidia NSight](https://developer.nvidia.com/nsight-graphics).
Tare
CC BY-SA 4.0
2023-09-21T15:26:20.540Z
Thank you so much for the guidance.
shawn_halayka
<c++><vulkan>
Path tracer -- How to debug erroneous behaviour?
shawn_halayka
# Path tracer -- How to debug erroneous behaviour?

(Asked by: username_0 on 2023-09-19)

Edit: I've pinpointed the problem. If I change:

```
local_colour *= (rayPayload.color.r*mask.r + rayPayload.color.g*mask.g + rayPayload.color.b*mask.b);

```

into

```
local_colour += (rayPayload.color.r*mask.r + rayPayload.color.g*mask.g + rayPayload.color.b*mask.b);

```

... then I get caustics, but not vibrant colour. Any path tracing experts care to enlighten me as to what I'm doing wrong? :)

The problem:

My code to do path tracing is:

```
float trace_path2(out vec3 final_pos, const int steps, const vec3 origin, const vec3 direction, const float hue, float eta)
{
    const RayPayload r = rayPayload;

    vec3 hitPos = vec3(0.0);

    float ret_colour = 0;

    vec3 o = origin;
    vec3 d = direction;

    int count = 0;

    
    float energy = 100.0;

    float local_colour = energy;

    float total = 0;

    for(int i = 0; i < steps; i++)
    {
        const float tmin = 0.001;
        const float tmax = 10000.0;
        traceRayEXT(topLevelAS, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, o.xyz, tmin, d.xyz, tmax, 0);

        const vec3 mask = hsv2rgb(vec3(hue, 1.0, 1.0));

        total += mask.r;
        total += mask.g;
        total += mask.b;

        local_colour *= (rayPayload.color.r*mask.r + rayPayload.color.g*mask.g + rayPayload.color.b*mask.b);

        if(rayPayload.distance == -1)
            break;

        hitPos = o + d * rayPayload.distance;

        if(rayPayload.color.r == 1.0 && rayPayload.color.g == 1.0 && rayPayload.color.b == 1.0)
            ret_colour += local_colour;

        vec3 o_reflect = hitPos + rayPayload.normal * 0.01;
        vec3 d_reflect = reflect(d, rayPayload.normal);

        vec3 temp_o = o_reflect;
        vec3 temp_d = d_reflect;

        if(rayPayload.reflector < 1.0) // if less than fully reflective, do scattering
        {
            vec3 o_scatter = hitPos + rayPayload.normal * 0.01;
            vec3 d_scatter = cosWeightedRandomHemisphereDirection(rayPayload.normal, prng_state);

            temp_o = mix(temp_o, o_scatter, 1.0 - rayPayload.reflector);
            temp_d = mix(temp_d, d_scatter, 1.0 - rayPayload.reflector);
        }

        return rayPayload.opacity;

        if(rayPayload.opacity < 1.0) // if partially transparent, do refraction
        {
            vec3 o_transparent = vec3(0.0);
            vec3 d_transparent = vec3(0.0);

            // Incoming
            if(dot(d, rayPayload.normal) <= 0.0)
            {
                o_transparent = hitPos.xyz - rayPayload.normal * 0.01f;
                d_transparent = refract(d, rayPayload.normal, eta);
            }
            else // Outgoing
            {
                vec3 temp_dir = refract(d, -rayPayload.normal, 1.0 / eta);

                if(temp_dir != vec3(0.0))
                {
                    o_transparent = hitPos.xyz + rayPayload.normal * 0.01f;
                    d_transparent = temp_dir;
                }
                else
                {
                    // total internal reflection
                    o_transparent = hitPos.xyz - rayPayload.normal * 0.01f;
                    d_transparent = reflect(d, -rayPayload.normal);
                }
            }

            temp_o = mix(temp_o, o_transparent, 1.0 - rayPayload.opacity);
            temp_d = mix(temp_d, d_transparent, 1.0 - rayPayload.opacity);
        }
            
        o = temp_o;
        d = normalize(temp_d);
        
    }

    final_pos = hitPos;
    rayPayload = r;
    return ret_colour / total;
}

```

When I make the statement `return rayPayload.opacity;` it returns the following image, which is what I expect:

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

However, if you comment out that return statement, the if statement on the next line is never run, even though it's obviously not 1.0 in some parts of the image. It's the strangest problem.

The full code is at: <https://github.com/sjhalayka/cornell_box_textured>

Basically, I have reflection caustics working, but I cannot get refraction caustics to work yet (in the new version 2.0 of my path tracer).

Any big errors that I'm not seeing here?

Thanks for your time.

**Tags:** c++, vulkan

> **Comments:**
> **username_1**: Can't dive into your code (though it seems you found the problem anyway). But regarding the question posted as a title: Vulkan with glsl on most cards supports `debugPrintfEXT` (see [LunarG paper about it](https://www.lunarg.com/wp-content/uploads/2021/08/Using-Debug-Printf-02August2021.pdf)). You have to be careful to limit the output - I print only when pressing a key and only for the center pixel. This limits the output to something I can actually read through and analyze. Also, depending on the bug checkout [NVidia NSight](https://developer.nvidia.com/nsight-graphics).  
> **username_0**: Thank you so much for the guidance.  

---

## 0 answers

