renderMeshExample, Metablobs, and creating Geometry
by Jack Stone · in Technical Issues · 09/13/2013 (12:15 pm) · 20 replies
Hello,
I am currently experimenting with metablobs, with a view to creating some kind of new water system for T3d. If successful, it should be possibly to get flowing liquids, and very realistic behaviour.
I have done a lot of research, and looked at a lot of sample code, but my low-level 3d Math skills are not as good as the probably need to be. Still, I'd like to give it a decent shot.
I am using the marching cubes algorithm to generate a metaBlob. I have a fairly good idea of the theory behind how this works, and I have spent some time looking around in renderMeshExample, particularly the createGeometry function. I have found some sample code that I am trying to use, but I am not clear on how to create the index and primitive buffers, and read the data in.
I am basing my work on this code:
http://www.paulsprojects.net/opengl/metaballs/metaballs.html
And the main rendering seems to be:
It seems that what I need to do is to replace the glNormal3fv and glVertex3fv calls with code to add the normal and position to the index buffer, but I don't seem to be doing this correctly. I also see no reference to a texcoord, or a primitive buffer?
Is there some basic reference to the T3D rendering system that I could have a look at?
Thanks for any advice!
I am currently experimenting with metablobs, with a view to creating some kind of new water system for T3d. If successful, it should be possibly to get flowing liquids, and very realistic behaviour.
I have done a lot of research, and looked at a lot of sample code, but my low-level 3d Math skills are not as good as the probably need to be. Still, I'd like to give it a decent shot.
I am using the marching cubes algorithm to generate a metaBlob. I have a fairly good idea of the theory behind how this works, and I have spent some time looking around in renderMeshExample, particularly the createGeometry function. I have found some sample code that I am trying to use, but I am not clear on how to create the index and primitive buffers, and read the data in.
I am basing my work on this code:
http://www.paulsprojects.net/opengl/metaballs/metaballs.html
And the main rendering seems to be:
numFacesDrawn=0;
static SURFACE_VERTEX edgeVertices[12];
glBegin(GL_TRIANGLES);
{
//loop through cubes
for(int i=0; i<numCubes; i++)
{
//calculate which vertices are inside the surface
unsigned char cubeIndex=0;
if(cubes[i].vertices[0]->value < threshold)
cubeIndex |= 1;
if(cubes[i].vertices[1]->value < threshold)
cubeIndex |= 2;
if(cubes[i].vertices[2]->value < threshold)
cubeIndex |= 4;
if(cubes[i].vertices[3]->value < threshold)
cubeIndex |= 8;
if(cubes[i].vertices[4]->value < threshold)
cubeIndex |= 16;
if(cubes[i].vertices[5]->value < threshold)
cubeIndex |= 32;
if(cubes[i].vertices[6]->value < threshold)
cubeIndex |= 64;
if(cubes[i].vertices[7]->value < threshold)
cubeIndex |= 128;
//look this value up in the edge table to see which edges to interpolate along
int usedEdges=edgeTable[cubeIndex];
//if the cube is entirely within/outside surface, no faces
if(usedEdges==0 || usedEdges==255)
continue;
//update these edges
for(int currentEdge=0; currentEdge<12; currentEdge++)
{
if(usedEdges & 1<<currentEdge)
{
CUBE_GRID_VERTEX * v1=cubes[i].vertices[verticesAtEndsOfEdges[currentEdge*2 ]];
CUBE_GRID_VERTEX * v2=cubes[i].vertices[verticesAtEndsOfEdges[currentEdge*2+1]];
float delta=(threshold - v1->value)/(v2->value - v1->value);
//edgeVertices[currentEdge].position=v1->position + delta*(v2->position - v1->position);
edgeVertices[currentEdge].position.x=v1->position.x + delta*(v2->position.x - v1->position.x);
edgeVertices[currentEdge].position.y=v1->position.y + delta*(v2->position.y - v1->position.y);
edgeVertices[currentEdge].position.z=v1->position.z + delta*(v2->position.z - v1->position.z);
//edgeVertices[currentEdge].normal=v1->normal + delta*(v2->normal - v1->normal);
edgeVertices[currentEdge].normal.x=v1->normal.x + delta*(v2->normal.x - v1->normal.x);
edgeVertices[currentEdge].normal.y=v1->normal.y + delta*(v2->normal.y - v1->normal.y);
edgeVertices[currentEdge].normal.z=v1->normal.z + delta*(v2->normal.z - v1->normal.z);
}
}
//send the vertices
for(int k=0; triTable[cubeIndex][k]!=-1; k+=3)
{
glNormal3fv(edgeVertices[triTable[cubeIndex][k+0]].normal);
glVertex3fv(edgeVertices[triTable[cubeIndex][k+0]].position);
glNormal3fv(edgeVertices[triTable[cubeIndex][k+2]].normal);
glVertex3fv(edgeVertices[triTable[cubeIndex][k+2]].position);
glNormal3fv(edgeVertices[triTable[cubeIndex][k+1]].normal);
glVertex3fv(edgeVertices[triTable[cubeIndex][k+1]].position);
numFacesDrawn++;
}
}
}
glEnd();It seems that what I need to do is to replace the glNormal3fv and glVertex3fv calls with code to add the normal and position to the index buffer, but I don't seem to be doing this correctly. I also see no reference to a texcoord, or a primitive buffer?
Is there some basic reference to the T3D rendering system that I could have a look at?
Thanks for any advice!
#2
I am aware of the performance problems of metaballs,and I am looking for a real-time solution. However. metaballs are relatively easy, and there is more example code and information out there on them than on most other solutions, so I thought it would be a good place to start. As I said, I need to brush up on my skills in this area, so I didn't want to do too much too soon.
I have seen Nvidia's fantastic work on the subject, it was one of the things that inspired me. Obviously, that's not something I intend to replicate, but if I was able to create even a flowing stream of water, as opposed to a large block, that would be a huge step forward. I have never seen water represented like that in a game before.
At any rate, even if my water simulation is too computationally intensive, I will at least get some cool "lava lamp" effects, which would be somewhat useful by themselves as an effect in a 3d world.
Dynamic geometry creation is incredibly powerful, and it's something I would like to be able to do, the possibilities are really endless if you have a good command of it. Deformable meshes, Terminator 2 style liquid-metal deformation, voxel-based geometry (like the original Red Faction game) allowing players to shoot through walls and terrain, this could all be done with some form of dynamic geometry.
09/13/2013 (9:11 pm)
Hello,I am aware of the performance problems of metaballs,and I am looking for a real-time solution. However. metaballs are relatively easy, and there is more example code and information out there on them than on most other solutions, so I thought it would be a good place to start. As I said, I need to brush up on my skills in this area, so I didn't want to do too much too soon.
I have seen Nvidia's fantastic work on the subject, it was one of the things that inspired me. Obviously, that's not something I intend to replicate, but if I was able to create even a flowing stream of water, as opposed to a large block, that would be a huge step forward. I have never seen water represented like that in a game before.
At any rate, even if my water simulation is too computationally intensive, I will at least get some cool "lava lamp" effects, which would be somewhat useful by themselves as an effect in a 3d world.
Dynamic geometry creation is incredibly powerful, and it's something I would like to be able to do, the possibilities are really endless if you have a good command of it. Deformable meshes, Terminator 2 style liquid-metal deformation, voxel-based geometry (like the original Red Faction game) allowing players to shoot through walls and terrain, this could all be done with some form of dynamic geometry.
#3
09/14/2013 (6:40 am)
Look at borderlands 2 it has efficient Real time fluids using the apex library by Nvidia. I even ran an Apex fluid simulation on my gtx 550 TI and it ran smoothly.
#4
09/14/2013 (9:36 am)
I hadn't seen the Apex library, thanks for that! What is the licence on Apex though, the same as PhysX? What are the options for integrating it to T3D? This is something I should look at, maybe post it as a resource?
#5
"2. License. Subject to the terms and conditions of this Agreement, NVIDIA grants you ("you") a limited, non-exclusive, non-transferable world-wide, royalty-free license to (a) internally install, use and display the APEX SDK, solely for purposes of developing APEX asset content for Physics Applications; (b) internally use, copy, modify and compile the Sample Code to design, develop and test APEX assets; and (c) reproduce and distribute the Redistributable Code only in object code form and only as fully integrated into Physics Applications, in each case solely for (i) your commercial purposes provided that you receive less than one hundred thousand dollars ($100,000) in gross revenue associated with Physics Applications or (ii) your non-commercial purposes."
So, it seems Apex is fine to use commercially for free, as long as you don't make more than $100,000 dollars, that's excellent.
09/14/2013 (9:38 am)
I just noticed this in the Apex EULA:"2. License. Subject to the terms and conditions of this Agreement, NVIDIA grants you ("you") a limited, non-exclusive, non-transferable world-wide, royalty-free license to (a) internally install, use and display the APEX SDK, solely for purposes of developing APEX asset content for Physics Applications; (b) internally use, copy, modify and compile the Sample Code to design, develop and test APEX assets; and (c) reproduce and distribute the Redistributable Code only in object code form and only as fully integrated into Physics Applications, in each case solely for (i) your commercial purposes provided that you receive less than one hundred thousand dollars ($100,000) in gross revenue associated with Physics Applications or (ii) your non-commercial purposes."
So, it seems Apex is fine to use commercially for free, as long as you don't make more than $100,000 dollars, that's excellent.
#6
I have verified that all of the data is the exact same in my T3D project, I just need to render these Faces using T3D's system. I am only rendering a static object for the moment, I am not animating it, so I know there are 3416 faces, which is 10248 verts. This is the code I am using to render them:
I'm getting nothing rendering on the screen except for one stray polygon. My knowledge of T3D's rendering system is quite poor, so I am sure I am doing something foolish somewhere, I just can't see it.
Thanks for any advice!
09/18/2013 (1:50 pm)
I have spent quite a lot of time working with some sample code I found, and I am very close to getting something working here, I just need some help converting these glVertex3fv calls to T3D's rendering system. The following code is from the original project (BSD license), it works perfectly:for(int k=0; triTable[cubeIndex][k]!=-1; k+=3)
{
//glNormal3fv(edgeVertices[triTable[cubeIndex][k+0]].normal);
glVertex3fv(edgeVertices[triTable[cubeIndex][k+0]].position);
//glNormal3fv(edgeVertices[triTable[cubeIndex][k+2]].normal);
glVertex3fv(edgeVertices[triTable[cubeIndex][k+2]].position);
//glNormal3fv(edgeVertices[triTable[cubeIndex][k+1]].normal);
glVertex3fv(edgeVertices[triTable[cubeIndex][k+1]].position);
}I have verified that all of the data is the exact same in my T3D project, I just need to render these Faces using T3D's system. I am only rendering a static object for the moment, I am not animating it, so I know there are 3416 faces, which is 10248 verts. This is the code I am using to render them:
// Fill the vertex buffer
VertexType *pVert = NULL;
mVertexBuffer.set( GFX, 10248, GFXBufferTypeStatic );
pVert = mVertexBuffer.lock();
for(int k=0; triTable[cubeIndex][k]!=-1; k+=3)
{
pVert[k].normal = (edgeVertices[triTable[cubeIndex][k+0]].normal);
pVert[k].point = edgeVertices[triTable[cubeIndex][k+0]].position;
pVert[k].texCoord = Point2F(0,0);
pVert[k+1].normal = (edgeVertices[triTable[cubeIndex][k+2]].normal);
pVert[k+1].point = edgeVertices[triTable[cubeIndex][k+2]].position;
pVert[k+1].texCoord = Point2F(0,0);
pVert[k+2].point = edgeVertices[triTable[cubeIndex][k+1]].position;
pVert[k+2].normal = (edgeVertices[triTable[cubeIndex][k+1]].normal);
pVert[k+2].texCoord = Point2F(0,0);
}
mVertexBuffer.unlock();
U16 *pIdx = NULL;
mPrimitiveBuffer.set( GFX, 10248, 12, GFXBufferTypeStatic );
mPrimitiveBuffer.lock(&pIdx);
for(int k=0; k<10248; k++)
pIdx[k] = k;
mPrimitiveBuffer.unlock();I'm getting nothing rendering on the screen except for one stray polygon. My knowledge of T3D's rendering system is quite poor, so I am sure I am doing something foolish somewhere, I just can't see it.
Thanks for any advice!
#7
09/19/2013 (8:52 am)
I'm no T3D Renderer guru either, but I'd check winding order and materials first.
#8
I am setting the texcoords to 0 for now, to just get a basic black material, will this work? I am basing this off of renderMeshExample, which requires a material to be specified, but setting it to pVert[k+2].texCoord = Point2F(0,0); seems to produce a simple black texture.
09/19/2013 (9:28 am)
@Richard, I'm sure the problem has something to do with winding order, but the problem is that I have verified the value and the order of every vertex being rendered between the T3D program and the original working program, and they are the same. Unless T3D uses a different order?I am setting the texcoords to 0 for now, to just get a basic black material, will this work? I am basing this off of renderMeshExample, which requires a material to be specified, but setting it to pVert[k+2].texCoord = Point2F(0,0); seems to produce a simple black texture.
#9
09/19/2013 (7:36 pm)
You got me, pal - I've got more of a bird's eye overview understanding of T3D, not the details.... lol
#10
Shameless plug I know, but if you want to see a picture of it:
phoenixgamedevelopment.com/blogs/index.php/2013/09/20/project-130-computational-...
09/20/2013 (10:07 am)
I finally got this working. I had made a few errors here and there, due mostly to misunderstandings of the rendering code. I learned a lot from doing this!Shameless plug I know, but if you want to see a picture of it:
phoenixgamedevelopment.com/blogs/index.php/2013/09/20/project-130-computational-...
#12
09/22/2013 (12:25 am)
Nice work! That's kind of fantastic. I'd be excited to see fluid particles, like Portal 2's gels.
#13
09/22/2013 (12:48 am)
Ah, so it was winding order....
#14
Daniel, I was thinking of Portal 2's gels when working on this as well, it must have been what they used, it looks exactly the same. I'm pretty sure I can create an effect like that with this concept.
Richard, yes, it seems to be, thanks!
I have a short video posted here:
phoenixgamedevelopment.com/blogs/index.php/2013/09/22/project-130-computational-...
09/22/2013 (6:02 am)
Thank you, I appreciate it! Daniel, I was thinking of Portal 2's gels when working on this as well, it must have been what they used, it looks exactly the same. I'm pretty sure I can create an effect like that with this concept.
Richard, yes, it seems to be, thanks!
I have a short video posted here:
phoenixgamedevelopment.com/blogs/index.php/2013/09/22/project-130-computational-...
#15
09/22/2013 (3:33 pm)
That looks pretty cool. Glad you got it working!
#16
I do have one minor vector maths question however. I am trying to get the metablobs to be affected by gravity, and by a direction vector which I specify. I have this almost working, but the metaballs are flowing along a striaght line, and not a parabolic curve. I think I need more advanced physics to represent this?
Here's a video of what I mean: (I love my new youtube channel, it's very useful for things like this!!)
The code I am using is this:
It's pretty simplistic, but it is almost working...
09/23/2013 (4:17 pm)
Thank you!I do have one minor vector maths question however. I am trying to get the metablobs to be affected by gravity, and by a direction vector which I specify. I have this almost working, but the metaballs are flowing along a striaght line, and not a parabolic curve. I think I need more advanced physics to represent this?
Here's a video of what I mean: (I love my new youtube channel, it's very useful for things like this!!)
The code I am using is this:
VectorF oldpos = metaballs[i].position; //Direction Vector: VectorF direction = Point3F(0.5,0.5,0.0); direction *= 10; VectorF BP = oldpos + ((F32)0.1 * direction); VectorF newPos = BP; //Gravity: float time = 0.1 const float gravity = -9.81f; float distance = (gravity * mPow(time,2))/2; VectorF gvec = Point3F(0,0,-1)*distance newPos = newPos - gvec; metaballs[i].position = newPos;
It's pretty simplistic, but it is almost working...
#17
09/25/2013 (4:46 am)
Uh, your time value is constant, so your particles will have constant velocity in the vertical axis.
#18
09/25/2013 (3:29 pm)
I know, I finally figured that out. It's basically the same equation as for a ballistic object, like a projectile? I am now trying to decide how to allow rotation of the object in world space (the editor) while still making gravity point "down" in object space...
#19
09/26/2013 (8:03 am)
Multiply the gravity with the world inverse matrix and you are back in object space.
#20
10/01/2013 (6:21 am)
Ah, that will help me a lot, thank you!
Associate Ron Kapaun
3tdstudios.com
Not to poo poo on your concept but, why metaballs? The final mesh (under normal conditions) is usually nowhere near real time efficient. The final poly count is normally way out of bounds for an efficient real time application.
I have looked a little bit into this (mostly due to Nvidia's recent 'water simulation' stuff) and I think (keeping in mind that I have NOT even experimented with it yet), an instanced geometric solution would be a more correct answer.
What am I basing this on? Well, if you look at how nvidia pulled off their demos, (by the way... this was done with some MAJOR top end hardware) you will note that they did something similar to metaballs but, they were using an 'approximation' algorithm to improve mesh efficiency. Anyway, just asking
Ron