Advertisement

Help with FBXSDK

Started by July 18, 2018 08:26 AM
3 comments, last by TeaTreeTim 6 years, 1 month ago

Anyone used the fbxsdk? I want to load models into my engine but when I load them, something is wrong. I load a sphere made and triangulated with maya and it looks like only the bottom of the sphere gets into the program. I did a cube too and it looks like just one side gets in. What is going on in FBXImport and the dx11 related functions in source.cpp? IT looks ok to me.  :(

 

Here is some code:

FBXImport.h


#pragma once

#include <fbxsdk.h>
#include <winerror.h>
#include <vector>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include <xnamath.h>

#include "wx/wx.h"
#include "wx/notebook.h"
#include <wx/timer.h>
#include <wx/time.h>


using namespace std;

struct Vertex    
{
	Vertex() {}
	Vertex(float x, float y, float z,
		float cr, float cg, float cb, float ca)
		: pos(x, y, z), color(cr, cg, cb, ca) {}

	XMFLOAT3 pos;
	XMFLOAT4 color;
};

void InitFBX();
void  DestroyManager();
HRESULT ImportFile(vector<Vertex>* pos, vector<DWORD>* indices, wxTextCtrl* ctrl);

FbxImport.cpp


#include "FBXImport.h"
#include <assert.h>
#include <xnamath.h>



FbxManager* fbxMgr = nullptr;
vector<Vertex> vrx_positions;

void InitFBX()
{
	fbxMgr = FbxManager::Create();
}

void DestroyManager()
{
	fbxMgr->Destroy();
}

HRESULT ImportFile(vector<Vertex>* pos, vector<DWORD>* indices, wxTextCtrl* console)
{

	if(fbxMgr == nullptr)
	InitFBX();
	

	FbxIOSettings* ios = FbxIOSettings::Create(fbxMgr, IOSROOT);
	fbxMgr->SetIOSettings(ios);

	FbxImporter* importer = FbxImporter::Create(fbxMgr, "");
	FbxScene* scene = FbxScene::Create(fbxMgr, "myScene");

	bool success = importer->Initialize("C:\\Models\\sphere.fbx", -1, fbxMgr->GetIOSettings());

	if (!success) return E_FAIL;

	success = importer->Import(scene);

	if (!success) return E_FAIL;

	importer->Destroy();

	FbxNode* root_node = scene->GetRootNode();

	if (root_node)
	{
		for (int i = 0; i < root_node->GetChildCount(); i++)
		{
			FbxNode* child_node = root_node->GetChild(i);

			if (child_node->GetNodeAttribute() == NULL)
				continue;

			FbxNodeAttribute::EType attribute_type = child_node->GetNodeAttribute()->GetAttributeType();

			if (attribute_type != FbxNodeAttribute::eMesh)
				continue;

			FbxMesh* mesh = (FbxMesh*)child_node->GetNodeAttribute();

			FbxVector4* verts = mesh->GetControlPoints();

			for (int j = 0; j < mesh->GetPolygonCount(); j++)
			{
				int numVerts = mesh->GetPolygonSize(j);
				assert(numVerts == 3);

				for (int k = 0; k < numVerts; k++)
				{
					DWORD control_pt_index = mesh->GetPolygonVertex(j, k);

					Vertex vrx((float)verts[control_pt_index].mData[0], (float)verts[control_pt_index].mData[1], 
						(float)verts[control_pt_index].mData[2], 0.6f, 0.8f, 0.6f, 1.0f);
					pos->push_back(vrx);
					indices->push_back(control_pt_index);
				}
			}
		}

	}
}

Source.cpp


#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include <xnamath.h>
#include "Source.h"
#include "FBXImport.h"

//Global Declarations - Interfaces//
IDXGISwapChain* SwapChain;
ID3D11Device* d3d11Device;
ID3D11DeviceContext* d3d11DevCon;
ID3D11RenderTargetView* renderTargetView;
ID3D11Buffer* squareIndexBuffer;
ID3D11DepthStencilView* depthStencilView;
ID3D11Texture2D* depthStencilBuffer;
ID3D11Buffer* squareVertBuffer;
ID3D11VertexShader* VS;
ID3D11PixelShader* PS;
ID3D10Blob* VS_Buffer;
ID3D10Blob* PS_Buffer;
ID3D11InputLayout* vertLayout;
ID3D11Buffer* cbPerObjectBuffer;
ID3D11Buffer* fbx_index_buf;
ID3D11Buffer* fbx_vert_buf;

//Global Declarations - Others//
LPCTSTR WndClassName = L"firstwindow";
HWND hwnd = NULL;
HRESULT hr;

int Width = 300;
int Height = 300;

vector<Vertex> verts;
vector<DWORD> indices;

Vertex* positions;
DWORD* index;

XMMATRIX WVP;
///////////////**************new**************////////////////////
XMMATRIX cube1World;
XMMATRIX cube2World;
XMMATRIX cube_fbx;
///////////////**************new**************////////////////////
XMMATRIX camView;
XMMATRIX camProjection;

XMVECTOR camPosition;
XMVECTOR camTarget;
XMVECTOR camUp;

///////////////**************new**************////////////////////
XMMATRIX Rotation;
XMMATRIX Scale;
XMMATRIX Translation;
float rot = 0.01f;
///////////////**************new**************////////////////////

//Create effects constant buffer's structure//
struct cbPerObject
{
	XMMATRIX  WVP;
};

cbPerObject cbPerObj;



D3D11_INPUT_ELEMENT_DESC layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

UINT numElements = ARRAYSIZE(layout);

// Event table for MyFrame
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(wxID_EXIT, MyFrame::OnQuit)
EVT_CLOSE(MyFrame::OnClose)
wxEND_EVENT_TABLE()

// Implements MyApp& GetApp()
DECLARE_APP(MyApp)
// Give wxWidgets the means to create a MyApp object
IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
	// Create the main application window
	MyFrame *frame = new MyFrame(wxT("Worgen Engine Version 0"));
	// Show it
	frame->Show(true);
	return true;
}

void MyFrame::OnQuit(wxCommandEvent& event)
{
	// Destroy the frame
	Close();
}

void MyFrame::OnClose(wxCloseEvent& event)
{
	timer->Stop();

	//Release the COM Objects we created
	SwapChain->Release();
	d3d11Device->Release();
	d3d11DevCon->Release();
	renderTargetView->Release();
	VS->Release();
	PS->Release();
	VS_Buffer->Release();
	PS_Buffer->Release();
	vertLayout->Release();
	depthStencilView->Release();
	depthStencilBuffer->Release();
	cbPerObjectBuffer->Release();
	event.Skip();
}


MyFrame::MyFrame(const wxString& title)
	: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition)
{
	// Create a menu bar
	wxMenu *fileMenu = new wxMenu;
	// The “About” item should be in the help menu
	wxMenu *helpMenu = new wxMenu;
	helpMenu->Append(wxID_ABOUT, wxT("&About...\tF1"),
		wxT("ABout this program."));
	fileMenu->Append(wxID_EXIT, wxT("E&xit\tAlt - X"),
		wxT("Quit this program"));
	// Now append the freshly created menu to the menu bar...
	wxMenuBar *menuBar = new wxMenuBar();
	menuBar->Append(fileMenu, wxT("&File"));
	menuBar->Append(helpMenu, wxT("&Help"));
	// ... and attach this menu bar to the frame
	SetMenuBar(menuBar);
	// Create a status bar just for fun
	CreateStatusBar(2);
	SetStatusText(wxT("Welcome to Worgen Engine!"));

	nbHierarchy = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(200, 300));
	nbScene = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(800, 600));
	nbInspector = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(200, 300));
	console = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(800, 300), wxTE_MULTILINE | wxTE_READONLY);

	timer = new RenderTimer();

	timer->dxPanel = new MyDxPanel((MyFrame*)nbScene);

	wxPanel* hierarchyWindow = new wxPanel(nbHierarchy, wxID_ANY);
	nbHierarchy->AddPage(hierarchyWindow, "Hierarchy", false);
	nbScene->AddPage(timer->dxPanel, "Game", false);
	wxPanel* inspectorWindow = new wxPanel(nbInspector, wxID_ANY);
	nbInspector->AddPage(inspectorWindow, "Inspector", false);

	wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
	sizer->Add(nbHierarchy, 0, wxEXPAND, 0);
	sizer->Add(nbScene, 1, wxEXPAND, 0);
	sizer->Add(nbInspector, 0, wxEXPAND, 0);

	wxBoxSizer* console_sizer = new wxBoxSizer(wxVERTICAL);
	console_sizer->Add(sizer, 0, wxEXPAND, 0);
	console_sizer->Add(console, 0, wxEXPAND, 0);

	SetSizerAndFit(console_sizer);

	HRESULT hr = ImportFile(&verts, &indices, console);

	if (hr == E_FAIL)
	{
		wxMessageBox("Error importing fbx");
	}

	positions = &verts[0];
	index = &indices[0];

	timer->dxPanel->initDx(timer->dxPanel->GetHWND());
	timer->dxPanel->initScene();

	timer->Start();
}

MyFrame::~MyFrame()
{
	delete timer;
}

wxBEGIN_EVENT_TABLE(MyDxPanel, wxPanel)
EVT_PAINT(MyDxPanel::OnPaint)
EVT_ERASE_BACKGROUND(MyDxPanel::OnEraseBackground)
wxEND_EVENT_TABLE()

MyDxPanel::MyDxPanel(MyFrame* parent) : wxPanel(parent)
{
	parentFrame = parent;
}

MyDxPanel::~MyDxPanel()
{

}

void MyDxPanel::OnEraseBackground(wxEraseEvent &WXUNUSED(event))
{
	//empty to avoid flashing
}

void MyDxPanel::updateScene()
{
	rot += .05f;
	if (rot > 6.26f)
		rot = 0.0f;

	XMVECTOR rotaxis = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);

	Rotation = XMMatrixRotationAxis(rotaxis, -rot);
	
	cube_fbx = Rotation;
}

void MyDxPanel::render()
{
	//Clear our backbuffer
	float bgColor[4] = { (0.0f, 0.0f, 0.0f, 0.0f) };
	d3d11DevCon->ClearRenderTargetView(renderTargetView, bgColor);

	//Refresh the Depth/Stencil view
	d3d11DevCon->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

	WVP = cube_fbx * camView * camProjection;
	cbPerObj.WVP = XMMatrixTranspose(WVP);
	d3d11DevCon->UpdateSubresource(cbPerObjectBuffer, 0, NULL, &cbPerObj, 0, 0);
	d3d11DevCon->VSSetConstantBuffers(0, 1, &cbPerObjectBuffer);

	d3d11DevCon->DrawIndexed(indices.size(), 0, 0);

	//Present the backbuffer to the screen
	SwapChain->Present(0, 0);
}

void MyDxPanel::OnPaint(wxPaintEvent& event)
{
	wxPaintDC dc(this);

	updateScene();
	render();
}


void MyDxPanel::initDx(HWND wnd)
{
	//Describe our SwapChain Buffer
	DXGI_MODE_DESC bufferDesc;

	ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));

	bufferDesc.Width = Width;
	bufferDesc.Height = Height;
	bufferDesc.RefreshRate.Numerator = 60;
	bufferDesc.RefreshRate.Denominator = 1;
	bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

	//Describe our SwapChain
	DXGI_SWAP_CHAIN_DESC swapChainDesc;

	ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));

	swapChainDesc.BufferDesc = bufferDesc;
	swapChainDesc.SampleDesc.Count = 1;
	swapChainDesc.SampleDesc.Quality = 0;
	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.BufferCount = 1;
	swapChainDesc.OutputWindow = wnd;
	swapChainDesc.Windowed = TRUE;
	swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;


	//Create our SwapChain
	hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, NULL, NULL, NULL,
		D3D11_SDK_VERSION, &swapChainDesc, &SwapChain, &d3d11Device, NULL, &d3d11DevCon);

	//Create our BackBuffer
	ID3D11Texture2D* BackBuffer;
	hr = SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&BackBuffer);

	//Create our Render Target
	hr = d3d11Device->CreateRenderTargetView(BackBuffer, NULL, &renderTargetView);
	BackBuffer->Release();

	//Describe our Depth/Stencil Buffer
	D3D11_TEXTURE2D_DESC depthStencilDesc;

	depthStencilDesc.Width = Width;
	depthStencilDesc.Height = Height;
	depthStencilDesc.MipLevels = 1;
	depthStencilDesc.ArraySize = 1;
	depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthStencilDesc.SampleDesc.Count = 1;
	depthStencilDesc.SampleDesc.Quality = 0;
	depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
	depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	depthStencilDesc.CPUAccessFlags = 0;
	depthStencilDesc.MiscFlags = 0;

	//Create the Depth/Stencil View
	d3d11Device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer);
	d3d11Device->CreateDepthStencilView(depthStencilBuffer, NULL, &depthStencilView);

	//Set our Render Target
	d3d11DevCon->OMSetRenderTargets(1, &renderTargetView, depthStencilView);
}

void MyDxPanel::initScene()
{
	//Compile Shaders from shader file
	hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "VS", "vs_4_0", 0, 0, 0, &VS_Buffer, 0, 0);
	hr = D3DX11CompileFromFile(L"Effects.fx", 0, 0, "PS", "ps_4_0", 0, 0, 0, &PS_Buffer, 0, 0);

	//Create the Shader Objects
	hr = d3d11Device->CreateVertexShader(VS_Buffer->GetBufferPointer(), VS_Buffer->GetBufferSize(), NULL, &VS);
	hr = d3d11Device->CreatePixelShader(PS_Buffer->GetBufferPointer(), PS_Buffer->GetBufferSize(), NULL, &PS);

	//Set Vertex and Pixel Shaders
	d3d11DevCon->VSSetShader(VS, 0, 0);
	d3d11DevCon->PSSetShader(PS, 0, 0);

	
	D3D11_BUFFER_DESC indexBufferDesc;
	ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));

	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	indexBufferDesc.ByteWidth = sizeof(DWORD) * indices.size();
	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;

	D3D11_SUBRESOURCE_DATA iinitData;

	iinitData.pSysMem = index;
	d3d11Device->CreateBuffer(&indexBufferDesc, &iinitData, &fbx_index_buf);

	d3d11DevCon->IASetIndexBuffer(fbx_index_buf, DXGI_FORMAT_R32_UINT, 0);


	D3D11_BUFFER_DESC vertexBufferDesc;
	ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));

	vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	vertexBufferDesc.ByteWidth = sizeof(Vertex) * verts.size();
	vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexBufferDesc.CPUAccessFlags = 0;
	vertexBufferDesc.MiscFlags = 0;
	///////////////**************new**************////////////////////

	D3D11_SUBRESOURCE_DATA vertexBufferData;

	ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
	vertexBufferData.pSysMem = positions;
	hr = d3d11Device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &fbx_vert_buf);

	//Set the vertex buffer
	UINT stride = sizeof(Vertex);
	UINT offset = 0;
	d3d11DevCon->IASetVertexBuffers(0, 1, &fbx_vert_buf, &stride, &offset);

	//Create the Input Layout
	hr = d3d11Device->CreateInputLayout(layout, numElements, VS_Buffer->GetBufferPointer(),
		VS_Buffer->GetBufferSize(), &vertLayout);

	//Set the Input Layout
	d3d11DevCon->IASetInputLayout(vertLayout);

	//Set Primitive Topology
	d3d11DevCon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	//Create the Viewport
	D3D11_VIEWPORT viewport;
	ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

	viewport.TopLeftX = 0;
	viewport.TopLeftY = 0;
	viewport.Width = Width;
	viewport.Height = Height;
	viewport.MinDepth = 0.0f;
	viewport.MaxDepth = 1.0f;

	//Set the Viewport
	d3d11DevCon->RSSetViewports(1, &viewport);

	//Create the buffer to send to the cbuffer in effect file
	D3D11_BUFFER_DESC cbbd;
	ZeroMemory(&cbbd, sizeof(D3D11_BUFFER_DESC));

	cbbd.Usage = D3D11_USAGE_DEFAULT;
	cbbd.ByteWidth = sizeof(cbPerObject);
	cbbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	cbbd.CPUAccessFlags = 0;
	cbbd.MiscFlags = 0;

	hr = d3d11Device->CreateBuffer(&cbbd, NULL, &cbPerObjectBuffer);

	//Camera information
	///////////////**************new**************////////////////////
	camPosition = XMVectorSet(0.0f, 3.0f, -8.0f, 0.0f);
	///////////////**************new**************////////////////////
	camTarget = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
	camUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);

	//Set the View matrix
	camView = XMMatrixLookAtLH(camPosition, camTarget, camUp);

	//Set the Projection matrix
	camProjection = XMMatrixPerspectiveFovLH(0.4f*3.14f, (float)Width / Height, 1.0f, 1000.0f);
}

RenderTimer::RenderTimer() : wxTimer()
{

}

void RenderTimer::Notify()
{
	dxPanel->Refresh();
}

void RenderTimer::start()
{
	wxTimer::Start(10);
}

 

I have but a while ago now so I'll try to remember a few points:

Some of the official examples are wrong. They don't account for nurbs or only accout for a particular fbx format.I remember you will have an easier time if you triangulate before saving your meshes, although you should really expand your code to support nurbs (see below near the end for how).

There's more to it than that but I'd have to look back over my work to remember sorry. Just take it for granted you will have to practice loading several different examples of fbx meshes with slightly different formats before you get it all working (eg coloured vertices, multiple nodes, multiple uv coordinates, skin and joints). Also the data like vertex positions can be direct or indexed but I don't remember the terminology they use to describe that.

Here is some code of mine that works for a lot of different sources of fbx's. It wont plug and play (it references some of my own stuff) but should help give you an idea I hope. If you don't plan to animate you could probably strip out half of it, but I added it verbatim in-case that's your intention:

 

EDIT: The colour stuff is my own system, ignore it if its confusing.


void AnimMesh::AddMeshFBX(FbxMesh* mesh, FbxSkin *skin, FbxAMatrix geometryMatrix)
{
    float maxDist = 0;
    Vector4 maxWV;
    Vector4 maxW;

    Vector3 min = Vector3(1000, 10000, 10000);
    Vector3 max = Vector3(-1000, -10000, -10000);

    std::vector<std::string> bonePos;
    bonePos.clear();
    
    int mTriangleCount = mesh->GetPolygonCount();
    int vertexCounter = vertices.size();

    int * fbxIndices = mesh->GetPolygonVertices();
    
    FbxVector4 * fbxVertices = mesh->GetControlPoints();

    FbxStringList uvSetNameList;
    mesh->GetUVSetNames(uvSetNameList);

    int uvSetCount = uvSetNameList.GetCount(); 
    const fbxsdk::FbxGeometryElementUV* lUVElement = nullptr;

    if (uvSetCount > 0)
    {
        const char* lUVSetName = uvSetNameList.GetStringAt(0);
        lUVElement = mesh->GetElementUV(lUVSetName);
    }

    const fbxsdk::FbxGeometryElementVertexColor* colorElement = mesh->GetElementVertexColor();

    Vector4 diffuseColor = DiffuseMaterial(mesh);

    transformOffset = geometryMatrix;

    unsigned int numOfClusters = 0;
    WeightMap *weights[BONES_PER_SKELETON];

    for (int i = 0; i < BONES_PER_SKELETON; i++)
        weights[i] = nullptr;

    if (skin)
    {
        numOfClusters = skin->GetClusterCount();
        
        for (unsigned int clusterIndex = 0; clusterIndex < numOfClusters; ++clusterIndex)
        {
            FbxCluster* currCluster = skin->GetCluster(clusterIndex);
            std::string currJointName = currCluster->GetLink()->GetName();
            AnimNode *jointNode = rootNode->NodeFromName(currJointName);
            int jointID = -1;
            if (jointNode)
                jointID = jointNode->id;
    
            if (jointID >= 0)
            {
                FbxAMatrix bonePose;
                currCluster->GetTransformLinkMatrix(bonePose);
                FbxVector4 boneTrans = bonePose.GetT();
                jointNode->bonePose = bonePose;

                meshPose;
                currCluster->GetTransformMatrix(meshPose);
                FbxVector4 meshTrans = meshPose.GetT();

                FbxVector4 fbxBoneHead =  boneTrans; 

                jointNode->boneHead = Vector4(fbxBoneHead[0], fbxBoneHead[1], fbxBoneHead[2], 1);
                jointNode->hasDeformer = true;
                jointNode->currentMatrix = bonePose.Inverse() * meshPose * geometryMatrix;

                WeightMap newMap = WeightMap(jointID, currCluster->GetControlPointIndicesCount(), currCluster->GetControlPointIndices(), currCluster->GetControlPointWeights());
                
                weights[jointID] = (WeightMap *)malloc(sizeof(WeightMap));
                memcpy(weights[jointID], &newMap, sizeof(WeightMap));
            }
            else
            {
                dprintf(" NOT FOUND\n");
            }
        }
    }


    for (unsigned int polygonIndex = 0; polygonIndex < mTriangleCount; polygonIndex++)
    {
        int pointsInPoly = mesh->GetPolygonSize(polygonIndex);

        if (pointsInPoly < 0)
        {
            dprintf("Mesh Error\n");
            exit(ERROR);
        }

        int firstVert = vertices.size();

        for (unsigned int polyVertexIndex = 0; polyVertexIndex < pointsInPoly; polyVertexIndex++)
        {
            int ctrlPointIndex = mesh->GetPolygonVertex(polygonIndex, polyVertexIndex);
            if (ctrlPointIndex < 0)
            {
                dprintf("Vert Index -1\n");
            }
            else
            {
                AnimNode::AnimVertice vert;

                FbxVector4 currCtrlPoint = geometryMatrix.MultT(fbxVertices[ctrlPointIndex]);
                            
                vert.position = Vector4(currCtrlPoint.mData[0], currCtrlPoint.mData[1], currCtrlPoint.mData[2], id);

                FbxVector4 norm;
                mesh->GetPolygonVertexNormal(polygonIndex, polyVertexIndex, norm);
                vert.normal = Vector3(norm.mData[0], norm.mData[1], norm.mData[2]); 

                int texIndex = mesh->GetTextureUVIndex(polygonIndex, polyVertexIndex);
                if (texIndex < 0)
                {
                    vert.texCoord = diffuseColor;

                    fbxsdk::FbxGeometryElementVertexColor *color = mesh->GetElementVertexColor(ctrlPointIndex);
                    if (color)
                    {
                        fbxsdk::FbxColor col = color->GetDirectArray()[0];
                        vert.texCoord = Vector4(col.mRed, col.mGreen, col.mBlue, -16);
                    }
                }
                else
                {
                    FbxVector2 lUVValue = lUVElement->GetDirectArray().GetAt(texIndex);

                    vert.texCoord = Vector4(lUVValue.mData[0], lUVValue.mData[1], iType, 0);
                }

                if (colorElement)
                {
                    FbxColor color = GetColor(colorElement, ctrlPointIndex, vertexCounter);
                    int red = (int)(4 * color.mRed);
                    if (red == 4)
                        red = 3;
                    int green = (int)(4 * color.mGreen);
                    if (green == 4)
                        green = 3;
                    int blue = (int)(4 * color.mBlue);
                    if (blue == 4)
                        blue = 3;

                    vert.texCoord.w = red + green * 4 + blue * 16;
                }
                

                vert.weights = Vector4(0, 0, 0, 0);
                int weightV[4] = {};
                
                for (int cWeight = 0; cWeight < BONES_PER_SKELETON; cWeight++)
                {
                    WeightMap *weightMap = weights[cWeight];

                    if (weightMap)
                    {
                        for (int ccp = 0; ccp < weightMap->count; ccp++)
                        {
                            if (weightMap->controlPoints[ccp] == ctrlPointIndex)
                            {
                                SortWeight(weightMap->weights[ccp], cWeight, weightV, vert.weights);
                            }
                        }
                    }
                }

                vert.weightID = weightV[0] * 0x1000000 + weightV[1] * 0x10000 + weightV[2] * 0x100 + weightV[3];
                
                float weightTotal = 0;
                for (int cb = 0; cb < 4; cb++)
                    weightTotal += vert.weights[cb];

                if (weightTotal > 0)
                    for (int cb = 0; cb < 4; cb++)
                        vert.weights[cb] /= weightTotal;

                Vector4 newPos = Vector4();
                for (int cb = 0; cb < 4; cb++)
                {
                    if (vert.weights[cb] > 0)
                    {
                        AnimNode *jointNode = FindNode(weightV[cb], rootNode);
                        newPos += (vert.position + jointNode->boneHead) * vert.weights[cb];
                    }
                }
                
                vertices.push_back(vert);

                int vertexIndex = vertices.size() - 1;

                if (polyVertexIndex > 2)
                {
                    indices.push_back(vertexIndex - 1);
                    indices.push_back(vertexIndex);
                    indices.push_back(firstVert);
                }
                else
                {
                    indices.push_back(vertexIndex);
                }
                vertexCounter++;
            }
        }
    }

    for (int i = 0; i < BONES_PER_SKELETON; i++)
    {
        if (weights[i])
            free(weights[i]);
    }


    bonePos.clear();
}

 

Advertisement

I got models loading by just doing a Draw instead of a DrawIndexed. But how do u load uvs? I loaded the UVSetName looking at your code. But I don't even see in the docs where it explains uv maps and stuff. Am I missing something?   O_o

 

Also, lets say I get the uv map into the program. I have the uv map painted with substance painter and its a separate file. In unity I import the model, import the painted uv texture, make material, add painted uv texture, and apply it to the model. How do I load this painted uv into my program?   O_O   Or whats the workflow I should use as an artist to get the painted uv correctly on my model?

I'm sorry I should have simplified and tidied the code first. In that code I directly access the UV's


int texIndex = mesh->GetTextureUVIndex(polygonIndex, polyVertexIndex);

FbxVector2 lUVValue = lUVElement->GetDirectArray().GetAt(texIndex);

Notice I only set 2 uv coordinates, this implies there is only one set. For GetTextureUVIndex, you can specify the uv set (basically the material), so that example grabs the default (first).

Other examples use GetPolygonVertexUVs which returns an array and you can use the name in there. That's where the naming matters if you have multiple sets, and you'd need to iterate through them. That's what I used to do but didn't tidy my code so I apologise for that. The thing is if I included a comprehensive example it would be quite complicated, for example:

Here is a better way to get your normal (by better I mean accommodate different systems):


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

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

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

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

 

Here is a better way of getting colour info:

 


    FbxColor color;
    switch (colorElement->GetMappingMode())
    {
    case FbxGeometryElement::eByControlPoint:
    {
        switch (colorElement->GetReferenceMode())
        {
        case FbxGeometryElement::eDirect:
        {
            color = colorElement->GetDirectArray().GetAt(ctrlPointIndex);
            break;
        }
        case FbxGeometryElement::eIndexToDirect:
        {
            int id = colorElement->GetIndexArray().GetAt(ctrlPointIndex);
            color = colorElement->GetDirectArray().GetAt(id);
            break;
        }
        default:
        {
            break;
        }
        }
        break;
    }
    case FbxGeometryElement::eByPolygonVertex:
    {
        switch (colorElement->GetReferenceMode())
        {
        case FbxGeometryElement::eDirect:
        {
            color = colorElement->GetDirectArray().GetAt(vertIndex);
            break;
        }
        case FbxGeometryElement::eIndexToDirect:
        {
            int id = colorElement->GetIndexArray().GetAt(vertIndex);
            color = colorElement->GetDirectArray().GetAt(id);
            break;
        }
        default:
        {
            break;
        }
        }
        break;
    }
    default:
    {
        break;
    }
    }

This gets materials better:
 


    int mcount = mesh->GetSrcObjectCount<FbxSurfaceMaterial>();
    if (mcount > 0)
    {
        for (int index = 0; index < mcount; index++)
        {
            FbxSurfaceMaterial *material = (FbxSurfaceMaterial*)mesh->GetSrcObject<FbxSurfaceMaterial>(index);
            if (material)
            {
                FbxProperty prop = material->FindProperty(FbxSurfaceMaterial::sDiffuse);

                int layered_texture_count = prop.GetSrcObjectCount<FbxLayeredTexture>();
                if (layered_texture_count > 0)
                {
                    for (int j = 0; j < layered_texture_count; j++)
                    {
                        FbxLayeredTexture* layered_texture = FbxCast<FbxLayeredTexture>(prop.GetSrcObject<FbxLayeredTexture>(j));
                        int lcount = layered_texture->GetSrcObjectCount<FbxTexture>();
                        for (int k = 0; k < lcount; k++)
                        {
                            FbxTexture* texture = FbxCast<FbxTexture>(layered_texture->GetSrcObject<FbxTexture>(k));
                            const char* texture_name = texture->GetName();
                        }
                    }
                }
                else
                {
                    int texture_count = prop.GetSrcObjectCount<FbxTexture>();
                    for (int j = 0; j < texture_count; j++)
                    {
                        const FbxTexture* texture = FbxCast<FbxTexture>(prop.GetSrcObject<FbxTexture>(j));
                        const char* texture_name = texture->GetName();
                    }
                }
            }
        }
    }
    else
    {
        int layerCount = mesh->GetLayerCount();
        for (int i = 0; i < layerCount; i++)
        {
            fbxsdk::FbxLayer * layer = mesh->GetLayer(i);
            if (layer)
            {
                fbxsdk::FbxLayerElementVertexColor *vColor = layer->GetVertexColors();
                if (vColor)
                {

                }
                fbxsdk::FbxLayerElementMaterial * vMat = layer->GetMaterials();
                if (vMat)
                {

                }
            }
        }
    }

 

So you see to handle every fbx format becomes a bit complicated.

This topic is closed to new replies.

Advertisement