I have been trying to do raytracing of an helix in a spatial shader in godot 4.2, but apparently I missed something because the result is bloby and melty at the cylinder level.

The basics is that I trace a 2d circle in the depth plane along U, then try to extrude it as a cylinder by scaling the view vector by the t values given in 2d. But that didn't turn out as expected and I'm a loss of where it got wrong, the normal also don't look correct.

I have already try many permutation, originally I was doing two cylinder packed in sizzling, and removed one for reproduction and removing noise. I used the scratchpixel raytracing's article notation.

uniform sampler2D text;

void fragment()
    vec3 viewDirTangentSpace = TBN * VIEW;

    const float mydepth = 1.0;
    vec3 raydir = viewDirTangentSpace;///.5; // ray direction/depth

    const vec2 centers = vec2(-0.0,.5);//x and depth
    const float radius = 0.3;
    const float r2 = radius * radius;
    const vec2 UVsurfacePos = vec2(UV.x,0);

    //vector: 2d origine to circles center in 2d along vertical depth plane
    const vec2 L = centers.xy-UVsurfacePos.xy; const vec2 L2 = L*L;

    //dot projection: 2d centers to 2d ray line
    vec2 raydir2d = normalize(raydir.xz);
    float tca = dot(L,raydir2d);

    //2d distances to projected
    float distances = abs( (L2.x + L2.y) - (tca) );
    float d = sqrt( distances );float d2 = d * d;
    //float d2 = distances * distances;

    //2d intersections points
    float thcdiff = r2 - d2; float thc = sqrt (thcdiff);
    vec2 t = vec2(tca +thc, tca -thc);

    //get extrusion in y
    //vec3 p11 = vec3(UV,0) + raydir * t.x; //first impact column 1
    //vec3 p12 = vec3(UV,0) + raydir * t.y; //second impact column 1
    vec3 p11 = raydir * t.x; //first impact column 1
    vec3 p12 = raydir * t.y; //second impact column 1

    //get normal
    vec3 N11 = normalize( vec3(  (UV+p11.xz - centers),0) );
    vec3 N12 = normalize( vec3( -(UV+p12.xz - centers),0) );

    //get twist
    float twist11 = atan(N11.x, N11.y);
    float twist12 = atan(-N12.x, -N12.y);//reverse the N
    vec3 result = vec3(0.0); // black color if not intersecting
    if( t.x > 0.0 && t.y > 0.0 )
        result = vec3(1.0, 0.0, 0.0); // red color if intersecting cylinder1

    float ptmin = min(t.x,t.y);
    vec2 UVoffset = UV+raydir.xy * ptmin;

    NORMAL = N11.xzy;
    ALBEDO = texture(text, UVoffset).xyz;


The helix interception is supposed to work in this way:

  • we find the hit point angle relative to the cylinder axis (using the normal orientation)
  • we find at which height of the cylinder, the similar angle of the spiral land (angle change linearly across height)
  • we compute if the hit point land with width of the spiral point at the same angle. else we discard.


You must log in to answer this question.