I know the theory of glFrustumf and glOrthof but I'm quite
puzzled by the fact that there is another parameter in android
method that sets projection which is mOffset which does not exist in normal OpenGL implementation.``
public static void orthoM(float[] m, int mOffset, <---- mOffset
float left, float right, float bottom, float top,
float near, float far)
In the implementation it seems that this mOffset parameter shifts matrix index by the value that is setted:
m[mOffset + 0] = x;
m[mOffset + 5] = y;
m[mOffset +10] = z;
m[mOffset +12] = tx;
m[mOffset +13] = ty;
m[mOffset +14] = tz;
m[mOffset +15] = 1.0f;
m[mOffset + 1] = 0.0f;
m[mOffset + 2] = 0.0f;
m[mOffset + 3] = 0.0f;
m[mOffset + 4] = 0.0f;
m[mOffset + 6] = 0.0f;
m[mOffset + 7] = 0.0f;
m[mOffset + 8] = 0.0f;
m[mOffset + 9] = 0.0f;
m[mOffset + 11] = 0.0f;
Can anyone please explain why would you ever need to offset matrix index for the projection? What is a purpouse of mOffset?
Related
I am trying to have a JavaFX 3D Sphere, textured with a texture of the earth. The texture is this one (from Wikipedia, an equirectangular projection):
The sphere is rendered as follows:
You can clearly see that, at the poles, the texture is not preserving the proportions anymore. I found a bug files on the openJDK system, which I think is related to this behaviour: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8092112
Sadly, in 7 years nobody made the change that the person filing the bug requested. Do you know if there is an alternative way to properly render an equirectangular sphere projection on a JavaFX 3D Sphere?
Just for reference, the code that I using is:
Sphere earthSphere = new Sphere(EARTH_RADIUS, 256);
PhongMaterial material = new PhongMaterial();
material.setDiffuseMap(new Image(Main.class.getResourceAsStream("/images/earth2.jpg")));
earthSphere.setMaterial(material);
At the end I implement it myself using a mesh, for the purposes I needed for. Here is the code, in case you are interested (it will end up in a GitHub project anyway):
public static Group createEarthSphere() {
// Use triangular mesh
int latLevels = 90;
int lonLevels = 180;
TriangleMesh mesh = new TriangleMesh(VertexFormat.POINT_NORMAL_TEXCOORD);
double radius = EARTH_RADIUS;
double latIncAngle = (Math.PI/latLevels);
double lonIncAngle = (Math.PI * 2)/lonLevels;
double textLatIncr = 1.0/latLevels;
double textLonIncr = 1.0/lonLevels;
int currentPointOffset = 0;
int currentNormalOffset = 0;
int currentTextOffset = 0;
for(int i = 0; i < latLevels; ++i) {
for(int j = 0; j < lonLevels; ++j) {
// The point list is: top left - bottom left - bottom right - top right
// The faces-normal points are: (0,0) (1,1) (2,2) (0,3) (2,4) (3,5)
Point3D tp1 = new Point3D(0,radius * Math.cos(Math.PI - (i * latIncAngle)), radius * Math.sin(Math.PI - (i * latIncAngle)));
Point3D tp2 = new Point3D(0,radius * Math.cos(Math.PI - (i * latIncAngle + latIncAngle)), radius * Math.sin(Math.PI - (i * latIncAngle + latIncAngle)));
Point3D topLeft = new Rotate(Math.toDegrees(j * lonIncAngle), new Point3D(0, 1, 0)).transform(tp1);
Point3D bottomLeft = new Rotate(Math.toDegrees(j * lonIncAngle), new Point3D(0, 1, 0)).transform(tp2);
Point3D bottomRight = new Rotate(Math.toDegrees(j * lonIncAngle + lonIncAngle), new Point3D(0, 1, 0)).transform(tp2);
Point3D topRight = new Rotate(Math.toDegrees(j * lonIncAngle + lonIncAngle), new Point3D(0, 1, 0)).transform(tp1);
// Compute normals
Point3D topLeftNormal_1 = computeNormal(topLeft, bottomLeft, bottomRight); // 0
Point3D bottomLeftNormal_1 = computeNormal(bottomLeft, bottomRight, topLeft); // 1
Point3D bottomRightNormal_1 = computeNormal(bottomRight, topLeft, bottomLeft); // 2
Point3D topLeftNormal_2 = computeNormal(topLeft, bottomRight, topRight); // 3
Point3D bottomRightNormal_2 = computeNormal(bottomRight, topRight, topLeft); // 4
Point3D topRightNormal_2 = computeNormal(topRight, topLeft, bottomRight); // 5
// Add points
mesh.getPoints().addAll((float) topLeft.getX(), (float) topLeft.getY(), (float) topLeft.getZ()); // 0
mesh.getPoints().addAll((float) bottomLeft.getX(), (float) bottomLeft.getY(), (float) bottomLeft.getZ()); // 1
mesh.getPoints().addAll((float) bottomRight.getX(), (float) bottomRight.getY(), (float) bottomRight.getZ()); // 2
mesh.getPoints().addAll((float) topRight.getX(), (float) topRight.getY(), (float) topRight.getZ()); // 3
// Add normals
mesh.getNormals().addAll((float) topLeftNormal_1.getX(), (float) topLeftNormal_1.getY(), (float) topLeftNormal_1.getZ()); // 0
mesh.getNormals().addAll((float) bottomLeftNormal_1.getX(), (float) bottomLeftNormal_1.getY(), (float) bottomLeftNormal_1.getZ()); // 1
mesh.getNormals().addAll((float) bottomRightNormal_1.getX(), (float) bottomRightNormal_1.getY(), (float) bottomRightNormal_1.getZ()); // 2
mesh.getNormals().addAll((float) topLeftNormal_2.getX(), (float) topLeftNormal_2.getY(), (float) topLeftNormal_2.getZ()); // 3
mesh.getNormals().addAll((float) bottomRightNormal_2.getX(), (float) bottomRightNormal_2.getY(), (float) bottomRightNormal_2.getZ()); // 4
mesh.getNormals().addAll((float) topRightNormal_2.getX(), (float) topRightNormal_2.getY(), (float) topRightNormal_2.getZ()); // 5
// Add texture
float[] p0t = { (float) (i * textLatIncr), 1.0f - (float) (j * textLonIncr) };
float[] p1t = { (float) (i * textLatIncr + textLatIncr), 1.0f - (float) (j * textLonIncr) };
float[] p2t = { (float) (i * textLatIncr + textLatIncr), 1.0f - (float) (j * textLonIncr + textLonIncr) };
float[] p3t = { (float) (i * textLatIncr), 1.0f - (float) (j * textLonIncr + textLonIncr) };
mesh.getTexCoords().addAll(
p0t[1], p0t[0],
p1t[1], p1t[0],
p2t[1], p2t[0],
p3t[1], p3t[0]
);
// Add faces
mesh.getFaces().addAll(
currentPointOffset + 0, currentNormalOffset + 0, currentTextOffset + 0,
currentPointOffset + 2, currentNormalOffset + 2, currentTextOffset + 2,
currentPointOffset + 1, currentNormalOffset + 1, currentTextOffset + 1,
currentPointOffset + 0, currentNormalOffset + 3, currentTextOffset + 0,
currentPointOffset + 3, currentNormalOffset + 5, currentTextOffset + 3,
currentPointOffset + 2, currentNormalOffset + 4, currentTextOffset + 2
);
currentPointOffset += 4;
currentNormalOffset += 6;
currentTextOffset += 4;
}
}
MeshView meshView = new MeshView(mesh);
meshView.setCullFace(CullFace.BACK);
PhongMaterial material = new PhongMaterial();
material.setDiffuseMap(new Image(Main.class.getResourceAsStream("/images/earth.jpg")));
meshView.setMaterial(material);
return new Group(meshView);
}
private static Point3D computeNormal(Point3D p1, Point3D p2, Point3D p3) {
return (p3.subtract(p1).normalize()).crossProduct(p2.subtract(p1).normalize()).normalize();
}
The result is:
Now everything is exactly where it should be, and lat/lon are correctly matching the texture.
Im trying to work out how to smooth a big list of longitude latitude points i currently draw a line from point to point and interpolate each point in-between but as i change direction it shows a sharp turn where i would like to smooth this out to a neat curve, but i dont know exactly where the turns are so i need an algorithm to smooth over an average of points.
I have done some research into this already and had a look at the Bezier curve but does not work as i expect, i took the implementation that i found here.
http://sourcecodesforfree.blogspot.co.uk/2013/05/33-bezier-curve.html
I cant really find much documentation on how the Bezier Curve algorithm works, or at least not fully understanding how it works.
function bspline(lats, lons) {
var i, t, ax, ay, bx, by, cx, cy, dx, dy, lat, lon, points;
points = [];
// For every point
for (i = 2; i < lats.length - 2; i++) {
for (t = 0; t < 1; t += 0.2) {
ax = (-lats[i - 2] + 3 * lats[i - 1] - 3 * lats[i] + lats[i + 1]) / 6;
ay = (-lons[i - 2] + 3 * lons[i - 1] - 3 * lons[i] + lons[i + 1]) / 6;
bx = (lats[i - 2] - 2 * lats[i - 1] + lats[i]) / 2;
by = (lons[i - 2] - 2 * lons[i - 1] + lons[i]) / 2;
cx = (-lats[i - 2] + lats[i]) / 2;
cy = (-lons[i - 2] + lons[i]) / 2;
dx = (lats[i - 2] + 4 * lats[i - 1] + lats[i]) / 6;
dy = (lons[i - 2] + 4 * lons[i - 1] + lons[i]) / 6;
lat = ax * Math.pow(t + 0.1, 3) + bx * Math.pow(t + 0.1, 2) + cx * (t + 0.1) + dx;
lon = ay * Math.pow(t + 0.1, 3) + by * Math.pow(t + 0.1, 2) + cy * (t + 0.1) + dy;
points.push(new google.maps.LatLng(lat, lon));
}
}
return points;
}
Above code in JavaScript else logic are same just change bit variables and method as JAVA then check
Or
please find an Algorithm from this link en.wikipedia.org/wiki/Interpolation#Linear_interpolation
This is a follow-up question of my previous question in here: How to draw the middle half of a sphere (in code)
We've already created the middle half of a sphere. My problem is how can I split the middle part into 4 similar parts (each as shown with 90 degree)? I already did 4 vertical parts for a full sphere simply with phi0/=4; and phi1/=4; in the slice loop and it was working perfectly. I did the same trick for the middle body that we got, but I see some edging problems on top and bottom boundaries when the top cap and bottom cap are connecting to the body. What is wrong with my approach?
Here is the popular code for generating a sphere programmatically:
UPDATE: It is not easy for me to take a screenshot, now. So basically when I texture all parts, I see they are not smoothly connected at the top and bottom boundaries. Splitting within the middle body is just fine.
private void generateSphere(int stackNumber, int sliceNumber, boolean facingOut) {
int capVertexNumber = 3 * sliceNumber;
int bodyVertexNumber = 4 * sliceNumber * (stackNumber - 2);
int vertexNumber = (2 * capVertexNumber) + bodyVertexNumber;
int triangleNumber = (2 * capVertexNumber) + (6 * sliceNumber * (stackNumber - 2));
vertices = new float[3 * vertexNumber];
normals = new float[3 * vertexNumber];
texCoords = new float[2 * vertexNumber];
indices = new char[triangleNumber];
// bottom cap
// createCap(stackNumber, sliceNumber, false, facingOut);
// body
createBody(stackNumber, sliceNumber, facingOut);
// top cap
createCap(stackNumber, sliceNumber, true, facingOut);
}
private void createCap(int stackNumber, int sliceNumber, boolean top, boolean facingOut) {
float stackPercentage0;
float stackPercentage1;
if (!top) {
stackPercentage0 = ((float) (stackNumber - 1) / stackNumber);
stackPercentage1 = 1.0f;
} else {
stackPercentage0 = (1.0f / stackNumber);
stackPercentage1 = 0.0f;
}
float t0 = stackPercentage0;
float t1 = stackPercentage1;
double theta0 = stackPercentage0 * Math.PI;
double theta1 = stackPercentage1 * Math.PI;
double cosTheta0 = Math.cos(theta0);
double sinTheta0 = Math.sin(theta0);
double cosTheta1 = Math.cos(theta1);
double sinTheta1 = Math.sin(theta1);
for (int slice = 0; slice < sliceNumber; slice++) {
float slicePercentage0 = ((float) (slice) / sliceNumber);
float slicePercentage1 = ((float) (slice + 1) / sliceNumber);
double phi0 = slicePercentage0 * 2.0 * Math.PI;
double phi1 = slicePercentage1 * 2.0 * Math.PI;
float s0, s1;
if (facingOut) {
s0 = 1 - slicePercentage0;
s1 = 1 - slicePercentage1;
} else {
s0 = slicePercentage0;
s1 = slicePercentage1;
}
float s2 = (s0 + s1) / 2.0f;
double cosPhi0 = Math.cos(phi0);
double sinPhi0 = Math.sin(phi0);
double cosPhi1 = Math.cos(phi1);
double sinPhi1 = Math.sin(phi1);
float x0 = (float) (sinTheta0 * cosPhi0);
float y0 = (float) cosTheta0;
float z0 = (float) (sinTheta0 * sinPhi0);
float x1 = (float) (sinTheta0 * cosPhi1);
float y1 = (float) cosTheta0;
float z1 = (float) (sinTheta0 * sinPhi1);
float x2 = (float) (sinTheta1 * cosPhi0);
float y2 = (float) cosTheta1;
float z2 = (float) (sinTheta1 * sinPhi0);
vertices[vertexCount + 0] = x0;
vertices[vertexCount + 1] = y0;
vertices[vertexCount + 2] = z0;
vertices[vertexCount + 3] = x1;
vertices[vertexCount + 4] = y1;
vertices[vertexCount + 5] = z1;
vertices[vertexCount + 6] = x2;
vertices[vertexCount + 7] = y2;
vertices[vertexCount + 8] = z2;
if (facingOut) {
normals[vertexCount + 0] = x0;
normals[vertexCount + 1] = y0;
normals[vertexCount + 2] = z0;
normals[vertexCount + 3] = x1;
normals[vertexCount + 4] = y1;
normals[vertexCount + 5] = z1;
normals[vertexCount + 6] = x2;
normals[vertexCount + 7] = y2;
normals[vertexCount + 8] = z2;
} else {
normals[vertexCount + 0] = -x0;
normals[vertexCount + 1] = -y0;
normals[vertexCount + 2] = -z0;
normals[vertexCount + 3] = -x1;
normals[vertexCount + 4] = -y1;
normals[vertexCount + 5] = -z1;
normals[vertexCount + 6] = -x2;
normals[vertexCount + 7] = -y2;
normals[vertexCount + 8] = -z2;
}
texCoords[texCoordCount + 0] = s0;
texCoords[texCoordCount + 1] = t0;
texCoords[texCoordCount + 2] = s1;
texCoords[texCoordCount + 3] = t0;
texCoords[texCoordCount + 4] = s2;
texCoords[texCoordCount + 5] = t1;
if ((facingOut && top) || (!facingOut && !top)) {
indices[indexCount + 0] = (char) (triangleCount + 1);
indices[indexCount + 1] = (char) (triangleCount + 0);
indices[indexCount + 2] = (char) (triangleCount + 2);
} else {
indices[indexCount + 0] = (char) (triangleCount + 0);
indices[indexCount + 1] = (char) (triangleCount + 1);
indices[indexCount + 2] = (char) (triangleCount + 2);
}
vertexCount += 9;
texCoordCount += 6;
indexCount += 3;
triangleCount += 3;
}
}
private void createBody(int stackNumber, int sliceNumber, boolean facingOut) {
for (int stack = 1; stack < stackNumber - 1; stack++) {
float stackPercentage0 = ((float) (stack) / stackNumber);
float stackPercentage1 = ((float) (stack + 1) / stackNumber);
float t0 = stackPercentage0;
float t1 = stackPercentage1;
double theta0 = stackPercentage0 * Math.PI;
double theta1 = stackPercentage1 * Math.PI;
double cosTheta0 = Math.cos(theta0);
double sinTheta0 = Math.sin(theta0);
double cosTheta1 = Math.cos(theta1);
double sinTheta1 = Math.sin(theta1);
for (int slice = 0; slice < sliceNumber; slice++) {
float slicePercentage0 = ((float) (slice) / sliceNumber);
float slicePercentage1 = ((float) (slice + 1) / sliceNumber);
double phi0 = slicePercentage0 * 2.0 * Math.PI;
double phi1 = slicePercentage1 * 2.0 * Math.PI;
float s0, s1;
if (facingOut) {
s0 = 1.0f - slicePercentage0;
s1 = 1.0f - slicePercentage1;
} else {
s0 = slicePercentage0;
s1 = slicePercentage1;
}
double cosPhi0 = Math.cos(phi0);
double sinPhi0 = Math.sin(phi0);
double cosPhi1 = Math.cos(phi1);
double sinPhi1 = Math.sin(phi1);
float x0 = (float) (sinTheta0 * cosPhi0);
float y0 = (float) cosTheta0;
float z0 = (float) (sinTheta0 * sinPhi0);
float x1 = (float) (sinTheta0 * cosPhi1);
float y1 = (float) cosTheta0;
float z1 = (float) (sinTheta0 * sinPhi1);
float x2 = (float) (sinTheta1 * cosPhi0);
float y2 = (float) cosTheta1;
float z2 = (float) (sinTheta1 * sinPhi0);
float x3 = (float) (sinTheta1 * cosPhi1);
float y3 = (float) cosTheta1;
float z3 = (float) (sinTheta1 * sinPhi1);
vertices[vertexCount + 0] = x0;
vertices[vertexCount + 1] = y0;
vertices[vertexCount + 2] = z0;
vertices[vertexCount + 3] = x1;
vertices[vertexCount + 4] = y1;
vertices[vertexCount + 5] = z1;
vertices[vertexCount + 6] = x2;
vertices[vertexCount + 7] = y2;
vertices[vertexCount + 8] = z2;
vertices[vertexCount + 9] = x3;
vertices[vertexCount + 10] = y3;
vertices[vertexCount + 11] = z3;
if (facingOut) {
normals[vertexCount + 0] = x0;
normals[vertexCount + 1] = y0;
normals[vertexCount + 2] = z0;
normals[vertexCount + 3] = x1;
normals[vertexCount + 4] = y1;
normals[vertexCount + 5] = z1;
normals[vertexCount + 6] = x2;
normals[vertexCount + 7] = y2;
normals[vertexCount + 8] = z2;
normals[vertexCount + 9] = x3;
normals[vertexCount + 10] = y3;
normals[vertexCount + 11] = z3;
} else {
normals[vertexCount + 0] = -x0;
normals[vertexCount + 1] = -y0;
normals[vertexCount + 2] = -z0;
normals[vertexCount + 3] = -x1;
normals[vertexCount + 4] = -y1;
normals[vertexCount + 5] = -z1;
normals[vertexCount + 6] = -x2;
normals[vertexCount + 7] = -y2;
normals[vertexCount + 8] = -z2;
normals[vertexCount + 9] = -x3;
normals[vertexCount + 10] = -y3;
normals[vertexCount + 11] = -z3;
}
texCoords[texCoordCount + 0] = s0;
texCoords[texCoordCount + 1] = t0;
texCoords[texCoordCount + 2] = s1;
texCoords[texCoordCount + 3] = t0;
texCoords[texCoordCount + 4] = s0;
texCoords[texCoordCount + 5] = t1;
texCoords[texCoordCount + 6] = s1;
texCoords[texCoordCount + 7] = t1;
// one quad looking from outside toward center
//
// #formatter:off
//
// s1 --> s0
//
// t0 1-----0
// | | |
// v | |
// t1 3-----2
//
// #formatter:on
//
// Note that tex_coord t increase from top to bottom because the
// texture image is loaded upside down.
if (facingOut) {
indices[indexCount + 0] = (char) (triangleCount + 0);
indices[indexCount + 1] = (char) (triangleCount + 1);
indices[indexCount + 2] = (char) (triangleCount + 2);
indices[indexCount + 3] = (char) (triangleCount + 2);
indices[indexCount + 4] = (char) (triangleCount + 1);
indices[indexCount + 5] = (char) (triangleCount + 3);
} else {
indices[indexCount + 0] = (char) (triangleCount + 0);
indices[indexCount + 1] = (char) (triangleCount + 2);
indices[indexCount + 2] = (char) (triangleCount + 1);
indices[indexCount + 3] = (char) (triangleCount + 2);
indices[indexCount + 4] = (char) (triangleCount + 3);
indices[indexCount + 5] = (char) (triangleCount + 1);
}
vertexCount += 12;
texCoordCount += 8;
indexCount += 6;
triangleCount += 4;
}
}
}
I have my objects in a game engine described by two objects:
a position vector: (x, y, z); and
a rotation quaternion: (w, a, b, c)
I am now looking for the maths I need to build my model view matrix, I have a mathematics rather than programming background so the tutorials I have found reference functions, and I'd rather have a better understanding of the raw calculations.
It is being built in Java, with opengl as a rendering engine
As an aside, does anyone know of a method in java for setting the model matrix? Ie:
Float [3][3] matrix = new matrix;
ModelMatrix.set (matrix)
?
Here's the method from jMonkeyEngine's Quaternion class
It's for a 4x4 matrix structured in a float[16].
public float[] toRotationMatrix(float[] result) {
float norm = norm();
// we explicitly test norm against one here, saving a division
// at the cost of a test and branch. Is it worth it?
float s = (norm == 1f) ? 2f : (norm > 0f) ? 2f / norm : 0;
// compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
// will be used 2-4 times each.
float xs = x * s;
float ys = y * s;
float zs = z * s;
float xx = x * xs;
float xy = x * ys;
float xz = x * zs;
float xw = w * xs;
float yy = y * ys;
float yz = y * zs;
float yw = w * ys;
float zz = z * zs;
float zw = w * zs;
// using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here
result[0] = 1 - (yy + zz);
result[1] = (xy - zw);
result[2] = (xz + yw);
result[4] = (xy + zw);
result[5] = 1 - (xx + zz);
result[6] = (yz - xw);
result[8] = (xz - yw);
result[9] = (yz + xw);
result[10] = 1 - (xx + yy);
return result;
}
Since you're asking for the whole model matrix:
Translation occupies position 3, 7 , 11 in the same matrix.
Edit: A lookup showed i was wrong about the scale.
This is what I use, with q being the Quaternion:
matrix = new float[3][3];
float x2 = q.x*q.x, y2 = q.y*q.y, z2 = q.z*q.z;
matrix[0][0] = (1-2*z2-2*y2);
matrix[0][1] = (2*q.x*q.y+2*q.w*q.z);
matrix[0][2] = (2*q.x*q.z-2*q.w*q.y);
matrix[1][0] = (2*q.x*q.y-2*q.w*q.z);
matrix[1][1] = (1-2*z2-2*x2);
matrix[1][2] = (2*q.y*q.z+2*q.w*q.x);
matrix[2][0] = (2*q.x*q.z+2*q.w*q.y);
matrix[2][1] = (2*q.y*q.z-2*q.w*q.x);
matrix[2][2] = (1-2*y2-2*x2);
I am doing a javafx visualisation application for 3d points. As I am new to javafx, I started from the tutorial provided in the oracle website:
http://docs.oracle.com/javase/8/javafx/graphics-tutorial/javafx-3d-graphics.htm#JFXGR256
The example above runs perfect on my Mac, But after adding more points, the mouse drag, which causes the camera to rotate and thus people can view the objects from different angle, became very slow and simply not applicable any more.
I currently have a data for a rabbit with about 40000 points:
The code I used to rotate camera:
cameraXform.ry.setAngle(cameraXform.ry.getAngle() - mouseDeltaX * MOUSE_SPEED * modifier * ROTATION_SPEED);
cameraXform.rx.setAngle(cameraXform.rx.getAngle() + mouseDeltaY * MOUSE_SPEED * modifier * ROTATION_SPEED);
which is the same as in the oracle example.
What I have tried:
set JVM flag -Djavafx.animation.fullspeed=true, this helped a bit, but not significant.
set JVM flag -Djavafx.autoproxy.disable=true, this did not help.
set Cache to true and CacheHint to Cache.SPEED, this did not make much difference.
create another thread to do the rotation, and sync back after calculation, this did not help neither.
Any help is appreciated.Thanks in advance!
Here is how I made a point cloud using tetrahedrons in a triangle mesh. seems to run faster than using spheres or squares. this code helped me scalafx google code
import java.util.ArrayList;
import javafx.scene.shape.TriangleMesh;
public class TetrahedronMesh extends TriangleMesh {
private ArrayList<Point3i> vertices;
private int[] facesLink;
public TetrahedronMesh(double length, ArrayList<Point3i> v) {
this.vertices = v;
if (length > 0.0) {
float[] points = new float[vertices.size() * 12];
int[] faces = new int[vertices.size() * 24];
facesLink = new int[vertices.size() * 4];
float[] texCoords = new float[vertices.size() * 12];
int vertexCounter = 0;
int primitiveCounter = 0;
int pointCounter = 0;
int facesCounter = 0;
int texCounter = 0;
for (Point3i vertex : vertices) {
vertex.scale(100);
points[primitiveCounter] = vertex.x;
points[primitiveCounter + 1] = (float) (vertex.y - (length
* Math.sqrt(3.0) / 3.0));
points[primitiveCounter + 2] = -vertex.z;
points[primitiveCounter + 3] = (float) (vertex.x + (length / 2.0));
points[primitiveCounter + 4] = (float) (vertex.y + (length
* Math.sqrt(3.0) / 6.0));
points[primitiveCounter + 5] = -vertex.z;
points[primitiveCounter + 6] = (float) (vertex.x - (length / 2.0));
points[primitiveCounter + 7] = (float) (vertex.y + (length
* Math.sqrt(3.0) / 6.0));
points[primitiveCounter + 8] = -vertex.z;
points[primitiveCounter + 9] = vertex.x;
points[primitiveCounter + 10] = vertex.y;
points[primitiveCounter + 11] = (float) -(vertex.z - (length * Math
.sqrt(2.0 / 3.0)));
faces[facesCounter] = pointCounter + 0;
faces[facesCounter + 1] = pointCounter + 0;
faces[facesCounter + 2] = pointCounter + 1;
faces[facesCounter + 3] = pointCounter + 1;
faces[facesCounter + 4] = pointCounter + 2;
faces[facesCounter + 5] = pointCounter + 2;
faces[facesCounter + 6] = pointCounter + 1;
faces[facesCounter + 7] = pointCounter + 1;
faces[facesCounter + 8] = pointCounter + 0;
faces[facesCounter + 9] = pointCounter + 0;
faces[facesCounter + 10] = pointCounter + 3;
faces[facesCounter + 11] = pointCounter + 3;
faces[facesCounter + 12] = pointCounter + 2;
faces[facesCounter + 13] = pointCounter + 2;
faces[facesCounter + 14] = pointCounter + 1;
faces[facesCounter + 15] = pointCounter + 1;
faces[facesCounter + 16] = pointCounter + 3;
faces[facesCounter + 17] = pointCounter + 4;
faces[facesCounter + 18] = pointCounter + 0;
faces[facesCounter + 19] = pointCounter + 0;
faces[facesCounter + 20] = pointCounter + 2;
faces[facesCounter + 21] = pointCounter + 2;
faces[facesCounter + 22] = pointCounter + 3;
faces[facesCounter + 23] = pointCounter + 5;
facesLink[pointCounter] = vertexCounter;
facesLink[pointCounter + 1] = vertexCounter;
facesLink[pointCounter + 2] = vertexCounter;
facesLink[pointCounter + 3] = vertexCounter;
texCoords[texCounter] = 0.5f;
texCoords[texCounter + 1] = 1.0f;
texCoords[texCounter + 2] = 0.75f;
texCoords[texCounter + 3] = (float) (1.0 - Math.sqrt(3.0) / 4.0);
texCoords[texCounter + 4] = 0.25f;
texCoords[texCounter + 5] = (float) (1.0 - Math.sqrt(3.0) / 4.0);
texCoords[texCounter + 6] = 1.0f;
texCoords[texCounter + 7] = 1.0f;
texCoords[texCounter + 8] = 0.5f;
texCoords[texCounter + 9] = (float) (1.0 - Math.sqrt(3.0) / 2.0);
texCoords[texCounter + 10] = 0.0f;
texCoords[texCounter + 11] = 1.0f;
vertexCounter++;
primitiveCounter += 12;
pointCounter += 4;
facesCounter += 24;
texCounter += 12;
}
getPoints().setAll(points);
getFaces().setAll(faces);
getTexCoords().setAll(texCoords);
// getFaceSmoothingGroups().setAll(0, 1, 2, 3);
}
}
public Point3i getPointFromFace(int faceId) {
return vertices.get(facesLink[faceId]);
}
}
Point3i code as follows
public class Point3i {
public int x;
public int y;
public int z;
public Point3i() {
x = 0;
y = 0;
z = 0;
}
}
Picking the point using the scene
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent me) {
PickResult pr = me.getPickResult();
int faceId = pr.getIntersectedFace();
if (faceId != -1) {
Point3i p = tetrahedronMesh.getPointFromFace(faceId);
}
}
});
I know this is old, But for others ..
Instead of creating a new shape all together, each of the predefined shapes
Sphere, Box, Cylinder, allow you to set the number of divisions in the constructor.
Sphere for example defaults to 64 divisions, 32 for longitude, 32 for latitude.
you can easily do ... = new Sphere(radius, divisions); (4 is the minimum I believe for Sphere).
Something that helps a lot is to set the mouse transparent on the root with:
root3D.setMouseTransparent(true);
This obviously disables clicking or hovering on objects of the view (i.e PickResult is null). The solution for that is to temporarily enable it when there is a click for example and simulate another identical click with impl_processMouseEvent.
#Override
public void handle(MouseEvent event) {
try {
if (event.getEventType() == MouseEvent.MOUSE_CLICKED
&& event.isStillSincePress()
&& (event.getTarget() == scene3d || event.getTarget() instanceof Shape3D)) {
Parent root3D = scene3d.getRoot();
// if the 3D scene has been set to mouse transparent,
// then we send another event and we disable the transparency temporarily
if (root3D.isMouseTransparent()) {
root3D.setMouseTransparent(false);
try {
scene3d.impl_processMouseEvent(event);
}
finally {
root3D.setMouseTransparent(true);
}
}
else {
// here you get the pick result you need :)
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}