Problem with DirectX 11 Vertex Layout

Started by
5 comments, last by Irlan Robson 9 years, 6 months ago

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:

results.png

Advertisement

Since you are using one vertex buffer per component, the AlignedByteOffset value in D3D11_INPUT_ELEMENT_DESC should be 0 because the data in each vertex buffer starts at offset 0.

Since you are using one vertex buffer per component, the AlignedByteOffset value in D3D11_INPUT_ELEMENT_DESC should be 0 because the data in each vertex buffer starts at offset 0.

"The problems of porting OpenGL to DirectX 11 starts here.". I forgot that. It solved my problem.

Thank you.

{ "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 }

I think that you have made a calculation error here : 24 + 3 x float = 36

You could/should use the automated location calculator (ie. D3D11_APPEND_ALIGNED_ELEMENT flag).

Cheers!

{ "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 }

I think that you have made a calculation error here : 24 + 3 x float = 36

You could/should use the automated location calculator (ie. D3D11_APPEND_ALIGNED_ELEMENT flag).

Cheers!

As megadan said, I'm using per component vertex buffers. I have my problem solved. Anyway, I think it was correct.
POSITION0 = 0
TEXCOORD0 = 16 (POSITION0)
NORMAL0 = 16 (POSITION0) + 8 (TEXCOORD0) = 24
NORMAL1 = 16 (POSITION0) + 8 (TEXCOORD0) + 16 (NORMAL0) = 40
etc.


NORMAL1 = 16 (POSITION0) + 8 (TEXCOORD0) + 16 (NORMAL0) = 40

Since you don't need to specify these offsets at all to solve your problem this is pretty tangential to the solution, but I'm with kauna in asking why would NORMAL0 create an offset of 16 and not 12?


NORMAL1 = 16 (POSITION0) + 8 (TEXCOORD0) + 16 (NORMAL0) = 40

Since you don't need to specify these offsets at all to solve your problem this is pretty tangential to the solution, but I'm with kauna in asking why would NORMAL0 create an offset of 16 and not 12?

Yeah you're right. I need to take a sleep a little. he correct is:

POSITION0 = 0
TEXCOORD0 = 16 (POSITION0)
NORMAL0 = 16 (POSITION0) + 8 (TEXCOORD0) = 24
NORMAL1 = 16 (POSITION0) + 8 (TEXCOORD0) + 12 (NORMAL0) = 36
etc.

This topic is closed to new replies.

Advertisement