Trouble when rendering voxels with pathtracing

Viewed 69

I'm currently working on a pathtracer in c and open cl. I'm using this algorithm for rendering. The first collision works well, however, from the second collision onwards there is a dark shadow on the lower side of the voxels.

This is the color of the voxel the initial ray hits:

result

This is the color of the voxel that the second ray hits:

result

And this is the result after rendering to a depth of 1000:

result

This is the code I used (openCL):

int cast_ray(Renderer *r, Ray ray, float3 *hitPos, int3 *normal, Material *material) {
    int3 voxel = convert_int3(ray.origin);
    
    int3 step = {
        (ray.direction.x >= 0) ? 1 : -1,
        (ray.direction.y >= 0) ? 1 : -1,
        (ray.direction.z >= 0) ? 1 : -1
    };

    float3 tMax = {
        (ray.direction.x != 0) ? (voxel.x + step.x - ray.origin.x) / ray.direction.x : MAXFLOAT,
        (ray.direction.y != 0) ? (voxel.y + step.y - ray.origin.y) / ray.direction.y : MAXFLOAT,
        (ray.direction.z != 0) ? (voxel.z + step.z - ray.origin.z) / ray.direction.z : MAXFLOAT
    };
    
    float3 tDelta = {
        (ray.direction.x != 0) ? 1 / ray.direction.x * step.x : MAXFLOAT,
        (ray.direction.y != 0) ? 1 / ray.direction.y * step.y : MAXFLOAT,
        (ray.direction.z != 0) ? 1 / ray.direction.z * step.z : MAXFLOAT
    };
    
    int side;

    while(1) {
        if(tMax.x < tMax.y) {
            if(tMax.x < tMax.z) {
                voxel.x += step.x;
                tMax.x += tDelta.x;
                side = 0;
            } else {
                voxel.z += step.z;
                tMax.z += tDelta.z;
                side = 2;
            }
        } else {
            if(tMax.y < tMax.z) {
                voxel.y += step.y;
                tMax.y += tDelta.y;
                side = 1;
            } else {
                voxel.z += step.z;
                tMax.z += tDelta.z;
                side = 2;
            }
        }

        if(out_of_scene(r, voxel))
            return 0;

        MaterialID id = get_material_ID(r, voxel);

        if(id == 0)
            continue;

        *material = get_material(r, id);

        switch(side) {
            case 0:
                hitPos->x = (float)voxel.x;
                hitPos->y = ray.origin.y + (hitPos->x - ray.origin.x) * ray.direction.y / ray.direction.x;
                hitPos->z = ray.origin.z + (hitPos->x - ray.origin.x) * ray.direction.z / ray.direction.x;

                *normal = (int3){-step.x, 0, 0};

                break;
            
            case 1:
                hitPos->y = (float)voxel.y;
                hitPos->x = ray.origin.x + (hitPos->y - ray.origin.y) * ray.direction.x / ray.direction.y;
                hitPos->z = ray.origin.z + (hitPos->y - ray.origin.y) * ray.direction.z / ray.direction.y;

                *normal = (int3){0, -step.y, 0};

                break;
            
            case 2:
                hitPos->z = (float)voxel.z;
                hitPos->y = ray.origin.y + (hitPos->z - ray.origin.z) * ray.direction.y / ray.direction.z;
                hitPos->x = ray.origin.x + (hitPos->z - ray.origin.z) * ray.direction.x / ray.direction.z;

                *normal = (int3){0, 0, -step.z};

                break;

        }

        return 1;
        
    }
}

float3 get_color(Renderer *r, Ray ray) {
    float3 mask = 1;
    float3 color = 0;

    int maxDepth = 1000;

    for(int i = 0; i < maxDepth; i++) {

        float3 hitPos;
        int3 iNormal;
        Material material;

        if(cast_ray(r, ray, &hitPos, &iNormal, &material)) {
            float3 fNormal = convert_float3(iNormal);

            if(material.type == 1) {
                color = mask * material.color;
                break;

            } else if(material.type == 2) {
                float3 direction = fNormal + random_unit_vector(r->rng);
                ray = (Ray){hitPos, direction};
                mask *= material.color;
            
            } else if(material.type == 3) {
                float3 direction = reflection_dir(ray.direction, fNormal) + random_unit_vector(r->rng) * material.fuzzyness;
                ray = (Ray){hitPos, direction};
                mask = mask * (1 - material.tint) + mask * material.color * material.tint;

            }

        } else {
            color = mask * r->bgColor;
            break;
        
        }

        // if(i == 1)
        //      return material.color;

    }

    return color;
}

I think that the problem is that the new origin of the ray is somehow not correct, but I can't find a way to fix it.

0 Answers
Related