Meshes loaded via Assimp look distorted - c++

So I'm trying to load and render mesh with assimp and DirectX11.(Im loosely following tutorials on youtube) The problem is that it looks weird and distorted. I've checked my meshes - blender and assimp viewer load them correctly.
Results of rendering suzanne from obj file:
Suzanne from obj file
It looks kinda like the index buffer is wrong but i do not see a mistake when propagating it;
Mesh loading code:
struct Vertex
{
struct
{
float x;
float y;
float z;
}Position;
};
Model::Model(const std::string & path)
{
Ref<Zephyr::VertexShader> VertexShader = Zephyr::VertexShader::Create("MinimalShaders.hlsl", "VertexShaderMain");
AddBindable(VertexShader);
AddBindable(Zephyr::PixelShader::Create("MinimalShaders.hlsl", "PixelShaderMain"));
AddBindable(Zephyr::Topology::Create(Zephyr::Topology::TopologyType::TriangleList));
std::vector<Zephyr::InputLayout::InputLayoutElement> InputLayout =
{
{"Position",Zephyr::InputLayout::InputDataType::Float3}
};
AddBindable(Zephyr::InputLayout::Create(InputLayout, VertexShader));
Assimp::Importer Imp;
auto model = Imp.ReadFile(path, aiProcess_JoinIdenticalVertices | aiProcess_Triangulate);
const auto Mesh = model->mMeshes[0];
std::vector<Vertex> Vertices;
Vertices.reserve(Mesh->mNumVertices);
for (unsigned int i = 0; i < Mesh->mNumVertices; i++)
{
Vertex buf;
buf.Position = { Mesh->mVertices[i].x,Mesh->mVertices[i].y ,Mesh->mVertices[i].z };
Vertices.push_back(buf);
}
std::vector<unsigned short> Indices;
Indices.reserve(Mesh->mNumFaces * 3);
for (unsigned int i = 0; i < Mesh->mNumFaces; i++)
{
const auto & face = Mesh->mFaces[i];
if (face.mNumIndices != 3)
{
Zephyr::Log::Error("More than 3 indices per face ?!"); continue;
}
Indices.push_back(face.mIndices[0]);
Indices.push_back(face.mIndices[1]);
Indices.push_back(face.mIndices[2]);
}
AddBindable(Zephyr::VertexBuffer::Create(Vertices));
BindIndexBuffer(Zephyr::IndexBuffer::Create(Indices));
}
My shaders are pretty minimal to
cbuffer CBuff
{
matrix transform;
};
float4 VertexShaderMain(float3 position : Position) : SV_POSITION
{
return mul(float4(position, 1.0), transform);
}
float4 PixelShaderMain() : SV_TARGET
{
return float4(1.0,1.0,1.0,1.0);
}
My pipeline renders correctly, f. ex. cubes which are hard coded, but when i try to load cube from file this happens:
distorted cube
Assimp opens the file and loads the correct number of vertices. Also number of indices seems to be ok(for cube there are 12 triangles and 36 indices)
Honestly at this point I have no idea what im doing wrong. Am i missing sth obvious?
Thanks in advance

So I've figured it out. The issue was that in some other file i already defined structure named Vertex. That structure contained also uv's so ultimately my vertex buffer ended up being a mess. Silly mistake.

Related

Building the set of unique vertices gives trashed result with random triangles around initial mesh

I have a problem with creating a set of unique vertices containing Position Coordinate, Texture Coordinade and Normals. I decided to use std::set for this kind of problem. The problem is that it seems that it somehow does not creating the correct set of vertices. The data I loaded from .obj file 100% correct as it is renders the mesh as I expected. But new set of data is just creates a blob of triangles.
Correct result using only Positions of vertices, expected result:
And generated data:
The code routine:
struct vertex
{
glm::vec3 Position;
glm::vec2 TextureCoord;
glm::vec3 Normal;
bool operator==(const vertex& rhs) const
{
bool Res1 = this->Position == rhs.Position;
bool Res2 = this->TextureCoord == rhs.TextureCoord;
bool Res3 = this->Normal == rhs.Normal;
return Res1 && Res2 && Res3;
}
};
namespace std
{
template<>
struct hash<vertex>
{
size_t operator()(const vertex& VertData) const
{
size_t res = 0;
const_cast<hash<vertex>*>(this)->hash_combine(res, hash<glm::vec3>()(VertData.Position));
const_cast<hash<vertex>*>(this)->hash_combine(res, hash<glm::vec2>()(VertData.TextureCoord));
const_cast<hash<vertex>*>(this)->hash_combine(res, hash<glm::vec3>()(VertData.Normal));
return res;
}
private:
// NOTE: got from glm library
void hash_combine(size_t& seed, size_t hash)
{
hash += 0x9e3779b9 + (seed << 6) + (seed >> 2);
seed ^= hash;
}
};
}
void mesh::BuildUniqueVertices()
{
std::unordered_set<vertex> UniqueVertices;
//std::unordered_map<u32, vertex> UniqueVertices;
u32 IndexCount = CoordIndices.size();
std::vector<u32> RemapedIndices(IndexCount);
for(u32 VertexIndex = 0;
VertexIndex < IndexCount;
++VertexIndex)
{
vertex Vert = {};
v3 Pos = Coords[CoordIndices[VertexIndex]];
Vert.Position = glm::vec3(Pos.x, Pos.y, Pos.z);
if(NormalIndices.size() != 0)
{
v3 Norm = Normals[NormalIndices[VertexIndex]];
Vert.Normal = glm::vec3(Norm.x, Norm.y, Norm.z);
}
if(TextCoords.size() != 0)
{
v2 TextCoord = TextCoords[TextCoordIndices[VertexIndex]];
Vert.TextureCoord = glm::vec2(TextCoord.x, TextCoord.y);
}
// NOTE: think about something faster
auto Hint = UniqueVertices.insert(Vert);
if (Hint.second)
{
RemapedIndices[VertexIndex] = VertexIndex;
}
else
{
RemapedIndices[VertexIndex] = static_cast<u32>(std::distance(UniqueVertices.begin(), UniqueVertices.find(Vert)));
}
}
VertexIndices = std::move(RemapedIndices);
Vertices.reserve(UniqueVertices.size());
for(auto it = UniqueVertices.begin();
it != UniqueVertices.end();)
{
Vertices.push_back(std::move(UniqueVertices.extract(it++).value()));
}
}
What the error could be. I am suspecting that hash function is not doing its job right and therefor I am getting really trashed results of random triangles around initial mesh bounds. Thanks.
This construction shows that you're going down the wrong path:
RemapedIndices[VertexIndex] = static_cast<u32>(std::distance(UniqueVertices.begin(), UniqueVertices.find(Vert)));
It's clear that you want the "offset" of the vertex within the UniqueVertices but you're modifying the container in the same loop with UniqueVertices.insert(Vert);. That means that the std::distance result you calculate is potentially invalidated by the next loop. Every index except the very last one you calculate will potentially be garbage by the time you finish the outer loop.
Just use a vector<vertex> and stop trying to de-dupe vertices. If you later find you need to optimize for better performance, you're going to be better off trying to make sure that the mesh is optimized for cache locality.
If you really, really feel the need to dedupe, you need to do it in a multi-step process, something like this...
First map the original indices to some kind of unique key (NOT the full vertex... you want something that can be used as both a map key and value, so has good hashing and equality functionality, like std::string). For instance, you could take the 3 source indices and convert them to fixed length hex strings concatenated together. Just make sure the transformation is reversible. Here I've stubbed it out wit std::string to_key(uint32_t CoordIndex, uint32_t NormalIndex, uint32_t TextCoordIndex)
std::unordered_map<uint32_t, std::string> originalIndexToKey;
std::unordered_set<std::string> uniqueKeys;
uint32_t IndexCount = CoordIndices.size();
for (u32 VertexIndex = 0; VertexIndex < IndexCount; ++VertexIndex) {
uint32_t CoordIndex = UINT32_MAX, NormalIndex = UINT32_MAX, TextCoordIndex = UINT32_MAX;
CoordIndex = CoordIndices[VertexIndex];
if (NormalIndices.size() != 0) {
NormalIndex = NormalIndices[VertexIndex];
}
if (TextCoords.size() != 0) {
TextCoordIndex = TextCoordIndices[VertexIndex];
}
std::string key = to_key(CoordIndex, NormalIndex, TextCoordIndex);
originalIndexToKey.insert(VertexIndex, key);
uniqueKeys.insert(key);
}
Next, take all the unique keys and construct the unique vertices with them in a vector, so they have fixed positions. Here you need to get the sub-indices back from the key with a void from_key(const std::string& key, uint32_t & CoordIndex, uint32_t & NormalIndex, uint32_t & TextCoordIndex) function.
std::unordered_map<std::string, uint32_t> keyToNewIndex;
std::vector<vertex> uniqueVertices;
for (const auto& key : uniqueKeys) {
uint32_t NewIndex = uniqueVertices.size();
keyToNewIndex.insert(key, NewIndex)
// convert the key back into 3 indices
uint32_t CoordIndex, NormalIndex, TextCoordIndex;
from_key(key, CoordIndex, NormalIndex, TextCoordIndex);
vertex Vert = {};
v3 Pos = Coords[CoordIndex];
Vert.Position = glm::vec3(Pos.x, Pos.y, Pos.z);
if (NormalIndex != UINT32_MAX) {
v3 Norm = Normals[NormalIndices[VertexIndex]];
Vert.Normal = glm::vec3(Norm.x, Norm.y, Norm.z);
}
if (TextCoordIndex != UINT32_MAX) {
v2 TextCoord = TextCoords[TextCoordIndices[VertexIndex]];
Vert.TextureCoord = glm::vec2(TextCoord.x, TextCoord.y);
}
uniqueVertices.push_back(Vert);
}
Finally, you need to map from the original index out to the new index, preserving the triangle geometry.
std::vector<uint32_t> RemapedIndices;
RemapedIndices.reserve(IndexCount);
for(u32 OriginalVertexIndex = 0; OriginalVertexIndex < IndexCount; ++OriginalVertexIndex) {
auto key = originalIndexToKey[OriginalVertexIndex];
auto NewIndex = keyToNewIndex[key];
RemapedIndices.push_back(NewIndex );
}
The image is not completely randomly messed up. If you combine the two images, these fit perfectly:
The only problem, a mesh means triangles. You tell Vulkan how to draw each triangle. Having a mesh composed of 8 triangles, 9 unique vertices, you pass vertices for each one of 8 triangles separately, see screenshot below:
1:[1,2,4], 2:[2,5,4], 3:[2,3,5], 4:[3,6,5], 5:[4,5,7], 6:[5,8,7], 7:[5,6,8], 8:[6,9,8] (see red numbers).
So the vertex 5 will be repeated 6 times, because there the triangles 2,3,4,5,6,7 shares the vertex 5. Same goes for normals and textures. The vast majority of vertices with all set coordinates, normals, textures, colors, will be repeated exactly 6 times. If it is double coated it will be repeated 12 times. The boundary vertices will be repeated 3 and respectively 6 times if double coated. And the edge vertices will be repeated 1/2 times, see left and right edge, and respectively 2/4 times if double coated:
If you try to remove the duplicates, you transform a mesh in a mess. And this is regardless of how well these are sorted or unsorted. The order makes no more any sense.
If you want to use unique set of coordinates, there probably exists in Vulkan some technique to add an index buffer, similar to OpenGL. So you can pass unique coordinates, but build correctly the index array. All vertices will be unique, but the indexes in index array will not.

In FBX, how do you know which vert indexes correspond to which control point indexes?

I am currently trying to load an FBX mesh for use with DirectX, but my FBX file has it's UVs stored by vert index and the normals stored by control point index. How do I know which vertexes have which control point's values?
My code for loading positions, uvs and normals is ripped straight from the fbx example code, but I can post it if needed.
edit: as requested, here are the parts of my code I am talking about.
The UV code will go into the if statement for mapping mode by vert index, while the normal code is set to mapping mode by ctrl point
//load uvs
if (lUVElement->GetMappingMode() == FbxGeometryElement::eByControlPoint)
{
for (int lPolyIndex = 0; lPolyIndex < lPolyCount; ++lPolyIndex)
{
// build the max index array that we need to pass into MakePoly
const int lPolySize = mesh->GetPolygonSize(lPolyIndex);
for (int lVertIndex = 0; lVertIndex < lPolySize; ++lVertIndex)
{
//get the index of the current vertex in control points array
int lPolyVertIndex = mesh->GetPolygonVertex(lPolyIndex, lVertIndex);
//the UV index depends on the reference mode
int lUVIndex = lUseIndex ? lUVElement->GetIndexArray().GetAt(lPolyVertIndex) : lPolyVertIndex;
lUVValue = lUVElement->GetDirectArray().GetAt(lUVIndex);
_floatVec->push_back((float)lUVValue.mData[0]);
_floatVec->push_back((float)lUVValue.mData[1]);
}
}
}
else if (lUVElement->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
{
int lPolyIndexCounter = 0;
for (int lPolyIndex = 0; lPolyIndex < lPolyCount; ++lPolyIndex)
{
// build the max index array that we need to pass into MakePoly
const int lPolySize = mesh->GetPolygonSize(lPolyIndex);
for (int lVertIndex = 0; lVertIndex < lPolySize; ++lVertIndex)
{
if (lPolyIndexCounter < lIndexCount)
{
//the UV index depends on the reference mode
int lUVIndex = lUseIndex ? lUVElement->GetIndexArray().GetAt(lPolyIndexCounter) : lPolyIndexCounter;
lUVValue = lUVElement->GetDirectArray().GetAt(lUVIndex);
_floatVec->push_back((float)lUVValue.mData[0]);
_floatVec->push_back((float)lUVValue.mData[1]);
lPolyIndexCounter++;
}
}
}
}
//and now normals
if (lNormalElement->GetMappingMode() == FbxGeometryElement::eByControlPoint)
{
//Let's get normals of each vertex, since the mapping mode of normal element is by control point
for (int lVertexIndex = 0; lVertexIndex < mesh->GetControlPointsCount(); lVertexIndex++)
{
int test = mesh->GetControlPointsCount();
int lNormalIndex = 0;
//reference mode is direct, the normal index is same as vertex index.
//get normals by the index of control vertex
if (lNormalElement->GetReferenceMode() == FbxGeometryElement::eDirect)
lNormalIndex = lVertexIndex;
//reference mode is index-to-direct, get normals by the index-to-direct
if (lNormalElement->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
lNormalIndex = lNormalElement->GetIndexArray().GetAt(lVertexIndex);
//Got normals of each vertex.
FbxVector4 lNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex);
_floatVec->push_back((float)lNormal[0]);
_floatVec->push_back((float)lNormal[1]);
_floatVec->push_back((float)lNormal[2]);
}
}
else if (lNormalElement->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
{
//etc... code wont go here
}
}
}
}
So how can I know which vertexes will have which normals?

C++ obj loader texture coordinates messed up

I have written a simple obj parser in c++ that loads the vertices, indices and texture coordinates (that's all the data I need).
Here is the function:
Model* ModelLoader::loadFromOBJ(string objFile, ShaderProgram *shader, GLuint texture)
{
fstream file;
file.open(objFile);
if (!file.is_open())
{
cout << "ModelLoader: " << objFile << " was not found";
return NULL;
}
int vertexCount = 0;
int indexCount = 0;
vector<Vector3> vertices;
vector<Vector2> textureCoordinates;
vector<Vector2> textureCoordinatesFinal;
vector<unsigned int> vertexIndices;
vector<unsigned int> textureIndices;
string line;
while (getline(file, line))
{
vector<string> splitLine = Common::splitString(line, ' ');
// v - vertex
if (splitLine[0] == "v")
{
Vector3 vertex(stof(splitLine[1]), stof(splitLine[2]), stof(splitLine[3]));
vertices.push_back(vertex);
vertexCount++;
}
// vt - texture coordinate
else if (splitLine[0] == "vt")
{
Vector2 textureCoordinate(stof(splitLine[1]), 1 - stof(splitLine[2]));
textureCoordinates.push_back(textureCoordinate);
}
// f - face
else if (splitLine[0] == "f")
{
vector<string> faceSplit1 = Common::splitString(splitLine[1], '/');
vector<string> faceSplit2 = Common::splitString(splitLine[2], '/');
vector<string> faceSplit3 = Common::splitString(splitLine[3], '/');
unsigned int vi1 = stoi(faceSplit1[0]) - 1;
unsigned int vi2 = stoi(faceSplit2[0]) - 1;
unsigned int vi3 = stoi(faceSplit3[0]) - 1;
unsigned int ti1 = stoi(faceSplit1[1]) - 1;
unsigned int ti2 = stoi(faceSplit2[1]) - 1;
unsigned int ti3 = stoi(faceSplit3[1]) - 1;
vertexIndices.push_back(vi1);
vertexIndices.push_back(vi2);
vertexIndices.push_back(vi3);
textureIndices.push_back(ti1);
textureIndices.push_back(ti2);
textureIndices.push_back(ti3);
indexCount += 3;
}
}
// rearanging textureCoordinates into textureCoordinatesFinal based on textureIndices
for (int i = 0; i < indexCount; i++)
textureCoordinatesFinal.push_back(textureCoordinates[textureIndices[i]]);
Model *result = new Model(shader, vertexCount, &vertices[0], NULL, texture, indexCount, &textureCoordinatesFinal[0], &vertexIndices[0]);
models.push_back(result);
return result;
}
As you can see, I take into account the 1 - texCoord.y (because blender and opengl use a different coordinate system for textures).
I also arrange the texture coordinates based on the texture indices after the while loop.
However, the models I try to render have their textures messed up. Here is an example:
Texture messed up
I even tried it with a single cube which I unwrapped myself in blender and applied a very simple brick texture. In 1 or 2 faces, the texture was fine and working, then in some other faces, 1 of the tringles had a correct texture and the others appeared streched out (same as in the picture above).
To define a mesh, there is only one index list that indexes the vertex attributes. The vertex attributes (in your case the vertices and the texture coordinate) form a record set, which is referred by these indices.
This causes, that each vertex coordinate may occur several times in the list and each texture coordinate may occur several times in the list. But each combination of vertices and texture coordinates is unique.
Take the vertexIndices and textureIndices an create unique pairs of vertices and texture coordinates (verticesFinal, textureCoordinatesFinal).
Create new attribute_indices, which indexes the pairs.
Use the a temporary container attribute_pairs to manage the unique pairs and to identify their indices:
#include <vector>
#include <map>
// input
std::vector<Vector3> vertices;
std::vector<Vector2> textureCoordinates;
std::vector<unsigned int> vertexIndices;
std::vector<unsigned int> textureIndices;
std::vector<unsigned int> attribute_indices; // final indices
std::vector<Vector3> verticesFinal; // final vertices buffer
std::vector<Vector2> textureCoordinatesFinal; // final texture coordinate buffer
// map a pair of indices to the final attribute index
std::map<std::pair<unsigned int, unsigned int>, unsigned int> attribute_pairs;
// vertexIndices.size() == textureIndices.size()
for ( size_t i = 0; i < vertexIndices.size(); ++ i )
{
// pair of vertex index an texture index
auto attr = std::make_pair( vertexIndices[i], textureIndices[i] );
// check if the pair aready is a member of "attribute_pairs"
auto attr_it = attribute_pairs.find( attr );
if ( attr_it == attribute_pairs.end() )
{
// "attr" is a new pair
// add the attributes to the final buffers
verticesFinal.push_back( vertices[attr.first] );
textureCoordinatesFinal.push_back( textureCoordinates[attr.first] );
// the new final index is the next index
unsigned int new_index = (unsigned int)attribute_pairs.size();
attribute_indices.push_back( new_index );
// add the new map entry
attribute_pairs[attr] = new_index;
}
else
{
// the pair "attr" already exists: add the index which was found in the map
attribute_indices.push_back( attr_it->second );
}
}
Note the number of the vertex coordinates (verticesFinal.size()) is equal the number of the texture coordiantes (textureCoordinatesFinal.size()). But the number of the indices (attribute_indices.size()) is something completely different.
// verticesFinal.size() == textureCoordinatesFinal.size()
Model *result = new Model(
shader,
verticesFinal.size(),
verticesFinal.data(),
NULL, texture,
attribute_indices.size(),
textureCoordinatesFinal.data(),
attribute_indices.data() );

CGAL: Get face data from surface mesh

I'm trying to fill my own struct with data retrieved from a CGAL::Surface_mesh.
You can add a face to a surface mesh via..
CGAL::SM_Face_index face = SM_Surface_Mesh.add_face(SM_Vertex_Index, SM_Vertex_Index, SM_Vertex_Index);
.. but how does one retrieve that face given the SM_Face_Index? I've tried sifting through the documentation but to no avail.
InteropMesh * outputMesh = new InteropMesh();
uint32_t num = mesh1.number_of_vertices();
outputMesh->vertexCount = num;
outputMesh->vertices = new InteropVector3[num];
for (Mesh::Vertex_index vd : mesh1.vertices())
{
uint32_t index = vd; //via size_t
Point data = mesh1.point(vd);
outputMesh->vertices[index].x = (float)data.x();
outputMesh->vertices[index].y = (float)data.y();
outputMesh->vertices[index].z = (float)data.z();
}
outputMesh->indices = new uint32_t[mesh1.number_of_faces() * 3];
for (CGAL::SM_Face_index fd : mesh1.faces())
{
//? How do I get the three vertex indices?
}
A simple way of getting vertex and face indices can be done like this;
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
Mesh sm;
// sm created here or as a result of some CGAL function
std::vector<float> verts;
std::vector<uint32_t> indices;
//Get vertices ...
for (Mesh::Vertex_index vi : sm.vertices()) {
K::Point_3 pt = sm.point(vi);
verts.push_back((float)pt.x());
verts.push_back((float)pt.y());
verts.push_back((float)pt.z());
}
//Get face indices ...
for (Mesh::Face_index face_index : sm.faces()) {
CGAL::Vertex_around_face_circulator<Mesh> vcirc(sm.halfedge(face_index), sm), done(vcirc);
do indices.push_back(*vcirc++); while (vcirc != done);
}
This example assumes triangle output (i.e. every 3 indices describes a triangle) although faces could have more indices as Andry points out.
Another function should be added to check the face index count and split faces into triangles if there are more than 3 indices.
The Surface_mesh data structure can represent more than only triangle meshes. Meaning that you might have more than 3 vertices per face.
Once you get a face, you can navigate on its boundary edges and get the source and target vertices.
For example you can do:
Surface_mesh::Halfedge_index hf = sm.halfedge(fi);
for(Surface_mesh::Halfedge_index hi : halfedges_around_face(hf, sm))
{
Surface_mesh::Vertex_index vi = target(hi, sm);
}
You can also do it by hand:
Surface_mesh::Halfedge_index hstart = sm.halfedge(fi), hi=hstart;
do{
Surface_mesh::Vertex_index vi = target(hi, sm);
hi=sm.next(hi);
}
while(hi!=hstart)

Importing and Displaying .fbx files in OpenGl

I have been trying to import and display an fbx file using the FBX SDK.Untill. I managed to load in the file, but I got stuck at the part where I have to display it.
The questions:
What exactly are those indices?
How should I display the vertices?
Here is the class that I made:
3dModelBasicStructs.h
struct vertex
{
float x,y,z;
};
struct texturecoords
{
float a,b;
};
struct poligon
{
int a,b,c;
};
Model.h
#ifndef MODEL_H
#define MODEL_H
#define FBXSDK_NEW_API
#define MAX_VERTICES 80000
#define MAX_POLIGONS 80000
#include <fbxsdk.h>
#include "3dModelBasicStructs.h"
#include <iostream>
#include <GL/glut.h>
using namespace std;
class Model
{
public:
Model(char*);
~Model();
void ShowDetails();
char* GetModelName();
void SetModelName( char* );
void GetFbxInfo( FbxNode* );
void RenderModel();
void InitializeVertexBuffer( vertex* );
private:
char Name[25];
vertex vertices[MAX_VERTICES];
poligon poligons[MAX_POLIGONS];
int *indices;
int numIndices;
int numVertices;
};
#endif
Model.cpp
#include "Model.h"
Model::Model(char *filename)
{
cout<<"\nA model has been built!";
numVertices=0;
numIndices=0;
FbxManager *manager = FbxManager::Create();
FbxIOSettings *ioSettings = FbxIOSettings::Create(manager, IOSROOT);
manager->SetIOSettings(ioSettings);
FbxImporter *importer=FbxImporter::Create(manager,"");
importer->Initialize(filename,-1,manager->GetIOSettings());
FbxScene *scene = FbxScene::Create(manager,"tempName");
importer->Import(scene);
importer->Destroy();
FbxNode* rootNode = scene->GetRootNode();
this->SetModelName(filename);
if(rootNode) { this->GetFbxInfo(rootNode); }
}
Model::~Model()
{
cout<<"\nA model has been destroied!";
}
void Model::ShowDetails()
{
cout<<"\nName:"<<Name;
cout<<"\nVertices Number:"<<numVertices;
cout<<"\nIndices which i never get:"<<indices;
}
char* Model::GetModelName()
{
return Name;
}
void Model::SetModelName(char *x)
{
strcpy(Name,x);
}
void Model::GetFbxInfo( FbxNode* Node )
{
int numKids = Node->GetChildCount();
FbxNode *childNode = 0;
for ( int i=0 ; i<numKids ; i++)
{
childNode = Node->GetChild(i);
FbxMesh *mesh = childNode->GetMesh();
if ( mesh != NULL)
{
//================= Get Vertices ====================================
int numVerts = mesh->GetControlPointsCount();
for ( int j=0; j<numVerts; j++)
{
FbxVector4 vert = mesh->GetControlPointAt(j);
vertices[numVertices].x=(float)vert.mData[0];
vertices[numVertices].y=(float)vert.mData[1];
vertices[numVertices++].z=(float)vert.mData[2];
cout<<"\n"<<vertices[numVertices-1].x<<" "<<vertices[numVertices- 1].y<<" "<<vertices[numVertices-1].z;
this->InitializeVertexBuffer(vertices);
}
//================= Get Indices ====================================
int *indices = mesh->GetPolygonVertices();
numIndices+=mesh->GetPolygonVertexCount();
}
this->GetFbxInfo(childNode);
}
}
void Model::RenderModel()
{
glDrawElements(GL_TRIANGLES,36,GL_INT,indices);
}
void Model::InitializeVertexBuffer(vertex *vertices)
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3,GL_FLOAT,0,vertices);
//glDrawArrays(GL_TRIANGLES,0,36);
}
Sadly , When i try to use drawelements i get this error:
Unhandled exception at 0x77e215de in A new begging.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd.
2) How should I display the vertices?
Questions like these indicate, that you should work through some OpenGL tutorials. Those are the basics and you need to know them.
This is a good start regarding your problem, but you'll need to work through the whole tutorial
http://opengl.datenwolf.net/gltut/html/Basics/Tut01%20Following%20the%20Data.html
1) What exactly are those indices ?
You have a list of vertices. The index of a vertex is the position at which it is in that list. You can draw vertex arrays by its indices using glDrawElements
Update due to comment
Say you have a cube with shared vertices (uncommon in OpenGL, but I'm too lazy for writing down 24 vertices).
I have them in my program in an array, that forms a list of their positions. You load them from a file, I'm writing them a C array:
GLfloat vertices[3][] = {
{-1,-1, 1},
{ 1,-1, 1},
{ 1, 1, 1},
{-1, 1, 1},
{-1,-1,-1},
{ 1,-1,-1},
{ 1, 1,-1},
{-1, 1,-1},
};
This gives the vertices indices (position in the array), in the picture it looks like
To draw a cube we have to tell OpenGL in which vertices, in which order make a face. So let's have a look at the faces:
We're going to build that cube out of triangles. 3 consecutive indices make up a triangle. For the cube this is
GLuint face_indices[3][] = {
{0,1,2},{2,3,0},
{1,5,6},{6,2,1},
{5,4,7},{7,6,5},
{4,0,3},{3,7,4},
{3,2,6},{6,7,2},
{4,5,0},{1,0,5}
};
You can draw this then by pointing OpenGL to the vertex array
glVertexPointer(3, GL_FLOAT, 0, &vertices[0][0]);
and issuing a batches call on the array with vertices. There are 6*2 = 12 triangles, each triangle consisting of 3 vertices, which makes a list of 36 indices.
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, &face_indices[0][0]);