[Solved] Problem retreiving skeletally animated vertex data

Problems building or running the engine, queries about how to use features etc.
Post Reply
User avatar
derdragon
Halfling
Posts: 57
Joined: Mon Oct 23, 2006 2:08 am

[Solved] Problem retreiving skeletally animated vertex data

Post by derdragon »

I actually got around the whole deal by just setting the Entity's material to a material that didn't use shaders and then setting it right back. I was surprised that this works, particularly because I do this within the same frame.

Code: Select all


                        std::string tempmat = D->ent->getSubEntity(0)->getMaterialName();
                        if(D->ent->hasSkeleton()) D->ent->setMaterialName("default");
                        GetEntityInformation(D->ent,vertex_count,vertices,index_count,indices);
                        if(D->ent->hasSkeleton()) D->ent->setMaterialName(tempmat);

I see no slowdown when using this, and it works, so it's what I'm sticking with. Hopefully it will be of some help to others.

Previous Message:
I'm having some issues trying to set up polygon-level raycasting for skeletally animated entities. The code I have below seems to generate the offsets for the vertexes, not the actual positions of them. I'm not sure if I'm using the addSoftwareAnimationRequest() right. One more quick question... I'm assuming this doesn't take care of pose animations, if it doesn't can anyone point me in the right direction for taking care of that as well?

Code: Select all

void GetEntityInformation(Ogre::Entity * ent,
                        size_t &vertex_count,
                        Ogre::Vector3* &vertices,
                        size_t &index_count,
                        unsigned long* &indices
                        ) {
    ent->addSoftwareAnimationRequest(false);
    bool added_shared = false;
    index_count = 0;
    vertex_count = 0;
    Ogre::MeshPtr mesh = ent->getMesh();
    for(unsigned short i=0; i < mesh->getNumSubMeshes(); ++i) {
        Ogre::SubMesh* submesh = mesh->getSubMesh(i);
        if(submesh->useSharedVertices) {
            if(!added_shared) {
                vertex_count += mesh->sharedVertexData->vertexCount;
                added_shared = true;
            }
        }
        else {
            vertex_count += submesh->vertexData->vertexCount;
        }
        index_count += submesh->indexData->indexCount;
    }
    added_shared = false;
    size_t current_offset = 0;
    size_t shared_offset = 0;
    size_t next_offset = 0;
    size_t index_offset = 0;
    bool skeleton = ent->hasSkeleton();
    if(skeleton) ent->_updateAnimation();
    vertices = new Ogre::Vector3[vertex_count];
    indices = new unsigned long[index_count];
    for(size_t i=0; i<mesh->getNumSubMeshes(); ++i) {
        Ogre::SubMesh* submesh = mesh->getSubMesh(i);
        const Ogre::VertexData* vertex_data;
        if(skeleton) vertex_data = submesh->useSharedVertices ? ent->_getSkelAnimVertexData() : ent->getSubEntity(i)->_getSkelAnimVertexData();
        else vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
        if(!submesh->useSharedVertices || (submesh->useSharedVertices && !added_shared)) {
            if(submesh->useSharedVertices) {
                added_shared = true;
                shared_offset = current_offset;
            }
            const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
            Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
            unsigned char* vertex = (unsigned char*)vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY);
            float* pReal;
            for(size_t j=0; j<vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize()) {
                posElem->baseVertexPointerToElement(vertex, &pReal);
                size_t n = current_offset*3 + j;
                vertices[n] = Ogre::Vector3(pReal[0],pReal[1],pReal[2]);
                std::cout << STR(vertices[n]) + ", ";
            }
            vbuf->unlock();
            next_offset += vertex_data->vertexCount;
        }
        Ogre::IndexData* index_data = submesh->indexData;
        size_t numTris = index_data->indexCount / 3;
        Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
        bool use32bitIndices = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
        Ogre::uint32 *pLong = (Ogre::uint32*)ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY);
        Ogre::uint16 *pShort = (Ogre::uint16*)pLong;
        size_t offset = submesh->useSharedVertices ? shared_offset : current_offset;
        if(use32bitIndices) for(size_t k=0; k<numTris*3; ++k) indices[index_offset++] = pLong[k] + (int)offset;
        else for(size_t k=0; k<numTris*3; ++k) indices[index_offset++] = (int)pShort[k] + (int)offset;
        ibuf->unlock();
        current_offset = next_offset;
    }
    ent->removeSoftwareAnimationRequest(false);
}
Last edited by derdragon on Wed Jan 30, 2008 6:54 pm, edited 1 time in total.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

You can't call addSoftwareAnimationRequest / removeSoftwareAnimationRequest like that, because the animation data is not updated at that point (_updateAnimation() will do something at most once per frame, it tries not to update the animation if nothing has changed). addSoftwareAnimationRequest simply registers the intention to access the animation results in software, thus cusing Ogre to perform some calculations in software always and to store the results. It must be done before the animation is updated (which typically happens at frame update time unless you manually trigger it earlier), and you should not remove it until you never want to access the results in software again. Chances are that something else (like frame rendering) is triggering the animation update for that frame while the software request is still off, and thus your animation update request is doing nothing. Leave it on all the time if you intend to access it every frame.

This feature deals with both skeletal and pose animation. As a general rule, if you can avoid having to pull the animation results back in software, do. It's much faster to let the GPU do the animation without the CPU getting involved.
User avatar
derdragon
Halfling
Posts: 57
Joined: Mon Oct 23, 2006 2:08 am

Post by derdragon »

I just wanted to say, I'm impressed with the speed and quality of the help here.

That aside, I'm not sure where to put addSoftwareAnimation request, because I'm not testing everything every frame, it's usually just one or two objects at most whenever a click occurs (and later, whenever I test a ray). I understand that the GPU handling the animation makes it a lot faster, I only need the CPU to handle it for the single frames in which I'm casting a ray. What I want to do, if possible, is just grab the vertex information of the mesh in software just at that one instant, and then continue to render the mesh deformation in hardware after the checks have been run against the triangles.

I don't think the information I had was actually "offsets", since there really were only 3 unique values I was getting, I'm assuming they had to do with the 2 bones that were posed, and the rest of them being at rest, but it's more or less irrelevant now.

Thanks again for the response!
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

derdragon wrote:What I want to do, if possible, is just grab the vertex information of the mesh in software just at that one instant, and then continue to render the mesh deformation in hardware after the checks have been run against the triangles.
The problem is that your "one instant" stalls the GPU while you pull that information back across the bus.

When you create your object or apply its material, that's when you want to register the software request. Leave it on, like Sinbad said, and turn it off when you are completely done with ever checking again (probably when the object is unloaded, it sounds).
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
derdragon
Halfling
Posts: 57
Joined: Mon Oct 23, 2006 2:08 am

Post by derdragon »

xavier wrote: The problem is that your "one instant" stalls the GPU while you pull that information back across the bus.

When you create your object or apply its material, that's when you want to register the software request. Leave it on, like Sinbad said, and turn it off when you are completely done with ever checking again (probably when the object is unloaded, it sounds).
How much of a stall are we talking? This is something that I'd want to be able to use on all objects. (Static geometry is obviously not a problem) If I enable it for all my hardware animated objects, wouldn't I be taking a large consistent performance hit?
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

Yes, if you are bringing back large numbers of objects' post-transformed state each frame, it's a rather significant hit. Could be as much of a hitch as you see when you take a screenshot.

Ogre provides the ability to keep buffers on the CPU precisely for this purpose -- use that feature, that's what it's there for.
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
derdragon
Halfling
Posts: 57
Joined: Mon Oct 23, 2006 2:08 am

Post by derdragon »

I'm still having trouble with this. I added the "addSoftwareAnimationRequest(false)" at the point where the entity gets created, but when I cast my ray, it crashes when trying to render the next frame. This does not occur if I remove ent->_updateAnimation(), but then I still end up with the same bogus vertex positions.

xavier, what I'm wanting to set up is to only enable the software request for the objects that are going to be sampled, and just for the frame I'm going to test their vertex positions for. Is there a CPU hit because of adding and removing the request? or is it just when the request is enabled? I'm assuming that it's more CPU intensive to leave it on for the entire life of the object, particularly since the frames in which the animated vertex positions are tested are virtually non existent compared to the frames in which they are not.

Anyways, I'm still having issues. Aside from calling addSoftwareAnimationRequest earlier, is there anything else I may be missing? What I'm doing so far allows several frames to pass before I'm making the check in the code there.
Post Reply