Нормальное картирование и перевод нарушают мое освещение

У меня нормальная проблема с отображением. У меня есть текстура и нормальная текстура для каждой модели, загруженной через библиотеку ASSIMP. Я рассчитываю касательные векторы на каждом объекте с помощью библиотеки ASSIMP, поэтому они должны быть в порядке. Объекты отлично работают с нормальным отображением, но как только я начинаю переводить один из объектов (таким образом, влияя на матрицу модели с помощью переводов), освещение перестает работать. Как вы можете видеть на изображении, пол (который переводится вниз по оси y), по-видимому, теряет большую часть рассеянного освещения, а его зеркальное освещение направлено в неправильном направлении (оно должно быть между лампочкой и положением игрока)

Нормальное отображение пошло не так

Это может быть связано с нормальной матрицей (хотя переводы должны быть потеряны), возможно, с неправильной матрицей, используемой в шейдерах. У меня нет идей, и я надеялся, что вы могли бы пролить свет на эту проблему.

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

#version 330

layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 tangent;
layout(location = 3) in vec3 color;
layout(location = 4) in vec2 texCoord;

// fragment pass through
out vec3 Position;
out vec3 Normal;
out vec3 Tangent;
out vec3 Color;
out vec2 TexCoord;

out vec3 TangentSurface2Light;
out vec3 TangentSurface2View;

uniform vec3 lightPos;
uniform vec3 playerPos;

// vertex transformation
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
mat3 normalMatrix = mat3(transpose(inverse(model)));
Position = vec3(model * vec4(position, 1.0));
Normal = normalMatrix * normal;
Tangent = tangent;
Color = color;
TexCoord = texCoord;

gl_Position = projection * view * model * vec4(position, 1.0);

// Calculate tangent matrix and calculate fragment bump mapping coord space.
vec3 light = lightPos;
vec3 n = normalize(normalMatrix * normal);
vec3 t = normalize(normalMatrix * tangent);
vec3 b = cross(n, t);
// create matrix for tangent (from vertex to tangent-space)
mat3 mat = mat3(t.x, b.x ,n.x, t.y, b.y ,n.y, t.z, b.z ,n.z);
vec3 vector = normalize(light - Position);
TangentSurface2Light = mat * vector;
vector = normalize(playerPos - Position);
TangentSurface2View = mat * vector;
}

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

    #version 330

in vec3 Position;
in vec3 Normal;
in vec3 Tangent;
in vec3 Color;
in vec2 TexCoord;

in vec3 TangentSurface2Light;
in vec3 TangentSurface2View;

out vec4 outColor;

uniform vec3 lightPos;
uniform vec3 playerPos;
uniform mat4 view;
uniform sampler2D texture0;
uniform sampler2D texture_normal; // normal

uniform float repeatFactor = 1;

void main()
{
vec4 texColor = texture(texture0, TexCoord * repeatFactor);
vec4 matColor = vec4(Color, 1.0);
vec3 light = vec3(vec4(lightPos, 1.0));
float dist = length(light - Position);
// float att = 1.0 / (1.0 + 0.01 * dist + 0.001 * dist * dist);
float att = 1.0;
// Ambient
vec4 ambient = vec4(0.2);
// Diffuse
// vec3 surface2light = normalize(light - Position);
vec3 surface2light = normalize(TangentSurface2Light);
// vec3 norm = normalize(Normal);
vec3 norm = normalize(texture(texture_normal, TexCoord * repeatFactor).xyz * 2.0 - 1.0);
float contribution = max(dot(norm, surface2light), 0.0);
vec4 diffuse = contribution * vec4(0.6);
// Specular
// vec3 surf2view = normalize(-Position); // Player is always at position 0
vec3 surf2view = normalize(TangentSurface2View);
vec3 reflection = reflect(-surface2light, norm); // reflection vector
float specContribution = pow(max(dot(surf2view, reflection), 0.0), 32);
vec4 specular = vec4(1.0) * specContribution;

outColor = (ambient + (diffuse * att)+ (specular * pow(att, 3))) * texColor;
// outColor = vec4(Color, 1.0) * texture(texture0, TexCoord);
}

РЕДАКТИРОВАТЬ

Отредактировал код шейдера, чтобы вычислить все в мировом пространстве вместо пинг-понга между миром и пространством камеры (проще для понимания и менее подвержен ошибкам).

7

Решение

Вы делаете странные манипуляции с матрицами. В VS вы преобразуете обычное (то есть модельное пространство) с помощью обратного мировоззрения. Это не имеет никакого смысла. Может быть проще делать вычисления в мировом пространстве. У меня есть некоторый рабочий пример кода, но он использует немного другое наименование.

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

void main_vs(in A2V input, out V2P output)
{
output.position = mul(input.position, _worldViewProjection);
output.normal = input.normal;
output.binormal = input.binormal;
output.tangent = input.tangent;
output.positionWorld = mul(input.position, _world);
output.tex = input.tex;
}

Здесь мы преобразуем положение в пространство проекции (экрана), TBN остается в пространстве модели, они будут использованы позже. Также мы получаем позицию в мировом пространстве для оценки освещения.

Пиксельный шейдер:

void main_ps(in V2P input, out float4 output : SV_Target)
{
float3x3 tbn = float3x3(input.tangent, -input.binormal, input.normal);

//extract & decode normal:
float3 texNormal = _normalTexture.Sample(_normalSampler, input.tex).xyz * 2 - 1;

//now transform TBN-space texNormal to world space:
float3 normal = mul(texNormal, tbn);
normal = normalize(mul(normal, _world));

float3 lightDirection = -_lightPosition.xyz;//directional
float3 viewDirection = normalize(input.positionWorld - _camera);
float3 reflectedLight = reflect(lightDirection, normal);

float diffuseIntensity = dot(normal, lightDirection);
float specularIntensity = max(0, dot(reflectedLight, viewDirection)*1.3);

output = ((_ambient + diffuseIntensity * _diffuse) * _texture.Sample(_sampler, input.tex)
+ pow(specularIntensity, 7) * float4(1,1,1,1)) * _lightColor;
}

Здесь я использую направленный свет, вы должны сделать что-то вроде

float3 lightDirection = normalize(input.positionWorld - _lightPosition.xyz);//omni

Здесь мы сначала имеем нормальную текстуру, то есть в TBN-пространстве. Затем мы применяем матрицу TBN, чтобы преобразовать ее в модельное пространство. Затем примените мировую матрицу, чтобы преобразовать ее в мировое пространство, где у нас уже есть светлая позиция, глаз и т. Д.

Некоторый другой код шейдера, опущенный выше (DX11, но его легко перевести):

cbuffer ViewTranforms
{
row_major matrix _worldViewProjection;
row_major matrix _world;
float3 _camera;
};

cbuffer BumpData
{
float4 _ambient;
float4 _diffuse;
};

cbuffer Textures
{
texture2D _texture;
SamplerState _sampler;

texture2D _normalTexture;
SamplerState _normalSampler;
};

cbuffer Light
{
float4 _lightPosition;
float4 _lightColor;
};

//------------------------------------

struct A2V
{
float4 position : POSITION;
float3 normal : NORMAL;
float3 binormal : BINORMAL;
float3 tangent : TANGENT;
float2 tex : TEXCOORD;
};

struct V2P
{
float4 position : SV_POSITION;
float3 normal : NORMAL;
float3 binormal : BINORMAL;
float3 tangent : TANGENT;
float3 positionWorld : NORMAL1;
float2 tex : TEXCOORD;
};

Кроме того, здесь я использую предварительно вычисленный бинормаль: вы должны оставить свой код, который его вычисляет (через кросс (нормальный, касательный)).
Надеюсь это поможет.

4

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

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

По вопросам рекламы [email protected]