jME3 create Plane with Mesh class

I would like to create objects with vertices and points, similar to class "box"

My problem is, I have no clue how to use the indices and normals.



Maybe someone can give me an example for a "plane" (best with two faces)



Mesh seems to be TriMesh? Is that correct?


private static final short[] GEOMETRY_INDICES_DATA = {
         2,  1,  0,  3,  2,  0, // back
         6,  5,  4,  7,  6,  4, // right
        10,  9,  8, 11, 10,  8, // front
        14, 13, 12, 15, 14, 12, // left
        18, 17, 16, 19, 18, 16, // top
        22, 21, 20, 23, 22, 20  // bottom
    };

    private static final float[] GEOMETRY_NORMALS_DATA = {
        0,  0, -1,  0,  0, -1,  0,  0, -1,  0,  0, -1, // back
        1,  0,  0,  1,  0,  0,  1,  0,  0,  1,  0,  0, // right
        0,  0,  1,  0,  0,  1,  0,  0,  1,  0,  0,  1, // front
       -1,  0,  0, -1,  0,  0, -1,  0,  0, -1,  0,  0, // left
        0,  1,  0,  0,  1,  0,  0,  1,  0,  0,  1,  0, // top
        0, -1,  0,  0, -1,  0,  0, -1,  0,  0, -1,  0  // bottom
    };

    private static final float[] GEOMETRY_TEXTURE_DATA = {
        1, 0, 0, 0, 0, 1, 1, 1, // back
        1, 0, 0, 0, 0, 1, 1, 1, // right
        1, 0, 0, 0, 0, 1, 1, 1, // front
        1, 0, 0, 0, 0, 1, 1, 1, // left
        1, 0, 0, 0, 0, 1, 1, 1, // top
        1, 0, 0, 0, 0, 1, 1, 1  // bottom
    };

jME3 already supports a Plane through the "Quad" class.

I'm learning it right now so I post a sample.



First, when building stuff "by hand" use triangle mode. It's the most understandable way to do it. It is also the least efficient but you can always use automated tools to post-process the geometry producing more efficient data packs.



Here's the test for 1 triangle.


package jme3tests;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.util.BufferUtils;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

public class Main extends SimpleApplication {

    public static void main(String[] args) {
        new Main().start();
    }

    @Override
    public void simpleInitApp() {
        Vector3f p0 = new Vector3f(0, 0, 0);
        Vector3f p1 = new Vector3f(1, 0, 0);
        Vector3f p2 = new Vector3f(0, 1, 0);
        FloatBuffer vertices = BufferUtils.createFloatBuffer(p0, p1, p2);

        Vector3f n0 = new Triangle(p0, p1, p2).getNormal();
        FloatBuffer normals = BufferUtils.createFloatBuffer(n0, n0, n0);

        IntBuffer indices = BufferUtils.createIntBuffer(0, 1, 2);

        Mesh mesh = new Mesh();
        mesh.setMode(Mesh.Mode.Triangles);

        mesh.setBuffer(VertexBuffer.Type.Position, 3, vertices);
        mesh.setBuffer(VertexBuffer.Type.Normal, 3, normals);
        mesh.setBuffer(VertexBuffer.Type.Index, 1, indices);

        Material material = assetManager.loadMaterial("/Common/Materials/RedColor.j3m");
        Geometry geometry = new Geometry("Triangle");
        geometry.setMaterial(material);
        geometry.setMesh(mesh);

        this.rootNode.attachChild(geometry);
    }
}



First there are the coordinates: 1 triangle 3 points, in counterclockwise order (whatever it means). Of course you can use an array of float or directly a FloatBuffer but I like meaningful entities (when there is no need for raw power).

The normals. I don't know if it is possible to use less than one normal per vertex. I have always used that amount. For complex meshes you would use a normal generator: just throw 1 empty normal per vertex and let the generator assign the right values. I don't know if there's a normal generator in JME3, you can use the Java3D one if there's not.

Indices. In triangle mode three consecutive indices form a triangle. Each index is a subscript ie it determines where to start looking in the coordinates array to form a value that has N components. In our coordinate buffer there are three vertices. Each vertex has three components. The first vertex is the first point of the triangle, the second vertex is the second point of the triangle, the third one is... the third.

The indices are 0, 1, 2 because:

0 = starts at 3 (number of components for a vertex) * 0 and grab three values = vertices[0], vertices[1], vertices[2] = p0
1 = 3 * 1 = start at 3 =vertices[3], vertices[4], vertices[5] = p1
2 = 3 * 2 = start at 6 = vertices[6], vertices[7], vertices[8] = p2

If we say:

2, 0, 1 we have p2, p0, p1 = the same triangle

But if we say:

0, 2, 1 we have p0, p2, p1 = a clockwise triangle which is "bad" in OpenGL (if I remember well)

And that's all. The rest of the code just fills a Mesh object with the data. The setBuffer methods require the number of components that makes up one value in the supplied buffer. In a FloatBuffer a vertex requires 3 values to be defined. The same for a normal. For indices in an IntBuffer 1 int is 1 index so the component count is 1.

If you want a plane you just create another triangle:

    @Override
    public void simpleInitApp() {
        Vector3f p0 = new Vector3f(0, 0, 0);
        Vector3f p1 = new Vector3f(1, 0, 0);
        Vector3f p2 = new Vector3f(0, 1, 0);
        Vector3f p3 = p1;
        Vector3f p4 = new Vector3f(1, 1, 0);
        Vector3f p5 = p2;
        FloatBuffer vertices = BufferUtils.createFloatBuffer(p0, p1, p2, p3, p4, p5);

        Vector3f n0 = new Triangle(p0, p1, p2).getNormal();
        Vector3f n1 = new Triangle(p3, p4, p5).getNormal();
        FloatBuffer normals = BufferUtils.createFloatBuffer(n0, n0, n0, n1, n1, n1);

        IntBuffer indices = BufferUtils.createIntBuffer(0, 1, 2, 3, 4, 5);

        Mesh mesh = new Mesh();
        mesh.setMode(Mesh.Mode.Triangles);

        mesh.setBuffer(VertexBuffer.Type.Position, 3, vertices);
        mesh.setBuffer(VertexBuffer.Type.Normal, 3, normals);
        mesh.setBuffer(VertexBuffer.Type.Index, 1, indices);

        Material material = assetManager.loadMaterial("/Common/Materials/RedColor.j3m");
        Geometry geometry = new Geometry("Triangle");
        geometry.setMaterial(material);
        geometry.setMesh(mesh);

        this.rootNode.attachChild(geometry);
    }



In Triangle mode, the IndexBuffer is just a sequence from 0 to [number of points].

For "complex" shapes you can use extrusion: define the outline of the shape as a sequence of points, translate it to the end of the extrusion, use a triangulator, apply a stripifier and it's done.