Strange rendering problems, batch geometry(manual meshes)

baishan

28-09-2009 17:40:38

Hi,
I'm doing some research in procedural modeling. I have developed a system that will generate building meshes and display them using Ogre.
I am using the paged geometry plugin to speed up the rendering by using batched geometry. Everything was going fine until I tried to run the system outside of the visual studio debug environment (without the debug heap). When I run the system without the debug heap I get some very strange rendering problems. The problems only appear when I use the batch page LOD in the pagedgeometry plugin and do not appear (in opengl or directX) if I use the normal ogre scenegraph with moveable entities. However, the batch page geometry works fine with either rendering system when I use a mesh thats stored on my harddisk(suggesting the problem is not with the plugin). I have created some videos on youtube to demonstrate the problem.

Buildings rendered with DirectX: http://www.youtube.com/watch?v=qVi0ex-aTLk
Buildings rendered with Opengl: http://www.youtube.com/watch?v=LVo5IdRqZyw

As you can see 'some' of the buildings appear to bounce around with camera movement and the meshes are completely corrupted in Opengl. Again this only happens with the batched geometry and does not happen with normal moveable entities. I have tried to simplify the program to generate only quads. The quads display fine in DirectX but only display as triangles in OpenGl.

Quad meshes displayed in OpenGl: http://www.youtube.com/watch?v=brscXruG4U8
Quad meshes displayed in DirectX: http://www.youtube.com/watch?v=CEOYPJJf-o4

Its as if the index buffer is corrupted in Opengl but only when using the batched geometry, and only when using my meshes. This is the code I use to generate the mesh. In the simple quad case there is only one wall being generated. The wall is simply a position, orientation, and size that is turned into 4 vertices.

void BuildingGenerator::addWallToBuffer(const vector<ShapeSystem::Shape *,boost::pool_allocator<ShapeSystem::Shape *> > &walls)
{
//PROFILE_FUNC();
using namespace::Ogre;
this->buildingMemoryPool->wallSize = walls.size();
//this->buildingMemoryPool->wallVertexPool->resize(walls.size()*32);
//this->buildingMemoryPool->wallIndexPool->resize(walls.size()*6);
int sizeVertexBuffer = 0;
int sizeIndexBuffer = 0;
float * wallVertexBuffer = new float[walls.size()*32];//this->buildingMemoryPool->wallVertexPool->get(0);
unsigned short * wallIndexBuffer = new unsigned short[walls.size()*6];//this->buildingMemoryPool->wallIndexPool->get(0);
this->buildingMemoryPool->wallBuf = wallVertexBuffer;
this->buildingMemoryPool->wallInd = wallIndexBuffer;

for(int x = 0; x < walls.size(); ++x)
{
float distanceXZ = sqrt((walls[x]->textureStartLoc.x - walls[x]->position.x)*(walls[x]->textureStartLoc.x - walls[x]->position.x) + (walls[x]->textureStartLoc.z - walls[x]->position.z)*(walls[x]->textureStartLoc.z - walls[x]->position.z));
float distanceY = abs(walls[x]->textureStartLoc.y - walls[x]->position.y);

float x1 = wallVertexBuffer[x*32] = walls[x]->position.x;
float y1 = wallVertexBuffer[x*32+1] = walls[x]->position.y;
float z1 = wallVertexBuffer[x*32+2] = walls[x]->position.z;
sizeVertexBuffer += sizeof(float) * 3;

//normals
Ogre::Vector3 normalVector = walls[x]->axis * Ogre::Vector3::UNIT_Z;
wallVertexBuffer[x*32+3] = normalVector.x;
wallVertexBuffer[x*32+4] = normalVector.y;
wallVertexBuffer[x*32+5] = normalVector.z;
sizeVertexBuffer += sizeof(float) * 3;

//textCoords
wallVertexBuffer[x*32+6] = distanceXZ;
wallVertexBuffer[x*32+7] = distanceY;
sizeVertexBuffer += sizeof(float) * 2;

Ogre::Vector3 wallVertex = (walls[x]->axis * Ogre::Vector3(walls[x]->size.x,0,0))+walls[x]->position;
float x2 = wallVertexBuffer[x*32+8] = wallVertex.x;
float y2 = wallVertexBuffer[x*32+9] = wallVertex.y;
float z2 = wallVertexBuffer[x*32+10] = wallVertex.z;
sizeVertexBuffer += sizeof(float) * 3;

wallVertexBuffer[x*32+11] = normalVector.x;
wallVertexBuffer[x*32+12] = normalVector.y;
wallVertexBuffer[x*32+13] = normalVector.z;
sizeVertexBuffer += sizeof(float) * 3;

//textCoords
wallVertexBuffer[x*32+14] = distanceXZ + walls[x]->size.x;
wallVertexBuffer[x*32+15] = distanceY;
sizeVertexBuffer += sizeof(float) * 2;

wallVertex = (walls[x]->axis * Ogre::Vector3(walls[x]->size.x,walls[x]->size.y,0))+walls[x]->position;
float x3 = wallVertexBuffer[x*32+16] = wallVertex.x;
float y3 = wallVertexBuffer[x*32+17] = wallVertex.y;
float z3 = wallVertexBuffer[x*32+18] = wallVertex.z;
sizeVertexBuffer += sizeof(float) * 3;

wallVertexBuffer[x*32+19] = normalVector.x;
wallVertexBuffer[x*32+20] = normalVector.y;
wallVertexBuffer[x*32+21] = normalVector.z;
sizeVertexBuffer += sizeof(float) * 3;

//textCoords
wallVertexBuffer[x*32+22] = distanceXZ + walls[x]->size.x;
wallVertexBuffer[x*32+23] = distanceY+walls[x]->size.y;
sizeVertexBuffer += sizeof(float) * 2;

wallVertex = (walls[x]->axis * Ogre::Vector3(0,walls[x]->size.y,0))+walls[x]->position;
float x4 = wallVertexBuffer[x*32+24] = wallVertex.x;
float y4 = wallVertexBuffer[x*32+25] = wallVertex.y;
float z4 = wallVertexBuffer[x*32+26] = wallVertex.z;
sizeVertexBuffer += sizeof(float) * 3;

wallVertexBuffer[x*32+27] = normalVector.x;
wallVertexBuffer[x*32+28] = normalVector.y;
wallVertexBuffer[x*32+29] = normalVector.z;
sizeVertexBuffer += sizeof(float) * 3;

//textCoords
wallVertexBuffer[x*32+30] = distanceXZ;
wallVertexBuffer[x*32+31] = distanceY+walls[x]->size.y;
sizeVertexBuffer += sizeof(float) * 2;

//indices
wallIndexBuffer[x*6] = x*4;
wallIndexBuffer[x*6+1] = x*4+2;
wallIndexBuffer[x*6+2] = x*4+3;

wallIndexBuffer[x*6+3] = x*4;
wallIndexBuffer[x*6+4] = x*4+1;
wallIndexBuffer[x*6+5] = x*4+2;
sizeIndexBuffer += sizeof(unsigned short) * 6;

float minX = min(min(x1,x2),min(x3,x4));
float maxX = max(max(x1,x2),max(x3,x4));

float minY = min(min(y1,y2),min(y3,y4));
float maxY = max(max(y1,y2),max(y3,y4));

float minZ = min(min(z1,z2),min(z3,z4));
float maxZ = max(max(z1,z2),max(z3,z4));

if(minX < this->buildingMemoryPool->minX) this->buildingMemoryPool->minX = minX;
if(minY < this->buildingMemoryPool->minY) this->buildingMemoryPool->minY = minY;
if(minZ < this->buildingMemoryPool->minZ) this->buildingMemoryPool->minZ = minZ;
if(maxX > this->buildingMemoryPool->maxX) this->buildingMemoryPool->maxX = maxX;
if(maxY > this->buildingMemoryPool->maxY) this->buildingMemoryPool->maxY = maxY;
if(maxZ > this->buildingMemoryPool->maxZ) this->buildingMemoryPool->maxZ = maxZ;
}

}
The above code generates two buffers that are used to construct the vertex and index declarations in the ogre submesh.


void OgreFuncs::createSubMesh(Ogre::MeshPtr mesh, int numVertices, int numIndices, float * vertexBuffer, unsigned short * indexBuffer)
{

Ogre::SubMesh * subMesh= mesh->createSubMesh();

Ogre::VertexData* data = new Ogre::VertexData();
// Then, we link it to our Mesh/SubMesh :
subMesh->useSharedVertices = false;
subMesh->vertexData = data;
// We have to provide the number of verteices we'll put into this Mesh/SubMesh
data->vertexCount = numVertices;
// Then we can create our VertexDeclaration
Ogre::VertexDeclaration* decl = data->vertexDeclaration;

size_t offset = 0;
decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);

Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
offset, // This value is the size of a vertex in memory
numVertices, // The number of vertices you'll put into this buffer
Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY // Properties
);

vbuf->writeData(0,vbuf->getSizeInBytes(),vertexBuffer,true);

Ogre::VertexBufferBinding * bind = data->vertexBufferBinding;
bind->setBinding(0,vbuf);

Ogre::HardwareIndexBufferSharedPtr ibuf= Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
Ogre::HardwareIndexBuffer::IT_16BIT,
numIndices,
Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);

subMesh->indexData->indexBuffer = ibuf;
subMesh->indexData->indexCount = numIndices;
subMesh->indexData->indexStart = 0;

ibuf->writeData(0,ibuf->getSizeInBytes(),indexBuffer,true);


}


If you have any ideas on what could cause these difference between opengl and directx and what could cause the flickering problem please let me know.
I have been trying to debug this problem for about a week now and haven't really gotten anywhere. I'm hoping someone might have seen something similar before and could direct me on how to fix this problem. Any help is much appreciated :)

tdev

28-09-2009 22:40:21

now that looks strange :/
i hope johnj has a clue about whats going on there.

baishan

08-10-2009 22:41:45

Hi,
I just want to update this in case anyone else was having the same problem. I switched to use the Ogre ManualObject interface to create the meshes and everything seems to work fine.

Brian

tdev

27-03-2010 13:50:43

I just want to update this in case anyone else was having the same problem. I switched to use the Ogre ManualObject interface to create the meshes and everything seems to work fine.

thanks for letting us know :)