Pan Long
Pan Long

Reputation: 1032

How to improve Javafx 3d performance?

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: visualisation of 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:

  1. set JVM flag -Djavafx.animation.fullspeed=true, this helped a bit, but not significant.
  2. set JVM flag -Djavafx.autoproxy.disable=true, this did not help.
  3. set Cache to true and CacheHint to Cache.SPEED, this did not make much difference.
  4. create another thread to do the rotation, and sync back after calculation, this did not help neither.

Any help is appreciated.Thanks in advance!

Upvotes: 3

Views: 2854

Answers (3)

Adrien
Adrien

Reputation: 17

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();
        }
    }

Upvotes: 1

jdub1581
jdub1581

Reputation: 669

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).

Upvotes: 0

MitchBroadhead
MitchBroadhead

Reputation: 899

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);
            }
        }
    });

Upvotes: 3

Related Questions