View Full Version : Vertex interpolation in a shader - how?

06-19-2014, 12:12 AM
I have the following situation:

I got an object with, say 100 vertices per frame and 10 animation frames.
All this data is located within one vertex buffer, frame 1 starting at index 0, frame 2 at 100 and so on.
Each frame has an entry in the index buffer for its triangles, say 150 indices per frame, so frame 0 starting at index 0, frame 1 at 150 and so on.

So far, so good - rendering each frame is simple.
But now I want to add frame interpolation to that code and can't just find the way to do it. To pass two frames to the shader I'd need two index buffers and that's simply something OpenGL was never designed for.

Is there any solution to this, other than packing each frame into a separate buffer? This is clearly not what I'd like to do because with hundreds of objects I'd end up with a huge amount of buffers that need constant rebinding. I intentionally tried to put all data for all models into one large buffer to simplify management.

Intended target for the implementation is OpenGL 3.x.

carsten neumann
06-19-2014, 01:01 AM
Aren't the index buffers the same for all frames of the animation? Oh, I see they have a constant offset of 100 from frame to frame - use glDrawElementsBaseVertex to be able to use just one index buffer (for the no-iterpolation case).

For each vertex attribute you want to interpolate set up two vertex shader inputs (i.e. for positions have "vtxPos0" and "vtxPos1", for normals "vtxN0" and "vtxN1"). Use glVertexAttribPointer with a non-zero offset (last argument) to source vtxPos0 from place in the buffer where your first frame for interpolation is stored and vtxPos1 for where the second frame is stored:

glBindAttribLocation(progId, 0, "vtxPos0");
glBindAttribLocation(progId, 1, "vtxPos1");

glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);

// interpolate between frames 3 and 4:
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, bufferOffset(300));
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, bufferOffset(400));

Where bufferOffset is a function that convertes the integer offset into a pointer, e.g.

inline void*
bufferOffset(GLuint offset)
return static_cast<void*>(static_cast<char*>(NULL) + offset);

06-19-2014, 01:18 AM
Thanks. That function is precisely what I was looking for - even though it probably means that I'll have to implement a fallback path, just to be sure that it still works on older Intel chipsets that do not support GL 3.2 and do not have the corresponding extension.

06-19-2014, 10:08 AM
You don't actually need glDrawElementsBaseVertex for this at all.

Your indices are going to be the same for each frame anyway, so your index buffer just needs to contain indices for a single frame. Then you change the buffer offset in your glVertexAttribPointer calls to point to the start of each of the two frames you wish to blend between, send your blend factor as a uniform, and make a regular glDrawElements call.

I've successfully used this setup on hardware going back to an Intel 910 (using GL_ARB_vertex_program, but the vertex setup is the same) so that covers your "older Intel chipsets" requirement, and then some.

06-19-2014, 01:15 PM
Ok, thanks for the tip. I wonder which one performs better.

Just yesterday I got a nasty surprise with glMultiDrawArrays. To my surprise it actually was slower on my Geforce 550Ti than doing a loop over the array and calling glDrawArrays for each entry. I would have expected that as worst case scenario it'd be the same.