HelloMesh tutorial (JME3)

That makes sense, thanks.

Yes, i render my mesh as points for some shader experiments, and setPointSize() just sets their size… Could you get running any simple custom mesh? like the most simple you can think of, a quad, cube, single triangle or just some points with just simple material, in the SimpleApplication environment… Maybe your call of verticesArray = vertices.toArray(verticesArray); is not doing what it should, or your position buffer is incorrect for some other reasons… or maybe you should define normals, cause the shader is doing some incorrect lightning??? No more ideas, but still good luck!

I wonder, do beginners ever care to create custom meshes?

It's not the case. I think the main reason for any tutorial is that somebody may have questions how to make certain things, and it's good to have a tutorial on it.

@KayTrance I think you missed the second part of @zathras’ query:

zathras said:
What I want to say is, I would like to use your code sample for the “advanced” section of the documentation page. What do you think?
erlend_sh said:
@KayTrance I think you missed the second part of @zathras' query:

oh, my mistake, sorry..
Well, I actually don't know.. From one side this is kind of simple technique to construct a small mesh. From the other side, it's true, that not every day you need to construct such meshes..
Maybe @zathras is right, it's more logical to put it into advanced section, but before that the section with vertex color should be covered, I think.. Or this topic is more shader-related?

@KayTrance You can set color values like this:

[java]

// …

Mesh cMesh = m.clone();



//We have 4 vertices and 4 color values for each of them.

//if you have more vertices, you need ‘new float[yourVertexCount * 4]’ here

float[] colorArray = new float[44];

int colorIndex = 0;



//Set RGBA value for each Vertex, Values range from 0.0f to 1.0f

for(int i = 0; i < 4; i++){

// Red value (is increased by .2 on each next vertex here)

colorArray[colorIndex++]= 0.1f+(.2f
i);

// Green value (is reduced by .2 on each next vertex)

colorArray[colorIndex++]= 0.9f-(0.2f*i);

// Blue value (remains the same in our case)

colorArray[colorIndex++]= 0.5f;

// Alpha value (no transparency set here)

colorArray[colorIndex++]= 1.0f;

}



cMesh.setBuffer(Type.Color, 4, colorArray);



Geometry coloredMesh = new Geometry (“ColoredMesh”, cMesh);

// …

[/java]



Also i think that after you set the position vertexbuffer, updateBound() and maybe also updateCounts() should be called, at least it is how Meshes are created in the jme3-library… hope it helps…

So, this is the final version of the tutorial. I believe I shouldn’t write more detailed explanations on each row because it’s pretty self-explanatory. Correct me if I am wrong. Thanks @trival for the source on vertex coloring, I have added it to the tutorial. Here’s the final code.





package hellomesh;



import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector2f;

import com.jme3.scene.Mesh;

import com.jme3.scene.VertexBuffer.Type;

import com.jme3.util.BufferUtils;



public class HelloMesh extends SimpleApplication {



public static void main(String[] args){

HelloMesh app = new HelloMesh();

app.start();

}



@Override

public void simpleInitApp() {



Mesh m = new Mesh();



// Vertex positions in space

Vector3f [] vertexes = new Vector3f[4];

vertexes[0] = new Vector3f(0,0,0);

vertexes[1] = new Vector3f(3,0,0);

vertexes[2] = new Vector3f(0,3,0);

vertexes[3] = new Vector3f(3,3,0);



// Texture coordinates

Vector2f [] texCoord = new Vector2f[4];

texCoord[0] = new Vector2f(0,0);

texCoord[1] = new Vector2f(1,0);

texCoord[2] = new Vector2f(0,1);

texCoord[3] = new Vector2f(1,1);



// Indexes. We define the order in which mesh should be constructed

int [] indexes = {2,0,1,1,3,2};



// Setting buffers

m.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertexes));

m.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord));

m.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indexes));



// Creating a geometry, and apply a single color shader to it

Geometry geom = new Geometry(“OurMesh”, m);

Material mat = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);

mat.setColor(“m_Color”, ColorRGBA.Blue);

geom.setMaterial(mat);



// Attaching our geometry to the root node.

rootNode.attachChild(geom);



// Updating bounds. This is needed to update the bounds of an mesh so that it will cull correctly.

m.updateBound();





// *************************************************************************

// Second mesh will use vertex colors to color each vertex

// **********************************************************************

Mesh cMesh = m.clone();

Geometry coloredMesh = new Geometry (“ColoredMesh”, cMesh);

Material matVC = new Material(assetManager, “Common/MatDefs/Misc/VertexColor.j3md”);



//We have 4 vertices and 4 color values for each of them.

//if you have more vertices, you need ‘new float[yourVertexCount * 4]’ here

float[] colorArray = new float[4
4];

int colorIndex = 0;



//Set RGBA value for each Vertex, Values range from 0.0f to 1.0f

for(int i = 0; i < 4; i++){

// Red value (is increased by .2 on each next vertex here)

colorArray[colorIndex++]= 0.1f+(.2f
i);

// Green value (is reduced by .2 on each next vertex)

colorArray[colorIndex++]= 0.9f-(0.2f
i);

// Blue value (remains the same in our case)

colorArray[colorIndex++]= 0.5f;

// Alpha value (no transparency set here)

colorArray[colorIndex++]= 1.0f;

}



cMesh.setBuffer(Type.Color, 4, colorArray);

coloredMesh.setMaterial(matVC);



// move mesh a bit so that it don’t intersect with the first one

coloredMesh.setLocalTranslation(4, 0, 0);



rootNode.attachChild(coloredMesh);





// *************************************************************************

// Third mesh will use a wireframe shader to show wireframe

// *************************************************************************

Mesh wfMesh = m.clone();

Geometry wfGeom = new Geometry(“wireframeGeometry”, wfMesh);

Material matWireframe = new Material(assetManager, “Common/MatDefs/Misc/WireColor.j3md”);

matWireframe.setColor(“m_Color”, ColorRGBA.Green);

wfGeom.setMaterial(matWireframe);

wfGeom.setLocalTranslation(4, 4, 0);

rootNode.attachChild(wfGeom);



}

}





This is the result of the tutorial. I truly hope this will be helpful.



2 Likes

Thank you, this is great!



Here is a copy as part of the official documentation:

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:custom_meshes

Google Code Archive - Long-term storage for Google Code Project Hosting.

Cool :slight_smile: It’s nice for me to be a part of the game :slight_smile:

@trival: Thanks for your reply. I was abroad, so didn’t have a chance to reply until now. The problem persists with the code from the tutorial (ie https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:custom_meshes): That is, the mesh disappears once I move around…

@trival & @zathras: My bad. As a previous poster mentioned, specifying vertices for both sides does the trick. Maybe the tutorial should be modified to demonstrate this? ie int[] indexes = {2, 0, 1, 1, 3, 2, 2, 3, 1, 1, 0, 2};

1 Like

Thanks, I will add this info tomorrow. This tip is useful if someone wants to create a flat mesh that is visible from both sides.



In many other cases, people create closed meshes, like polyhedrons, and for them it doesn’t matter whether the backside (inside) is “non-existant”. It would even be overkill to define an inside that nobody will ever be able to see anyway.



So your tutorial is correct, I will just mention this tip explicitly because it will be a frequently asked question. Solution is so simple that it may indeed not be obvious. :slight_smile:

Actually you don’t need to provide identical indices for backfaces. Just disable backface culling:

[java]material.getAdditionalRenderState().setCullMode(CullMode.Off);[/java]

2 Likes

Yup, that works too. (@ those using JME 3.0, it’s getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off));

Well, @javatar, it’s like a hack, actually, because normally, the face is generated as one sided, with appropriate normals, and that is why a culling occurs. Imagine it as a piece of wood that is painted blue from one side (your material) - if you turn it around you won’t see any blue anymore :slight_smile:

Maybe as @zathras said, this should be covered in tutorial, so nobody get frustrated…

1 Like

Added it now, hope it helps someone.

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:custom_meshes

I personally already have some ideas where I could make use of custom meshes for my project, so it’s already useful for me. :slight_smile:

Great!


I personally already have some ideas where I could make use of custom meshes for my project, so it’s already useful for me.

Mine uses a lot custom meshes, with LoD :)

@ KayTrance. Thanks! Great analogy :slight_smile: