Почему модель растягивается при повороте камеры и как решить текстурирование? - PullRequest
2 голосов
/ 15 апреля 2020

Я работаю над OpenGL ray-tracer, который способен загружать файлы obj и трассировать его. Мое приложение загружает файл obj с помощью assimp, а затем отправляет все грани треугольника (вершины и индексы) в фрагментный шейдер с помощью объектов хранения шейдеров. Структура basi c собирается визуализировать результаты для четырехугольника из фрагментного шейдера.

Вот мой вершинный шейдер. Его форма отвечает за расположение пикселя на квад.

#version 460 core
layout(location = 0) in vec2 cCamWindowVertex;

    uniform vec3 wLookAt, wRight, wUp;    
    out vec3 p;
    out vec2 pos;

    void main()
    {
        pos=cCamWindowVertex.xy;
        gl_Position = vec4(cCamWindowVertex, 0, 1);
        p = wLookAt + wRight * cCamWindowVertex.x + cCamWindowVertex.y * wUp;
    }

Это фрагментный шейдер с методами, связанными с трассировкой лучей. Существует метод, который проверяет пересечения между гранями луча и треугольника (грань состоит из трех элементов из primitveCoordinates []). Униформа WEye - это позиция камеры.

#version 460 core

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

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

out      vec4       FragColor;
in       vec3       p;
uniform  vec3       wEye;

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

};

uniform Light lights[];

struct Ray{
    vec3 orig, dir;
};

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

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;
        shadowRay.dir=lights[0].direction;

        Hit shadowHit=firstIntersect(shadowRay);

         if (shadowHit.t<0 || shadowHit.t > length(shadowRay.orig-hit.orig))
            color= color+lights[0].Le;
        }
    }
    return color;
}

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

В main есть несколько унифицированных переменных. cpp:

float fov = 145;
glm::vec3 eye = glm::vec3(0, 0, 2);
glm::vec3 vup = glm::vec3(0, 1, 0);
glm::vec3 lookat = glm::vec3(0, 0, 0);
glm::vec3 w = eye - lookat;
float f = length(w);
glm::vec3 right1 = normalize(cross(vup, w)) ;
glm::vec3 up = normalize(cross(w, right1)) ;

У меня есть три вопроса, связанных с этим.

В настоящее время я работаю с простой моделью куба (созданной в blender). Я могу это визуализировать, но при вращении камеры куб растягивается. Я не знаю почему. Вот изображение куба. Если я поверну камеру слишком сильно, она станет такой же, как во втором пи c.

enter image description here

enter image description here

Мой второй вопрос связан с текстурированием. Смогу ли я добавить текстуры obj (из mtl) с такой структурой приложения? Я могу загрузить текстуры с Assimp. Я собираюсь написать texture(texture_diffuse1, TexCoords); и умножить его на цвет, рассчитанный методами fs, отвечающими за трассировку лучей. Но если грань содержит больше текстур, кроме диффузной, это может быть проблемой для реализации.

Мой третий вопрос: выбрал ли я правильное направление для реализации трассировки лучей в opengl?

В любом случае, вот моя ссылка на источник на github: https://github.com/fox-1942/rayTracerBoros/tree/testforRayTracing (Используемые в настоящее время шейдеры - это те, у которых в именах есть «четверные» окончания).

Любая помощь приветствуется , Спасибо!


Обновление 1:

Я обновил код по совету Rabbid76:

На моем основном. cpp Я обновил детали, отвечающие за область просмотра:

const float SCR_WIDTH = 1280;
const float SCR_HEIGHT = 720;
.
.
.
glm::vec3 eye = glm::vec3(0, 0, 2);
glm::vec3 vup = glm::vec3(0, 1, 0);
glm::vec3 lookat = glm::vec3(0, 0, 0);
glm::vec3 w = eye - lookat;
float aspect = (float)SCR_WIDTH/(float)SCR_HEIGHT;
glm::vec3 right1 = normalize(cross(vup, w))*aspect;
glm::vec3 up = normalize(cross(w, right1))*aspect;
.
.
.
// Then giving the variables to the corresponding uniforms


glUniform3fv(glGetUniformLocation(shaderQuadProgram.getShaderProgram_id(), "wLookAt"), 1, &lookat.x);

glUniform3fv(glGetUniformLocation(shaderQuadProgram.getShaderProgram_id(), "wRight"), 1, &right1.x);

glUniform3fv(glGetUniformLocation(shaderQuadProgram.getShaderProgram_id(), "wUp"), 1, &vup.x);

glUniform3fv(glGetUniformLocation(shaderQuadProgram.getShaderProgram_id(), "wEye"), 1, &eye.x);

К сожалению, модель все еще растянута.


Обновление 2:

Я совершенно уверен, проблема в том, что мне приходится пересчитывать переменные eye, up, f и right1 каждый раз, когда я изменяю одну из координат переменной глаза. Я создал метод пересчета:

void setCamera(float param) {
    eye.x += param;
    w = eye - lookat;
    float f = length(w);
    right1 = normalize(cross(vup, w)) * f * tanf(fov / 2);
    up = normalize(cross(w, right1)) * f * tanf(fov / 2);
}

Однако что-то все же не так. Мне кажется, что приложение не обновляет униформу в шейдерах, несмотря на то, что я попытался добавить glUniform3fv в метод выше, чтобы обновить eye, lookat, right1 и up. В любом случае, я использую glfw.


Обновление 3:

Я нашел решение, но оно может вращать камеру только горизонтально:

void setCamera(float param) {

    eye = glm::vec3(eye.x * cos(param) + eye.z * sin(param), eye.y, -eye.x * sin(param) + eye.z * cos(param)) + lookat;
    w = eye - lookat;
    float f = length(w);
    right1 = normalize(cross(vup, w)) * f * tanf(fov / 2);
    up = normalize(cross(w, right1)) * f * tanf(fov / 2);
}

Этот метод должен применяться при нажатии определенной клавиши c. Если кто-то знает, как сделать свободную летающую камеру на двумерном квадроцикле (используя такую ​​структуру), не стесняйтесь поделиться ею.

1 Ответ

1 голос
/ 15 апреля 2020

Вы должны соблюдать соотношение сторон окна просмотра.

Соотношение сторон учитывается wRight и wUp, когда вычисляется точка для направления луча:

p = wLookAt + wRight * cCamWindowVertex.x + cCamWindowVertex.y * wUp;

right - вектор от центра вправо, а up - вектор от центра к вершине. Таким образом, длина right1 должна быть масштабирована на соотношение сторон ((float)SCR_WIDTH/(float)SCR_HEIGHT):

float     aspect = (float)SCR_WIDTH/(float)SCR_HEIGHT;
glm::vec3 right1 = normalize(cross(vup, w)) * aspect;
glm::vec3 up     = normalize(cross(w, right1));
...