Файл obj трассировки лучей в opengl / glsl

Я хотел бы реализовать трассировку лучей в opengl и glsl для рендеринга моделей, загруженных из файлов .obj, но я не понимаю, как именно это сделать. Раньше я использовал файлы obj, но для их рендеринга использовал растеризацию. До сих пор я реализовал простой трассировщик лучей с использованием фрагментного шейдера, который визуализирует некоторые простые формы (плоскости, сферы, блоки). Дело в том, что при трассировке лучей я вычисляю пересечения с объектами, но они также определены во фрагментном шейдере.

Вот как я сделал рендеринг с использованием растеризации: после загрузки данных вершин (положение, нормаль, uvs) я сохраняю их в VBO и привязываю их к VAO. Я отправляю их в вершинный шейдер и преобразую их, умножая на матрицы MVP. Затем я отправляю преобразованные вершины во фрагментный шейдер, когда их затеняю. Но это та часть, которую я не понимаю, как реализовать с помощью трассировки лучей, потому что теперь я преобразовал вершины в качестве входных данных для фрагментного шейдера, а это означает, что я не знаю, как вычислять пересечения лучей с треугольниками сетки. Итак, как это сделать?


person mezo    schedule 29.11.2014    source источник


Ответы (2)


Ну, по сути, для каждого фрагмента вы выполняете тест на пересечение лучей со всей сценой. Таким образом, проблема заключается в кодировании сцены в некую структуру данных, к которой можно получить доступ из фрагментного шейдера, и которая предлагает достаточно места для нее. Непосредственным выбором будут три одномерные текстуры с 3-мя компонентами одинакового размера, где для каждого индекса текселя тройка из трех текстур представляет собой треугольник. Затем для каждого луча, брошенного в сцену (т.е. для каждого фрагмента), итерация по треугольникам.

Если вы хотите стать немного более привлекательным, вы можете вместо этого использовать три 3D-текстуры, поместив данные треугольника в правую область текстуры, чтобы ограничить тексели для итерации, использовать их уровни mipmap для LOD и использовать разреженное хранилище текстур для уменьшения памяти след.

person datenwolf    schedule 29.11.2014

В последнее время я работаю именно над этим. Я использую библиотеку Assimp для импорта файла obj и получения вершин и индексов в отдельные массивы. Я отправляю вершины и индексы во фрагментный шейдер через буферы хранения шейдеров. К сожалению, когда я хочу отследить более 100 граней треугольников и проверить пересечения, мой компьютер выйдет из строя. Я предполагаю, что именно поэтому в настоящее время существуют графические процессоры, предназначенные для трассировки лучей (мой графический процессор - gtx750 ti). В моем шейдере фрагментов есть алгоритм пересечения Меллера – Трумборе для проверки пересечения между треугольником и лучом.

Вот мой фрагментный шейдер (в стадии разработки, поэтому не завершен):

#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);
}
person Fox42    schedule 18.04.2020