Box2D + Opengl ES 2.0 (XCode, iPhone): Efficiently updating body vertex locations
If you've used Box2d, you're familiar with setting a b2Body->userData
property which is then used to update rendered shape x,y coordinates:
// Physics update:
int32 velocityIterations = 6;
int32 positionIterations = 2;
world->Step(timeDelta, velocityIterations, positionIterations);
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) {
id obj = (id)b->GetUserData();
if ((obj != NULL)) {
Shape *s = (MyType*)obj;
CGPoint newCentre = CGPointMake(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
[s drawAt:newCentre];
}
}
Conceptually, the rendering procedure for this data flow is straightforward: create a Shape
class to represent each body, add a drawAt
method that uses OpenGL ES 2.0 to render all desired vertices (with at开发者_Go百科tributes) for the body, and have that class redraw upon its coordinates being changed.
However, I want to optimise rendering by sticking vertices for all bodies into one single vertex buffer. Therefore I intend to modify class Shape
to include offsets in the buffer for where its vertices are located, then it can simply update these in the buffer upon drawAt
.
I realise the management of these offsets could get messy for additions/removals to the buffer, however these are infrequent in my application and I want to squeeze every drop of rendering performance out of the pipeline that I can.
My questions are:
- Does Opengl ES 2.0 allow me to specify a set of vertices as a 'shape' which can then be translated with one matrix operation, or must I explicitly update vertices one-by-one in this way?
- Must I create a unique updatable object to assign to each b2Body->userData, or is there some more efficient practise?
- Is it better to update graphical objects in their own timeline, reading positions from associated b2Body instances, or update graphical objects immediately in the b2Body update loop listed above?
I'd appreciate some advice, thank you.
-1. If you set the vertices in the buffer as the positions as you gave when creating fixtures for the bodies, should should be able to do this:
b2Vec2 pos = m_body->GetPosition();
float angle = m_body->GetAngle();
glPushMatrix();
glTranslatef( pos.x, pos.y, 0 );
glRotatef( angle * RADTODEG, 0, 0, 1 );//OpenGL uses degrees here
glDrawArrays(GL_WHATEVER, startIndex, vertexCount);
glPopMatrix();
See http://www.iforce2d.net/b2dtut/drawing-objects for a more in-depth discussion.
-2. Typically you will only want to draw what's visible. The above method could be done only after you've determined that this particular object should be drawn at all. The code in your question above may needlessly update positions for objects that never get drawn.
-3. uh... I think I just answered that. I think it's better to have a list of your game objects, each of them holding a pointer to the b2Body* that represents them in the physics world, rather than referring to Box2D's body list.
精彩评论