Я создаю программу загрузки моделей на OpenGL. Я позаботился о свете и зеркальном отражении, но застрял на карте нормалей. Я думаю, что я делаю ошибку в расчете карты нормалей.
Нормальное изображение:
Когда я применяю эффект «Нормальное сопоставление», он выглядит следующим образом:
Мой вершинный шейдер:
#version 430 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 uvw;
layout(location = 3) in vec3 tangent;
layout(location = 4) in vec3 biTangent;
uniform mat4 M;
uniform mat4 MVP;
uniform mat3 N;
out block
{
vec4 position;
vec3 normal;
vec2 uvw;
vec3 tangent;
vec3 biTangent;
mat3 TBN;
} Out;
void main()
{
Out.position = M * vec4(position, 1.0);
Out.normal = normalize(N * normal);
Out.uvw = uvw;
Out.tangent = (M * vec4(tangent, 0.0)).xyz;
Out.TBN = mat3(tangent, biTangent, normal);
gl_Position = MVP * vec4(position, 1.0);
}
Фрагмент шейдера:
#version 430 core
#define M_PI 3.14159265358979323846
layout(binding = 0) uniform sampler2D dts;
layout(binding = 1) uniform sampler2D sts;
layout(binding = 2) uniform sampler2D nts;
struct Light {
vec3 position;
vec3 filterColor;
float multiplier;
};
struct Material {
vec3 baseColor;
float baseColorMultiplier;
float roughness;
float ior;
};
uniform Light light;
uniform Material material;
in block
{
vec4 position;
vec3 normal;
vec2 uvw;
vec3 tangent;
vec3 biTangent;
mat3 TBN;
} In;
out vec4 color;
vec3 Le(Light light, vec4 position, vec3 wi) {
vec3 Le;
float dist = length(wi);
Le = light.filterColor / (dist * dist);
return Le;
}
vec3 Fresnel(vec3 spec, vec3 normal, vec3 wi)
{
return spec + (1 - spec) * pow((1 - max(0.0, dot(wi, normal))), 5);
}
vec3 Normal()
{
vec4 norm = texture2D(nts, In.uvw);
return vec3(norm);
}
vec3 Diffuse(Material material, vec2 uvw) {
vec4 diff = texture2D(dts, uvw);
return vec3(diff) / M_PI;
}
vec3 Reflection(Material material, vec3 wi, vec3 normal, vec2 uvw)
{
vec3 f;
float cosTheta = dot(normal, wi);
vec4 spec = texture2D(sts, uvw);
f += vec3(1.0) * vec3(spec) * pow(max(0.0, abs(cosTheta)), material.roughness);
f += Fresnel(vec3(spec), normal, wi);
return f;
}
vec3 BRDF(Light light, Material material, vec3 wo, vec3 wi, vec4 position, vec3 normal, vec2 uvw) {
vec3 L;
// Evaluate emitted light
vec3 Li = Le(light, position, wi);
// Diffuse
vec3 f = Diffuse(material, uvw);
// Reflection
float cosThetaI = max(0.0, dot(wi, normal));
if(cosThetaI > 0.0) {
f += Reflection(material, wi, normal, uvw);
}
// BRDF function
L += f * Li * max(0.0, dot(wi, normal));
return L;
}
void main(void)
{
vec3 L;
vec3 wi, wo;
// Evaluate incoming and outgoing light direction
wi = normalize(light.position - vec3(In.position));
wo = reflect(-wi, In.normal);
// Evaluate normal map
vec4 normal = texture2D(nts, In.uvw);
normal = normalize(normal * 2.0 -1.0);
normal = vec4(normalize(In.TBN * normal.xyz), 0.0);
L += BRDF(light, material, wo, wi, In.position, normal.xyz, In.uvw);
color = vec4(L, 1.0);
}
Мой расчетный и касательный код вычисления:
void CGLPrimitive::CalculateTangentBiTangent()
{
for (unsigned int i = 0; i < positions.size(); i+=3) {
CVector3<float> p1 = positions[i];
CVector3<float> p2 = positions[i + 1];
CVector3<float> p3 = positions[i + 2];
CVector2<float> uv1 = uv[i];
CVector2<float> uv2 = uv[i+1];
CVector2<float> uv3 = uv[i+2];
CVector3<float> e1 = p2 - p1;
CVector3<float> e2 = p3 - p1;
CVector2<float> deltaUV1 = uv2 - uv1;
CVector2<float> deltaUV2 = uv3 - uv1;
float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
CVector3<float> t;
t.x = f * (deltaUV2.y * e1.x - deltaUV1.y * e2.x);
t.y = f * (deltaUV2.y * e1.y - deltaUV1.y * e2.y);
t.z = f * (deltaUV2.y * e1.z - deltaUV1.y * e2.z);
t = Normalize(t);
tangents.push_back(t);
tangents.push_back(t);
tangents.push_back(t);
CVector3<float> b;
b.x = f * (-deltaUV2.x * e1.x + deltaUV1.x * e2.x);
b.y = f * (-deltaUV2.x * e1.y + deltaUV1.x * e2.y);
b.z = f * (-deltaUV2.x * e1.z + deltaUV1.x * e2.z);
b = Normalize(b);
biTangents.push_back(b);
biTangents.push_back(b);
biTangents.push_back(b);
}
}
Интересно, где я ошибаюсь? Спасибо.