Class Object Not Modifying Other Class Object Correctly - c++

I am trying to create a Model class that does the following:
- creates a Mesh class instance
- calls the addVertex function of the created Mesh object
- calls the addTriangle function of the created Mesh object
The Mesh class has two vectors to which the functions add to but when I print the contents in main.cpp they are empty.
Here is my code:
Model Class:
class Model
{
public:
/* Model Data */
/...
//using default constructor
Mesh createMesh() {
Mesh mesh;
meshes.push_back(mesh);
return mesh;
}
void addVertex(Mesh mesh, Vertex v) {
mesh.addVertex(v);
}
void addTriangle(Mesh mesh, Vertex a, Vertex b, Vertex c) {
mesh.addTriangle(a,b,c);
}
/...
Mesh Class:
class Mesh {
public:
/* Mesh Data */
vector<Vertex> vertices;
vector<unsigned int> indices;
/...
// constructor
Mesh(vector<Vertex> vertices, vector<unsigned int> indices, vector<Texture> textures)
{
this->vertices = vertices;
this->indices = indices;
this->textures = textures;
for (Vertex v: vertices) {
pairings.insert( std::pair<Vertex,unsigned int>(v,count) );
count++;
}
setupMesh();
}
Mesh () {
}
//function 1
void addVertex(Vertex vertex) {
vertices.push_back(vertex);
pairings.insert( std::pair<Vertex,unsigned int>(vertex,count));
count++;
}
//function 2
void addTriangle(Vertex a, Vertex b, Vertex c) {
unsigned int index = pairings[a];
indices.push_back(index);
index = pairings[b];
indices.push_back(index);
index = pairings[c];
indices.push_back(index);
setupMesh();
}
main.cpp:
Model m;
Mesh mesh = m.createMesh();
Vertex a;
a.Position = glm::vec3 (-1,0,0);
m.addVertex(mesh, a);
Vertex b;
b.Position = glm::vec3 (0,1,0);
m.addVertex(mesh,b);
Vertex c;
c.Position = glm::vec3 (1,0,0);
m.addVertex(mesh,c);
m.addTriangle(mesh,a,b,c);
std::cout << mesh.indices.size(); //prints 0
Any help would be greatly appreciated!

I believe it is because on your addVertex and addTriangle methods within your Model class, you are passing the parameters by value, not by reference or pointer. This means that when you call the method you will pass a copy of your Mesh and Vertex objects and any changes you make inside the method will be lost as soon as execution of the method is complete. Try the following changes:
void addVertex(Mesh &mesh, Vertex &v) {
mesh.addVertex(v);
}
void addTriangle(Mesh &mesh, Vertex &a, Vertex &b, Vertex &c) {
mesh.addTriangle(a,b,c);
}
For more information on passing by reference, please refer to the following.

Related

Meshes loaded via Assimp look distorted

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.

Extracting vectors from Structure in header file

This is the header file in question:
namespace osc {
using namespace gdt;
struct TriangleMesh {
std::vector<vec3f> vertex;
std::vector<vec3f> normal;
std::vector<vec2f> texcoord;
std::vector<vec3i> index;
// material data:
vec3f diffuse;
};
struct Model {
~Model()
{ for (auto mesh : meshes) delete mesh; }
std::vector<TriangleMesh *> meshes;
//! bounding box of all vertices in the model
box3f bounds;
};
Model *loadOBJ(const std::string &objFile);
}
I have successfully been able to use this header file to import an .obj of the 3D model in my main C++ code using the loadOBJ() function described in the header. I now want to operate on the vertices of that model. From the looks of it, the vertex points are in the structures defined in the header file. How do I extract these vertex vectors from the structure (and display them)?
loadOBJ() gives you a pointer to a Model object.
Model has a std::vector (a dynamic array) member named meshes that holds pointers to TriangleMesh objects.
TriangleMesh has a std::vector member named vertex holding vec3f objects.
You can iterate the various vectors like this:
osc::Model *model = osc::loadOBJ(...);
if (!model) ... // error handling
for (auto&& mesh : model->meshes)
{
cout << "vertex:\n";
for (auto&& vtx : mesh->vertex)
{
cout << "x=" << vtx.x << ", y=" << vtx.y << "z=" << vtx.z << "\n";
}
cout << "\n";
// repeat for mesh->normal, mesh->texcoord, mesh->index, etc...
}
delete model;
std::vector is a dynamic array in c++
if you want to enumerate
std::vector<vec3f> vertex;
you do
for(auto vert: vertex)
{
// here vert is of type vec3F
}
you can also access it like an array
vec3f v2 = vertex[2];
of course you must make sure vertex has at least 2 elements. You can find the length with vertex.size()

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() );

Bone weights to GPU in vectors

I've been working on skeletal animation using OPenGL and sending bone weight influences to the GPU in a struct containing a pair of arrays, however changing these arrays to vectors doesn't seem to work (as in the model ceases to render, as if the bone information was missing or wrong in some manner).
Asides from the declaration of the vectors within the struct, the code path is identical. I've debugged through and ensured the size/values of the elements are okay. The only thing I can think of is that C++ is freeing the contents of the vectors before it can be uploaded to the GPU, but I've seen no evidence to support that claim.
It's worth noting that the resizes used are to make the structure compatible with the existing array functionality and will be removed to allow for dynamic scaling after this issue is resolved.
Here's the structure as it stands, using vectors:
struct VertexBoneData
{
std::vector<glm::uint> IDs;
std::vector<float> weights;
VertexBoneData()
{
Reset();
IDs.resize(NUM_BONES_PER_VEREX);
weights.resize(NUM_BONES_PER_VEREX);
};
void Reset()
{
IDs.clear();
weights.clear();
}
void AddBoneData(glm::uint p_boneID, float p_weight);
};
Edit: Additional information.
Here's the loop to get the bone information in to the struct:
void Skeleton::LoadBones(glm::uint baseVertex, const aiMesh* mesh, std::vector<VertexBoneData>& bones)
{
for (glm::uint i = 0; i < p_mesh->mNumBones; i++) {
glm::uint boneIndex = 0;
std::string boneName(mesh->mBones[i]->mName.data);
if (_boneMap.find(boneName) == _boneMap.end()) {
//Allocate an index for a new bone
boneIndex = _numBones;
_numBones++;
BoneInfo bi;
_boneInfo.push_back(bi);
SetMat4x4(_boneInfo[boneIndex].boneOffset, mesh->mBones[i]->mOffsetMatrix);
_boneMap[boneName] = boneIndex;
}
else {
boneIndex = _boneMap[boneName];
}
for (glm::uint j = 0; j < mesh->mBones[i]->mNumWeights; j++) {
glm::uint vertId = baseVertex + mesh->mBones[i]->mWeights[j].mVertexId;
float weight = mesh->mBones[i]->mWeights[j].mWeight;
bones[vertId].AddBoneData(boneIndex, weight);
}
}
}
The code to add the ID/weights to the vertex:
void VertexBoneData::AddBoneData(glm::uint p_boneID, float p_weight)
{
for (glm::uint i = 0; i < ARRAY_SIZE_IN_ELEMENTS(IDs); i++) {
if (weights[i] == 0.0) {
IDs[i] = p_boneID;
weights[i] = p_weight;
return;
}
}
assert(0); //Should never get here - more bones than we have space for
}
Loop to load the Skeleton and insert to the VBO object from the Mesh class:
if (_animator.HasAnimations())
{
bones.resize(totalIndices);
for (unsigned int i = 0; i < _scene->mNumMeshes; ++i){
_animator.LoadSkeleton(_subMeshes[i].baseVertex, _scene->mMeshes[i], bones);
}
_vertexBuffer[2].AddData(&bones);
}
Insert to the VBO object:
void VertexBufferObject::AddData(void* ptr_data)
{
data = *static_cast<std::vector<BYTE>*>(ptr_data);
}
Finally the code to add the information to the GPU from the Mesh class:
_vertexBuffer[2].BindVBO();
_vertexBuffer[2].UploadDataToGPU(GL_STATIC_DRAW);
glEnableVertexAttribArray(BONE_ID_LOCATION);
glVertexAttribIPointer(BONE_ID_LOCATION, 4, GL_INT, sizeof(VertexBoneData), (const GLvoid*)0);
glEnableVertexAttribArray(BONE_WEIGHT_LOCATION);
glVertexAttribPointer(BONE_WEIGHT_LOCATION, 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData), (const GLvoid*)(sizeof(VertexBoneData) / 2));
This can't possibly work. A std::vector instance is an object that internally contains a pointer to dynamically allocated data.
So with this definition:
struct VertexBoneData
{
std::vector<glm::uint> IDs;
std::vector<float> weights;
The values for the IDs and weights aren't stored directly in the structure. The are in dynamically allocated heap memory. The structure only contains the vector objects, which contain pointers and some bookkeeping attributes.
You can't store these structs directly in an OpenGL buffer, and have the GPU access the data. OpenGL won't know what do with vector objects.

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]);