🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

FBX Geometry Normal/UV Issues

Started by
0 comments, last by KarimIO 8 years, 10 months ago

Hello, Gamedev! I'm working on my own game engine, and I've been frustrated, trying to implement FBX for the past few days. Because the API is so awkwardly implemented, I've resorted to following some tutorials, specifically for the Normals and UV, which is where my problem is, including: http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/how-to-work-with-fbx-sdk-r3582

The UVs and Normals end up in game but they seem randomly set. In fact, using complex models, it looks like each face has a different color, and on simpler ones, it's just a smooth rainbow-esque view.

Here is my Import Code:


void ReadUV(FbxMesh* inMesh, int inCtrlPointIndex, int inVertexCounter, glm::vec2& outUV)
{
	if (inMesh->GetElementUVCount() < 1)
	{
		throw std::exception("Invalid Normal Number");
	}

	FbxGeometryElementUV* vertexUV = inMesh->GetElementUV(0);
	switch (vertexUV->GetMappingMode())
	{
	case FbxGeometryElement::eByControlPoint:
		switch (vertexUV->GetReferenceMode())
		{
		case FbxGeometryElement::eDirect:
		{
			outUV.x = static_cast<float>(vertexUV->GetDirectArray().GetAt(inCtrlPointIndex).mData[0]);
			outUV.y = static_cast<float>(vertexUV->GetDirectArray().GetAt(inCtrlPointIndex).mData[1]);
			//outUV.z = static_cast<float>(vertexUV->GetDirectArray().GetAt(inCtrlPointIndex).mData[2]);
		}
		break;

		case FbxGeometryElement::eIndexToDirect:
		{
			int index = vertexUV->GetIndexArray().GetAt(inCtrlPointIndex);
			outUV.x = static_cast<float>(vertexUV->GetDirectArray().GetAt(index).mData[0]);
			outUV.y = static_cast<float>(vertexUV->GetDirectArray().GetAt(index).mData[1]);
			//outUV.z = static_cast<float>(vertexUV->GetDirectArray().GetAt(index).mData[2]);
		}
		break;

		default:
			throw std::exception("Invalid Reference");
		}
		break;

	case FbxGeometryElement::eByPolygonVertex:
		switch (vertexUV->GetReferenceMode())
		{
		case FbxGeometryElement::eDirect:
		{
			outUV.x = static_cast<float>(vertexUV->GetDirectArray().GetAt(inVertexCounter).mData[0]);
			outUV.y = static_cast<float>(vertexUV->GetDirectArray().GetAt(inVertexCounter).mData[1]);
			//outUV.z = static_cast<float>(vertexUV->GetDirectArray().GetAt(inVertexCounter).mData[2]);
		}
		break;

		case FbxGeometryElement::eIndexToDirect:
		{
			int index = vertexUV->GetIndexArray().GetAt(inVertexCounter);
			outUV.x = static_cast<float>(vertexUV->GetDirectArray().GetAt(index).mData[0]);
			outUV.y = static_cast<float>(vertexUV->GetDirectArray().GetAt(index).mData[1]);
			//outUV.z = static_cast<float>(vertexUV->GetDirectArray().GetAt(index).mData[2]);
		}
		break;

		default:
			throw std::exception("Invalid Reference");
		}
		break;
	}
}

void ReadNormal(FbxMesh* inMesh, int inCtrlPointIndex, int inVertexCounter, glm::vec3& outNormal)
{
	if (inMesh->GetElementNormalCount() < 1)
	{
		throw std::exception("Invalid Normal Number");
	}

	FbxGeometryElementNormal* vertexNormal = inMesh->GetElementNormal(0);
	switch (vertexNormal->GetMappingMode())
	{
	case FbxGeometryElement::eByControlPoint:
		switch (vertexNormal->GetReferenceMode())
		{
		case FbxGeometryElement::eDirect:
		{
			outNormal.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inCtrlPointIndex).mData[0]);
			outNormal.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inCtrlPointIndex).mData[1]);
			outNormal.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inCtrlPointIndex).mData[2]);
		}
		break;

		case FbxGeometryElement::eIndexToDirect:
		{
			int index = vertexNormal->GetIndexArray().GetAt(inCtrlPointIndex);
			outNormal.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[0]);
			outNormal.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[1]);
			outNormal.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[2]);
		}
		break;

		default:
			throw std::exception("Invalid Reference");
		}
		break;

	case FbxGeometryElement::eByPolygonVertex:
		switch (vertexNormal->GetReferenceMode())
		{
		case FbxGeometryElement::eDirect:
		{
			outNormal.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inVertexCounter).mData[0]);
			outNormal.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inVertexCounter).mData[1]);
			outNormal.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inVertexCounter).mData[2]);
		}
		break;

		case FbxGeometryElement::eIndexToDirect:
		{
			int index = vertexNormal->GetIndexArray().GetAt(inVertexCounter);
			outNormal.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[0]);
			outNormal.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[1]);
			outNormal.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[2]);
		}
		break;

		default:
			throw std::exception("Invalid Reference");
		}
		break;
	}
}

void ProcessMesh(FbxManager* lSdkManager, RenderComponent *renderer, FbxNode* inNode) {
	int numSides = 3;

	FbxMesh *fbxMesh = inNode->GetMesh();

	// Triangulate Mesh
	if (!fbxMesh->IsTriangleMesh()) {
		FbxGeometryConverter lConverter(lSdkManager);
		bool status = lConverter.Triangulate(inNode->GetNodeAttribute(), false);

		if (!status) {
			std::cout << "WARNING: Could not triangulate FBX Mesh." << std::endl;
			return;
		}
	}

	int numVertices = fbxMesh->GetControlPointsCount();
	int numPolys = fbxMesh->GetPolygonCount();

	glm::vec3 *vertices = new glm::vec3[numVertices];
	glm::vec3 *normals = new glm::vec3[numPolys * numSides];
	glm::vec2 *UVs = new glm::vec2[numPolys * numSides];
	unsigned short *indices = new unsigned short[numPolys * numSides];

	FbxVector4 *sourceVertices = fbxMesh->GetControlPoints();

	for (unsigned int i = 0; i < numVertices; i++) {
		vertices[i] = glm::vec3(sourceVertices[i][0], sourceVertices[i][1], sourceVertices[i][2]);
	}

	for (unsigned int i = 0; i < numPolys; i++) {
		for (unsigned int j = 0; j < numSides; j++) {
			int ctrlPtIndex = fbxMesh->GetPolygonVertex(i, j);
			indices[i * numSides + j] = ctrlPtIndex;
			ReadNormal(fbxMesh, ctrlPtIndex, i * numSides + j, normals[i * numSides + j]);
			ReadUV(fbxMesh, ctrlPtIndex, i * numSides + j, UVs[i * numSides + j]);
		}
	}

	glGenBuffers(1, &renderer->vbo);
	glBindBuffer(GL_ARRAY_BUFFER, renderer->vbo);
	glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);

	glGenBuffers(1, &renderer->ubo);
	glBindBuffer(GL_ARRAY_BUFFER, renderer->ubo);
	glBufferData(GL_ARRAY_BUFFER, numPolys * numSides * sizeof(glm::vec2), &UVs[0], GL_STATIC_DRAW);

	glGenBuffers(1, &renderer->nbo);
	glBindBuffer(GL_ARRAY_BUFFER, renderer->nbo);
	glBufferData(GL_ARRAY_BUFFER, numPolys * numSides * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW);

	glGenBuffers(1, &renderer->ibo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->ibo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, numPolys * numSides * sizeof(unsigned short), &indices[0], GL_STATIC_DRAW);

	renderer->indicesCount = numPolys * numSides;
}

And my Rendering (Which works fine for my OBJ models):


glEnableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

	glEnableVertexAttribArray(1);
	glBindBuffer(GL_ARRAY_BUFFER, ubo);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

	glEnableVertexAttribArray(2);
	glBindBuffer(GL_ARRAY_BUFFER, nbo);
	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
	
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
	glDrawElements(GL_TRIANGLES, indicesCount, GL_UNSIGNED_SHORT, (void*)0);

Sorry for the wall of text. Can anyone figure this out?

Advertisement

Sorry, but I haven't received any responses so...bump?

This topic is closed to new replies.

Advertisement