I used memcpy to copy a struct Vertex comprised of glm::vec3 objects.
It worked to copy the struct in a class function.
It did not work in the copy constructor that was called when that function returned the class object.
Why?
Class function returning object
ShapeData ShapeGenerator::drawTriangle() {
ShapeData ret;
Vertex verts[] = {
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(-1.0f, -1.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(1.0f, -1.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f),
};
ret.numVerts = NUM_ARRAY_ELEMENTS(verts);
ret.verts = new Vertex[ret.numVerts];
memcpy(ret.verts, verts, sizeof(verts)); //WORKS
GLushort indicies[] = {0,1,2};
ret.numIndicies = NUM_ARRAY_ELEMENTS(indicies);
ret.indicies = new GLushort[ret.numIndicies];
memcpy(ret.indicies, indicies, sizeof(indicies));
return ret;
}
Copy Constructor
ShapeData(const ShapeData& data) {
verts = new Vertex[data.numVerts];
//memcpy(verts, data.verts, sizeof(data.verts)); //DOES NOT WORK
std::copy( data.verts, data.verts + data.numVerts, verts);
indicies = new GLushort[data.numIndicies];
memcpy(indicies, data.indicies, sizeof(data.indicies));
numVerts = data.numVerts;
numIndicies = data.numIndicies;
std::cout << numVerts << std::endl;
}
Vertex:
#ifndef VERTEX_H
#define VERTEX_H
#include <glm/glm.hpp>
struct Vertex {
glm::vec3 position;
glm::vec3 color;
};
#endif
memcpy(verts, data.verts, sizeof(data.verts)); //DOES NOT WORK
does not work since verts is a pointer, not an array. sizeof(data.verts) does not evaluate to the size of the array the pointer points to. It simply evaluates to the size of a pointer on your platform.
You should be able to use:
size_t n = sizeof(*data.verts)*data.numVerts;
memcpy(verts, data.verts, n);
Related
I am looking for an algorithm that can generate level of details of a given mesh.
Meshes have a vertex and index buffers. Each LOD number of vertices may be computed as following:
LOD0 -> 1 / 2^0 -> 1 * <mesh_number_of_vertices>
LOD1 -> 1 / 2^1 -> 1/2 * <mesh_number_of_vertices>
...
LOD8 -> 1 / 2^8 -> 1 / 256 * <mesh_number_of_vertices>
In term of code, I am looking how to implement the GenerateLOD function:
struct Vertex
{
Math::Vec3 Position;
Math::Vec2 Texcoord;
};
void GenerateLOD(const std::vector<Vertex>& InVertices,
const std::vector<uint32_t>& InIndices,
std::vector<Vertex>& outVertices,
std::vector<uint32_t>& outIndices,
int LODLevel)
{
const float LODFactor = 1.0f / pow(2, LODLevel);
// Generation here...
}
int main()
{
const std::vector<Vertex> MeshVertices{
{ Math::Vec3(-1.0f, -1.0f, 0.0f), Math::Vec2(0.0f, 1.0f)},
{ Math::Vec3(1.0f, -1.0f, 0.0f), Math::Vec2(1.0f, 1.0f)},
{ Math::Vec3(-1.0f, 1.0f, 0.0f), Math::Vec2(0.0f, 0.0f)},
{ Math::Vec3(1.0f, 1.0f, 0.0f), Math::Vec2(1.0f, 0.0f)}
//etc.....
};
const std::vector<uint32_t> MeshIndices{ 0, 1, 2, 1, 2, 3/* etc...*/ };
std::vector<Vertex> OutVertices;
std::vector<uint32_t> OutIndices;
const int LODLevel = 2;
GenerateLOD(MeshVertices, MeshIndices, OutVertices, OutIndices, LODLevel);
return EXIT_SUCCESS;
}
I found that the problem is known as Mesh simplification.
Here great papers about it:
https://www.cs.cmu.edu/~garland/Papers/quadric2.pdf
https://cragl.cs.gmu.edu/seamless/
Open source implementations can be found here:
https://github.com/cnr-isti-vclab/meshlab
https://github.com/cnr-isti-vclab/vcglib/
i am trying to do chess with openGL c ++, for now i have created the pawn object, where its constructor takes an unsigned int parameter. So I tried to create an array of these pawns, and the only working way I've found to do this is this :
Pawn *pawn[n];
for (int i = 0; i < n; i++) {
pawn[i] = new Pawn(Unsigned int var);
}
To call a function of pawn [0], for example, I have to do this :
pawn[0]->function(parameters);
This is the Pawn class :
class Pawn
{
private:
float vertices [16] = {
//position //text coord
-0.08f, -0.10f, 0.0f, 0.0f,
0.08f, -0.10f, 1.0f, 0.0f,
0.08f, 0.10f, 1.0f, 1.0f,
-0.08f, 0.10f, 0.0f, 1.0f
};
GLuint indices[6] {
0, 1, 2,
0, 2, 3
};
unsigned int shaderID, VBO, VAO, EBO, texture;
public:
glm::vec2 Position = glm::vec2(0.0f, 0.0f);
Pawn () {}
Pawn(GLuint shaderID) {
...
}
~Pawn() {
...
}
void setTexture();
void draw (glm::vec2 position);
};
I also tried this :
Pawn pawn[8];
for (int i = 0; i < 8; i++) {
pawn[i] = Pawn(shaderID);
}
but when i run it doesn't work.
I was wondering if this method is efficient or not, and if so, why it works, since I didn't understand it. Thanks for your help
I am against one problem with my C++ code. I am using the Assimp library, and I have one class that has one attribute of type const aiScene*. In the constructor of the class, I assign this value and all works fine, but when I exit the constructor code, the parameter const aiScene* does not have any data assigned
I paste you here the code.
Model.h
class Model
{
public:
Model(std::string objectLoc, std::string vertexLoc, std::string fragmentLoc,
glm::vec3 position, glm::vec3 scale, glm::vec3 rotation,
Camera* camera);
void render();
~Model();
private:
std::string objectLoc, vertexLoc, fragmentLoc;
Shader* shader;
glm::mat4 model;
glm::vec3 position, scale, rotation;
Camera* camera;
std::vector<Mesh*> meshes;
std::vector<Texture*> textures;
std::vector<unsigned int> meshToTex;
std::unordered_map<std::string, GLuint> boneMapping;
std::vector<glm::mat4> bonesTransformations;
const aiScene* scene;
glm::mat4 globalInverseTransform;
GLuint boneCount;
};
Model.cpp
Model::Model(std::string objectLoc, std::string vertexLoc, std::string fragmentLoc, glm::vec3
position, glm::vec3 scale, glm::vec3 rotation, Camera* camera)
: objectLoc(objectLoc), vertexLoc(vertexLoc), fragmentLoc(fragmentLoc),
position(position), scale(scale), rotation(rotation),
camera(camera),
boneCount(0)
{
shader = new Shader(vertexLoc, fragmentLoc,
DirectionalLight(glm::vec3(1.0f, 1.0f, 1.0f), 0.4f, 0.1f, glm::vec3(0.0f, 0.0f, -1.0f)),
SpecularLight(1.0f, 250.0f),
SpotLight(glm::vec3(1.0f, 1.0f, 1.0f), 0.0f, 1.0f, glm::vec3(0.0f, 0.0f, 0.0f), 1.0f, 0.0f, 0.0f,
glm::vec3(0.0f, 0.0f, -1.0f), glm::radians(10.0f)));
shader->addPointLight(PointLight(glm::vec3(1.0f, 0.0f, 0.0f), 0.2f, 0.2f, glm::vec3(0.0f, 0.0f,
-15.0f), 0.3f, 0.2f, 0.1f));
shader->addPointLight(PointLight(glm::vec3(0.0f, 1.0f, 0.0f), 0.2f, 0.2f, glm::vec3(10.0f, 0.0f,
-15.0f), 0.3f, 0.2f, 0.1f));
shader->addPointLight(PointLight(glm::vec3(0.0f, 0.0f, 1.0f), 0.2f, 1.2f, glm::vec3(-10.0f, 0.0f,
-15.0f), 0.8f, 0.2f, 0.1f));
model = glm::translate(glm::mat4(1.0f), position)
* glm::scale(glm::mat4(1.0f), scale)
* glm::rotate(glm::mat4(1.0f), glm::radians(rotation.x), glm::vec3(1, 0, 0))
* glm::rotate(glm::mat4(1.0f), glm::radians(rotation.y), glm::vec3(0, 1, 0))
* glm::rotate(glm::mat4(1.0f), glm::radians(rotation.z), glm::vec3(0, 0, 1));
Assimp::Importer importer;
scene = importer.ReadFile(objectLoc,
aiProcess_Triangulate |
aiProcess_FlipUVs |
aiProcess_GenSmoothNormals |
aiProcess_JoinIdenticalVertices);
if (!scene)
{
printf("Cannot load model %s: %s\n", objectLoc.c_str(), importer.GetErrorString());
return;
}
aiNode* rootNode = scene->mRootNode;
globalInverseTransform = aiMatrix4x4ToGlm(rootNode->mTransformation.Inverse());
loadNode(rootNode);
loadTextures();
}
I have tried everything, from copy one by one the attributes to the object scene, to make a clone method in all classes involved, but nothing. Even, I have thought that the problem could be the const identifier in the scene attribute, but if I make the object not constant, it works wrongly the same.
I am not modifying that attribute in any of the methods of the Model class.
I paste you here some photos of the problem.
Good result in the constructor
Bad result out of the constructor
If you could help me it would be great.
The documentation says
The returned data is intended to be read-only, the importer object keeps ownership of the data and will destroy it upon destruction.
[Assimp::Importer::ReadFile]
When the constructor is left Assimp::Importer importer; and the object scene is pointing to are destroyed.
You have to make a copy of it before you leave the constructor or
Use GetOrphanedScene() to take ownership of it.
[Assimp::Importer::ReadFile]
aiScene* Assimp::Importer::GetOrphanedScene ( )
Returns the scene loaded by the last successful call to ReadFile() and releases the scene from the ownership of the Importer instance.
The application is now responsible for deleting the scene. Any further calls to GetScene() or GetOrphanedScene() will return NULL - until a new scene has been loaded via ReadFile().
Returns:
Current scene or NULL if there is currently no scene loaded
Note:
Use this method with maximal caution, and only if you have to. By design, aiScene's are exclusively maintained, allocated and deallocated by Assimp and no one else. The reasoning behind this is the golden rule that deallocations should always be done by the module that did the original allocation because heaps are not necessarily shared. GetOrphanedScene() enforces you to delete the returned scene by yourself, but this will only be fine if and only if you're using the same heap as assimp. On Windows, it's typically fine provided everything is linked against the multithreaded-dll version of the runtime library. It will work as well for static linkage with Assimp.
[Assimp::Importer::GetOrphanedScene]
I have a vertex buffer created as follows:
ID3D10Buffer * VertexBuffer;
Vertex_PosCol * Vertices;
D3D10_SUBRESOURCE_DATA VertexData;
Vertices = new Vertex_PosCol[VerticeCount];
Vertices[0].Position = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
Vertices[0].Color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
Vertices[1].Position = D3DXVECTOR3(-1.0f, 2.0f, 0.0f);
Vertices[1].Color = D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f);
Vertices[2].Position = D3DXVECTOR3(1.0f, 2.0f, 0.0f);
Vertices[2].Color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);
Vertices[3].Position = D3DXVECTOR3(2.0f, 1.0f, 0.0f);
Vertices[3].Color = D3DXVECTOR4(0.0f, 0.0f, 1.0f, 1.0f);
Vertices[4].Position = D3DXVECTOR3(2.0f, -1.0f, 0.0f);
Vertices[4].Color = D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f);
Vertices[5].Position = D3DXVECTOR3(1.0f, -2.0f, 0.0f);
Vertices[5].Color = D3DXVECTOR4(0.0f, 1.0f, 1.0f, 1.0f);
Vertices[6].Position = D3DXVECTOR3(-1.0f, -2.0f, 0.0f);
Vertices[6].Color = D3DXVECTOR4(1.0f, 0.0f, 1.0f, 1.0f);
Vertices[7].Position = D3DXVECTOR3(-2.0f, -1.0f, 0.0f);
Vertices[7].Color = D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f);
Vertices[8].Position = D3DXVECTOR3(-2.0f, 1.0f, 0.0f);
Vertices[8].Color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);
D3D10_BUFFER_DESC vbd;
vbd.Usage = D3D10_USAGE_DYNAMIC;
vbd.ByteWidth = sizeof(Vertex_PosCol) * VerticeCount;
vbd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
vbd.MiscFlags = 0;
VertexData.pSysMem = Vertices;
HRESULT result = this->GDM.Device->CreateBuffer(&vbd, &VertexData, &VertexBuffer);
I am currently using ID3D10Buffer::Map() to update my vertices which works fine right now. This issue is that my application may require large amounts of vertex updates in the future but not every vertex in every mesh/buffer(one day, a buffer will hold multiple meshes). As far as I have looked everywhere says to use ID3D10Device::CopySubresourceRegion(). That is exactly what i want to do! Except I can't get it to work. I simply don't understand how it works. I read Microsoft's page on it and it's not directed towards vertex buffers. I was hoping that someone can explain to me how to implement it in regards to vertex buffers and/or link me to some helpful resources that do the same.
It's not quite clear what you're asking, because you cannot update buffer with ID3D10Device::CopySubresourceRegion(). I'm trying to clarify resource copying and resource updating in my answer.
Updating resource
By "updating" resource we usually mean transferring data from system memory to GPU memory1, with overwriting.
For updating resource you use either ID3D10Buffer::Map()/ID3D10Buffer::Unmap() pair or ID3D10Device::UpdateSubresource() method. Which is better to use depends on resource properties and update frequency (read Nvidia's "canonical" paper).
Usage is really straightforward. Here is a case for simple 1D buffer, such as vertex buffer.
// Source array/vector (srcData): [xxxxDATADATADATADATADATAxxxxxxxxxxx]
// ^ ^
// srcBegin (srcBegin+bytesToCopy)
//
// Destination buffer (pBuffer): [xxDATADATADATADATADATAxxxxxxxxxxxxx]
// ^ ^
// destinationBegin (destinationBegin+bytesToCopy)
D3D11_BOX box{};
box.left = destinationBegin;
box.right = destinationBegin + bytesToCopy;
box.top = 0;
box.bottom = 1;
box.front = 0;
box.back = 1;
Device->UpdateSubresource(pBuffer, 0, &box, (uint8_t*)srcData+srcBegin, 0, 0);
Copying resource
As name states, ID3D10Device::CopySubresourceRegion() method is suited for copying data between two resources (such as buffers or textures). Simplifying, you can think of it as of copying chunks of data inside videocard's memory (but that's not always true). You cannot "update" GPU memory with that method, as data being copied already there.
Here is a simple example:
D3D11_BOX srcBox{};
srcBox.left = srcBegin;
srcBox.right = srcBegin + size;
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
Device->CopySubresourceRegion(pDst, 0, dstBegin, 0, 0, pSrc, 0, &srcBox);
Hope it helps.
BTW, there is no any reason to learn DirectX 10 in 2013. You can start with DirectX 11, its API is almost the same, but more features.
1 This explanation is overly simplified. We can never be sure where given resource resides (GPU, system memory, whatever storage), as it is up to driver implementer to decide where when and which kinds of resources to store.
tip: size is the amount of verts times their bytesize each
D3D11_BOX srcBox{};
srcBox.left = srcBegin;
srcBox.right = srcBegin + size; <-here
srcBox.top = 0;
srcBox.bottom = 1;
srcBox.front = 0;
srcBox.back = 1;
Device->CopySubresourceRegion(pDst, 0, dstBegin, 0, 0, pSrc, 0, &srcBox);
I need to generate dynamically a 3D matrix like this:
float vCube[8][3] = {
{1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, 1.0f},
{-1.0f, -1.0f, 1.0f}, {-1.0f, -1.0f, -1.0f},
{1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f},
{-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f}
};
I mean, to take a value and put it inside the matrix on running time.
I tried to make a pointer to float, then adding 3D elements by new, but the results were not what I want.
Note that I don't want to use STL like vector and so on, just a plane matrix.
Whether you use a vector or not, I would suggest you use:
struct Elem3D
{
float v[3];
};
Then you can quite easily create a vector:
vector <Elem3D> cube(8);
or dynamically allocate a number of elements
Elem3D *cube = new Elem3D[8];
Working with two-dimensiona arrays without using struct or class quite quickly gets VERY messy both syntactically and "brainhurt".
You can also store a 3D matrix in one dimensional array
x = height
y = width
z = depth
float VCube[x*y*z]
a_ijk = VCube[i + y * (j + z * k)]
One interesting question is to know which solution (this or Mats Petersson solution) reduces cache misses if we want to do matrix operations
To initialize a 2 dimension array first define the variable;
float vCube[8][3];
Then create a function that would initialize the vCube, or you can do the initialization in the constructor like this.
void function(float a, float b, float c) {
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 3; j +=3) {
vCube[i][j] = a;
vCube[i][j+1] = b;
vCube[i][j+2] = c;
}
}
}