Mesh smoothing using Gaussion

Hi,

I’m wondering about something, I have a simple idea: implement mesh smoothing in Jmonkey. Now this shouldn’t be too hard, however I’m wondering if its any usefull. I was thinking it might be handy for beautifying low poly models (low downloadsize!) and ultimately a cool automatic lod system. Especially the latter I’m interested in: would this take up lots of resources? I guesst it will (thats why its mostly used on terrain right?) but comments are appreciated.



The function would work like this:


  1. subdivision
  2. Gaussian blur



    If itll be a nice feature, I’ll try to create it the coming days.

Sounds like a nice idea… Though one would generate that data not “live” in the application but rather before, e.g. using a model importer / jMP plugin or similar. The terrain system does live LOD because in the future it will support “endless” terrain that might be procedurally generated, thus you cannot prepare the data in advance.

Why would one not be able to do this live? Would this be too heavy? Or because one cannot create/edit models in JME on the fly :s ? I see no other roadblocks…

Also, this very feature is usually implemented in a geometry shader. The low poly mesh data is sent to the geometry shader, that just tessellate the model on the GPU side.

But for now jME3 does not support geometry shaders.

Doing it on the cpu might be doable, but i guess, the issue would be the memory used to store the new vertices…

Also I don’t know if it would be fast enough to consider “on the fly” tessellation. Which would make this feature not worth the effort. (better pre compute lod levels).

But that just thoughts, i did not actually tried it so maybe i’m wrong. You seem motivated by this feature so why not give it a try?

But for now jME3 does not support geometry shaders.


Why jME3 doesn't support geometry feature? is it something that just needed to be plugged in or it will never be in this engine structure?

Geometry shaders have limited use. Smoothing models doesn’t exactly make sense …

Hardware tessellation is a completely different feature from geometry shaders and requires your meshes to have a completely different data format, one which none of our current importers support.

Momoko_Fan said:
Smoothing models doesn't exactly make sense ...

I think its more efficient than mesh decimation, making automatic Lod using smoothing. Plus, high quality models can only go so far, untill you run out of memory right?
I guess you can call it regressive mesh? Dunno.
kajos said:
I think its more efficient than mesh decimation, making automatic Lod using smoothing. Plus, high quality models can only go so far, untill you run out of memory right?
I guess you can call it regressive mesh? Dunno.

Its called hardware tessellation

http://www.youtube.com/watch?v=bkKtY2G3FbU

Yeah, its not called regressive mesh… Tesselation is supported by opengl 4 on the gpu, however its apparently not uncommon to do it on the cpu, if I may believe wikipedia…

So, its no limitation of jME3…these features can be added as new feature without any major undertaking?

I’m trying to add it right now, using the Lodcalculator, however adding opengl support (gpu) is another thing (but jme wouldnt be in the way I assume).



EDIT: Using the LodCalculator is wrong I know, will replace that later.

Is there a fast and efficient way in JME to get the neighbors of a vertex?



EDIT: Guess looping through the indices is the way to go.

Look at TangentBinormalGenerator, it gathers triangle data by scanning the mesh’s buffers

Okay, so now I have the most pretty much worked out I think, but I’m getting index out of bound errors. Now I’m thinking this is because the way I do it now is, looping through all the indices < mesh.getVertexCount(), then looping through the indexbuffer to find a threesome with the vertex in it, if so I have found two neighbors. Then I try to get the positions of the vertices to do the calculation for the smoothing. The gatheringof the positions of the vertices is probably wrong in my code:



new Vector3f(

mesh.getFloatBuffer(Type.Position).get((k+g)*3),

mesh.getFloatBuffer(Type.Position).get((k+g)*3+1),

mesh.getFloatBuffer(Type.Position).get((k+g)*3+2)

)



where k+g is an index for a vertex.

Isn’t there one index per three vertices… Its triangle indices, no?

Ok, so I changed the code a little. Instead of vertexcount Im using indexbuffersize / 3 and some other stuff. Maybe you would be so kind to take a look at the code I have now?

EDIT: So I’m still getting an out of bounds exception at the first floatbuffer.

EDIT: The error was → mesh.getIndexBuffer().get((k+g))+1) etc…

This is the function to smooth right now:

pre type="java"
public static Mesh smoothedMesh(Mesh mesh) {


long start = System.currentTimeMillis();


double sigma = 3;


Mesh smoothedMesh = mesh.clone();


for (int v = 0; v < mesh.getIndexBuffer().size()/3; v++) {


double totalWeight = 0;


// find neighbors with index key


double[] weights = new double[mesh.getIndexBuffer().size()];


for (int k = 0; k < mesh.getIndexBuffer().size(); k+:3) {


for (int n = 0; n<3; n++) {


if (mesh.getIndexBuffer().get(k+n) == v) {


// loop all but k+n because it is equal to k


for (int g = 0; g<3; g++) {


if (g != n) {


float dist = new Vector3f(


mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get((k+g))),


mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get((k+g)+1)),


mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get((k+g)+2))


).distance(


new Vector3f(


mesh.getFloatBuffer(Type.Position).get(v),


mesh.getFloatBuffer(Type.Position).get(v+1),


mesh.getFloatBuffer(Type.Position).get(v+2)


)


);


double weight = (1./(sigma*Math.sqrt(2.*Math.PI)))Math.exp(-(distdist)/(2.sigmasigma));


totalWeight += weight;


weights[k+g] = weight;


}


}


}


}


}


Vector3f newPos = new Vector3f(


mesh.getFloatBuffer(Type.Position).get(v),


mesh.getFloatBuffer(Type.Position).get(v+1),


mesh.getFloatBuffer(Type.Position).get(v+2)


);


for (int k = 0; k < mesh.getIndexBuffer().size(); k+:3) {


for (int n = 0; n<3; n++) {


if (mesh.getIndexBuffer().get(k+n) == v) {


for (int g = 0; g<3; g++) {


if (g != n) {


newPos.add(new Vector3f(


mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get((k+g))),


mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get((k+g)+1)),


mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get((k+g)+2))


).mult((float)(weights[k+g]/totalWeight)));


}


}


}


}


}


}


System.out.println(“Time: “+(System.currentTimeMillis()-start)+” for “+mesh.getVertexCount()+” vertices.”);


return smoothedMesh;


}
/pre

Okay, so I now some weak result with recreating the mesh looping through all the indices and stuff, however I cant get all indices to be added or ill run into a out of bounds exception:



pre type="java"



        public static Mesh smoothedMesh(Mesh mesh) {


            long start = System.currentTimeMillis();


              double sigma = .003;


                


              Mesh smoothedMesh = mesh.clone();


              // mesh.getIndexBuffer().size() to mesh.vertexcount to display mesh else, out of bounds at floatbuffer put!!!111111


              for (int v = 0; v < mesh.getIndexBuffer().size(); v++) {


                double totalWeight = 0;


                


                double[] weights = new double[mesh.getIndexBuffer().size()];





                for (int k = 0; k < mesh.getIndexBuffer().size(); k+:3) {


                    for (int n = 0; n<3; n++) {


                        if (mesh.getIndexBuffer().get(k+n) == v) {





                            for (int g = 0; g<3; g++) {


                                if (g != n) {


                                    float dist = new Vector3f(


                                            mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get(k+g)3),


                                            mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get(k+g)3+1),


                                            mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get(k+g)3+2)


                                        ).distance(


                                        new Vector3f(


                                            mesh.getFloatBuffer(Type.Position).get(v
3),


                                            mesh.getFloatBuffer(Type.Position).get(v
3+1),


                                            mesh.getFloatBuffer(Type.Position).get(v
3+2)


                                        )


                                    );


                                    double weight = (1./(sigma*Math.sqrt(2.*Math.PI)))Math.exp(-(distdist)/(2.sigmasigma));


                                    totalWeight += weight;


                                    weights[k+g] = weight;


                                }


                            }


                        }


                    }


                }


                Vector3f newPos = new Vector3f(0,0,0


                );


                for (int k = 0; k < mesh.getIndexBuffer().size(); k+:3) {


                    for (int n = 0; n<3; n++) {


                        if (mesh.getIndexBuffer().get(k+n) == v) {


                            for (int g = 0; g<3; g++) {


                                if (g != n) {


                                    newPos.addLocal(new Vector3f(


                                            mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get(k+g)3),


                                            mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get(k+g)3+1),


                                            mesh.getFloatBuffer(Type.Position).get(mesh.getIndexBuffer().get(k+g)3+2)


                                        ).mult((float)(weights[k+g]/totalWeight)));


                                }


                            }


                        }


                    }


                }


                mesh.getFloatBuffer(Type.Position).put(v
3, newPos.x);


                mesh.getFloatBuffer(Type.Position).put(v
3+1, newPos.y);


                mesh.getFloatBuffer(Type.Position).put(v
3+2, newPos.z);


                


              }      


              System.out.println(“Time: “+(System.currentTimeMillis()-start)+” for “+mesh.getVertexCount()+” vertices.”);


              return smoothedMesh;


        }
/pre

Okay, I’m gonna quit this. The calculations take like 4 seconds for 3000 vertices so thats a long time. I thought it would do more, but ah well…