kajos
May 3, 2011, 9:32am
1
Hi,
I’m trying to port a JME2 “engine” to JME3, however I get a memory access violation. The engine is for marching tetrahedrons and its original version is here: https://wiki.jmonkeyengine.org/legacy/doku.php/jme2:rendering_scalar_fields?s[]=marching&s[]=cubes
I changed:
TriangleBatch batch = mesh.getBatch(0);
batch.setIndexBuffer(BufferUtils.createIntBuffer(triangles.toNativeArray()));
batch.setVertexBuffer(BufferUtils.createVector3Buffer(vertexList.size()/3));
batch.setNormalBuffer(BufferUtils.createVector3Buffer(vertexList.size()/3));
batch.setVertexCount(vertexList.size()/3);
//batch.getTextureBuffers().set(0, BufferUtils.createVector2Buffer(???));
FloatBuffer vb = batch.getVertexBuffer();
FloatBuffer nb = batch.getNormalBuffer();
for (int i = 0; i < vertexList.size(); i++) {
vb.put(vertexList.get(i));
nb.put(normalList.get(i));
}
to
mesh.setBuffer(Type.Normal, vertexList.size()/3, BufferUtils.createVector3Buffer(vertexList.size()/3));
mesh.setBuffer(Type.Position, vertexList.size()/3, BufferUtils.createVector3Buffer(vertexList.size()/3));
FloatBuffer vb = mesh.getFloatBuffer(Type.Position);
FloatBuffer nb = mesh.getFloatBuffer(Type.Normal);
for (int i = 0; i < vertexList.size(); i++) {
vb.put(vertexList.get(i));
nb.put(normalList.get(i));
}
and the TFloatArrayList to ArrayList etc.
The error
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x062fc11b, pid=4228, tid=4504
#
# JRE version: 6.0_23-b05
# Java VM: Java HotSpot(TM) Client VM (19.0-b09 mixed mode, sharing windows-x86 )
# Problematic frame:
# C [ig4icd32.dll+0x12c11b]
#
# An error report file with more information is saved as:
# C:UsersKajosDocumentsjMonkeyProjectsCitySccapehs_err_pid4228.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
So the crash happens somewhere in the rendering right?
Any help would be great! Or maybe a tip on another voxel based engine?
Greetings,
Kajos
90% sure that this:
[java]mesh.setBuffer(Type.Normal, vertexList.size()/3, BufferUtils.createVector3Buffer(vertexList.size()/3));
mesh.setBuffer(Type.Position, vertexList.size()/3, BufferUtils.createVector3Buffer(vertexList.size()/3));[/java]
Should really be more like this:
[java]mesh.setBuffer(Type.Normal, 3, BufferUtils.createVector3Buffer(vertexList.size()/3));
mesh.setBuffer(Type.Position, 3, BufferUtils.createVector3Buffer(vertexList.size()/3));[/java]
kajos
May 3, 2011, 10:27am
3
Thanks! That did the trick! However, I still dont get quite the effect that Im after; instead of Tetrahedrons I get triangles or something not quite right.
I’ve never created a mesh without indexes before… so I’m not sure I can help any further. It does look similar to index problems, though.
nehon
May 3, 2011, 11:28am
5
pspeed said:
I've never created a mesh without indexes before...
Well...is that even possible? Not in jME3 anyway.
@kajos You have to specify the index buffer so the mesh displays correctly
This doc can help
https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:custom_meshes
Alternatively, you can use the very same code that I ported to jME3 a while back
[java]
import com.jme3.math.ColorRGBA;
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.util.BufferUtils;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Map;
/**
Based on Paul Bourke’s code from “Polygonising a Scalar Field Using Tetrahedrons”
http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/
*
@author Daniel Gronau
@author Irrisor (replaced array lists by using buffers)
@author basixs (replaced creation of objects with global ‘calc’ vectors, for better performance)
*/
public class ScalarFieldPolygonisator {
private final ScalarField scalarField;
private final Vector3f boxSize;
private final float cubeSize;
public final float[][][] field;
private final Vector3f[] cellPoints = new Vector3f[] {
new Vector3f(), new Vector3f(), new Vector3f(), new Vector3f(),
new Vector3f(), new Vector3f(), new Vector3f(), new Vector3f()
};
private final int[] gridVal = new int[ 8 ];
private final Map<Edge, Integer> interpol = new HashMap<Edge, Integer>(5000);
private final Edge tmpEdge = new Edge();
private final int xSize;
private final int ySize;
private final int zSize;
private FloatBuffer vertexBuffer;
private FloatBuffer normalBuffer;
private IntBuffer indexBuffer;
private FloatBuffer textureBuffer;
private FloatBuffer colorBuffer;
//
// Temporary calc vars
private final ColorRGBA calcColor = new ColorRGBA();
private final Vector3f calcVector = new Vector3f();
private final Vector3f calcVector1 = new Vector3f();
private final Vector2f calcVector2f = new Vector2f();
public ScalarFieldPolygonisator(Vector3f boxSize, float cubeSize, final ScalarField field) {
this.boxSize = boxSize;
this.cubeSize = cubeSize;
xSize = (int) FastMath.ceil(2 * boxSize.x / cubeSize);
ySize = (int) FastMath.ceil(2 * boxSize.y / cubeSize);
zSize = (int) FastMath.ceil(2 * boxSize.z / cubeSize);
this.field = new float[xSize + 1][ySize + 1][zSize + 1];
this.scalarField = field;
}
/**
Updates all cells with a given iso
@param iso
*/
protected void calculateCells(final float iso) {
for(int x = 0; x < xSize; x++) {
for(int y = 0; y < ySize; y++) {
for(int z = 0; z < zSize; z++) {
calculateCell(iso, x, y, z);
}
}
}
}
/**
Updates a given cell with a given iso
@param iso cutoff value
@param xk
@param yk
@param zk
@return result
/
protected int calculateCell(final float iso, final int xk, final int yk, final int zk) {
int cubeIndex = 0;
gridVal[0] = field[xk][yk][zk] > iso ? 1 : 0;
gridVal[1] = field[xk + 1][yk][zk] > iso ? 1 : 0; // go left
gridVal[2] = field[xk + 1][yk][zk + 1] > iso ? 1 : 0; // go left
gridVal[3] = field[xk][yk][zk + 1] > iso ? 1 : 0; // go left
gridVal[4] = field[xk][yk + 1][zk] > iso ? 1 : 0; // go left and up
gridVal[5] = field[xk + 1][yk + 1][zk] > iso ? 1 : 0; // go left
gridVal[6] = field[xk + 1][yk + 1][zk + 1] > iso ? 1 : 0; // go left
gridVal[7] = field[xk][yk + 1][zk + 1] > iso ? 1 : 0; // go left
for(int i = 0; i < gridVal.length; ++i) {
cubeIndex |= (gridVal == 1 ? (1 << i) : 0);
}
if(cubeIndex == 0 || cubeIndex == 255) {
return cubeIndex; // 0 = all vertices inside, 255 = all vertices above
}
calcVector.x = xk * cubeSize - boxSize.x;
calcVector.y = yk * cubeSize - boxSize.y;
calcVector.z = zk * cubeSize - boxSize.z;
calcVector1.x = calcVector.x + cubeSize;
calcVector1.y = calcVector.y + cubeSize;
calcVector1.z = calcVector.z + cubeSize;
cellPoints[0].set(calcVector.x, calcVector.y, calcVector.z);
cellPoints[1].set(calcVector1.x, calcVector.y, calcVector.z);
cellPoints[2].set(calcVector1.x, calcVector.y, calcVector1.z);
cellPoints[3].set(calcVector.x, calcVector.y, calcVector1.z);
cellPoints[4].set(calcVector.x, calcVector1.y, calcVector.z);
cellPoints[5].set(calcVector1.x, calcVector1.y, calcVector.z);
cellPoints[6].set(calcVector1.x, calcVector1.y, calcVector1.z);
cellPoints[7].set(calcVector.x, calcVector1.y, calcVector1.z);
calculateTetra(iso, 0, 4, 7, 6, xk, yk, zk);
calculateTetra(iso, 0, 4, 6, 5, xk, yk, zk);
calculateTetra(iso, 0, 2, 6, 3, xk, yk, zk);
calculateTetra(iso, 0, 1, 6, 2, xk, yk, zk);
calculateTetra(iso, 0, 3, 6, 7, xk, yk, zk);
calculateTetra(iso, 0, 1, 5, 6, xk, yk, zk);
// return the cell triangle bits
return cubeIndex;
}
private void calculateTetra(final float iso, final int v0, final int v1, final int v2, final int v3, final int xk, final int yk, final int zk) {
final int triindex = gridVal[v0] + (gridVal[v1] * 2) + (gridVal[v2] * 4) + (gridVal[v3] * 8);
/ Form the vertices of the triangles for each case */
switch(triindex) {
case 0x00: // 0
case 0x0F: // 255
break;
case 0x0E:
addIndex(interpolate(iso, v0, v3, xk, yk, zk));
addIndex(interpolate(iso, v0, v2, xk, yk, zk));
addIndex(interpolate(iso, v0, v1, xk, yk, zk));
break;
case 0x01:
addIndex(interpolate(iso, v0, v2, xk, yk, zk));
addIndex(interpolate(iso, v0, v3, xk, yk, zk));
addIndex(interpolate(iso, v0, v1, xk, yk, zk));
break;
case 0x0D:
addIndex(interpolate(iso, v1, v2, xk, yk, zk));
addIndex(interpolate(iso, v1, v3, xk, yk, zk));
addIndex(interpolate(iso, v0, v1, xk, yk, zk));
break;
case 0x02:
addIndex(interpolate(iso, v1, v3, xk, yk, zk));
addIndex(interpolate(iso, v1, v2, xk, yk, zk));
addIndex(interpolate(iso, v0, v1, xk, yk, zk));
break;
case 0x0C: {
int temp1 = interpolate(iso, v0, v2, xk, yk, zk);
int temp2 = interpolate(iso, v1, v3, xk, yk, zk);
addIndex(temp1);
addIndex(temp2);
addIndex(interpolate(iso, v0, v3, xk, yk, zk));
addIndex(temp1);
addIndex(interpolate(iso, v1, v2, xk, yk, zk));
addIndex(temp2);
break;
}
case 0x03: {
int temp1 = interpolate(iso, v0, v2, xk, yk, zk);
int temp2 = interpolate(iso, v1, v3, xk, yk, zk);
addIndex(temp2);
addIndex(temp1);
addIndex(interpolate(iso, v0, v3, xk, yk, zk));
addIndex(interpolate(iso, v1, v2, xk, yk, zk));
addIndex(temp1);
addIndex(temp2);
break;
}
case 0x0B:
addIndex(interpolate(iso, v2, v3, xk, yk, zk));
addIndex(interpolate(iso, v1, v2, xk, yk, zk));
addIndex(interpolate(iso, v0, v2, xk, yk, zk));
break;
case 0x04:
addIndex(interpolate(iso, v1, v2, xk, yk, zk));
addIndex(interpolate(iso, v2, v3, xk, yk, zk));
addIndex(interpolate(iso, v0, v2, xk, yk, zk));
break;
case 0x0A: {
int temp1 = interpolate(iso, v0, v1, xk, yk, zk);
int temp2 = interpolate(iso, v2, v3, xk, yk, zk);
addIndex(interpolate(iso, v0, v3, xk, yk, zk));
addIndex(temp2);
addIndex(temp1);
addIndex(temp2);
addIndex(interpolate(iso, v1, v2, xk, yk, zk));
addIndex(temp1);
break;
}
case 0x05: {
int temp1 = interpolate(iso, v0, v1, xk, yk, zk);
int temp2 = interpolate(iso, v2, v3, xk, yk, zk);
addIndex(temp2);
addIndex(interpolate(iso, v0, v3, xk, yk, zk));
addIndex(temp1);
addIndex(interpolate(iso, v1, v2, xk, yk, zk));
addIndex(temp2);
addIndex(temp1);
break;
}
case 0x09: {
int temp1 = interpolate(iso, v0, v1, xk, yk, zk);
int temp2 = interpolate(iso, v2, v3, xk, yk, zk);
addIndex(temp2);
addIndex(interpolate(iso, v1, v3, xk, yk, zk));
addIndex(temp1);
addIndex(interpolate(iso, v0, v2, xk, yk, zk));
addIndex(temp2);
addIndex(temp1);
break;
}
case 0x06: {
int temp1 = interpolate(iso, v0, v1, xk, yk, zk);
int temp2 = interpolate(iso, v2, v3, xk, yk, zk);
addIndex(interpolate(iso, v1, v3, xk, yk, zk));
addIndex(temp2);
addIndex(temp1);
addIndex(temp2);
addIndex(interpolate(iso, v0, v2, xk, yk, zk));
addIndex(temp1);
break;
}
case 0x07:
addIndex(interpolate(iso, v1, v3, xk, yk, zk));
addIndex(interpolate(iso, v2, v3, xk, yk, zk));
addIndex(interpolate(iso, v0, v3, xk, yk, zk));
break;
case 0x08:
addIndex(interpolate(iso, v2, v3, xk, yk, zk));
addIndex(interpolate(iso, v1, v3, xk, yk, zk));
addIndex(interpolate(iso, v0, v3, xk, yk, zk));
break;
}
}
private int interpolate(float iso, int v1, int v2, int xk, int yk, int zk) {
if(v1 > v2) {
final int tmp = v2;
v2 = v1;
v1 = tmp;
}
switch(v1) {
default:
tmpEdge.x1 = xk;
tmpEdge.y1 = yk;
tmpEdge.z1 = zk;
break;
case 1:
tmpEdge.x1 = xk + 1;
tmpEdge.y1 = yk;
tmpEdge.z1 = zk;
break;
case 2:
tmpEdge.x1 = xk + 1;
tmpEdge.y1 = yk;
tmpEdge.z1 = zk + 1;
break;
case 3:
tmpEdge.x1 = xk;
tmpEdge.y1 = yk;
tmpEdge.z1 = zk + 1;
break;
case 4:
tmpEdge.x1 = xk;
tmpEdge.y1 = yk + 1;
tmpEdge.z1 = zk;
break;
case 5:
tmpEdge.x1 = xk + 1;
tmpEdge.y1 = yk + 1;
tmpEdge.z1 = zk;
break;
case 6:
tmpEdge.x1 = xk + 1;
tmpEdge.y1 = yk + 1;
tmpEdge.z1 = zk + 1;
break;
case 7:
tmpEdge.x1 = xk;
tmpEdge.y1 = yk + 1;
tmpEdge.z1 = zk + 1;
break;
}
switch(v2) {
default:
tmpEdge.x2 = xk;
tmpEdge.y2 = yk;
tmpEdge.z2 = zk;
break;
case 1:
tmpEdge.x2 = xk + 1;
tmpEdge.y2 = yk;
tmpEdge.z2 = zk;
break;
case 2:
tmpEdge.x2 = xk + 1;
tmpEdge.y2 = yk;
tmpEdge.z2 = zk + 1;
break;
case 3:
tmpEdge.x2 = xk;
tmpEdge.y2 = yk;
tmpEdge.z2 = zk + 1;
break;
case 4:
tmpEdge.x2 = xk;
tmpEdge.y2 = yk + 1;
tmpEdge.z2 = zk;
break;
case 5:
tmpEdge.x2 = xk + 1;
tmpEdge.y2 = yk + 1;
tmpEdge.z2 = zk;
break;
case 6:
tmpEdge.x2 = xk + 1;
tmpEdge.y2 = yk + 1;
tmpEdge.z2 = zk + 1;
break;
case 7:
tmpEdge.x2 = xk;
tmpEdge.y2 = yk + 1;
tmpEdge.z2 = zk + 1;
break;
}
final Integer index = interpol.get(tmpEdge);
if(index != null) {
return index;
}
float ratio = 0.5f;
final float value1 = tmpEdge.getValue1(this);
final float value2 = tmpEdge.getValue2(this);
if(value1 != value2) {
ratio = (value1 - iso) / (value1 - value2);
}
final int currentVertexIndex = vertexBuffer.position() / 3;
calcVector1.set(cellPoints[v2].mult(ratio));
calcVector.set(cellPoints[v1]).multLocal(1 - ratio).addLocal(calcVector1);
addVertex(calcVector.x, calcVector.y, calcVector.z);
scalarField.normal(calcVector, calcVector1);
addNormal(calcVector1.x, calcVector1.y, calcVector1.z);
scalarField.textureCoords(calcVector1, calcVector2f);
addTextureCoord(calcVector2f.x, calcVector2f.y);
scalarField.color(calcVector, calcColor);
addColor(calcColor.r, calcColor.g, calcColor.b, calcColor.a);
interpol.put(new Edge(tmpEdge), currentVertexIndex);
return currentVertexIndex;
}
public void calculate(Mesh mesh, float iso) {
precalc(mesh);
clearField(); // tmp
populateFieldArray(scalarField); // tmp
calculateCells(iso); // tmp
postcalc(mesh);
}
public void precalc(Mesh mesh) {
vertexBuffer = mesh.getFloatBuffer(Type.Position);
if(vertexBuffer == null) {
vertexBuffer = BufferUtils.createFloatBuffer(16000 * 3);
} else {
vertexBuffer.clear();
}
normalBuffer = mesh.getFloatBuffer(Type.Normal);
if(normalBuffer == null) {
normalBuffer = BufferUtils.createFloatBuffer(16000 * 3);
} else {
normalBuffer.clear();
}
colorBuffer = mesh.getFloatBuffer(Type.Color);
if(colorBuffer == null) {
colorBuffer = BufferUtils.createFloatBuffer(16000 * 4);
} else {
colorBuffer.clear();
}
// final TexCoords texCoords = mesh.getTextureCoords(0);
// if(texCoords != null) {
// textureBuffer = texCoords.coords;
// } else {
// textureBuffer = null;
// }
textureBuffer = mesh.getFloatBuffer(Type.TexCoord);
if(textureBuffer == null) {
textureBuffer = BufferUtils.createFloatBuffer(16000 * 2);
} else {
textureBuffer.clear();
}
VertexBuffer vb = mesh.getBuffer(Type.Index);
if(vb != null) {
indexBuffer = (IntBuffer) vb.getData();
} else {
indexBuffer = null;
}
if(indexBuffer == null) {
indexBuffer = BufferUtils.createIntBuffer(16000 * 1);
} else {
indexBuffer.clear();
}
}
public void postcalc(Mesh mesh) {
indexBuffer.flip();
mesh.clearBuffer(Type.Index);
mesh.setBuffer(Type.Index, 1, indexBuffer);
vertexBuffer.flip();
mesh.clearBuffer(Type.Position);
mesh.setBuffer(Type.Position, 3, vertexBuffer);
normalBuffer.flip();
mesh.clearBuffer(Type.Normal);
mesh.setBuffer(Type.Normal, 3, normalBuffer);
colorBuffer.flip();
mesh.clearBuffer(Type.Color);
mesh.setBuffer(Type.Color, 4, colorBuffer);
// mesh.setTriangleCount(indexBuffer.limit() / 3);
// mesh.setVertexCount(vertexBuffer.limit() / 3);
mesh.updateCounts();
mesh.updateBound();
textureBuffer.flip();
mesh.clearBuffer(Type.TexCoord);
mesh.setBuffer(Type.TexCoord, 2, textureBuffer);
// mesh.setTextureCoords(new TexCoords(textureBuffer));
}
protected void clearField() {
interpol.clear();
for(int x = 0; x < xSize; x++) {
for(int y = 0; y < ySize; y++) {
for(int z = 0; z < zSize; z++) {
field[x][y][z] = 0;
}
}
}
}
protected void populateFieldArray(ScalarField field) {
for(int x = 0; x < xSize; x++) {
for(int y = 0; y < ySize; y++) {
for(int z = 0; z < zSize; z++) {
gridToWorld(x, y, z, calcVector);
this.field[x][y][z] = field.weightAtPoint(calcVector);
}
}
}
}
protected void gridToWorld(final int x, final int y, final int z, final Vector3f store) {
store.setX(x * cubeSize - boxSize.x);
store.setY(y * cubeSize - boxSize.y);
store.setZ(z * cubeSize - boxSize.z);
}
protected void worldToGrid(final Vector3f world, final int[] store) {
worldToGrid(world.getX(), world.getY(), world.getZ(), store);
}
protected void worldToGrid(final float x, final float y, final float z, final int[] store) {
store[0] = new Float((x + boxSize.x) / cubeSize + 0.5f).intValue();
store[1] = new Float((y + boxSize.y) / cubeSize + 0.5f).intValue();
store[2] = new Float((z + boxSize.z) / cubeSize + 0.5f).intValue();
}
private void addIndex(int index) {
indexBuffer = enlargeIfNeeded(indexBuffer);
indexBuffer.put(index);
}
private void addVertex(float x, float y, float z) {
vertexBuffer = enlargeIfNeeded(vertexBuffer);
vertexBuffer.put(x).put(y).put(z);
}
private void addNormal(float x, float y, float z) {
normalBuffer = enlargeIfNeeded(normalBuffer);
normalBuffer.put(x).put(y).put(z);
}
private void addColor(float r, float g, float b, float a) {
colorBuffer = enlargeIfNeeded(colorBuffer);
colorBuffer.put®.put(g).put(b).put(a);
}
private void addTextureCoord(float x, float y) {
textureBuffer = enlargeIfNeeded(textureBuffer);
textureBuffer.put(x).put(y);
}
private IntBuffer enlargeIfNeeded(IntBuffer buffer) {
// System.out.println("Enlarging");
if(buffer.capacity() == buffer.position()) {
final IntBuffer oldBuffer = buffer;
buffer = BufferUtils.createIntBuffer(oldBuffer.capacity() * 2);
oldBuffer.flip();
buffer.put(oldBuffer);
}
return buffer;
}
private FloatBuffer enlargeIfNeeded(FloatBuffer buffer) {
// System.out.println("Enlarging");
if(buffer.capacity() < buffer.position() + 4) {
final FloatBuffer oldBuffer = buffer;
buffer = BufferUtils.createFloatBuffer(oldBuffer.capacity() * 2);
oldBuffer.flip();
buffer.put(oldBuffer);
}
return buffer;
}
static class Edge {
int x1, y1, z1, x2, y2, z2;
private Edge() { }
public Edge(Edge e) {
x1 = e.x1;
y1 = e.y1;
z1 = e.z1;
x2 = e.x2;
y2 = e.y2;
z2 = e.z2;
}
@Override
public int hashCode() {
int hash = 3;
hash = 59 * hash + this.x1;
hash = 61 * hash + this.y1;
hash = 67 * hash + this.z1;
hash = 71 * hash + this.x2;
hash = 73 * hash + this.y2;
hash = 79 * hash + this.z2;
return hash;
}
@Override
public boolean equals(Object o) {
if(o instanceof Edge) {
Edge e = (Edge) o;
return x1 == e.x1 && y1 == e.y1 && z1 == e.z1 && x2 == e.x2 && y2 == e.y2 && z2 == e.z2;
}
return false;
}
public float getValue1(ScalarFieldPolygonisator t) {
return t.field[x1][y1][z1];
}
public float getValue2(ScalarFieldPolygonisator t) {
return t.field[x2][y2][z2];
}
}
}
[/java]
1 Like
kajos
May 3, 2011, 11:56am
7
Cool, thanks, could you maybe upload the src in a rar? I get some serious parse errors.
EDIT: Nvm, found it. Its called cave3d for jme.
kajos
May 3, 2011, 9:36pm
8
Did anyone do true voxels already (not polygonal ones) or is anybody experienced with that? Im about to read a paper on it, but is it possible at all in jme? I’m looking for an effect like voxelstein’s.
nehon
May 4, 2011, 7:12am
9
kajos
May 4, 2011, 8:49am
10
Ha, yeah, something like that, but not polygonal, but 100% voxels (yummi).