I'm having some trouble while seen the correct result of my computations. I'll post my current setup.
I'll ommit the others parts of the code like matrices, device creation because I've already checked and its 100% working.
I'm loading models from .fbx and I tried to convert the order of drawing to CCW and CW. Also, I tried to invert the Z coordinate of the normals, positions, and the UV's Y coordinate like 1.0f - UV.y.
For the vertex buffers I'm using one per attribute. In my case 5 vertex buffers one for each attribute.
I have the DirectX 11's Debug Layer activated (no warnings/errors) and I don't have PIX, Render Doc working and I don't have money to buy a version of Visual Studio with integrated Graphics Debugger.
Vertex Shader:
cbuffer Model : register(b0) {
float4x4 mWorldView;
float4x4 mProjection;
float4x4 mNormal;
};
struct VS_INPUT {
float4 vPos : POSITION0;
float2 vTexCoord : TEXCOORD0;
float3 vNormal : NORMAL0;
float3 vBinormal : NORMAL1;
float3 vTangent : TANGENT0;
};
struct VS_OUTPUT {
float4 vPos : SV_POSITION;
float4 vViewSpacePos : POSITION0;
float2 vTexCoord : TEXCOORD0;
float3 vNormal : NORMAL0;
float3 vToLight : NORMAL1;
float3 vToViewer : NORMAL2;
};
void main( in VS_INPUT _viIn, out VS_OUTPUT _voOut ) {
_voOut.vViewSpacePos = mul( mWorldView, _viIn.vPos );
_voOut.vTexCoord = _viIn.vTexCoord;
_voOut.vNormal = _viIn.vNormal;
_voOut.vToLight = float3(0.0, 10.0, 0.0) - _voOut.vViewSpacePos.xyz;
_voOut.vToViewer = -_voOut.vViewSpacePos.xyz;
_voOut.vPos = mul( mProjection, _voOut.vViewSpacePos );
}
Vertex Layout:
D3D11_INPUT_ELEMENT_DESC CDirectX11Shader::m_pcDefaultVertexDesc[VA_MAX] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 1, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 2, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 1, DXGI_FORMAT_R32G32B32_FLOAT, 3, 40, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 4, 56, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
Here's my .fbx simple loading (wich I'll convert to my own file format later).
std::vector<glm::vec4> vPos(iFaceVertexCount);
std::vector<glm::vec2> vTexCoord(iFaceVertexCount);
std::vector<glm::vec3> vNormal(iFaceVertexCount);
std::vector<glm::vec3> vBinormal(iFaceVertexCount);
std::vector<glm::vec3> vTangent(iFaceVertexCount);
std::vector<unsigned int> vIndex(iFaceCount * 3);
CMesh* pMesh = new CMesh();
for (int iFace = 0; iFace < iFaceCount; ++iFace) {
unsigned int ui32RenderPart = static_cast<unsigned int>( vMaterialIndex.GetAt(iFace) );
if ( (ui32RenderPart + 1) > pMesh->m_vRenderPart.size() ) {
pMesh->m_vRenderPart.resize(ui32RenderPart + 1);
CMaterialManager::CreateMaterial(pfbxnMeshNode->GetMaterial(ui32RenderPart), pMesh->m_vRenderPart[ui32RenderPart].miMaterial);
}
++pMesh->m_vRenderPart[ui32RenderPart].ui32FaceCount;
}
unsigned int ui32LastFaceStart = 0;
for (size_t ui32RenderPart = 0; ui32RenderPart < pMesh->m_vRenderPart.size(); ++ui32RenderPart) {
pMesh->m_vRenderPart[ui32RenderPart].ui32FaceStart = ui32LastFaceStart;
ui32LastFaceStart += pMesh->m_vRenderPart[ui32RenderPart].ui32FaceCount;
pMesh->m_vRenderPart[ui32RenderPart].ui32FaceCount = 0;
}
int iVertex = 0;
for (int iFace = 0; iFace < iFaceCount; ++iFace) {
int iFaceSize = _pfbxmMesh->GetPolygonSize(iFace);
int iRenderPart = vMaterialIndex.GetAt(iFace);
unsigned int ui32IndexStart = pMesh->m_vRenderPart[iRenderPart].ui32FaceStart * iFaceSize;
unsigned int ui32IndexCount = pMesh->m_vRenderPart[iRenderPart].ui32FaceCount * iFaceSize;
unsigned int ui32IndexOffset = ui32IndexStart + ui32IndexCount;
for (int iFaceVertex = 0; iFaceVertex < iFaceSize; ++iFaceVertex) {
int iControlPoint = _pfbxmMesh->GetPolygonVertex(iFace, iFaceVertex);
FbxVector4 vFbxPos = _pfbxmMesh->GetControlPointAt(iControlPoint);
vPos[iVertex].x = static_cast<float>(vFbxPos[0]);
vPos[iVertex].y = static_cast<float>(vFbxPos[1]);
vPos[iVertex].z = static_cast<float>(vFbxPos[2]);
vPos[iVertex].w = 1.0f;
if ( lUVNames.GetCount() ) {
FbxVector2 vFbxUv;
bool bUnmappedUv;
_pfbxmMesh->GetPolygonVertexUV(iFace, iFaceVertex, lUVNames[0], vFbxUv, bUnmappedUv);
vTexCoord[iVertex].x = static_cast<float>(vFbxUv[0]);
vTexCoord[iVertex].y = static_cast<float>(1.0f - vFbxUv[1]);
}
FbxVector4 vFbxNormal;
_pfbxmMesh->GetPolygonVertexNormal(iFace, iFaceVertex, vFbxNormal);
vNormal[iVertex].x = static_cast<float>(vFbxNormal[0]);
vNormal[iVertex].y = static_cast<float>(vFbxNormal[1]);
vNormal[iVertex].z = static_cast<float>(vFbxNormal[2]);
/*
FbxVector4 vFbxBinormal;
_pfbxmMesh->GetPolygonVertex(iFace, iFaceVertex, vFbxNormal);
vNormal[iVertex].x = static_cast<float>(vFbxNormal[0]);
vNormal[iVertex].y = static_cast<float>(vFbxNormal[1]);
vNormal[iVertex].z = static_cast<float>(vFbxNormal[2]);
*/
/*
FbxVector4 vFbxTangent;
_pfbxmMesh->GetPolygonVertex(iFace, iFaceVertex, vFbxNormal);
vNormal[iVertex].x = static_cast<float>(vFbxNormal[0]);
vNormal[iVertex].y = static_cast<float>(vFbxNormal[1]);
vNormal[iVertex].z = static_cast<float>(vFbxNormal[2]);
*/
vIndex[ui32IndexOffset + iFaceVertex] = iVertex;
++iVertex;
}
//0 1 2 -> 2 1 0 In the case I want to convert to CW.
//unsigned int ui32TmpIndex = vIndex[ui32IndexOffset + 0];
//vIndex[ui32IndexOffset + 0] = vIndex[ui32IndexOffset + 2];
//vIndex[ui32IndexOffset + 2] = ui32TmpIndex;
++pMesh->m_vRenderPart[iRenderPart].ui32FaceCount;
}
pMesh->m_vvbVertexBuffer.resize(5);
pMesh->m_vvbVertexBuffer[0].CreateApi( sizeof(glm::vec4) * vPos.size(), &vPos[0], BU_STATIC);
pMesh->m_vvbVertexBuffer[0].m_uiStrides = sizeof(glm::vec4);
pMesh->m_vvbVertexBuffer[0].m_uiStartSlot = 0;
pMesh->m_vvbVertexBuffer[1].CreateApi(sizeof(glm::vec2) * vTexCoord.size(), &vTexCoord[0], BU_STATIC);
pMesh->m_vvbVertexBuffer[1].m_uiStrides = sizeof(glm::vec2);
pMesh->m_vvbVertexBuffer[1].m_uiStartSlot = 1;
pMesh->m_vvbVertexBuffer[2].CreateApi( sizeof(glm::vec3) * vNormal.size(), &vNormal[0], BU_STATIC);
pMesh->m_vvbVertexBuffer[2].m_uiStrides = sizeof(glm::vec3);
pMesh->m_vvbVertexBuffer[2].m_uiStartSlot = 2;
pMesh->m_vvbVertexBuffer[3].CreateApi(sizeof(glm::vec3) * vBinormal.size(), &vBinormal[0], BU_STATIC);
pMesh->m_vvbVertexBuffer[3].m_uiStrides = sizeof(glm::vec3);
pMesh->m_vvbVertexBuffer[3].m_uiStartSlot = 3;
pMesh->m_vvbVertexBuffer[4].CreateApi(sizeof(glm::vec3) * vTangent.size(), &vTangent[0], BU_STATIC);
pMesh->m_vvbVertexBuffer[4].m_uiStrides = sizeof(glm::vec3);
pMesh->m_vvbVertexBuffer[4].m_uiStartSlot = 4;
pMesh->m_ibIndexBuffer.CreateApi( sizeof(unsigned int) * vIndex.size(), reinterpret_cast<const void*>(&vIndex[0]), BU_STATIC);
Here's my drawing calls:
Ex:
//For each attribute...
CDirectX11::GetDeviceContext()->IASetVertexBuffers(m_uiStartSlot, 1, &m_pbBuffer, &m_uiStrides, &m_uiOffsets);
Later:
CDirectX11::GetDeviceContext()->IASetIndexBuffer(m_pd3dBuffer, DXGI_FORMAT_R32_UINT, 0);
CDirectX11::GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
CDirectX11::GetDeviceContext()->DrawIndexed(_ui32IndexCount, _ui32StartIndex, 0);
Results: