0

I am trying to do ray tracing on a couple of spheres. However, when I put a light source directly in front of a circle, I get a X mark (X mark with 3 lines instead of 4) instead of a circle lighting up on the surface of my spheres. I am not using shadow rays and the lighting is only coming from my 2 light sources. I have also implemented the ray tracer in c++ with very similar code as this but without the problems I described so I suspect that it might be some rounding issues. What do you guys think might be causing the problem with the X mark on the sphere?

The 3 pictures below are:

one of them have a "working?" ray tracer but the lights mark an X on the sphere

one of them is the normal map of the scene

one of them is when I use reflect for the ray direction instead of scattering it in random directions

enter image description hereenter image description hereenter image description here

Here is my shader code

#version 410 core

in vec2 v_texCoord;
in vec2 v_rayCoord;

uniform sampler2D u_randTexture;
uniform vec2 u_randSampler;

out vec4 FragColor;

void main()
{
    float window_width = 800.f;
    float window_height = 600.f;
    float focal_distance = -400.f;

    const int sphere_count = 4;
    const int ray_bounce = 3;

    // might be a better way to randomize
    vec2 tex_coord = v_texCoord + u_randSampler;
    vec4 rand_vec = texture(u_randTexture, tex_coord);
    rand_vec = (rand_vec - vec4(0.5f)) * vec4(2.f);

    float radius[sphere_count] = float[](0.5f, 100.f, 80.f, 0.1f);
    vec3 positions[sphere_count] = vec3[](vec3(0.f, -2.7f, -5.f), vec3(0.f, -103.f, -5.f), vec3(100.f, 80.f, -100.f), vec3(-0.8f, -1.7f, -4.f));
    vec3 color[sphere_count] = vec3[](vec3(1.f, 0.5f, 0.5f), vec3(0.5f, 0.5f, 1.f), vec3(0.9f, 0.9f, 0.3f), vec3(0.48f, 0.38f, 0.57f));
    float brightness[sphere_count] = float[](0.f, 0.f, 7.f, 500.f);

    vec3 ray_origin = vec3(0.f, 0.f, 0.f);
    vec3 ray_direction = vec3(v_rayCoord.x, v_rayCoord.y, focal_distance);

    vec3 absorb_col = vec3(1.f);
    vec3 light_col = vec3(0.f);

    for(int i=0;i<ray_bounce;++i)
    {
        float closest_hit = 10000.f; // arbitrary large number
        int idx = -1;
        // loop through all the different objects
        for(int j=0;j<sphere_count;++j)
        {
            vec3 origin_to_center = ray_origin - positions[j];
            float a = dot(ray_direction, ray_direction);
            float b = 2.f * dot(origin_to_center, ray_direction);
            float c = dot(origin_to_center, origin_to_center) - radius[j] * radius[j];
            float discriminant = b * b - 4.f * a * c;
            if(discriminant < 0.f)
                continue;

            float t = (-b - sqrt(discriminant)) / (2.f * a);
            if(t > 0.f && t < closest_hit)
            {
                closest_hit = t;
                idx = j;
            }
        }

        if(idx < 0)
        {
            //light_col += vec3(0.627f, 1.f, 1.f) * vec3(0.3) * absorb_col;
            light_col += vec3(0.f);
            break;
        }

        vec3 surface = ray_origin + ray_direction * closest_hit;
        vec3 normal = normalize(surface - positions[idx]);
        vec3 incident_vector = normalize(-ray_direction);

        ray_origin = surface + normal * 0.00000000001f;
        ray_direction = normal + rand_vec.xyz * 0.99f;

        if(brightness[idx] > 0.f)
        {
            light_col += color[idx] * absorb_col * brightness[idx];
            break;
        } else
        {
            absorb_col *= color[idx];
        }
    }

    FragColor = vec4(light_col, 1.0);
}

For the random, I sample them from a texture generated by this function in the cpu

// dis(gen) should generate a float from 0.f to 1.f
void randVec3(Renderer::Vec3<float>& _vec3)
{

    _vec3.x = dis(gen) * 2.f - 1.f;
    _vec3.y = dis(gen) * 2.f - 1.f;
    _vec3.z = dis(gen) * 2.f - 1.f;

    _vec3.normalize();
}
int main()
{
        ...
    unsigned char* rand_vec_data = new unsigned char[WINDOW_WIDTH * WINDOW_HEIGHT * 3];
    for(unsigned int i=0;i<WINDOW_WIDTH * WINDOW_HEIGHT;++i)
    {
        Renderer::Vec3<float> rand_vector;
        randVec3(rand_vector);
        rand_vector = (rand_vector + Renderer::Vec3<float>(1.f)) * Renderer::Vec3<float>(0.5f);

        rand_vec_data[i * 3] = static_cast<unsigned char>(rand_vector.x * 255);
        rand_vec_data[i * 3 + 1] = static_cast<unsigned char>(rand_vector.y * 255);
        rand_vec_data[i * 3 + 2] = static_cast<unsigned char>(rand_vector.z * 255);
    }
        ...
}

By the way, when I replaced my code for scattering rays with reflect, my whole scene becomes dark.

ray_direction = reflect(incident_vector, normal);

I tried to change my ray direction to reflect across the normal instead of scattering it. I was hopeing to isolate the problem to see if it was due to the scattering of the rays or a flaw in my calculations. However, when I do that, my whole scene went dark.

1 Answer 1

0

It turns out that my randVec3() function is to blame. The distribution is not uniform in all directions. Since I am not using BRDF, the color of my sphere is purely based on the direction in which the rays are bounced (which depends on the distribution of my random vectors).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.