raytracing obj file in opengl/glsl

2.5k views Asked by At

I would like to implement ray tracing in opengl and glsl to render models loaded from .obj files but I don't understand how exactly do this. I've used obj files before but I used rasterization to render them. So far I've implemented simple ray tracer using fragment shader that render some simple shapes (planes, spheres, boxes). The thing is that in ray tracing I'm calculating intersections with objects but these are defined also in fragment shader.

This is how I've done rendering using rasterization: After loading vertices data (position, normal, uvs) I store them into VBO and bind them to VAO. These I send to vertex shader and transform them by multiplying them with MVP matrices. Then I send transformed vertices to fragment shader when I shade them. But this is the part I don't understand how to implement by ray tracing, because now I have transformed vertices as inputs to fragment shader and that means I don't know how to calculate ray intersections with mesh triangles. So, how to do this?

2

There are 2 answers

0
datenwolf On

Well, essentially for every fragment you perform a ray-intersection test with the whole scene. So the challenge is encoding the scene in some data structure that can be accessed from the fragment shader and offers enough space for it. An immediate choice would be three 1D textures with 3-components of the same size, where for each texel index the triple of the three textures represents a triangle. Then for each ray cast into the scene (i.e. for every fragment) iterate over the triangles.

If you want to get a bit more fancier you could use three 3D textures instead, placing triangle data into the right region of the texture to limit the texels to iterate over, use their mipmap levels for LOD and use sparse texture storage to reduce the memory footprint.

0
Fox1942 On

Recently, I am working exactly on this. I use Assimp library to import the obj file and get the vertices and indices into separate arrays. I send the vertices and indices to the fragment shader through shader storage buffers. Unfortunately, when I want to trace more than 100 triangle faces and check the intersections my computer crashes. I guess that is why GPU-s exist dedicated for raytracing nowadays (My GPU is a gtx750 ti)
In my fragment shader there is a Möller–Trumbore intersection algorithm for checking intersection between triangle and the ray.

Here is my fragment shader (under construction, so not complete):

#version 460 core

layout(std140, binding=2) buffer primitives{
    vec3 primitiveCoordinates[];
};

layout(std140, binding=3) buffer indices{
    vec3 indicesC[];
};

in       vec2       TexCoords;
out      vec4       FragColor;
in       vec3 p;
uniform vec3 wEye;
uniform  sampler2D  texture_diffuse1;


struct Light{
    vec3 Le, La;
    vec3 direction;
    vec3 position;

};

uniform Light lights[2];

struct Ray{
    vec3 orig, dir;
};

struct Hit{
    vec3 orig, dir, normal;
    float t;
};

struct IntersectionPoint{
    float t;

};

vec3 outIntersectionPoint;

Hit rayTriangleIntersect(Ray ray, vec3 v0, vec3 v1, vec3 v2){

    Hit hit;
    float t; float u; float v;
    vec3 v0v1 = v1 - v0;
    vec3 v0v2 = v2 - v0;
    vec3 pvec = cross(ray.dir, v0v2);
    float det = dot(v0v1, pvec);


    if (abs(det) < 0.008){
        hit.t=-1;
        return hit;// Culling is off
    }
    float invDet = 1 / det;

    vec3 tvec = ray.orig - v0;
    u = dot(tvec, pvec) * invDet;
    if (u < 0 || u > 1){
        hit.t=-1;
        return hit;
    }

    vec3 qvec = cross(tvec, v0v1);
    v = dot(ray.dir, qvec) * invDet;
    if (v < 0 || u + v > 1) {
        hit.t=-1;
        return hit;
    }

    hit.t = dot(v0v2, qvec) * invDet;
    hit.normal= cross(v0v1, v0v2);
    return hit;
}


vec3 getCoordinatefromIndices(float index){
    vec3 back;
    for (int i=0; i < primitiveCoordinates.length();i++){
        if (i==index){
            back=primitiveCoordinates[i];
            break;
        }
    }
    return back;
}


Hit firstIntersect(Ray ray){
    Hit besthit;
    besthit.t=-1;
    for (int i=0;i<indicesC.length();i++){
        vec3 TrianglePointA=getCoordinatefromIndices(indicesC[i].x);
        vec3 TrianglePointB=getCoordinatefromIndices(indicesC[i].y);
        vec3 TrianglePointC=getCoordinatefromIndices(indicesC[i].z);
        Hit hit=rayTriangleIntersect(ray, TrianglePointA, TrianglePointB, TrianglePointC);

        if (hit.t>0 && (besthit.t>hit.t|| besthit.t<0)){
            besthit=hit;
        }

    }
    return besthit;
}

vec3 trace(Ray ray){
    vec3 color;
    vec3 ka=vec3(0.5215, 0.1745, 0.0215);

    Hit hit;
    hit=firstIntersect(ray);
    if (hit.t==-1){
        return lights[0].La;
    }
    color=lights[0].La*ka;

    for (int i=0;i<lights.length();i++){
    Ray shadowRay;
    shadowRay.orig=hit.orig+hit.normal*0.0001f;
    shadowRay.dir=lights[i].direction;

        Hit shadowHit=firstIntersect(shadowRay);
        if (shadowHit.t<0){
            color+=lights[i].Le;
        }
    }
    return color;
}

void main()
{
    Ray ray;
    ray.orig = wEye;
    ray.dir = normalize(p - wEye);
    FragColor = vec4(trace(ray), 1);
}