Hi, new to JME so excuse my noobiness. I’m trying to create a terrain type mesh, programmatically.
In essense, I create a, say, 100 by 100 size mesh with 5000 “quads” (10,000 triangles), connected together in a flat grid along the X and Z axis. Starting from 0,0 and going up in both directions.
It looks as though when the origin of the mesh (0,0,0) is hidden from the camera, parts of the mesh becomes invisible. As though the bounds of the mesh hasn’t been updated?
At the beginning of the video I showcase some of the code. The main method is ‘generate’ which loops through width and length and creates some helper objects which I call “quads” which each contain 4 vertices that make up that given quad.
I add those quads to the “vertices” ArrayList, as well as create indices in the “indices” arraylist.
The other method is the ‘apply’ method, which sets the vertex and indices buffers (and calls updateBound on the mesh).
Any help would be greatly appreciated. Thanks in advance!
Outside the class, I simply create a new Terrain instance, call “generate” and then create a geometry based on the mesh created.
package mygame;
import com.jme3.bounding.BoundingVolume;
import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.terrain.noise.basis.Noise;
import com.jme3.util.BufferUtils;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Random;
/**
*
* @author petter
*/
public class Terrain {
/**
* The width of the terrain.
*/
public int width = 100;
/**
* The length of the terrain.
*/
public int length = 100;
/**
* The size (width and length (x and z)) of each quad in the terrain.
*/
public int gridSize = 1;
public Mesh mesh = new Mesh();
public ArrayList<Quad> quads;
public ArrayList<Vector3f> vertices;
public ArrayList<Integer> indices;
public ArrayList<Vector2f> texCoords;
public class Quad {
public int index;
public Vector3f position;
public Vector3f[] vertices = new Vector3f[4];
public Quad(int index, Vector3f position) {
this.index = index;
this.position = position;
}
}
/**
* Create a new terrain instance of the given width, length and gridSize.
* @param width
* @param length
* @param gridSize
*/
public Terrain(int width, int length, int gridSize) {
this.width = width;
this.length = length;
this.gridSize = gridSize;
}
public float getSize() {
return width + length / 2f;
}
/**
* Generates quad objects, vertices, indices and texcoords for the given width, length and gridSize.
* Remember to call the apply method after generating or changing the terrain data.
*/
public void generate() {
//initialize verts, indices and texcoords lists
vertices = new ArrayList<Vector3f>();
indices = new ArrayList<Integer>();
texCoords = new ArrayList<Vector2f>();
//and the quads list
quads = new ArrayList<Quad>();
//create the quads and vertices
int index = 0;
int x;
int z;
int i;
Quad q;
for(x = 0; x < width/gridSize; x++) {
for(z = 0; z < length/gridSize; z++) {
q = new Quad(index, new Vector3f(x * gridSize, 0, z * gridSize));
System.out.println("Creating Quad at: " + q.position.x + ", " + q.position.z);
quads.add(q);
//create the 4 vertices of this quad
q.vertices[0] = new Vector3f(q.position.x, 0, q.position.z + gridSize);
q.vertices[1] = new Vector3f(q.position.x + gridSize, 0, q.position.z + gridSize);
q.vertices[2] = new Vector3f(q.position.x, 0, q.position.z);
q.vertices[3] = new Vector3f(q.position.x + gridSize, 0, q.position.z);
//create the vertices on the mesh itself
Vector3f vert;
for(int v = 0; v < q.vertices.length; v++) {
vert = q.vertices[v];
if (vertices.indexOf(vert) < 0) {
System.out.println("Vert: " + vert.x + ", " + vert.z);
//create this vertex and texture coordinate
vertices.add(vert);
texCoords.add(v, new Vector2f(vert.x / width, vert.z / length));
System.out.println("texcoord: " + texCoords.get(v).x + "," + texCoords.get(v).y);
}
}
//create the indices
indices.add(vertices.indexOf(q.vertices[2]));
indices.add(vertices.indexOf(q.vertices[0]));
indices.add(vertices.indexOf(q.vertices[1]));
System.out.println("Creating triangle: " + q.vertices[2] + ", " + q.vertices[0] + ", " + q.vertices[1]);
indices.add(vertices.indexOf(q.vertices[1]));
indices.add(vertices.indexOf(q.vertices[3]));
indices.add(vertices.indexOf(q.vertices[2]));
System.out.println("Creating triangle: " + q.vertices[1] + ", " + q.vertices[3] + ", " + q.vertices[2]);
index++;
}
}
}
/**
* Updates the mesh. This must be called after generating, or modifying the vertices manually.
*/
public void apply() {
//vertices
Vector3f[] verticesArray = new Vector3f[vertices.size()];
for(int i = 0; i < vertices.size(); i++) {
verticesArray[i] = vertices.get(i);
}
mesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(verticesArray));
//texture coords
Vector2f[] texCoordsArray = new Vector2f[texCoords.size()];
for(int i = 0; i < texCoords.size(); i++) {
texCoordsArray[i] = texCoords.get(i);
}
mesh.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoordsArray));
//indices
int[] indicesArray = new int[indices.size()];
for(int i = 0; i < indices.size(); i++) {
indicesArray[i] = indices.get(i);
}
mesh.setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(indicesArray));
//update bounds
mesh.updateBound();
BoundingVolume v = mesh.getBound();
System.out.println(v.contains(new Vector3f(99f, 0, 99f)));// false (ought to be true)
}
}
True. It has 0 height so it doesn’t contain anything. So I guess that test is right to return false… and I was right to steer you away from early assumptions.
Doesn’t explain the frustum culling issue, though.
The mesh only needs tangents if you are doing bump mapping.
And yeah, lit meshes need normals or the light doesn’t know what direction the surface is. Note: the Quad source code is like two clicks away and sets everything needed for Lighting.j3md (without normalmaps or bumpmaps).
What the… I swear it looked OK earlier… with the unshaded material…
Hm. Does it matter in what order I define the vertices?.. It seemed to me that the only requirement is that the indices (triangles) connect the right vertices (obviously ) and that they’re connected in a counter-clockwise fashion. Which I am doing.