How to understand JavaFX triangular mesh?

Just trying to understand the 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 are taken from the TriangleMesh class . My problem is that I don't see a match between their faces array definition and faces array in the code. So you don't understand how to use the face array in general for other cases. If it doesn't:

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

      

But then nothing displays the rectangle. What am I missing and what should go to the face array in general?

0


source to share


1 answer


Explanation of how face direction works

The direction in which the face is determined is important. In the working selection, the point of the first face is 2, 1, 0 (that is, the triangle is defined in counterclockwise order). In the array of faces you suggest, the first face is 2, 0, 1 (clockwise). The face, which is defined clockwise, is facing away from the viewer. The face, which is defined counterclockwise, is facing the viewer.

How to make the grid visible

If you take the suggested face definition and rotate the mesh 180 degrees around the Y-axis, you see a face. Without rotating the mesh, you will be looking at the back of the face by default, and the back of the mesh will be rejected (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 reverse side of the mesh will appear (although it will only show as black, not a shaded area).

A note about comments in the code you specified.

The comment in your code example is a bit misleading, it should reflect the actual face definition, not the face definition that doesn't work as expected.

Proposal to change the documentation request

IMO the TriangleMesh documentation needs to be improved, I have filed a change request in JavaFX Bug Tracking vs Runtime Project to request this improvement.

Modify documentation request to highlight the order of points in mesh faces:



RT-34292 Document the importance of the order of the TriangleMesh elements

Umbrella Change Request for Java 8 3D API Documentation:

RT-26385 Complete javadoc for FX 8 3D interface

Demonstration

Here is an example test harness you can use to play around with these concepts to better understand them.

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 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 exit

The front and back sides of the grid rectangle when the rectangle is drawn are facing the viewer by default (by defining the face clockwise) and with the CullFace.NONE setting (win7 jdkb115).

backfront

+9


source







All Articles