PDA

View Full Version : Storing Geometry indices



Meanz
01-11-2012, 02:01 AM
Hey folks.

I am having a few problems that I can't resolve on my own.

1.
I have a default shader for each of my Geometry objects.
A geometry object in my case is a vao with vertices, texture coords and normals. And also each geometry object has a shader. Or more precisely one frag and one vert shader with a shader program.

I was wondering if it is okay to create, compile and link a new shader for each geometry object. Or some prefer to call it a spatial or something like that. I could have used the same shader for all the geometry objects, but each geometry object might have different textures.

Would be lovely if you could reach a hand out on this one.

2.
I am trying to store my geometry objects, or pointers to them in a central place. So the renderer can iterate them and just call their draw functions on every frame.
But I can't figure out the best way to store them.
I do know this much.
There will be objects added and removed from the storage frequently. And it is going to be iterated every frame too.
So first I was thinking of creating an array that I can resize when needed. But I figured that resizing the array frequently would be to costly. So I am kinda stuck here, I am not too familiar with C++, in java I think I would have gone with a linkedlist, but I don't seem to be able to find something similar for c++.

tksuoran
01-11-2012, 04:01 AM
1. It is possible, but there are better ways. The main issue I*think is, if you have 100 geometry objects, you will need to switch OpenGL*program 100 times. I have used following classes: Buffer : contains index, vertex and uniform buffers. Vertex Buffers have OpenGL VAO. BufferRange : specifies a range within one Buffer. Mesh : specifies one BufferRange for vertices and another one for indices. This would be closest to your Geometry class (although actual data in my classes is contained in Buffers). Program : has vertex, fragment etc. shaders compiled and linked. Has OpenGL*program object. Material : specifies Program and values for uniforms. Frame : specifies 3D transformation for objects with position and orientation. Model : has Frame, Mesh and Material. Group : a set of Models. This allows sharing resources: Multiple Models can share single Material Multiple Materials can share single Program Multiple Models can share vertex and index Buffers. For each Models in group can be sorted by Program and Material, minimizing number of program and material switches when rendering a Group. You could put OpenGL program object also into each Material. This way you could switch a material simply with glUseProgram(), as this will restore uniform values you last set for that program. That could be useful if you are not using uniform buffers. If however you use uniform buffers, this is no longer significant.

2. For Group I use std::vector in C++ and List<Model> in C#. If you use C++, std::vector is quite easy to use and standard tool - just search Internet for examples and reference if you are new to it. With C I use plain old C-array coupled with current count and maximum capacity - and I*don't resize it, I*just prepare for sufficient maximum capacity in advance.

Meanz
01-11-2012, 04:13 AM
Sincerely thank you.

This was a really good and informative reply, and it opened my eyes.
I never thought of it that way. Ehh I guess I got a long way to go.

Edit:
Do you mind explaining the "Frame" part a bit more?

And also, why should I use indices for my vbo's?
Isn't that just more data?

And the bufferange class, are you saying you are storing vertice data for more than one model at a time in one vbo?

tksuoran
01-11-2012, 06:45 AM
Frame maintains the animation hierarchy / transformation information. My Frame has name, pointer to parent Frame, transformation "local to parent", and transformation "local to world". For unparented Frames, these transformations are the same. For parented Frames, local to world transformation is updated based on parent and local to parent transformations.

Transformation is 4 by 4 matrix and it's inverse matrix. Whenever transformation is modified, the inverse modification is applied to the inverse matrix in the transformation. This avoids some matrix inverse operations.

Models (and Cameras and Lights) are positioned and oriented by modifying their Frame.

The buffer range is relatively recent addition - so you could start without it. You are correct, it allows to store multiple shapes in single vertex, index buffer pair. Doing this will reduce need to do buffer object / VAO switches, improving performance. Using glDrawElementsBaseVertex makes it simpler to place multiple shapes in single buffer (pair).

My current implementation maintains CPU / main memory copy of the data I write to each BufferRange instance. When BufferRange is modified, it and the Buffer is marked dirty. At draw time Buffer is checked if it is dirty, if so, BufferRanges will be written to the Buffer. This works well enough for mostly static buffers, but is not ideal for streaming buffers.

Edit: Using index buffer can reduce number of vertices, as a single vertex is typically shared by 3 to 6 triangles. This also to cache vertex processing work. Using index plus vertex buffer is a good idea for most general 3D models.