Vertex Colors with CollisionShapeFactory.createMeshShape() for a voxel world

I am currently working out the lighting for my MInecraft clone, and I’ve stumbled onto a problem. Appearently CollisionShapeFactory.createMeshShape() will replace the meshes of all of the spatials inside the given node to the same mesh. I HAVE to use this or the physics will drop by frame rate 50 times over. But this is makes me unable to set the color (and therefore the appearence of lighting) of the individual vertices of each spatial; it will change the vertices of it’s parent’s mesh. Anyways, is there some kind of workaround for this where I can have lighting while being able to use CollisionShapeFactory.createMeshShape?

Trying to read between the lines here because what you say makes no sense.
I guess you mean GeometryBatchFactory.optimize instead of CollisionShapeFactory.createMeshShape, right?
CollisionShapeFactory.createMeshShape doesn’t change your mesh, it creates a shape for physic interactions.

However GeometryBatchFactory.optimize will merge your meshes. It should keep and merge any buffers of your meshes including the vertex color buffer.
how do you write your color buffer inside your mesh?

<cite>@nehon said:</cite> Trying to read between the lines here because what you say makes no sense. I guess you mean GeometryBatchFactory.optimize instead of CollisionShapeFactory.createMeshShape, right? CollisionShapeFactory.createMeshShape doesn't change your mesh, it creates a shape for physic interactions.

However GeometryBatchFactory.optimize will merge your meshes. It should keep and merge any buffers of your meshes including the vertex color buffer.
how do you write your color buffer inside your mesh?

I actually didn’t batch my meshes with GeometryBatchFactory.optimize because it did more harm than good. CollisionShapeFactory.createMeshShape is my only suspicion on the code that could be merging my spatial’s meshes, but I could be wrong. Is GeometryBatchFactory.optimize the only way to merge the meshes? There are many points in my code that could potentially do this. Note that they are still seperate geometries, but all the geometries share the same mesh

@Kuru said: I actually didn't batch my meshes with GeometryBatchFactory.optimize because it did more harm than good. CollisionShapeFactory.createMeshShape is my only suspicion on the code that could be merging my spatial's meshes, but I could be wrong. Is GeometryBatchFactory.optimize the only way to merge the meshes? There are many points in my code that could potentially do this. Note that they are still seperate geometries, but all the geometries share the same mesh

CollisionShapeFactory only reads meshes. It doesn’t modify them.

If all of your Geometries share the same Mesh then of course they will share the same mesh. I don’t understand what the issue is then.

It sounds like you were changing the color buffer (of the mesh) and wondering why it changed the color buffer of the other geometry (with the same mesh). If not then you should describe your problem differently and include code.

<cite>@pspeed said:</cite> CollisionShapeFactory only reads meshes. It doesn't modify them.

If all of your Geometries share the same Mesh then of course they will share the same mesh. I don’t understand what the issue is then.

It sounds like you were changing the color buffer (of the mesh) and wondering why it changed the color buffer of the other geometry (with the same mesh). If not then you should describe your problem differently and include code.

That’s exactly my situation, but rather I don’t understand why theey share the same mesh, and it’s because they share the same mesh that all my geometries change. Anyways is there a way to have them not share the same mesh, or some other kind of work around?

Yes its possible, you just need to create the mesh for every block then.

However:
dont use vertex lights, really its kinde outdated.

I suggest a shader approach, where you keep the lighting data in a array or similar, and the shader just loops trough all nearby lights and increases the light value for the side then.

@Kuru said: That's exactly my situation, but rather I don't understand why theey share the same mesh, and it's because they share the same mesh that all my geometries change. Anyways is there a way to have them not share the same mesh, or some other kind of work around?

Well, the code you’ve posted so far looks fine for me. It would be hard for us to help you tell how your geometries end up with the same mesh if we can’t see how you setup your geometry.

<cite>@pspeed said:</cite> Well, the code you've posted so far looks fine for me. It would be hard for us to help you tell how your geometries end up with the same mesh if we can't see how you setup your geometry.

Well all the relevant code is pretty much spread out through numerous methods in a multiple classes in 1-2 lines chunks(and my entire code is thousands of lines spread throughout around 50 classes) , so ill just explain how the geometries are set up instead.

So I have a wavefront file Cube.obj in my assets folder that’s the model for my voxel

  • I use Geometry cube = (Geometry) assetManager.loadModel(“Models/Cube.obj”); to store it, that way I can simply change materials when I want to change the appearance

  • Every time I create a new block (the voxel unit), I create a new geometry for it using spatial = Main.blockGeometry.clone(); (It’s spatial because there are some cases where I use nodes and not geometries, but I cast it later on) I’ve also tried deepClone(), which gave me a vertex count of -1 and clone(true)
    -I have a field in my block class that stores the light level
    -I use the following code to set the light intensity:
    float newColors = new float[spatial.getVertexCount() * 4];

          for (int i = 0; i &lt; newColors.length; i += 4) { 
              newColors[i] = lightLevel;
              newColors[i + 1] = lightLevel;
              newColors[i + 2] = lightLevel;
              newColors[i + 3] = lightLevel;
          }
          ((Geometry) spatial).getMesh().setBuffer(Type.Color, 4, newColors);
    

a) you would have to deeply clone your Geometry/Meshes for this to work.
b) for future reference, block worlds are not made of cubes.

<cite>@pspeed said:</cite> a) you would have to deeply clone your Geometry/Meshes for this to work. b) for future reference, block worlds are not made of cubes.

It’s not exactly cubes, but I didn’t feel like changing the name of my files or I’ll get confused. Also, I tried to use deepClone(), but then when I call getVertexCount() it returns -1

Well, block worlds are made of visible quads. No cubes or blocks or any single object representing a cell. If you make each block its own object then your world size is limited to about 10x10x10 blocks or so. The key will be creating a batched mesh of quads… which is covered two or three times a week here every week for about two years. :slight_smile:

Also, there are a few open source block world frameworks that run around here… one that has even been turned into an SDK plug-in as I recall.

<cite>@pspeed said:</cite> Also, there are a few open source block world frameworks that run around here... one that has even been turned into an SDK plug-in as I recall.

Yeah, that’s similar to what I did (well not exactly, but my world isn’t just made up of individual blocks). Anyways any idea why getVertexCount() returns -1 on the deepClone()? I’ve tried looking through my code for possible clues, but I cant seem to find why it’s not working properly. Also, if I end up getting this stack trace when I try to use CollisionShapeFactory.createMeshShape:

java.lang.IllegalArgumentException: Negative capacity: -12
at java.nio.Buffer.<init>(Buffer.java:191)
at java.nio.ByteBuffer.<init>(ByteBuffer.java:276)
at java.nio.ByteBuffer.<init>(ByteBuffer.java:284)
at java.nio.MappedByteBuffer.<init>(MappedByteBuffer.java:89)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:119)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
at com.jme3.util.BufferUtils.createByteBuffer(BufferUtils.java:956)
at com.jme3.bullet.collision.shapes.MeshCollisionShape.createCollisionMesh(MeshCollisionShape.java:72)
at com.jme3.bullet.collision.shapes.MeshCollisionShape.<init>(MeshCollisionShape.java:68)
at com.jme3.bullet.util.CollisionShapeFactory.createSingleMeshShape(CollisionShapeFactory.java:214)
at com.jme3.bullet.util.CollisionShapeFactory.createCompoundShape(CollisionShapeFactory.java:112)
at com.jme3.bullet.util.CollisionShapeFactory.createCompoundShape(CollisionShapeFactory.java:134)
at com.jme3.bullet.util.CollisionShapeFactory.createMeshCompoundShape(CollisionShapeFactory.java:143)
at com.jme3.bullet.util.CollisionShapeFactory.createMeshShape(CollisionShapeFactory.java:173)
at voxels.Main.simpleInitApp(Main.java:326)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:225)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:207)
at java.lang.Thread.run(Thread.java:722)

I don’t know… maybe your mesh is huge and overlaps a “short” buffer. Since you are loading your mesh from a model instead of just making it, I don’t really have any idea how it’s created.

Any reason you aren’t just starting with one of the existing cube world libraries?

<cite>@pspeed said:</cite> I don't know... maybe your mesh is huge and overlaps a "short" buffer. Since you are loading your mesh from a model instead of just making it, I don't really have any idea how it's created.

Any reason you aren’t just starting with one of the existing cube world libraries?

To answer your question, I like a challenge.

Also, I’ve looked into the Mesh.deepClone() method, and found something interesting:

/**
 * Creates a deep clone of this mesh. 
 * The {@link VertexBuffer vertex buffers} and the data inside them
 * is cloned.
 * 
 * @return a deep clone of this mesh.
 */
public Mesh deepClone(){
    try{
        Mesh clone = (Mesh) super.clone();
        clone.meshBound = meshBound != null ? meshBound.clone() : null;

        // TODO: Collision tree cloning
        //clone.collisionTree = collisionTree != null ? collisionTree : null;
        clone.collisionTree = null; // it will get re-generated in any case

        clone.buffers = new IntMap&lt;VertexBuffer&gt;();
        clone.buffersList = new SafeArrayList&lt;VertexBuffer&gt;(VertexBuffer.class);
        for (VertexBuffer vb : buffersList.getArray()){
            VertexBuffer bufClone = vb.clone();
            clone.buffers.put(vb.getBufferType().ordinal(), bufClone);
            clone.buffersList.add(bufClone);
        }
        
        clone.vertexArrayID = -1;
        clone.vertCount = -1; &lt;---- WHY IS THIS HERE
        clone.elementCount = -1;
        
        // although this could change
        // if the bone weight/index buffers are modified
        clone.maxNumWeights = maxNumWeights; 
        
        clone.elementLengths = elementLengths != null ? elementLengths.clone() : null;
        clone.modeStart = modeStart != null ? modeStart.clone() : null;
        return clone;
    }catch (CloneNotSupportedException ex){
        throw new AssertionError();
    }
}

So why exactly is there clone.vertCount = -1 in this? There’s no return call either so it’s going to be called no matter what, and it will stay at -1.

This is why seeing code is often useful:
http://hub.jmonkeyengine.org/javadoc/com/jme3/scene/Mesh.html#updateCounts()

I don’t know why it doesn’t clone the count.

1 Like
<cite>@pspeed said:</cite> This is why seeing code is often useful: http://hub.jmonkeyengine.org/javadoc/com/jme3/scene/Mesh.html#updateCounts()

I don’t know why it doesn’t clone the count.

Thanks! That was exactly the solution I was looking for!

Maybe we should call updateCounts at the end of clone…or just clone the count…
@Momoko_Fan, resetting the id makes sense, but why the counts?