Mesh precision problem

Problems building or running the engine, queries about how to use features etc.
Post Reply
xrgo
OGRE Expert User
OGRE Expert User
Posts: 1148
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 168

Mesh precision problem

Post by xrgo »

Hello, I am having this problem:
Image

I made a sphere (obviously this happens with other meshes, the sphere is just a test) in Blender, but the center of the object is far away ( (-200,-200,-200) in this test ):
Image
and when exporting and/or *reading from the blender file alla assimp/gamkit* I get this precision problem, it seems that it can only accept 6 digits for the vertex pos, so when the vertex is far from the center I get less decimals =(
In blender everything looks good =)

I really don't care about the exporter, my engine *reads from the blender file alla assimp/gamkit*, and if I print the vertex pos with std::setprecision(16) I see that the numbers readed from the blender file has the corresponding decimals, so I am guessing is something to do with the ogre mesh generation (?).

Any ideas how to solve this problem?
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1280
Contact:

Re: Mesh precision problem

Post by dark_sylinc »

Is that voxel-like thing supposed to be a sphere???
There are multiple possible failure points (basically, every time position data is read or written), but top candidates are:
  • Half floating point precision is not enough for that particular mesh. Use full 32-bit precision.
  • The exporter exports to XML with low precision due to the bigger numbers. I don't know the exporter plugin in detail, but you would have to locate how it is being written to the file and check how to increase the precision using Python commands.
  • OgreMeshTool/OgreXMLConverter for some reason is not reading with enough precision.
If it's 1. (half floating precision not enough), another solution (aside using 32-bit precision) is to export the mesh as a smaller mesh, then make it bigger again at runtime using SceneNode::setScale. Floating point has far more precision closer to 0, than being away from 0 (precision distribution is not even).
xrgo
OGRE Expert User
OGRE Expert User
Posts: 1148
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 168

Re: Mesh precision problem

Post by xrgo »

Thanks!
dark_sylinc wrote:Is that voxel-like thing supposed to be a sphere???
Yes!
since my engine reads data directly from the blender file (I did mention that) option 2 and 3 don't fit this case, so about option 1...
I am constructing my mesh like this (lets imagine "yVertexTriangleBuffer* currentBuffer" has the correct values to make the perfect sphere):

Code: Select all

            yVertexTriangleBuffer* currentBuffer = triangleBufferCombo.vertexTriangleBuffers.at(sm);

            static const unsigned short index16BitClamp = (0xFFFF) - 1;

            Ogre::v1::SubMesh *newSubMesh = newMesh->createSubMesh();
            newSubMesh->setMaterialName("DebugMat"); //just to avoid missing material warning

            newSubMesh->useSharedVertices = false;
            newSubMesh->operationType = Ogre::v1::RenderOperation::OT_TRIANGLE_LIST;

            Ogre::v1::HardwareVertexBufferSharedPtr vertexBuffer;

            unsigned int vertexCount = currentBuffer->vertexs.size();
            unsigned int iBufSize = currentBuffer->triangles.size() * 3;

            newSubMesh->vertexData[0] = OGRE_NEW Ogre::v1::VertexData();
            newSubMesh->vertexData[0]->vertexCount = currentBuffer->vertexs.size();

            unsigned int offs = 0;

            Ogre::v1::VertexDeclaration *decl = newSubMesh->vertexData[0]->vertexDeclaration;
            //position
            decl->addElement(0, offs, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
            offs += Ogre::v1::VertexElement::getTypeSize(Ogre::VET_FLOAT3);

            //normals
            decl->addElement(0, offs, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
            offs += Ogre::v1::VertexElement::getTypeSize(Ogre::VET_FLOAT3);

            //colors
            if(currentBuffer->hasVertexColors){
                decl->addElement(0, offs, Ogre::VET_FLOAT3, Ogre::VES_DIFFUSE);
                offs += Ogre::v1::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
            }

            //uvs
            for(int i=0; i<currentBuffer->uvSetCount; i++){
                decl->addElement(0, offs, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i);
                offs += Ogre::v1::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
            }

            vertexBuffer = Ogre::v1::HardwareBufferManager::getSingleton().createVertexBuffer(
                        offs, vertexCount, Ogre::v1::HardwareBuffer::HBU_STATIC);

            Ogre::v1::VertexBufferBinding *bind = newSubMesh->vertexData[0]->vertexBufferBinding;
            bind->setBinding(0, vertexBuffer);



            //Index buffer
            Ogre::v1::HardwareIndexBuffer::IndexType buff_type = (currentBuffer->maxIndex > index16BitClamp) ?
                        Ogre::v1::HardwareIndexBuffer::IT_32BIT : Ogre::v1::HardwareIndexBuffer::IT_16BIT;

            Ogre::v1::HardwareIndexBufferSharedPtr indexBuffer = Ogre::v1::HardwareBufferManager::getSingleton().createIndexBuffer(buff_type,
                                                                                                                                   iBufSize,
                                                                                                                                   Ogre::v1::HardwareBuffer::HBU_STATIC);
            newSubMesh->indexData[0] = OGRE_NEW Ogre::v1::IndexData();
            newSubMesh->indexData[0]->indexCount = iBufSize;
            newSubMesh->indexData[0]->indexBuffer = indexBuffer;



            //Build index items
            bool using32 = buff_type == Ogre::v1::HardwareIndexBuffer::IT_32BIT;

            unsigned int *indices32 = 0;
            unsigned short *indices16 = 0;

            if (!using32)
                indices16 = static_cast<unsigned short*>(indexBuffer->lock(Ogre::v1::HardwareBuffer::HBL_NORMAL));
            else
                indices32 = static_cast<unsigned int*>(indexBuffer->lock(Ogre::v1::HardwareBuffer::HBL_NORMAL));

            for (unsigned int cur = 0; cur < currentBuffer->triangles.size(); cur++)
            {
                const yTriangleIndex& currentTriangle = currentBuffer->triangles.at(cur);
                for(unsigned int i=0; i<3; i++){
                    if(using32)
                        *indices32++ = (unsigned int)currentTriangle.index[i];
                    else
                        *indices16++ = (unsigned short)currentTriangle.index[i];
                }
            }

            indexBuffer->unlock();

            //Build vertex buffer
            float *bufferArray = static_cast<float*>(vertexBuffer->lock(Ogre::v1::HardwareBuffer::HBL_NORMAL));
            for(int i=0; i<currentBuffer->vertexs.size(); i++)
            {
                //Position
                Ogre::Vector3 pos = convertToYup(currentBuffer->vertexs.at(i).co);
                *bufferArray++ = pos.x;
                *bufferArray++ = pos.y;
                *bufferArray++ = pos.z;

                //Normals
                Ogre::Vector3 norm = convertToYup(currentBuffer->vertexs.at(i).no);//.normalisedCopy();
                *bufferArray++ = norm.x;
                *bufferArray++ = norm.y;
                *bufferArray++ = norm.z;

                //Colors
                if(currentBuffer->hasVertexColors){
                    *bufferArray++ = currentBuffer->vertexs.at(i).col.r;
                    *bufferArray++ = currentBuffer->vertexs.at(i).col.g;
                    *bufferArray++ = currentBuffer->vertexs.at(i).col.b;
                }

                //uvs
                for(int j=0; j<currentBuffer->uvSetCount; j++){
                    *bufferArray++ = currentBuffer->vertexs.at(i).uv[j].x;
                    *bufferArray++ = 1.0-currentBuffer->vertexs.at(i).uv[j].y;
                }

                //Calc Bounds
                minBB.makeFloor(pos);
                maxBB.makeCeil(pos);

            }
            vertexBuffer->unlock();
How do I use full 32-bit precision? I thought that I was already using it, since I store the position data as Ogre::Vector3 (currentBuffer->vertexs.at(i).co is a Vector3) and Vector3 are Real and Real are float and floats are 32 bit (¿?) and the vertex buffer is float* and the elements are Ogre::VET_FLOAT3/2. So it seems I already store everything in 32 bit???
[ so this comes to mi mind, if I already doing full precision float, using half (for those meshes that would look good using half) would I get performance boost? or just memory? ]

So I tried setting the buffer as double* and the elements as Ogre::VET_DOUBLE3/2 and the mesh looks worst :P
dark_sylinc wrote:is to export the mesh as a smaller mesh, then make it bigger again at runtime using SceneNode::setScale
I am going to try that as last option :P

thanks again!
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1280
Contact:

Re: Mesh precision problem

Post by dark_sylinc »

Yes, you're already using 32-bit floats. I thought you were using v2 meshes. You're constructing v1 meshes.

You need to watch out for:

Code: Select all

v2Mesh->importV1( v1Mesh.get(), halfPosition, halfUVs, useQtangents );
Mesh::arrangeEfficient //(v2 mesh)
v1::Mesh::arrangeEfficient //(v1 mesh)
If you import from v1 to v2, watch out halfPosition (should be false). Also place breakpoints inside both arrangeEfficient to see if they're being called, and if they are, that their arguments aren't halfPosition = true.
xrgo
OGRE Expert User
OGRE Expert User
Posts: 1148
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 168

Re: Mesh precision problem

Post by xrgo »

YEEEESSSS I was importV1 and didn't noticed that halfPosition flag, that did the trick! thank youuuuuu
Post Reply