Hello all,
I'm quite close to getting normal mapping to work with a quad. Using the calculations for the binormals and tangents (which I received from an awesome tutorial) it would appear that I am getting back valid normalized values. However I see nothing on the screen :\
There is a lot of code in this question, so I will recommend not to read all of it since I believe the problem lies in the .fx file, i.e. my shaders. So I thought I would bring it to you guys and you can show me the errors of my ways
Below is a snippet of code from the function LoadContent:
void Tesellator::LoadContent()
{
//Init the light for the scene
light.pos = XMFLOAT3(0.0f, 0.0f, 1.0f);
light.diffuse = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
light.ambient = XMFLOAT4(0.5f, 0.5f, 0.5f, 0.5f);
//add the inital vertices for my quad
calcInitVerts();
//calculate the normals, binormals and tangents for my quad
calcModelVectors();
finalVerts verts[6];
//fill in the array of structures to be sent to the vertexBuffer
for (int i = 0; i <= 5; i++)
{
verts[i].pos.x = vertices[i].pos.x;
verts[i].pos.y = vertices[i].pos.y;
verts[i].pos.z = vertices[i].pos.z;
verts[i].tex.x = vertices[i].tex.x;
verts[i].tex.y = vertices[i].tex.y;
verts[i].norm.x = model[i].norm.x;
verts[i].norm.y = model[i].norm.y;
verts[i].norm.z = model[i].norm.z;
verts[i].tang.x = model[i].tang.x;
verts[i].tang.y = model[i].tang.y;
verts[i].tang.z = model[i].tang.z;
verts[i].binorm.x = model[i].binorm.x;
verts[i].binorm.y = model[i].binorm.y;
verts[i].binorm.z = model[i].binorm.z;
}
D3D11_BUFFER_DESC vertexDesc;
ZeroMemory(&vertexDesc, sizeof(D3D11_BUFFER_DESC));
vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexDesc.Usage = D3D11_USAGE_DEFAULT;
vertexDesc.ByteWidth = sizeof(finalVerts) * 6;
D3D11_SUBRESOURCE_DATA resource;
ZeroMemory(&resource, sizeof(D3D11_SUBRESOURCE_DATA));
resource.pSysMem = verts;
dev->CreateBuffer(&vertexDesc, &resource, &vertexBuffer);
WORD indices[] =
{
0, 1, 2, 3, 4, 5,
};
D3D11_BUFFER_DESC indicesDesc;
ZeroMemory(&indicesDesc, sizeof(D3D11_BUFFER_DESC));
indicesDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indicesDesc.Usage = D3D11_USAGE_DEFAULT;
indicesDesc.ByteWidth = sizeof(WORD) * 6;
indicesDesc.CPUAccessFlags = 0;
resource.pSysMem = indices;
dev->CreateBuffer(&indicesDesc, &resource, &indexBuffer);
D3D11_BUFFER_DESC constDesc;
ZeroMemory(&constDesc, sizeof(D3D11_BUFFER_DESC));
constDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constDesc.Usage = D3D11_USAGE_DEFAULT;
constDesc.ByteWidth = sizeof(XMMATRIX);
dev->CreateBuffer(&constDesc, 0, &worldCB);
dev->CreateBuffer(&constDesc, 0, &viewCB);
dev->CreateBuffer(&constDesc, 0, &projCB);
constDesc.ByteWidth = sizeof(cbPerFrame);
dev->CreateBuffer(&constDesc, 0, &LightCB);
projMat = XMMatrixPerspectiveFovLH(XM_PIDIV4, 850.0f / 650.0f, 0.1f, 100.0f);
projMat = XMMatrixTranspose( projMat );
D3DX11CreateShaderResourceViewFromFile(dev, L"1.png", NULL, NULL, &colorMap[0], NULL);
D3DX11CreateShaderResourceViewFromFile(dev, L"2.png", NULL, NULL, &colorMap[1], NULL);
}
//Fill out the initial vertices for my quad
void Tesellator::calcInitVerts()
{
vertices[0].pos = XMFLOAT3(-1.0f, -1.0f, 0.0f);
vertices[0].tex = XMFLOAT2( 0.0f, 1.0f);
vertices[0].norm = XMFLOAT3(-1.0f, -1.0f, -1.0f);
vertices[1].pos = XMFLOAT3(-1.0f, 1.0f, 0.0f);
vertices[1].tex = XMFLOAT2(0.0f, 0.0f);
vertices[1].norm = XMFLOAT3(-1.0f, 1.0f, -1.0f);
vertices[2].pos = XMFLOAT3(1.0f, 1.0f, 0.0f);
vertices[2].tex = XMFLOAT2(1.0f, 0.0f);
vertices[2].norm = XMFLOAT3(1.0f, 1.0f, -1.0f);
vertices[3].pos = XMFLOAT3(1.0f, 1.0f, 0.0f);
vertices[3].tex = XMFLOAT2(1.0f, 0.0f);
vertices[3].norm = XMFLOAT3(1.0f, 1.0f, -1.0f);
vertices[4].pos = XMFLOAT3(1.0f, -1.0f, 0.0f);
vertices[4].tex = XMFLOAT2(1.0f, 1.0f);
vertices[4].norm = XMFLOAT3(1.0f, -1.0f, -1.0f);
vertices[5].pos = XMFLOAT3(-1.0f, -1.0f, 0.0f);
vertices[5].tex = XMFLOAT2(0.0f, 1.0f);
vertices[5].norm = XMFLOAT3(-1.0f, -1.0f, -1.0f);
}
Now as I said It would APPEAR that I am getting valid normalized values back from the preceding function calls, so I'm not to sure those are the roots of my problem, in fact I think it's the shader which is the code I will show next
[code]
/////////////
// GLOBALS //
/////////////
Texture2D shaderTextures[2] : register(t0);
SamplerState SampleType : register(s0);
struct Light
{
float3 dir;
float4 diffuse;
float4 ambient;
};
cbuffer LightBuffer : register(b0)
{
Light light;
};
cbuffer MatrixBuffer : register(b0)
{
matrix worldMatrix;
};
cbuffer MatrixBuffer2 : register(b1)
{
matrix viewMatrix;
};
cbuffer MatrixBuffer3 : register(b2)
{
matrix projectionMatrix;
};
//////////////
// TYPEDEFS //
//////////////
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD0;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 binormal : BINORMAL;
};
struct VertexInputType
{
float4 position : POSITION;
float2 tex : TEXCOORD0;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 binormal : BINORMAL;
};
PixelInputType BumpMapVertexShader(VertexInputType input)
{
PixelInputType output;
// Change the position vector to be 4 units for proper matrix calculations.
input.position.w = 1.0f;
// Calculate the position of the vertex against the world, view, and projection matrices.
output.position = mul(input.position, worldMatrix);
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);
// Store the texture coordinates for the pixel shader.
output.tex = input.tex;
// Calculate the normal vector against the world matrix only and then normalize the final value.
output.normal = mul(input.normal, viewMatrix);
output.normal = normalize(output.normal);
// Calculate the tangent vector against the world matrix only and then normalize the final value.
output.tangent = mul(input.tangent, worldMatrix);
output.tangent = normalize(output.tangent);
// Calculate the binormal vector against the world matrix only and then normalize the final value.
output.binormal = mul(input.binormal, worldMatrix);
output.binormal = normalize(output.binormal);
return output;
}
////////////////////////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////////////////////////
float4 BumpMapPixelShader(PixelInputType input) : SV_TARGET
{
float4 textureColor;
float4 bumpMap;
float3 bumpNormal;
float3 lightDir;
float lightIntensity;
float4 color;
// Sample the texture pixel at this location.
textureColor = shaderTextures[0].Sample(SampleType, input.tex);
// Sample the pixel in the bump map.
bumpMap = shaderTextures[1].Sample(SampleType, input.tex);
// 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 = input.normal + bumpMap.x * input.tangent + bumpMap.y * input.binormal;
// Normalize the resulting bump normal.
bumpNormal = normalize(bumpNormal);
// Calculate the amount of light on this pixel based on the bump map normal value.
lightIntensity = saturate(dot(bumpNormal, -light.dir));
// Determine the final diffuse color based on the diffuse color and the amount of light intensity.
color = saturate(light.diffuse * lightIntensity);
// Combine the final bump light color with the texture color.
color = color * textureColor;
return color;
}
[/code]
Notice in the top of the .fx file I am setting a Texture2D array of 2 elements, one for the image and the normal map of said image.
and last but not least the "SetShaders" Function where I bind the structures to Constant Buffers and Set the Shaders.
[code]
float clearColor[] = {0.0f, 0.0f, 1.0f, 0.0f};
devcon->ClearRenderTargetView(backBuffer, clearColor);
devcon->ClearDepthStencilView(depthStencil, D3D11_CLEAR_DEPTH, 1.0f, 0);
//InputAssembler:
////////////////////////////////////////
devcon->IASetInputLayout(inputL);
devcon->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R16_UINT, offset);
devcon->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
devcon->VSSetShader(vsColor, 0, 0);
devcon->PSSetShader(psColor, 0, 0);
devcon->PSSetShaderResources(0, 2, colorMap);
devcon->PSSetSamplers(0, 1, &colorSampler);
//////////////////////////////////////
cbPer.light = light;
devcon->PSSetConstantBuffers(0, 1, &LightCB);
devcon->UpdateSubresource(LightCB, 0, 0, &cbPer, 0, 0);
worldMat = XMMatrixIdentity();
worldMat = XMMatrixTranspose( worldMat );
rotationMat = XMMatrixRotationRollPitchYaw(0.0f, 0.0f, 0.0f);
translationMat = XMMatrixTranslation(0.0f, 0.0f, 3.0f);
viewMat = rotationMat * translationMat;
viewMat = XMMatrixTranspose( viewMat );
devcon->VSSetConstantBuffers(0, 1, &worldCB);
devcon->VSSetConstantBuffers(1, 1, &viewCB);
devcon->VSSetConstantBuffers(2, 1, &projCB);
devcon->UpdateSubresource(worldCB, 0, 0, &worldMat, 0, 0);
devcon->UpdateSubresource(viewCB, 0, 0, &viewMat, 0, 0);
devcon->UpdateSubresource(projCB, 0, 0, &projMat, 0, 0);
//Draw the quad
devcon->DrawIndexed(6, 0, 0);
I personally think the root of my problems lies in the shaders but I've been wrong before. As I said I emitted the code where I actually do the calculations for the tangent and binormals since Im getting back what would APPEAR to be valid normalized values.
So in conclusion I just would like to know what is it that I am overlooking that is giving me nothing on the screen.
-Marcus