• Advertisement
Sign in to follow this  

FBX Geometry Normal/UV Issues

This topic is 957 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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? 

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement