draw multiple objects with different MVP

Ah ok. Is it possible to make the size of the buffer dynamical?? Let’s say after i read in the mesh i know exactly how many matrices i need. Can i adjust the size after reading in the mesh??

And still the question how do i tell the shader what vertex belongs to what instance??

I’m still crashing when at glfwPollEvents();
https://git.rwth-aachen.de/carstenf/OpenGL/commit/8a36fe10b163bbb5b4cf3fffdfc03833177667f1

memory re-allocation is possible, just dont use glBufferStorage(…) to allocate memory
https://www.opengl.org/wiki/Buffer_Object#Mutable_Storage

why would you do that?

still crashing ?! maybe you got some pointers / delete[] wrong …
you are already using std::vector etc, whats the point for those new / delete calls ? :slight_smile:

Let’s say i have 2 models and each with a different mvp. How can i tell the shader that vertex 1-10 belong to MVP 1 and the vertex 11-20 belong to mvp 2? You said i should put the vertex all into one buffer. So i need to tell the shader the size of instance 1, 2,…

The program only crashes since i changed to the instanced draw.

you are already using std::vector etc, whats the point for those new / delete calls ?

what do you mean??

[QUOTE=3DPrgmer;1284507]Let’s say i have 2 models and each with a different mvp. How can i tell the shader that vertex 1-10 belong to MVP 1 and the vertex 11-20 belong to mvp 2? You said i should put the vertex all into one buffer. So i need to tell the shader the size of instance 1, 2,…
[/QUOTE]
Instancing renders multiple copies of a single set of vertices. It can’t be used to render multiple, distinct models.

If you want to coalesce multiple models into a single draw call, and you don’t want to replicate per-model data (e.g. a transformation) for each vertex, the usual solution is to add an integer vertex attribute containing the model number, and use that to index into uniform arrays containing per-model data.

That sounds easy. So i give a static array of mvp matrices to the shader and for each vertex the information what matrix need to be used, right?
with just one matrix it works :smiley: so i’m gonna do the step to 2 matrices now. But how would i access the different matrices in the shader??

here is my shader:


#version 450 core

// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec2 vertexUV;


// Output
out vec2 UV;

// Values that stay constant for the whole mesh.
uniform mat4 MVP;

void main(){

	// Output position of the vertex, in clip space : MVP * position
	gl_Position =  MVP * vec4(vertexPosition_modelspace, 1);

	UV = vertexUV;

}

how do i need to modify it?? Something like this?


#version 450 core

// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec2 vertexUV;
layout(location = 2) in unsigned int instanceIndex;

// Output
out vec2 UV;

// Values that stay constant for the whole mesh.
uniform mat4 MVP;

void main(){

	// Output position of the vertex, in clip space : MVP * position
	gl_Position =  MVP[instanceIndex] * vec4(vertexPosition_modelspace, 1);

	UV = vertexUV;

}

That needs to be an array:


uniform mat4 MVP[2];

If you have many models, you can quickly exhaust the maximum number of uniforms in the default uniform block (each mat4 is 4 vectors or 16 components), in which case you need to use named uniform blocks backed by uniform buffer objects (UBOs).

i don’t really understand what you mean with that UBOs. I implement some code in a different branch:
https://git.rwth-aachen.de/carstenf/OpenGL/commit/e54f439b0e61315c736d4c97924cea701f3e7afe

But i get an error:

Vertex Info

0(19): error C7559: OpenGL requires constant indexes for unsigned array access (MVP)

I tried to change the shader to this:


layout(location = 2) in const uint index;

and i get this error:

0(7): error C7522: OpenGL requires constants to be initialized

if i access the MVP array by hardcoded value it works:


	gl_Position =  MVP[0] * vec4(vertexPosition_modelspace, 1);

So how can i choose a dynamically index??

==EDIT==

i tried to run the program with some hardcoded index. And i noticed that this:


	std::vector<const float*> mvpMatrices;
	for (unsigned int i = 0; i < vModels.size(); i++)
		mvpMatrices.push_back(glm::value_ptr(getMVPMatrix(i)));

	glUniformMatrix4fv(gluiMatrixID, vModels.size(), GL_FALSE, *mvpMatrices.data());

doesn’t work. There is only one matrix given to the shader

[QUOTE=3DPrgmer;1284521]
i tried to run the program with some hardcoded index. And i noticed that this:


	std::vector<const float*> mvpMatrices;
	for (unsigned int i = 0; i < vModels.size(); i++)
		mvpMatrices.push_back(glm::value_ptr(getMVPMatrix(i)));

	glUniformMatrix4fv(gluiMatrixID, vModels.size(), GL_FALSE, *mvpMatrices.data());

doesn’t work. There is only one matrix given to the shader[/QUOTE]

because you didnt specify a uniform block in your shader
https://www.opengl.org/wiki/Interface_Block_(GLSL)#Block_buffer_binding

short description:
–> in your (vertex) shader:


layout (std140, binding = 0) uniform MVP_MatrixBlock
{
// declare here some variables
mat4 MVParray[100];
};

–> means that you ant to have a “uniform block” with a certain “memory layout”, backed by a buffer object which has to be bound at “uniform buffer binding point 0”

to understand that topic, read this chapter:
https://www.opengl.org/wiki/Interface_Block_(GLSL)#Memory_layout

to bind a buffer object at “uniform buffer binding point 0”, you call this:
glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
https://www.opengl.org/sdk/docs/man/html/glBindBufferBase.xhtml

–> “buffer” is the memory container which has all the data for the variables declared in between the { brackets } in your (vertex) shader, in this case: mat4 MVParray[100];

that fixed “100” array size is a restriction of uniform blocks, you have to define the array size
there is another kind of “block” which allows you to access an “unsized” array, its called “shader storage block”:
https://www.opengl.org/wiki/Interface_Block_(GLSL)#Shader_storage_blocks

the downside is that accessing it is generally slower than accessing an uniform block

[b]by the way:
std::vector<const float*> …
is an array of float pointers, not an array of float variables !!!

it should be:
std::vector …[/b]

if you want to figure out what’s the maximum uniform block size (which depends on your hardware):


int maxuniformblocksize_in_bytes = 0;
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxuniformblocksize_in_bytes);
cout << "max uniform block size (in bytes): " << maxuniformblocksize_in_bytes<< endl;

I see we already were at that point, right?? And i decided to use the buffer instead. btw the max size is for me: 65536

So let’s stop coding around without understanding. I still do not understand how the instanced buffer thing works and how it could solve my Problem.

If i understand it right, the instanced draw takes one mesh and draws it multiple times with different settings (for example i have a tree model and want to display a forest, so i have one model draw multiple times each time with a different MVP).

My Problem:
I have one .msh file that contains multiple models. Each model has a number of vertices/UV (all triangles for now) and all the vertices of one model belong to one MVP that is special for each model. For the beginning there will be only one texture for all models. But later there will be multiple textures that can be used for one or multiple models and even for only a part of one model. But let’s forget about the texture and concentrate on the Model.
What is the best way to display each model with it’s right MVP??

My idea:
1)


update{
     ....
     for (each model)
     {
          vertexBuffer.fill(model.vertex, model.uv)
          uniformMatrix(model.mvp)
          drawtriangles()
     }
}

But john told me that is not a good idea and much easier that way:


loadmesh{
     ....

     for (each model)
     {
          vertexBuffer.fill(model.vertex, model.uv)
     }
}

update{
     ....

     for (each model)
     {
          instanceBuffer.fill(model.mvp)
     }

     drawInstanced()

}

But if i understand the instanced draw right, that way (let’s say my msh contains 2 model - one is the roof and the other the walls of a house) i get the walls and roof painted each 2 times one time at the wall’s position and one time at the roof’s position and that’s not what i need. I want the wall to be painted with the wall’s MVP and the roof with the roof’s MVP

Maybe i didn’t got the point and i hope you can explain it to me before i try to continue coding.

the “trick” is to keep track of each models “vertexoffset” and “vertexcount” parameter since all models share the same buffer

when drawing:


for each model
{
int vertexoffset = ...
int vertexcount = ...

instancecount = whatever ...
// FILL THE INSTANCEBUFFER HERE WITH ALL MVP MATRICES FOR THIS MODEL

glDrawArraysInstanced(GL_TRIANGLES, vertexoffset , vertexcount , instancecount);
}

[ATTACH=CONFIG]1409[/ATTACH] Ahh, so i call the glDrawArraysInstanced one time for each model?? I thought i call it only once. The instancecount is the max number of instances right? or is it the current instance?

the number of instances you want to draw
https://sites.google.com/site/john87connor/home/tutorial-11-1-uniform-block
https://sites.google.com/site/john87connor/home/tutorial-12-instanced-rendering

Did you declare MVP with a size?

The array size must be known at compile time, so you either have to specify the size explicitly or use constant indices.

If you declared the array with a fixed size, try changing the attribute from uint to int.

@GClements: That’s the problem i know the size only at run time. Only way would be to change the shader code after reading in the mesh and recompile it.

@John:
Init my pipes:
https://git.rwth-aachen.de/carstenf/OpenGL/blob/master/MshViewer/Source/OpenGlController.cpp#L89

Question: Why do i need 4 pipes and why can’t i simply move the whole mat4 over one pipe? I don’t understand how i can put the data onto 4 pipes and catch it from only one.

fill the buffer:
https://git.rwth-aachen.de/carstenf/OpenGL/blob/master/MshViewer/Source/OpenGlController.cpp#L389

draw multiple times instanced:
https://git.rwth-aachen.de/carstenf/OpenGL/blob/master/MshViewer/Source/OpenGlController.cpp#L284

Question: not sure about the number of instance. shouldn’t it be only 1??

Result: nothing displayed :mad:

The last element of a shader storage block may be an unsized array. All other arrays require the size to be known at compile time, by either being explicitly sized in the declaration or being indexed only with constant expressions.

Another option is to use a texture or image as an array.

If you can put a reasonable upper bound on the maximum number of matrices, you can just size of the array for the maximum. There’s no requirement to use all of the entries.

If you use a uniform array in the default uniform block, bear in mind that the limit on the maximum number of components may be as low as 512 (corresponding to 32 mat4 variables), and may actually be slightly lower due to drivers “stealing” a few entries for internal use.

So you could just figure out how many matrices you can fit in the available space and size the array for that.

The size argument to glVertexAttribPointer(), glVertexAttribFormat(), etc can be 1, 2, 3 or 4. I.e. you can’t have anything larger than a vec4 as a single attribute. You can declare vertex shader inputs as matrices, but that’s little more than syntactic sugar; each column is essentially treated as a separate attribute.

there is no buffer bound at GL_ARRAY_BUFFER when you try to allocate memory
line 115


// set buffer size
glBufferData(GL_ARRAY_BUFFER, MAX_MODEL_COUNT * sizeof(glm::mat4), NULL, GL_STREAM_DRAW);

bind the instancebuffer before that line, and unbind it after that line again
i personallly find it easier to read if all the essential steps are separated, like:

  1. setup VAO (configure attributes / buffers)
  2. setup VBO (allocate memory / fill in data)

  3. and since memory allocation isnt part of te VAO, i remove the “glBufferData(…)” call while doing step 1

Question: not sure about the number of instance. shouldn’t it be only 1??

1 means you will get 1 triangle (or any mesh), 2 means 2 triangles (or any mesh), etc …

example:
you want to draw those “star wars soliders” right ?
assuming 1 solider has 9999 vertices, and assuming you already have some 500 vertices before that mesh in your vertex buffer (for any reason, doesnt matter for now), and assuming you want to draw 10 x 10 = 100 soliders, you would call:

glDrawArraysInstanced(GL_TRIANGLES, 500, 9999, 100);

but before you call that line, you have to myke sure that 100 proper MVP matrices are in your instance buffer
for (int x = -5; x < 5; x++)
for (int y = -5; y < 5; y++)
temp_instances.push_back(glm::translate(glm::vec3(x, y, 0)));

glBindBuffer(GL_ARRAY_BUFFER, instancebuffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(mat4) * instances.size(), instances.data());
glBindBuffer(GL_ARRAY_BUFFER, 0);

[QUOTE=john_connor;1284539]there is no buffer bound at GL_ARRAY_BUFFER when you try to allocate memory
line 115


// set buffer size
glBufferData(GL_ARRAY_BUFFER, MAX_MODEL_COUNT * sizeof(glm::mat4), NULL, GL_STREAM_DRAW);

bind the instancebuffer before that line, and unbind it after that line again
i personallly find it easier to read if all the essential steps are separated, like:

  1. setup VAO (configure attributes / buffers)
  2. setup VBO (allocate memory / fill in data)

  3. and since memory allocation isnt part of te VAO, i remove the “glBufferData(…)” call while doing step 1

[/QUOTE]

oops i forgot about binding the buffer first. Fixed it and moved it to the openMesh function, since i now in that function actually how many memory i need and so i don’t need to allocate first and fill the data later.
So removed it here: https://git.rwth-aachen.de/carstenf/OpenGL/blob/master/MshViewer/Source/OpenGlController.cpp#L115
and now it is here: https://git.rwth-aachen.de/carstenf/OpenGL/blob/master/MshViewer/Source/OpenGlController.cpp#L385

[QUOTE=john_connor;1284539]
1 means you will get 1 triangle (or any mesh), 2 means 2 triangles (or any mesh), etc …

example:
you want to draw those “star wars soliders” right ?
assuming 1 solider has 9999 vertices, and assuming you already have some 500 vertices before that mesh in your vertex buffer (for any reason, doesnt matter for now), and assuming you want to draw 10 x 10 = 100 soliders, you would call:

glDrawArraysInstanced(GL_TRIANGLES, 500, 9999, 100);

but before you call that line, you have to myke sure that 100 proper MVP matrices are in your instance buffer
for (int x = -5; x < 5; x++)
for (int y = -5; y < 5; y++)
temp_instances.push_back(glm::translate(glm::vec3(x, y, 0)));

glBindBuffer(GL_ARRAY_BUFFER, instancebuffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(mat4) * instances.size(), instances.data());
glBindBuffer(GL_ARRAY_BUFFER, 0);[/QUOTE]
but i don’t wanna draw 100 soldiers. i want just one soldier :frowning:

I would use 1 instead of vModels.size()); here: https://git.rwth-aachen.de/carstenf/OpenGL/blob/master/MshViewer/Source/OpenGlController.cpp#L281

and to be honest i don’t see a real different to my old idea calling n time the glDrawArrays function :-/

But still the same problem. Nothing is displayed (ich dreh langsam am Rad)

but according to the title of this topic, you want to draw multiple “objects” (which can be translated into “instances of a certain model”), is that correct ?

if so, glDrawArraysInstanced() is the way to do that for many instances
otherwise you can use glDrawArrays() as you did previously

was für ne art “mesh viewer” stellste dir vor?
.obj dateien z.B. haben öfters mehrere unterschiedlich “objekte”
http://tf3dm.com/3d-model/the-city-39441.html
das hier z.B ist ne ganze stadt in ner einzigen datei

it should be something like that: http://www.nexusmods.com/battlefront2/mods/1061/?

And i think there was a miss understanding. I have one mesh file and that contains multiple different model chunks. Such as one for the head, one for the left arm, one for the right arm, one for the upper body/lower body and a backpack. And each have their own MVP. So i want to draw the backpack with the backpack’s mvp and the upper body with the upper body’s mvp,…
The msh format is a bit different from .obj if you are interessted in the structure, you can take a look at http://schlechtwetterfront.github.io/ze_filetypes/msh.html

And yeah i found the problem, why nothing was displayed at the latest tries. I used the MVP variable (coming from uniform) instead of mvp (coming over the pipes) :doh:

now everything is like it should be: https://git.rwth-aachen.de/carstenf/OpenGL/tree/master

If you download the release folder, you can try the program :smiley: it’s a stable release build