Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (777)
Games in Android Showcase (231)
games submitted by our members
Games in WIP (856)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  [SOLVED]Instancing, Passing Changing Data to be Instanced  (Read 6509 times)
0 Members and 1 Guest are viewing this topic.
Offline bogieman987
« Posted 2014-06-03 16:37:03 »

Hi,

First off, I would like to mention that I feel that I understand what instancing is, and somewhat when the best times to use is would be, more or less.
And I've come to the conclusion that instancing would be better overall than looping several hundred/thousand times in my case.

How ever, I'm a bit stumped when it comes to passing certain data. Matrix data for each instance.

The book I'm reading is using an example of drawing four squares, with instanced positions and colors.
The colors and positions are hard coded and passed to the GPU during the stage in which you create a VAO and VBO, and pass the relevant data. It doesn't seem to use interleaving, where as for my data, I am.

In my situation, with what I'm thinking (of which may not be the best solution).
Is that I have the same space ship model, but I want it rendered in different places, with different rotations, so I figured the easiest way is to have everything permanent (vert positions, normals, uvs), but have a model matrix be instanced. But I don't create and initialize all ships at the beginning (when I create the VAO and VBO for that object).

So overall, I'm unsure with how I go about it. When it's not hard-coded, but dynamic.

If I'm unclear in what I'm stuck with, I apologize, it's rather difficult to for me to put into words.

Offline quew8

JGO Knight


Medals: 53



« Reply #1 - Posted 2014-06-03 18:54:05 »

Withdrawn - I was talking about completely the wrong thing. Sorry for wasting peoples time. 

 
Offline theagentd
« Reply #2 - Posted 2014-06-03 19:51:32 »

Pretty sure Bogieman is talking about OpenGL instancing, not Java instances.

It's possible to define per instance shader attributes using glVertexAttribDivisor():

Shader:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
#version 150

uniform mat4 viewMatrix, projectionMatrix;
uniform mat3 normalMatrix;

//Per vertex attributes
in vec3 position;
in vec2 texCoords;
in vec3 normal;

//Per instance attribute
in vec3 instancePosition;

...


VAO setup:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
         vao = glGenVertexArrays();
         glBindVertexArray(vao);

         glBindBuffer(GL_ARRAY_BUFFER, vbo);
         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, false, VERTEX_SIZE, POSITION_INDEX);
         glVertexAttribPointer(texCoordsLocation, 2, GL_FLOAT, false, VERTEX_SIZE, TEX_COORD_INDEX);
         glVertexAttribPointer(normalLocation, 3, GL_SHORT, true, VERTEX_SIZE, NORMAL_INDEX);
         glEnableVertexAttribArray(positionLocation);
         glEnableVertexAttribArray(texCoordsLocation);
         glEnableVertexAttribArray(normalLocation);
         
         glBindBuffer(GL_ARRAY_BUFFER, instanceDataVBO);
         glVertexAttribPointer(instancePositionLocation, 3, GL_FLOAT, false, 0, 0);
         glVertexAttribDivisorARB(instancePositionLocation, 1); // <--- important
         glEnableVertexAttribArray(instancePositionLocation);
         
         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
         
         glBindVertexArray(0);


You can do the same with an mat4 variable instead of a vec3 of course. In that case the matrix is split up into 4 separate vec4 attributes, with consecutive locations:

1  
2  
3  
4  
// model_matrix will be used as a per-instance transformation
// matrix. Note that a mat4 consumes 4 consecutive locations, so
// this will actually sit in locations, 3, 4, 5, and 6.
layout (location = 3) in mat4 model_matrix;


More information: http://www.informit.com/articles/article.aspx?p=2033340&seqNum=5

Myomyomyo.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline bogieman987
« Reply #3 - Posted 2014-06-03 20:06:10 »

Yeah, that's what I'm on about, I probably should have added that :/

Anyways, so from that example, does that mean that I'm creating a second VBO?

And would the "instancePositionLocation" have to be different, than all the previous ones?
Of which I have set to be from 0-4.
Meaning that it would have to be 5, with nothing in the slots for 6,7 and 8 as well as, since it's like 4 separate vectors that contain 4 separate values.
1  
 glVertexAttribPointer(instancePositionLocation, 3, GL_FLOAT, false, 0, 0);


Also, why is each attribute enabled after they are set.
I currently have it that I just enable them during the rendering part.
Is it optional, or do I have to do it in order to get instancing to work, or is it generally better to do it that way?

I'll try and set this up, and I'll come back if I have more questions, issues, or let you guys know that I got it working.

Offline theagentd
« Reply #4 - Posted 2014-06-03 20:41:21 »

You usually create a second VBO for per-instance data since you'll be updating that VBO each frame, while the per-vertex data is usually static.

Per-instance attributes work exactly the same as normal attributes, except that you call glVertexAttribDivisor() to tell OpenGL to go to the next attribute in the buffer after each instance has been processed, instead of after each vertex. You can use whatever code you already have for this and just add a call to glVertexAttribDivisor() where needed.

If you have a mat4, you'd instead do something like this:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
glVertexAttribPointer(modelMatrixLocation + 0, 4, GL_FLOAT, false, 64,  0);
glVertexAttribPointer(modelMatrixLocation + 1, 4, GL_FLOAT, false, 64, 16);
glVertexAttribPointer(modelMatrixLocation + 2, 4, GL_FLOAT, false, 64, 32);
glVertexAttribPointer(modelMatrixLocation + 3, 4, GL_FLOAT, false, 64, 48);

glVertexAttribDivisor(modelMatrixLocation + 0, 1);
glVertexAttribDivisor(modelMatrixLocation + 1, 1);
glVertexAttribDivisor(modelMatrixLocation + 2, 1);
glVertexAttribDivisor(modelMatrixLocation + 3, 1);

glEnableVertexAttribArray(modelMatrixLocation + 0);
glEnableVertexAttribArray(modelMatrixLocation + 1);
glEnableVertexAttribArray(modelMatrixLocation + 2);
glEnableVertexAttribArray(modelMatrixLocation + 3);
In essence, a mat4 attribute is just treated as 4 consecutive vec4 attributes.

In the code I posted I created a VAO (vertex array object) and set up my vertex attributes once. When I want to render stuff, I simply bind the VAO again and all my vertex attribute settings are automatically restored so I don't have to call all those functions again.

Myomyomyo.
Offline bogieman987
« Reply #5 - Posted 2014-06-03 22:14:51 »

And to update the data, do I use the following?
1  
glBufferSubData(GL_ARRAY_BUFFER, 0, getMatrixBuffer())


But would I set it up as, in my case, like the following?
(This would get called every time the game loop goes through the render part)
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
for(int j = 0; j < baseObject[i].getNumOf(); j++) {
   baseObject[i].getModelMatrix()[j].store(getMatrixBuffer());
}
getMatrixBuffer().flip();        
// IVbo stands for Instance Vertex Buffer Object, simply so I know it's separate from the normal Vbo
glBindBuffer(GL_ARRAY_BUFFER, baseObject[i].getModel().getIVbo());
// Would offset be 0, since it would be everything in the attribute being updated
glBufferSubData(GL_ARRAY_BUFFER, 0, getMatrixBuffer();
getMatrixBuffer().clear();
glBindBuffer(GL_ARRAY_BUFFER, 0);


This is what I have when I'm just doing it one by one.
1  
2  
3  
4  
5  
6  
7  
for(int j = 0; j < baseObject[i].getNumOf(); j++) {
   baseObject[i].getModelMatrix()[j].store(getMatrixBuffer());
}
getMatrixBuffer().flip();        
GL20.glUniformMatrix4(getShaders()[0].getUniform(UniformType.MODEL).getLocation(), false,
                       getMatrixBuffer());
getMatrixBuffer().clear();


Also, is it possible to have just one of the attributes instead of 4?
Like so?
1  
2  
// 3 is the last position used in the static VBO, so I put the location as 4
glVertexAttribPointer(4, 16, GL_FLOAT, false, 64,  0);

Or would OpenGL be unable to automatically divide the data so that it ends up getting 4 vec4s.

Offline theagentd
« Reply #6 - Posted 2014-06-03 23:37:40 »

Your code looks fine.

You really need all 4 of each vertex attribute setup call though. From the perspective of OpenGL, the shader simply has 4 vec4 attributes. They're not related or linked in any place, so if you only enable the first vec4 you're only going to update the first of the four rows in your mat4.

Myomyomyo.
Offline bogieman987
« Reply #7 - Posted 2014-06-04 00:02:25 »

Hmm, I'm getting an error.

I'm using LWJGL.
It's value is 1281.
And that seems to mean Invalid Value.

I don't really know the issue, it seems to go through all of it, and then, due to my error checking class, terminate the program.
(I have it, so if an error is found that it cleans up and calls System.exit(-1); )


Helped if I read the replies properly, anyways, it now just simply crashes, seems it crashes at the point when I do the error checking.

More specifically, it seems when it gets to,
1  
int val = GL11.glGetError();

Offline theagentd
« Reply #8 - Posted 2014-06-04 00:50:26 »

When you get to glGetError(), your driver is forced to actually complete all the commands that happened before glGetError(), so the error isn't due to glGetError(), but glGetError() is the trigger. Complete VM crashes are almost always related to access violations, e.g. that you're telling OpenGL to read vertex data from somewhere illegal. Double-check that you haven't forgotten a flip() and that your vertex attributes are correctly set up.

Myomyomyo.
Offline bogieman987
« Reply #9 - Posted 2014-06-04 12:51:30 »

Ok, so I got it semi working, it renders and all with one instance, how-ever, should I try and have more than one instance, I now get java.nio.BufferOverflowException

I assume it may be due to my limited knowledge when it comes to buffer objects in Java.
Anyways, here's a snippet where it happens, of which may look familiar.
(Note: I have it that the size is currently 64, but even if I up it to 1000, or even 1mil, it still happens.)
1  
2  
3  
4  
5  
6  
7  
8  
9  
for(int j = 0; j < 2; j++) {
   // It happens when getModelMatrix()[j] gets to 1, or rather, the second element in the array.
   baseObject[i].getModelMatrix()[j].store(getMatrixBuffer());
}      
getMatrixBuffer().flip();        
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, baseObject[i].getModel().getIVbo());
GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, getMatrixBuffer());
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
getMatrixBuffer().clear();

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
Administrator

« JGO Overlord »


Medals: 1357
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #10 - Posted 2014-06-04 15:09:21 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
+  // always make sure we know/set the state of the buffer *before* we write into it.

+  getMatrixBuffer().clear();
for(int j = 0; j < 2; j++) {
   // It happens when getModelMatrix()[j] gets to 1, or rather, the second element in the array.
   baseObject[i].getModelMatrix()[j].store(getMatrixBuffer());
}      
getMatrixBuffer().flip();        
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, baseObject[i].getModel().getIVbo());
GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, getMatrixBuffer());
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
-  getMatrixBuffer().clear();

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings!
Offline bogieman987
« Reply #11 - Posted 2014-06-04 15:20:01 »

Ah thank you, it doesn't crash anymore, but it seems I have a bug else where lol

Also, for the code snippet, how do I make it so you have a + and it's got a green highlight?
And the how do I it for the red as well?

Offline matheus23

JGO Kernel


Medals: 138
Projects: 3


You think about my Avatar right now!


« Reply #12 - Posted 2014-06-04 15:26:01 »

Also, for the code snippet, how do I make it so you have a + and it's got a green highlight?
And the how do I it for the red as well?

1  
2  
+ put a "+" in front of the line and it's highlighted green
- or put a "-" in front of it.

See my:
    My development Blog:     | Or look at my RPG | Or simply my coding
http://matheusdev.tumblr.comRuins of Revenge  |      On Github
Offline bogieman987
« Reply #13 - Posted 2014-06-05 10:50:24 »

I'm stumped, I can't figure out why the other instances aren't rendering.
I've got it so that a total of 3 instances of each object should appear, but only the first one appears.
Perhaps I didn't input enough or some data correctly.

This bit is what I'm only truly unsure about, but I'm unsure if this is the cause.
1  
2  
3  
4  
glDrawElementsInstanced(int mode, int indices_count, int type, long indices_buffer_offset, int primcount)
// Here's what I have
GL31.glDrawElementsInstanced(GL11.GL_TRIANGLES, baseObject[i].getModel().getNumOfIndeces(),
                  GL11.GL_UNSIGNED_INT, 0, baseObject[i].getNumOf());

Is it right that I have "indices_buffer_offset" at zero, messing with the value screws it all up.

I've figured out what the "indices_buffer_offset" does, doesn't seem too relevant.

Also, when I create the second VBO, I didn't use glBufferData(int target, java.nio.ByteBuffer data, int usage).
Instead, I put it in the rendering part, when I pass the matrix buffer like so.
1  
2  
3  
4  
5  
6  
7  
8  
9  
getMatrixBuffer().clear();
for(int j = 0; j < baseObject[i].getNumOf(); j++) {
   baseObject[i].getModelMatrix()[j].store(getMatrixBuffer());
}      
getMatrixBuffer().flip();        
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, baseObject[i].getModel().getIVbo());
+GL15.glBufferData(GL15.GL_ARRAY_BUFFER, getMatrixBuffer(), GL15.GL_DYNAMIC_DRAW);
-GL15.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, getMatrixBuffer());
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);


Could this cause issues, beside performance.

I don't think it's the shaders, could be, but I don't think it is.
As now I multiply the mvp matrix using the modelmatrix attribute and it works, instead of from a uniform.

Looking at the link theagentd provided.
They have a part like so.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
// Map the buffer
mat4 * matrices = (mat4 *)glMapBuffer(GL_ARRAY_BUFFER,
                                      GL_WRITE_ONLY);

// Set model matrices for each instance
for (n = 0; n < INSTANCE_COUNT; n++)
{
    float a = 50.0f * float(n) / 4.0f;
    float b = 50.0f * float(n) / 5.0f;
    float c = 50.0f * float(n) / 6.0f;

    matrices[n] = rotation(a + t * 360.0f, 1.0f, 0.0f, 0.0f) *
                  rotation(b + t * 360.0f, 0.0f, 1.0f, 0.0f) *
                  rotation(c + t * 360.0f, 0.0f, 0.0f, 1.0f) *
                  translation(10.0f + a, 40.0f + b, 50.0f + c);
}

// Done. Unmap the buffer.
glUnmapBuffer(GL_ARRAY_BUFFER);


Should I be doing it similar to this instead of redoing the buffer data every-time.

Oh, and thanks matheus. And thanks for the tip Riven. Cheesy

Offline bogieman987
« Reply #14 - Posted 2014-06-08 21:04:55 »

I've still not made any progress. Anyone have any idea?
Only one instance will render. Although the frame rate dips as if multiple instances are rendering.
Or at the very least, I can only see one instance.

Offline bogieman987
« Reply #15 - Posted 2014-06-09 22:18:36 »

Got it sorted guys, seems like I have to do the following when initializing the model.
1  
2  
3  
4  
// This is just a small part, no point showing all of it.
GL20.glVertexAttribPointer(4, 4, GL11.GL_FLOAT, false, 64, 0);
GL20.glEnableVertexAttribArray(4);
GL33.glVertexAttribDivisor(4, 1);


Instead of leaving it the way I had it.
Where I would called "glVertexAttribDivisor(num ,num);" just before rendering.

Anyways, thanks for the help guys, love this forum for the help Cheesy

Pages: [1]
  ignore  |  Print  
 
 

 
hadezbladez (349 views)
2018-11-16 13:46:03

hadezbladez (183 views)
2018-11-16 13:41:33

hadezbladez (348 views)
2018-11-16 13:35:35

hadezbladez (84 views)
2018-11-16 13:32:03

EgonOlsen (2179 views)
2018-06-10 19:43:48

EgonOlsen (2221 views)
2018-06-10 19:43:44

EgonOlsen (1378 views)
2018-06-10 19:43:20

DesertCoockie (2011 views)
2018-05-13 18:23:11

nelsongames (1668 views)
2018-04-24 18:15:36

nelsongames (2308 views)
2018-04-24 18:14:32
Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08

Deployment and Packaging
by gouessej
2018-08-22 08:03:45

Deployment and Packaging
by philfrei
2018-08-20 02:33:38

Deployment and Packaging
by philfrei
2018-08-20 02:29:55

Deployment and Packaging
by philfrei
2018-08-19 23:56:20

Deployment and Packaging
by philfrei
2018-08-19 23:54:46
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!