Привет, ребята, я пытаюсь реализовать Normal Mapping в Directx, и я очень близок к его созданию, но я получаю эти странные черные цвета на некоторых объектах. Вот как это выглядит без отображения нормалей:
И когда я применяю эффект Normal Mapping, это выглядит так:
Где я получаю черный цвет, например, на стене и какой-то части куба, что странно.
Мой файл Pixel Shader выглядит следующим образом:
cbuffer PositionBuffer : register(b1)
{
float3 cameraPos;
float pad;
float3 lightPos;
float pad1;
};
cbuffer PhongBuffer : register(b2) {
float4 ambient;
float4 diffus;
float4 blank;
float shininess;
float3 padd;
};
Texture2D texDiffuse : register(t0);
Texture2D texNormal : register(t1);
SamplerState texSampler : register(s0);
struct PSIn
{
float4 Pos : SV_Position;
float3 Normal : NORMAL;
float2 TexCoord : TEX;
float4 PosWorld : VIEWPOSITION;
float4 Tangent : TANGENT; //Added this
float4 Binormal : BINORMAL; //Added this
};
//-----------------------------------------------------------------------------------------
// Pixel Shader
//-----------------------------------------------------------------------------------------
float4 PS_main(PSIn input) : SV_Target
{
float3 N;
float3 L;
float3 R;
float3 V;
float3 I;
float3 textureColor;
float4 bumpMap;
float3 bumpNormal;
// Sample the texture pixel at this location.
textureColor = texDiffuse.Sample(texSampler, input.TexCoord).xyz;
// Sample the pixel in the bump map.
bumpMap = texNormal.Sample(texSampler, input.TexCoord);
// Expand the range of the normal value from (0, +1) to (-1, +1).
bumpMap = (bumpMap * 2.0f) - 1.0f;
// Calculate the normal from the data in the bump map.
bumpNormal = (bumpMap.x * input.Tangent) + (bumpMap.y * input.Binormal) + (bumpMap.z * input.Normal);
// Normalize the resulting bump normal.
//bumpNormal = Normalize(bumpNormal;L = lightPos - input.PosWorld;
//N = input.Normal;
N = bumpNormal;
V = cameraPos - input.PosWorld;
R = reflect(-L, N);
L = normalize(L);
N = normalize(N);
V = normalize(V);
R = normalize(R);I = ambient.xyz + (textureColor * max(dot(L,N), 0) + blank.xyz * max(pow(dot(R,V), shininess), 0)); //Phong Shader Formula
if(texNormal.Sample(texSampler, input.TexCoord).z <= 0) { //Prevent the objects that don't have bump map from being given the Normal Mapping effect
return texDiffuse.Sample(texSampler, input.TexCoord);
}
if(dot(L, N) < 0) {
return texDiffuse.Sample(texSampler, input.TexCoord);
}
return float4(I, 1);
}
И мой Vertex Shader выглядит так:
cbuffer MatrixBuffer : register(b0)
{
matrix ModelToWorldMatrix;
matrix WorldToViewMatrix;
matrix ProjectionMatrix;
};struct VSIn
{
float3 Pos : POSITION;
float3 Normal : NORMAL;
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
float2 TexCoord : TEX;
};
struct PSIn
{
float4 Pos : SV_Position;
float3 Normal : NORMAL;
float2 TexCoord : TEX;
float4 PosWorld : VIEWPOSITION;
float3 Tangent : TANGENT; //Added this
float3 Binormal : BINORMAL; //Added this
};
//-----------------------------------------------------------------------------------------
// Vertex Shader
//-----------------------------------------------------------------------------------------
PSIn VS_main(VSIn input)
{
PSIn output = (PSIn)0;
// Model->View transformation
matrix MV = mul(WorldToViewMatrix, ModelToWorldMatrix);
// Model->View->Projection (clip space) transformation
// SV_Position expects the output position to be in clip space
matrix MVP = mul(ProjectionMatrix, MV);
// Perform transformations and send to output
output.Pos = mul(MVP, float4(input.Pos, 1));
output.Normal = normalize( mul(ModelToWorldMatrix, float4(input.Normal,0)).xyz ); //Convert the Normal for the vertex to World Space
output.TexCoord = input.TexCoord;
output.PosWorld = mul(ModelToWorldMatrix, float4(input.Pos, 1)); //Convert to World Space
output.Tangent = normalize( mul(ModelToWorldMatrix, float4(input.Tangent,0)).xyz ); //Convert the Tangent for the vertex to World Space
output.Binormal = normalize( mul(ModelToWorldMatrix, float4(input.Binormal,0)).xyz ); //Convert the Binormal for the vertex to World Spacereturn output;
}
Этот метод используется для вычисления бинормали и тангенса для каждой вершины со стороны процессора (взято из руководства Rasterek Tutorial http://www.rastertek.com/dx11tut20.html):
void OBJModel_t::CalculateModelVectors(std::vector<vertex_t> & vertices) {
int faceCount, i, index;
vertex_t vertex1, vertex2, vertex3;
vec3f tangent, binormal, normal;
int m_vertexCount = vertices.size();
// Calculate the number of faces in the model.
faceCount = m_vertexCount / 3;
// Initialize the index to the model data.
index = 0;
// Go through all the faces and calculate the the tangent, binormal, and normal vectors.
for (i = 0; i<faceCount; i++)
{
// Get the three vertices for this face from the model.
vertex1.Pos.x = vertices[index].Pos.x;
vertex1.Pos.y = vertices[index].Pos.y;
vertex1.Pos.z = vertices[index].Pos.z;
vertex1.TexCoord.x = vertices[index].TexCoord.x;
vertex1.TexCoord.y = vertices[index].TexCoord.y;
vertex1.Normal.x = vertices[index].Normal.x;
vertex1.Normal.y = vertices[index].Normal.y;
vertex1.Normal.z = vertices[index].Normal.z;
index++;
vertex2.Pos.x = vertices[index].Pos.x;
vertex2.Pos.y = vertices[index].Pos.y;
vertex2.Pos.z = vertices[index].Pos.z;
vertex2.TexCoord.x = vertices[index].TexCoord.x;
vertex2.TexCoord.y = vertices[index].TexCoord.y;
vertex2.Normal.x = vertices[index].Normal.x;
vertex2.Normal.y = vertices[index].Normal.y;
vertex2.Normal.z = vertices[index].Normal.z;
index++;
vertex3.Pos.x = vertices[index].Pos.x;
vertex3.Pos.y = vertices[index].Pos.y;
vertex3.Pos.z = vertices[index].Pos.z;
vertex3.TexCoord.x = vertices[index].TexCoord.x;
vertex3.TexCoord.y = vertices[index].TexCoord.y;
vertex3.Normal.x = vertices[index].Normal.x;
vertex3.Normal.y = vertices[index].Normal.y;
vertex3.Normal.z = vertices[index].Normal.z;
index++;
// Calculate the tangent and binormal of that face.
CalculateTangentBinormal(vertex1, vertex2, vertex3, tangent, binormal);
// Calculate the new normal using the tangent and binormal.
CalculateNormal(tangent, binormal, normal);
// Store the normal, tangent, and binormal for this face back in the model structure.
vertices[index - 1].Normal.x = normal.x;
vertices[index - 1].Normal.y = normal.y;
vertices[index - 1].Normal.z = normal.z;
vertices[index - 1].Tangent.x = tangent.x;
vertices[index - 1].Tangent.y = tangent.y;
vertices[index - 1].Tangent.z = tangent.z;
vertices[index - 1].Binormal.x = binormal.x;
vertices[index - 1].Binormal.y = binormal.y;
vertices[index - 1].Binormal.z = binormal.z;
vertices[index - 2].Normal.x = normal.x;
vertices[index - 2].Normal.y = normal.y;
vertices[index - 2].Normal.z = normal.z;
vertices[index - 2].Tangent.x = tangent.x;
vertices[index - 2].Tangent.y = tangent.y;
vertices[index - 2].Tangent.z = tangent.z;
vertices[index - 2].Binormal.x = binormal.x;
vertices[index - 2].Binormal.y = binormal.y;
vertices[index - 2].Binormal.z = binormal.z;
vertices[index - 3].Normal.x = normal.x;
vertices[index - 3].Normal.y = normal.y;
vertices[index - 3].Normal.z = normal.z;
vertices[index - 3].Tangent.x = tangent.x;
vertices[index - 3].Tangent.y = tangent.y;
vertices[index - 3].Tangent.z = tangent.z;
vertices[index - 3].Binormal.x = binormal.x;
vertices[index - 3].Binormal.y = binormal.y;
vertices[index - 3].Binormal.z = binormal.z;
}
return;
}
void OBJModel_t::CalculateTangentBinormal(vertex_t vertex1, vertex_t vertex2, vertex_t vertex3, vec3f& tangent, vec3f& binormal) {
float vector1[3], vector2[3];
float tuVector[2], tvVector[2];
float den;
float length;// Calculate the two vectors for this face.
vector1[0] = vertex2.Pos.x - vertex1.Pos.x;
vector1[1] = vertex2.Pos.y - vertex1.Pos.y;
vector1[2] = vertex2.Pos.z - vertex1.Pos.z;
vector2[0] = vertex3.Pos.x - vertex1.Pos.x;
vector2[1] = vertex3.Pos.y - vertex1.Pos.y;
vector2[2] = vertex3.Pos.z - vertex1.Pos.z;
// Calculate the tu and tv texture space vectors.
tuVector[0] = vertex2.TexCoord.x - vertex1.TexCoord.x;
tvVector[0] = vertex2.TexCoord.y - vertex1.TexCoord.y;
tuVector[1] = vertex3.TexCoord.x - vertex1.TexCoord.x;
tvVector[1] = vertex3.TexCoord.y - vertex1.TexCoord.y;
// Calculate the denominator of the tangent/binormal equation.
den = 1.0f / (tuVector[0] * tvVector[1] - tuVector[1] * tvVector[0]);
// Calculate the cross products and multiply by the coefficient to get the tangent and binormal.
tangent.x = (tvVector[1] * vector1[0] - tvVector[0] * vector2[0]) * den;
tangent.y = (tvVector[1] * vector1[1] - tvVector[0] * vector2[1]) * den;
tangent.z = (tvVector[1] * vector1[2] - tvVector[0] * vector2[2]) * den;
binormal.x = (tuVector[0] * vector2[0] - tuVector[1] * vector1[0]) * den;
binormal.y = (tuVector[0] * vector2[1] - tuVector[1] * vector1[1]) * den;
binormal.z = (tuVector[0] * vector2[2] - tuVector[1] * vector1[2]) * den;
// Calculate the length of this normal.
length = sqrt((tangent.x * tangent.x) + (tangent.y * tangent.y) + (tangent.z * tangent.z));
// Normalize the normal and then store it
tangent.x = tangent.x / length;
tangent.y = tangent.y / length;
tangent.z = tangent.z / length;
// Calculate the length of this normal.
length = sqrt((binormal.x * binormal.x) + (binormal.y * binormal.y) + (binormal.z * binormal.z));
// Normalize the normal and then store it
binormal.x = binormal.x / length;
binormal.y = binormal.y / length;
binormal.z = binormal.z / length;
return;
}
void OBJModel_t::CalculateNormal(vec3f tangent, vec3f binormal, vec3f& normal)
{
float length;// Calculate the cross product of the tangent and binormal which will give the normal vector.
normal.x = (tangent.y * binormal.z) - (tangent.z * binormal.y);
normal.y = (tangent.z * binormal.x) - (tangent.x * binormal.z);
normal.z = (tangent.x * binormal.y) - (tangent.y * binormal.x);// Calculate the length of the normal.
length = sqrt((normal.x * normal.x) + (normal.y * normal.y) + (normal.z * normal.z));
// Normalize the normal.
normal.x = normal.x / length;
normal.y = normal.y / length;
normal.z = normal.z / length;
return;
}
Задача ещё не решена.
Других решений пока нет …