Is there a way to share some floatBuffers among geometries but not all. As an example I’m loading multiple models that will always have the same texture coordinates, color coordinates, and indicies, but will have diffrent vertex coordinates and normals depending upon where they are in their animation. I figure I’ld see a memory improvement if I could share just what needs to be shared. This is a somewhat common thing in games where you could have 30 -gremlin- all using the same texture coordinates and indicies, but at diffrent shapes because some are walking and some are fighting.
Along that effect, it would also be useful to have a setNormal(int index, Vector3f normal) function along the lines of setVertex(int,Vector3f) because at each step of any animation I’ld need to update normals and updateNormalBuffer(); makes an unneeded float[] buffer for that purpose.
Also, I have a class that extends TriMesh with a constructor that does…
super(copy.name+"*",copy.vertex,copy.normal,null,copy.texture[0],copy.indices);
when passed a -copy- of another object of the same class.
I’ve noticed when looking thru TriMesh’s code that Geometry.vertex is just set as a refrence to an array, but a floatbuffer is copied for “faster data processing”. My question is can I update my -copy-'s vertexes via setVertex(int index,Vector3f vertex) and have the two look diffrent? What would basicly happen is their vertBuf would correctly represent how each is animated, but their Vector3f[] vertex; would be totally out of wack.
We do need to figure out some way to share models (allowing different animation states). As DarkProphet has discovered, we are beginning to reach the memory boundary.
I like the idea of sharing the buffers. How would you go about building the shared geometry?
Along that effect, it would also be useful to have a setNormal(int index, Vector3f normal) function along the lines of setVertex(int,Vector3f) because at each step of any animation I'ld need to update normals and updateNormalBuffer()
No problem.
've noticed when looking thru TriMesh's code that Geometry.vertex is just set as a refrence to an array, but a floatbuffer is copied for "faster data processing". My question is can I update my -copy-'s vertexes via setVertex(int index,Vector3f vertex) and have the two look diffrent? What would basicly happen is their vertBuf would correctly represent how each is animated, but their Vector3f[] vertex; would be totally out of wack.
Yeah, if you were sharing the vertex array reference but not the buffer, the Geometry you called setVertex(int, vector3f) would get the change (in the buffer), but not the other Geometry. Although once you altered the second Geometry's vertex array it would update the buffer with the newest change and whatever other changes you made with the first Geometry.
What were you thinking you'd like to do?
Is it posible to do away with (in geometry)
//data that specifies how to render this leaf.
protected Vector3f[] vertex;
protected Vector3f[] normal;
protected ColorRGBA[] color;
protected Vector2f[][] texture;
and just use your buffers. Seems like a waste to make me create a whole []vertex when it’s copied into vertBuf. Do away with all that protected stuff, and support helper functions to convert passed information into the buffers. Also, create a helper -BufferMaker- class to create a buffer how I want it so that it’s refrence can be passed to multiple Geometries?
Also, the update fuctions (updateNormalBuffer, ect) create a |float[] buffer| when called and then put that into the buffer. Why not skip the use of the new float[] and put them directly in via FloatBuffer.put(normal.x), FloatBuffer.put(normal.y), ect )
No idea if this is posible in jME’s framework though, just an idea.
How about a Factory method in Geometry (TriMesh as well):
Geometry.createClone(Geometry copy, boolean copyColor, boolean copyTextures, boolean copyNormals, boolean copyVertices);
So if you wanted to copy everything:
Geometry other = Geometry.createClone(model, true, true, true, true);
or if you wanted to copy the texture coordinates and color, but want the same vertices (just be able to animate seperately).
Geometry other = Geometry.createClone(model, true, true, false, false);
other.setVertices(model.cloneVertices());
something along those lines.
Is it posible to do away with (in geometry)
//data that specifies how to render this leaf.
protected Vector3f[] vertex;
protected Vector3f[] normal;
protected ColorRGBA[] color;
protected Vector2f[][] texture;
possibly. I'll look into what that would entail.
Your boolean factory method wouldn’t allow the programmer to hotswap from one pre-stored Vertex Buffer to another during run time on the same geometry.
Ok, I’ll look into if we can remove the arrays easily. That will at least cut down on the memory usage if nothing else.
You should be able to also remove the use of
float[] buffer
in all your update functions by adding it directly one put at a time.
one put at a time is extremely slow and not recommended… (try it for kicks)
The following is a proposed better way to do public void Geometry.updateNormalBuffer()
The speed you loose in creating a buffer then copying it doesn’t match the speed an array put gains. Look at the following code. The new version actually runs faster than what you have, and uses 1/2 as much memory. The memory alone would even be worth it if the new one ran a few milliseconds slower. Note that if you make numNorms very large, I get output of your function taking a very long time to run.
This is the output I get
This is how fast yours runs 231
This is how fast yours could run 50
Yay it works
public class TestPut {
public static FloatBuffer normBuf1;
public static FloatBuffer normBuf2;
public static Vector3f[] normal;
public static int numNorms=100000;
public static void main(String[] args) {
normal=new Vector3f[numNorms*3];
randomize(normal);
long time;
time=System.currentTimeMillis();
whatYouDo();
System.out.println("This is how fast yours runs " + (System.currentTimeMillis()-time));
time=System.currentTimeMillis();
whatYouCouldDo();
System.out.println("This is how fast yours could run " + (System.currentTimeMillis()-time));
if (normBuf1.equals(normBuf2))
System.out.println("Yay it works");
else
System.out.println("back to the drawing board this doesn't work!");
System.exit(0);
}
private static void whatYouCouldDo() {
if (normal == null) { return; }
if (normBuf1 == null) {
normBuf1 = ByteBuffer.allocateDirect(4 * (normal.length*3)).order(
ByteOrder.nativeOrder()).asFloatBuffer();
}
normBuf1.clear();
for (int i = 0; i < normal.length; i++) { // changed vertex.length to normal.length
normBuf1.put(normal[i].x).put(normal[i].y).put(normal[i].z);
// normBuf.put(normal[i].y);
// normBuf.put(normal[i].z);
}
normBuf1.flip();
}
private static void whatYouDo() {
if (normal == null) { return; }
float[] buffer = new float[normal.length * 3];
if (normBuf2 == null) {
normBuf2 = ByteBuffer.allocateDirect(4 * buffer.length).order(
ByteOrder.nativeOrder()).asFloatBuffer();
}
for (int i = 0; i < normal.length; i++) { // changed vertex.length to normal.length
buffer[i * 3] = normal[i].x;
buffer[i * 3 + 1] = normal[i].y;
buffer[i * 3 + 2] = normal[i].z;
}
normBuf2.clear();
normBuf2.put(buffer);
normBuf2.flip();
}
private static void randomize(Vector3f[] buffer) {
Random r=new Random();
for (int i=0;i<buffer.length;i++){
buffer[i]=new Vector3f();
buffer[i].x=r.nextFloat();
buffer[i].y=r.nextFloat();
buffer[i].z=r.nextFloat();
}
}
}
Played around with it,
public static int numNorms=100000;
This is how fast yours runs 210
This is how fast yours could run 50
Yay it works
while
public static int numNorms=10000;
results in
This is how fast yours runs 30
This is how fast yours could run 20
Yay it works
While making this example I thought of even more reasons to allow programers to pass in their own floatbuffers. As it is now, there are still two copies of my normals a) The one I make b) The one jME makes. It’s no big deal for me to make my own floatBuffer and pass that to all my Geometry. That way there’s only one copy of it. You could still include arrayput functions in geometry for backwards compatibility and ease, and allow direct floatBuffer assignment for speed and memory.
Well I stand corrected on the single puts. Looking closer, I believe partly that is due to the extra overhead of additional array checks performed by Java when we stick the data into the temp float[]. Any way you slice it though, it would be worth it to switch to using the put at the very least.
I like the idea of using your own buffers but would need to hear Mojos thoughts before implementing anything there.
Ok, updated Geometry to use the new puts, also added a small change to your code that requires less array access so extra speedup there. I’m not noticing any large speed ups, but it’s hard to tell… At least we should be using less memory per frame.
I’m curious what you changed. Similar updates to color,vertex, ect can be updated similarly as this.
From what I can understand, it shouldn’t be too difficult to port to only using floatBuffers inside Geometry. The current functions that assign Vector3f[]'s to Geometry could simply be used as helper functions that make the floatBuffers, allowing backwards compatability.
Color, textures, vertex and normal were all done.
I saw inside updateNormalBuffer() you have
if (normBuf == null) {
normBuf = ByteBuffer.allocateDirect(4 * bufferLength).order(
ByteOrder.nativeOrder()).asFloatBuffer();
}
I'm curious if it's posible normBuf to be set to something small originally, then a call to reconstruct pass in a normal array larger resulting in a overflow? I can't test it myself because I seem to get errors trying to compile the src at
"import com.jcraft.jogg.Packet does not exist"
That’s 'cause you now need the Ogg Vorbis jars in order to compile jME. So, jogg-0.0.5.jar and jorbis-0.0.12.jar must be on your classpath.
Those checks were in there before, I just left the checks in place. I know what you mean though and have hit against it in the past. I’ll take a look at it.