How to make sense of JavaFX triangle mesh?


Question

Just trying to make sense of JavaFX documentation re triangle mesh. This code works and draws a rectangle.

public class Shape3DRectangle extends TriangleMesh {

    public Shape3DRectangle(float Width, float Height) {
        float[] points = {
            -Width/2,  Height/2, 0, // idx p0
            -Width/2, -Height/2, 0, // idx p1
             Width/2,  Height/2, 0, // idx p2
             Width/2, -Height/2, 0  // idx p3
        };
        float[] texCoords = {
            1, 1, // idx t0
            1, 0, // idx t1
            0, 1, // idx t2
            0, 0  // idx t3
        };
        /**
         * points:
         * 1      3
         *  -------   texture:
         *  |\    |  1,1    1,0
         *  | \   |    -------
         *  |  \  |    |     |
         *  |   \ |    |     |
         *  |    \|    -------
         *  -------  0,1    0,0
         * 0      2
         *
         * texture[3] 0,0 maps to vertex 2
         * texture[2] 0,1 maps to vertex 0
         * texture[0] 1,1 maps to vertex 1
         * texture[1] 1,0 maps to vertex 3
         * 
         * Two triangles define rectangular faces:
         * p0, t0, p1, t1, p2, t2 // First triangle of a textured rectangle 
         * p0, t0, p2, t2, p3, t3 // Second triangle of a textured rectangle
         */
        int[] faces = {
            2, 2, 1, 1, 0, 0,
            2, 2, 3, 3, 1, 1
        };

        this.getPoints().setAll(points);
        this.getTexCoords().setAll(texCoords);
        this.getFaces().setAll(faces);
    }
}

The last 3 lines of the comment come from Class TriangleMesh. My problem is that I do not see a match between their definition of the faces array and the faces array in the code. Thus don't understand how to use faces array in general for other cases. Should it not be this instead:

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

But then nothing renders of the rectangle. What am I missing and what should go into the faces array in general?

1
3
11/13/2013 6:21:35 PM

Accepted Answer

Explanation of how the face direction works

The direction in which the face is defined is important. In the working sample, the point of the first face is 2, 1, 0 (i.e. the triangle is defined in a counter-clockwise order). In the faces array you suggest, the first face is 2, 0, 1 (clockwise). A face which is defined in a clockwise manner faces away from the viewer. A face which is defined in a counter-clockwise manner faces toward the viewer.

How to make your mesh visible

If you take your suggested face definition and rotate the mesh 180 degrees round the Y axis, you will see the face. Without rotation of the mesh, you will by default be looking at the back of the face, and the back of the mesh will be culled (i.e. not visible).

Another way to see your mesh without rotation is to set the cull face of the Mesh to CullFace.NONE, then the back of the mesh will show (though as it will just show as black rather than a shaded region).

A note on the comments in your supplied code

The comment in your code sample is slightly misleading, it should reflect the the actual face definition rather than a face definition which doesn't really work as expected.

Documentation request change suggestion

IMO, the TriangleMesh documentation should be enhanced, I logged a change request in the JavaFX issue tracker against the runtime project to request this enhancement.

Change request for documentation to highlight ordering of points in mesh faces is:

RT-34292 Document importance of TriangleMesh order of elements

Umbrella change request for documentation of the Java 8 3D API is:

RT-26385 Finish javadoc for FX 8 3D API

Demo

Here is a sample test harness you can use for playing around with this concepts in order to understand them better.

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

// drag the mouse over the rectangle to rotate it.
public class RectangleViewer extends Application {

    double anchorX, anchorY, anchorAngle;

    private PerspectiveCamera addCamera(Scene scene) {
        PerspectiveCamera perspectiveCamera = new PerspectiveCamera(false);
        scene.setCamera(perspectiveCamera);
        return perspectiveCamera;
    }

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        final MeshView rect = new MeshView(
                new Shape3DRectangle(200, 200)
        );
        rect.setMaterial(new PhongMaterial(Color.DARKGREEN));
        rect.setRotationAxis(Rotate.Y_AXIS);
        rect.setTranslateX(250);
        rect.setTranslateY(250);
// try commenting this line out to see what it's effect is . . .
        rect.setCullFace(CullFace.NONE);

        final Group root = new Group(rect);
        final Scene scene = new Scene(root, 500, 500, true);

        scene.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override public void handle(MouseEvent event) {
                anchorX = event.getSceneX();
                anchorY = event.getSceneY();
                anchorAngle = rect.getRotate();
            }
        });

        scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override public void handle(MouseEvent event) {
                rect.setRotate(anchorAngle + anchorX - event.getSceneX());
            }
        });


        addCamera(scene);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public class Shape3DRectangle extends TriangleMesh {

        public Shape3DRectangle(float Width, float Height) {
            float[] points = {
                    -Width/2,  Height/2, 0, // idx p0
                    -Width/2, -Height/2, 0, // idx p1
                    Width/2,  Height/2, 0, // idx p2
                    Width/2, -Height/2, 0  // idx p3
            };
            float[] texCoords = {
                    1, 1, // idx t0
                    1, 0, // idx t1
                    0, 1, // idx t2
                    0, 0  // idx t3
            };
            /**
             * points:
             * 1      3
             *  -------   texture:
             *  |\    |  1,1    1,0
             *  | \   |    -------
             *  |  \  |    |     |
             *  |   \ |    |     |
             *  |    \|    -------
             *  -------  0,1    0,0
             * 0      2
             *
             * texture[3] 0,0 maps to vertex 2
             * texture[2] 0,1 maps to vertex 0
             * texture[0] 1,1 maps to vertex 1
             * texture[1] 1,0 maps to vertex 3
             *
             * Two triangles define rectangular faces:
             * p0, t0, p1, t1, p2, t2 // First triangle of a textured rectangle
             * p0, t0, p2, t2, p3, t3 // Second triangle of a textured rectangle
             */

// if you use the co-ordinates as defined in the above comment, it will be all messed up
//            int[] faces = {
//                    0, 0, 1, 1, 2, 2,
//                    0, 0, 2, 2, 3, 3
//            };

// try defining faces in a counter-clockwise order to see what the difference is.
//            int[] faces = {
//                    2, 2, 1, 1, 0, 0,
//                    2, 2, 3, 3, 1, 1
//            };

// try defining faces in a clockwise order to see what the difference is.
            int[] faces = {
                    2, 3, 0, 2, 1, 0,
                    2, 3, 1, 0, 3, 1
            };

            this.getPoints().setAll(points);
            this.getTexCoords().setAll(texCoords);
            this.getFaces().setAll(faces);
        }
    }
} 

Demo Output

Front and back faces of the rectangle mesh when the rectangle is drawn to be by default facing away the viewer (by defining a face in a clockwise direction) and with a CullFace.NONE setting (win7 jdkb115).

backfront

11
11/14/2013 9:03:38 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon