Jump to content
  • Advertisement
Sign in to follow this  
Danicco

Model Skeleton/Mesh Structure Design

This topic is 2125 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm coding the animation part of my engine and I'm having trouble coming up and figuring a good way to deal with models, meshes and animations.

 

For now, I have a class named Model which is a scene entity, and it has a ModelClass shared between the same models (same VBO/IBO).

 

class ModelClass
{
    public:
    private:
        float* _vertexData;
        unsigned int _vertexCount;

        float* _normalData;
        unsigned int _normalCount;

        float* _uvData;
        unsigned int _uvCount;

        int* _indexData;
        unsigned int _indexCount;
 
        VBO _vertexBO;
        VBO _normalBO;
        VBO _uvBO;
        IBO _indexBO;



}

 

VBO/IBO classes doesn't have the data pointer in them, they just keep track of their ID. I left the data outside so I can change it without having it bound to a specific VBO, and so multiple VBOs can share parts of the same data (such as a Cube with one face different from the others).

 

I'm going to have each ModelClass with an array of MeshClass, which has a starting vertex and starting index, and each MeshClass has it's own material/texture and the VBO/IBO specific for each.

 

Now, I'm adding a SkeletonClass which will be the skin with an array of Bones, and each bone has an vector of vertexIndex and vertexWeight, as well as position and rotation.

 

The code for changing the values is something like this:

 

void Model::Draw(Viewport* viewport, float& interpolation)
{
    Matrix4x4 transformationMatrix = viewport->GetPerspective() * viewport->camera->GetCamera();
 
    //Sending this object's MVP matrix
    unsigned int transformationMatrixLocation = glGetUniformLocation(_shader->programID, "transformationMatrix");
    glUniformMatrix4fv(transformationMatrixLocation, 1, GL_FALSE, &transformationMatrix);
 
    //This class manages the data and calling the proper VBOs
    _modelClass->ActivateModel(_shader);
}
 
void ModelClass::ActivateModel(Shader* shader)
{
    for(unsigned int i = 0; i < _skeleton->bones.size(); i++)
    {
        for(unsigned int j = 0; j < _skeleton->bones[i]->vertices.size(); j++)
        {
            //figure the positions in the float array
            int vertexID = _skeleton->bones[i]->vertices[j] * 3;
            Vector3 vertex = Vector3(_vertexData[vertexID], _vertexData[vertexID + 1], _vertexData[vertexID + 2]);
 
            //Here is the problem
            vertex.x = ??
        }
    }
 
    //Calling the vertex/uv/normals/indexes
}

 

I need to change the value of vertex according to the bone's weight, position and rotation.

However, this ModelClass is shared between all same models, so I can't simply change and upload it, or all my models would move the same.

I can't do "vertex.x += bones.position.x * bones.weight;" because then I'd be adding the value everytime it is draw, not only once.

 

So I got to think that I have to keep multiple copies of the vertexData/normalData so I can always go back to "neutral" position and this one has the VBO information/IDs, and one for each model on screen modified by it's own animation.

 

The Skeleton must be something similar, I need to have only one template, but each model will have it's own skeleton positions...

 

And I haven't even think of implementing double buffer VBOs...

Am I on the right track? Is there something I can do to improve this design or something terribly lacking with it?

 

Also, when updating the vertexData, I'm using:

 

glBindBuffer(GL_ARRAY_BUFFER, _vboVertexes._bufferID);
glBufferSubData(GL_ARRAY_BUFFER, 0, _vertexCount * sizeof(float), _vertexes);

 

But I've read in various places that calling glBufferData with a null pointer might be best for buffer re-specification and streaming data, but when I tried to:

 

glBindBuffer(GL_ARRAY_BUFFER, _vboVertexes._bufferID);
glBufferData(GL_ARRAY_BUFFER, _vertexCount * sizeof(float), NULL, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, _vertexCount * sizeof(float), _vertexes);

 

I had massive graphical lag. It was stuttering every second or so. Shouldn't it be nearly the same as the 1st option?

Share this post


Link to post
Share on other sites
Advertisement

        VBO _vertexBO;
        VBO _normalBO;
        VBO _uvBO;
        IBO _indexBO;

Vertices, normals, and UV’s should be in a single VBO and interleaved.



VBO/IBO classes doesn't have the data pointer in them, they just keep track of their ID.

The VBO/IBO classes should have the data in them, as well as the ID.


I left the data outside so I can change it without having it bound to a specific VBO,

This is unrelated. The VBI/IBO should have the data and an interface for allowing you to change said data.
There is no purpose in having a VBO ID that is not associated with any specific buffer. This is exactly the anti-Christ of performance, and completely defeats the purpose of a VBO in the first place.



and so multiple VBOs can share parts of the same data (such as a Cube with one face different from the others).

Let them share the same VBO class (and its data). Anything different can be done in the vertex shader or via a second VBO.


I need to change the value of vertex according to the bone's weight, position and rotation.
However, this ModelClass is shared between all same models, so I can't simply change and upload it, or all my models would move the same.
I can't do "vertex.x += bones.position.x * bones.weight;" because then I'd be adding the value everytime it is draw, not only once.

Skinning is done in shaders. You have absolutely no reason at all to be doing this on the CPU, which eliminates every single problem you have had until now. The same VBO and its data can be used for every single instance of that model without ever needing to be modified for any given model or for models in different animation poses.
All skinning is done on the GPU inside the vertex shader.


This solves all of your previous issues as well as the performance issues, so I am not going to respond to those directly.


L. Spiro

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!