opengl — вычисляет касательное пространство в переполнении стека

Я пытаюсь сделать сцену с использованием нормального отображения

Поэтому я вычисляю тангенциальное пространство в C ++ и храню бинормали и тангеты отдельно в массиве, который будет загружен в мой шейдер с помощью vertexattribpointer.

Вот как я рассчитываю пространство

void ObjLoader::computeTangentSpace(MeshData &meshData) {
GLfloat* tangents = new GLfloat[meshData.vertex_position.size()]();
GLfloat* binormals = new GLfloat[meshData.vertex_position.size()]();

std::vector<glm::vec3 > tangent;
std::vector<glm::vec3 > binormal;

for(unsigned int i = 0; i < meshData.indices.size(); i = i+3){

glm::vec3 vertex0 = glm::vec3(meshData.vertex_position.at(meshData.indices.at(i)), meshData.vertex_position.at(meshData.indices.at(i)+1),meshData.vertex_position.at(meshData.indices.at(i)+2));
glm::vec3 vertex1 = glm::vec3(meshData.vertex_position.at(meshData.indices.at(i+1)), meshData.vertex_position.at(meshData.indices.at(i+1)+1),meshData.vertex_position.at(meshData.indices.at(i+1)+2));
glm::vec3 vertex2 = glm::vec3(meshData.vertex_position.at(meshData.indices.at(i+2)), meshData.vertex_position.at(meshData.indices.at(i+2)+1),meshData.vertex_position.at(meshData.indices.at(i+2)+2));

glm::vec3 normal = glm::cross((vertex1 - vertex0),(vertex2 - vertex0));

glm::vec3 deltaPos;
if(vertex0 == vertex1)
deltaPos = vertex2 - vertex0;
else
deltaPos = vertex1 - vertex0;

glm::vec2 uv0 = glm::vec2(meshData.vertex_texcoord.at(meshData.indices.at(i)), meshData.vertex_texcoord.at(meshData.indices.at(i)+1));
glm::vec2 uv1 = glm::vec2(meshData.vertex_texcoord.at(meshData.indices.at(i+1)), meshData.vertex_texcoord.at(meshData.indices.at(i+1)+1));
glm::vec2 uv2 = glm::vec2(meshData.vertex_texcoord.at(meshData.indices.at(i+2)), meshData.vertex_texcoord.at(meshData.indices.at(i+2)+1));

glm::vec2 deltaUV1 = uv1 - uv0;
glm::vec2 deltaUV2 = uv2 - uv0;

glm::vec3 tan; // tangents
glm::vec3 bin; // binormal

// avoid divion with 0
if(deltaUV1.s != 0)
tan = deltaPos / deltaUV1.s;
else
tan = deltaPos / 1.0f;

tan = glm::normalize(tan - glm::dot(normal,tan)*normal);

bin = glm::normalize(glm::cross(tan, normal));

// write into array - for each vertex of the face the same value
tangents[meshData.indices.at(i)]   = tan.x;
tangents[meshData.indices.at(i)+1] = tan.y;
tangents[meshData.indices.at(i)+2] = tan.z;

tangents[meshData.indices.at(i+1)]   = tan.x;
tangents[meshData.indices.at(i+1)+1] = tan.y;
tangents[meshData.indices.at(i+1)+2] = tan.z;

tangents[meshData.indices.at(i+2)]   = tan.x;
tangents[meshData.indices.at(i+2)+1] = tan.y;
tangents[meshData.indices.at(i+2)+1] = tan.z;

binormals[meshData.indices.at(i)]   = bin.x;
binormals[meshData.indices.at(i)+1] = bin.y;
binormals[meshData.indices.at(i)+2] = bin.z;

binormals[meshData.indices.at(i+1)]   = bin.x;
binormals[meshData.indices.at(i+1)+1] = bin.y;
binormals[meshData.indices.at(i+1)+2] = bin.z;

binormals[meshData.indices.at(i+2)]   = bin.x;
binormals[meshData.indices.at(i+2)+1] = bin.y;
binormals[meshData.indices.at(i+2)+1] = bin.z;
}
// Copy the tangent and binormal to meshData
for(unsigned int i = 0; i < meshData.vertex_position.size(); i++){
meshData.vertex_tangent.push_back(tangents[i]);
meshData.vertex_binormal.push_back(binormals[i]);
}
}

А вот и мой вершинный и фрагментный шейдер

Вершинный шейдер

#version 330
layout(location = 0) in vec3 vertex;
layout(location = 1) in vec3 vertex_normal;
layout(location = 2) in vec2 vertex_texcoord;
layout(location = 3) in vec3 vertex_tangent;
layout(location = 4) in vec3 vertex_binormal;

struct LightSource {
vec3 ambient_color;
vec3 diffuse_color;
vec3 specular_color;
vec3 position;
};

uniform vec3 lightPos;

out vec3 vertexNormal;
out vec3 eyeDir;
out vec3 lightDir;
out vec2 textureCoord;uniform mat4 view;
uniform mat4 modelview;
uniform mat4 projection;

out vec4 myColor;void main() {

mat4 normalMatrix = transpose(inverse(modelview));

gl_Position = projection * modelview * vec4(vertex, 1.0);

vec4 binormal = modelview * vec4(vertex_binormal,1);
vec4 tangent = modelview * vec4(vertex_tangent,1);
vec4 normal =  vec4(vertex_normal,1);

mat3 tangentMatrix = mat3(tangent.xyz,binormal.xyz,normal.xyz);
vec3 vertexInCamSpace = (modelview * vec4(vertex, 1.0)).xyz;
eyeDir = tangentMatrix * normalize( -vertexInCamSpace);
vec3 lightInCamSpace = (view * vec4(lightPos, 1.0)).xyz;
lightDir = tangentMatrix * normalize((lightInCamSpace - vertexInCamSpace));

textureCoord = vertex_texcoord;
}

Фрагмент шейдера

#version 330

struct LightSource {
vec3 ambient_color;
vec3 diffuse_color;
vec3 specular_color;
vec3 position;
};

struct Material {
vec3 ambient_color;
vec3 diffuse_color;
vec3 specular_color;
float specular_shininess;
};

uniform LightSource light;
uniform Material material;

in vec3 vertexNormal;
in vec3 eyeDir;
in vec3 lightDir;
in vec2 textureCoord;uniform sampler2D texture;
uniform sampler2D normals;out vec4 color;in vec4 myColor;
in vec3 bin;
in vec3 tan;void main() {
vec3 diffuse  = texture2D(texture,textureCoord).rgb;vec3 E = normalize(eyeDir);

vec3 N = texture2D(normals,textureCoord).xyz;
N = (N - 0.5) * 2.0;

vec3 ambientTerm = vec3(0);
vec3 diffuseTerm = vec3(0);
vec3 specularTerm = vec3(0);
vec3 L, H;

L = normalize(lightDir);
H = normalize(E + L);
ambientTerm += light.ambient_color;
diffuseTerm += light.diffuse_color * max(dot(L, N), 0);
specularTerm += light.specular_color * pow(max(dot(H, N), 0), material.specular_shininess);

ambientTerm *= material.ambient_color;
diffuseTerm *= material.diffuse_color;
specularTerm *= material.specular_color;

color = vec4(diffuse, 1) * vec4(ambientTerm + diffuseTerm + specularTerm, 1);}

Проблема в том, что иногда в шейдере нет значений тангенса и касательного. Вот три снимка экрана, которые, я надеюсь, прояснят мою проблему:

Вот как выглядит сцена в данный момент, когда я рендерил ее с кодом выше:

Сцена с кодом сверху

Вот так выглядит сцена, когда я использую lightDir как цвет

LightDir как цвет

И третий показывает сцену с eyeDir в качестве цвета

EyeDir как цвет

Все снимки делаются под одним углом, без движения камеры или чего-либо вращающегося.
Я уже сравнил свой код с несколькими различными источниками в www, но я не нашел ошибку, которую я сделал …

Дополнительная информация:

Я перебираю все текущие лица. Три индекса дадут мне один треугольник. Значения UV для каждой вершины хранятся с тем же индексом. Имея много отладок, я очень уверен, что это правильные значения, так как я могу найти правильные значения в файле .obj при поиске с помощью gedit.

После вычисления тангенса и бинормаля я сохраняю нормаль с тем же индексом, что и положение вершины в массиве. Для моего понимания это должно дать мне правильную позицию, и я рассчитываю это для каждой вершины. Для каждой вершины грани я использую один и тот же касательный базис, который может быть позже перезаписан, когда другая грань использует эту вершину, это может испортить мой конечный результат, но только в очень мелких деталях …

РЕДАКТИРОВАТЬ:
Для любых других вопросов, вот весь проект:

http://www.incentivelabs.de/Sourcecode/normal_mapping.zip

3

Решение

В вашем вершинном шейдере у вас есть:

vec4 binormal = modelview * vec4(vertex_binormal,1);
vec4 tangent = modelview * vec4(vertex_tangent,1);
vec4 normal =  vec4(vertex_normal,1);

Это должно быть:

vec4 binormal = modelview * vec4(vertex_binormal,0);
vec4 tangent = modelview * vec4(vertex_tangent,0);
vec4 normal =  modelview * vec4(vertex_normal,0);

Обратите внимание на «0» вместо «1» (также я предполагаю, что вы также хотели изменить свое нормальное значение). Здесь вы используете ‘0’, потому что хотите игнорировать часть преобразования преобразования модели (вы трансформируете вектор, а не точку).

6

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector