| Volumes Of Fun http://www.volumesoffun.com/phpBB3/ |
|
| Polyvox to Ogre Mesh http://www.volumesoffun.com/phpBB3/viewtopic.php?f=14&t=387 |
Page 2 of 4 |
| Author: | David Williams [ Mon Jun 11, 2012 7:40 pm ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
drwbns wrote: ...but why would I update a neighboring region for a single voxel? The decision to draw any particular quad depends on two voxels. If two adjacent voxels are both solid or both empty then no quad is needed, but if one is solid and the other is empty then a quad is generated to represent the surface between them. Now imagine that we have two adjacent voxels but in different regions. One is solid and the other is empty so a quad is generated between them, and it lies exactly on the region boundary. To which region should it belong? The answer isn't obvious, but in either case the problem now is that if either of our two voxels changes state then the quad should be removed. That is, changing a voxel on the edge of a region can mean that a neighbouring region needs to be regenerated. By extension, a voxel in the corner of a region can be even more complex, requiring up to three neighbouring regions to be regenerated. The simplest solution is that whenever you modify a voxel you should update that region and all neighbouring regions. Obviously this is slow, so once that works you can improve it to check whether a voxel is actually on the edge of a region.The maths here isn't too compex and I can elaborate once you verify that it is indeed the problem. It would be nice if PolyVox made this easier though, perhaps a function which, for a given voxel, would tell you which Regions it affects. I've added this to the todo list. |
|
| Author: | drwbns [ Mon Jun 11, 2012 9:13 pm ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
Hmm, so what you're saying is a quad may actually belong to a neighboring region that has no solid voxels? I added a check to refresh neighboring regions but it's rather slow in release mode now, but on the other hand, seems to be drawing perfectly. Are there an speed enhancments I could try to speed up my program? I'm still having some trouble when trying to do math on a negative Y value, it comes up as an incorrect value as such - Code: Ogre::Math::Floor(myPoint.GetY() / divisor) is it because myPoint.GetY() is an unsigned int? |
|
| Author: | David Williams [ Tue Jun 12, 2012 6:45 pm ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
drwbns wrote: Hmm, so what you're saying is a quad may actually belong to a neighboring region that has no solid voxels? Yes, that's basically it. drwbns wrote: I added a check to refresh neighboring regions but it's rather slow in release mode now, but on the other hand, seems to be drawing perfectly. Are there an speed enhancments I could try to speed up my program? Ok, so we've identified the problem. I assume you've fixed it by updating a region and all neighbouring regions when any voxels changes (i.e. when any voxel changes you update 27 regions)?. That's fine as a starting poit, but there are a couple of optimizations:
drwbns wrote: I'm still having some trouble when trying to do math on a negative Y value, it comes up as an incorrect value as such - Code: Ogre::Math::Floor(myPoint.GetY() / divisor) is it because myPoint.GetY() is an unsigned int? Perhaps, but you should also check the C++ rules for integer division (even if not unsigned). There's weird rules such as 8 / 3 = 2 (i.e. integer division always returns an integer result). |
|
| Author: | drwbns [ Thu Jun 14, 2012 2:34 am ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
I wrote a function to try to cut down on updating duplicate regions, but I now end up with a checkerboard mesh. One region visible, the next not and so on. It just adds any updated or created regions to a std::map and checks against that. But where is my logic flawed in doing that? From what I can tell, I'm somehow ending up with regions that have no verts or indices to display a mesh from. Is it possible that every other region has it's verts in the neighboring region? This is getting confusing but I'm trying to cut down the draw time. Code: void WorldCraft::updateNeighbors(Vector3DInt32 polyMesh) { polysIter = polys.find(Vector3DInt32(polyMesh.getX() - 1, polyMesh.getY(), polyMesh.getZ())); if(polysIter == polys.end()){ polys.insert(std::pair<Vector3DInt32, Vector3DInt32>(Vector3DInt32(polyMesh.getX() - 1, polyMesh.getY(), polyMesh.getZ()), Vector3DInt32(polyMesh.getX() - 1, polyMesh.getY(), polyMesh.getZ()))); createOrUpdate(Vector3DInt32(polyMesh.getX() - 1, polyMesh.getY(), polyMesh.getZ())); } polysIter = polys.find(Vector3DInt32(polyMesh.getX() + 1, polyMesh.getY(), polyMesh.getZ())); if(polysIter == polys.end()){ polys.insert(std::pair<Vector3DInt32, Vector3DInt32>(Vector3DInt32(polyMesh.getX() + 1, polyMesh.getY(), polyMesh.getZ()), Vector3DInt32(polyMesh.getX() + 1, polyMesh.getY(), polyMesh.getZ()))); createOrUpdate(Vector3DInt32(polyMesh.getX() + 1, polyMesh.getY(), polyMesh.getZ())); } polysIter = polys.find(Vector3DInt32(polyMesh.getX(), polyMesh.getY()-1, polyMesh.getZ())); if(polysIter == polys.end()){ polys.insert(std::pair<Vector3DInt32, Vector3DInt32>(Vector3DInt32(polyMesh.getX(), polyMesh.getY()-1, polyMesh.getZ()), Vector3DInt32(polyMesh.getX(), polyMesh.getY()-1, polyMesh.getZ()))); createOrUpdate(Vector3DInt32(polyMesh.getX() , polyMesh.getY()- 1, polyMesh.getZ())); } polysIter = polys.find(Vector3DInt32(polyMesh.getX(), polyMesh.getY()+1, polyMesh.getZ())); if(polysIter == polys.end()){ polys.insert(std::pair<Vector3DInt32, Vector3DInt32>(Vector3DInt32(polyMesh.getX(), polyMesh.getY()+1, polyMesh.getZ()), Vector3DInt32(polyMesh.getX(), polyMesh.getY()+1, polyMesh.getZ()))); createOrUpdate(Vector3DInt32(polyMesh.getX() , polyMesh.getY()+ 1, polyMesh.getZ())); } polysIter = polys.find(Vector3DInt32(polyMesh.getX(), polyMesh.getY(), polyMesh.getZ()-1)); if(polysIter == polys.end()){ polys.insert(std::pair<Vector3DInt32, Vector3DInt32>(Vector3DInt32(polyMesh.getX(), polyMesh.getY(), polyMesh.getZ()-1), Vector3DInt32(polyMesh.getX(), polyMesh.getY(), polyMesh.getZ()-1))); createOrUpdate(Vector3DInt32(polyMesh.getX(), polyMesh.getY(), polyMesh.getZ() - 1)); } polysIter = polys.find(Vector3DInt32(polyMesh.getX(), polyMesh.getY(), polyMesh.getZ()+1)); if(polysIter == polys.end()){ polys.insert(std::pair<Vector3DInt32, Vector3DInt32>(Vector3DInt32(polyMesh.getX(), polyMesh.getY(), polyMesh.getZ()+1), Vector3DInt32(polyMesh.getX(), polyMesh.getY(), polyMesh.getZ()+1))); createOrUpdate(Vector3DInt32(polyMesh.getX(), polyMesh.getY(), polyMesh.getZ() + 1)); } } and here's my region filling code - Code: void WorldCraft::fillVoxelsBetween(Vector3DInt32 start, Vector3DInt32 end, Density8 tValue) {
int startx, starty, startz, endx, endy, endz; int startxPoly, startyPoly, startzPoly, endxPoly, endyPoly, endzPoly; if(start.getX() < end.getX() ) { startx = start.getX(); endx = end.getX(); } else { startx = end.getX(); endx = start.getX(); } if(start.getY() < end.getY() ) { starty = start.getY(); endy = end.getY(); } else { starty = end.getY(); endy = start.getY(); } if(start.getZ() < end.getZ() ) { startz = start.getZ(); endz = end.getZ(); } else { startz = end.getZ(); endz = start.getZ(); } for( int x = startx; x < endx; x++) { for ( int y = starty; y < endy; y ++) { for ( int z = startz; z < endz; z++) { volume.setVoxelAt(Vector3DInt32(x,y,z), tValue); } } } startxPoly = Ogre::Math::Floor(startx / divisor); startyPoly = Ogre::Math::Floor(starty / divisor); startzPoly = Ogre::Math::Floor(startz / divisor); endxPoly = Ogre::Math::Floor(endx / divisor); endyPoly = Ogre::Math::Floor(endy / divisor); endzPoly = Ogre::Math::Floor(endz / divisor); for( int x = startxPoly; x < endxPoly + 1; x++) { for ( int y = startyPoly; y < endyPoly + 1; y ++) { for ( int z = startzPoly; z < endzPoly + 1; z++) { polysIter = polys.find(Vector3DInt32(x,y,z)); createOrUpdate(Vector3DInt32(x,y,z)); if(polysIter == polys.end()){ polys.insert(std::pair<Vector3DInt32, Vector3DInt32>(Vector3DInt32(x,y,z), Vector3DInt32(x,y,z))); updateNeighbors(Vector3DInt32(x,y,z)); } } } } CEGUI::Window * myWindow = mKeyDevices.windowManager->getWindow("Root/VertBuffer"); myWindow->setText(""); for(polysIter = polys.begin(); polysIter != polys.end(); polysIter++) { guiOutput(myWindow, const_cast<Vector3DInt32&>((*polysIter).first)); } polys.clear(); } |
|
| Author: | David Williams [ Thu Jun 14, 2012 8:02 pm ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
I can't answer you're question directly because it's quite hard for me to spot a logic error in that kind of code (you're better off stepping through in the debugger), but I will share some ideas about a different approach to this problem You said previously: drwbns wrote: ...if I'm adding multiple voxels using a radius value... Which implies to that you have some mechanism for setting multiple voxels at a time. When you do this, do you regenerate the mesh every time you set a voxel, or do you make all the voxel changes and then just regenerate the mesh once? Obviously the second approach is better. Assuming you aready have the second approach, then you must have a way to mark voxels and/or regions as invalid and needing an update without actually performing the update yet. You should be able to extend this to handle your neighbouring regions problem. For example, when you mark voxel (x,y,z) as invalid you could also mark voxels (x-1, y, z), (x+1, y, z), (x, y-1, z), etc as invalid. If the extra voxel are in the same regions then you are marking this region as invalid several times... but that doesn't matter because you still regenerate the mesh just once. And if they are in different regions then you've automatially handled the neighbouring regions problem. I bring this up now because I just checked the Voxeliens code base and that's how I've done it. You can stick with your other approach if you prefer (there is no single right way to do it), but maybe this approach is easier to understand. |
|
| Author: | drwbns [ Fri Jun 15, 2012 12:55 am ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
Basically everything you're assuming to be correct is what I'm doing, hence my confusion with this approach. I'm iterating through all affected regions setting their densities for affected voxels, then iterating through the regions again creating or updating their meshes and any neighboring meshes. This approach worked but is slow because the duplicate neighbor updating. I'd like to draw an image to better illustrate what's happening and why of coarse neighbor checking is redundant but I think you understand why. Granted I can get a fully completed mesh by not skipping any duplicate regions but what I can't understand is how marking my duplicate regions is creating an incomplete mesh. I'll just have to spend a little more time debugging to find the bug / solution, thanks |
|
| Author: | David Williams [ Fri Jun 15, 2012 8:46 am ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
I think we're on the same page here, but allow me to summarise.
Sorry if I'm repeating myself here... just want to make sure the information is clear |
|
| Author: | drwbns [ Fri Jun 15, 2012 12:45 pm ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
I'm basically already using the alternative method of marking the entire region as invalid, along with neighboring regions. This works fine without a duplicate invalid region check - which is weird to me. But where I hit some trouble is in the negative Y regions - which is half my world obviously. |
|
| Author: | drwbns [ Sun Jun 17, 2012 3:21 am ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
I got my duplicate updated region checking working, but it's still really slow to draw large regions, any other tips that can speed up region / neighbor updates? |
|
| Author: | David Williams [ Sun Jun 17, 2012 6:48 am ] |
| Post subject: | Re: Polyvox to Ogre Mesh |
So you're now seeing the correct behaviour (no more graphical artifacts) and you're only updating the mesh for regions when really required? And now you are saying that the process of regenerating the mesh for a single region is taking too long? |
|
| Page 2 of 4 | All times are UTC |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
|