为什么这些JavaFX TriangleMesh渲染时会出现暗影伪影?

时间:2018-06-09 10:25:53

标签: javafx-3d

解决

与平滑组相关的解决方案。

在loadFixedSphereMeshView()方法中,我添加了:

... after points array
int faceSmoothingGroups[] = {
    0, 0, 0, 0, 0, 0, 0, 0
};
... before faces array

然后补充说:

... after setting the faces
mesh.getFaceSmoothingGroups().setAll(faceSmoothingGroups);

注意:faceSmootingGroups数组中的项目数必须等于网格中的面数。

我的两个基于TriangleMesh的Octahedron正在呈现奇怪的黑暗'阴影',而标准的Box正在渲染完美。我在构建八面体时试图理解我做错了什么。

请快速浏览一下我所包含的图片和短片,因为这些图片说明了我想要了解的视觉神器。

Image Illustrating Rendering

Short Video Illustrating Rendering

The Coordinate System I am referencing

我正在开发一个小应用程序,它将显示由MeshBuilder生成的3D球形网格 - 另一个项目中的一个类。该球形网格的起点是一个简单的八面体。下面包含的代码是一个小应用程序,旨在让我了解JavaFX 3D如何工作,因为我是新手。

程序在中间显示一个标准的JavaFX绿色框,右边是红色八面体,左边是第二个蓝色八面体。在程序运行时,有一些复选框可以更改八面体的渲染。

红色八面体是在loadFixedSphereMeshView()方法中“手动”构造的,蓝色八面体是在loadProceeduralSphereMeshView()中使用MeshBuilder构造的。 MeshBuilder中的代码是针对硬编码的八面体进行单元测试的,以确保它构建相同的八面体。

我已经这样设置,以便我可以:

  • 了解如何通过引用Box
  • 呈现网格
  • 更改红色八面体的代码以使其正确呈现
  • 对正确渲染的红色八面体数据进行单元测试

当我手动构造红色Octahedron时,我专注于试图理解我做错了什么,导致它使用那些'阴影'工件进行渲染。

视频的急动是捕捉软件而不是程序。

感谢阅读。

public class Main extends Application {

    private static final int VIEWPORT_SIZE = 800;

    private static final String textureLoc = "https://www.sketchuptextureclub.com/public/texture_f/slab-marble-emperador-cream-light-preview.jpg";

    private Image texture;
    private final PhongMaterial texturedMaterial = new PhongMaterial();
    private final PhongMaterial redMaterial = new PhongMaterial();
    private final PhongMaterial blueMaterial = new PhongMaterial();
    private final PhongMaterial greenMaterial = new PhongMaterial();
    private final MeshView fixedSphereMeshView = loadFixedSphereMeshView();
    private final MeshView proceeduralSphereMeshView = loadProceeduralSphereMeshView();

    @Override
    public void start(Stage stage) throws Exception {
        texture = new Image(textureLoc);
        texturedMaterial.setDiffuseMap(texture);
        redMaterial.setDiffuseColor(Color.RED);
        blueMaterial.setDiffuseColor(Color.BLUE);
        greenMaterial.setDiffuseColor(Color.GREEN);
        Group group = buildScene();
        RotateTransition rotate = rotate3dGroup(group);
        VBox layout = new VBox(
            createControls(rotate),
            createScene3D(group)
        );
    //        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
        Scene scene = new Scene(layout);
        stage.setTitle("Icosphere Viewer");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        System.setProperty("prism.dirtyopts", "false");
        launch(args);
    }

    private MeshView loadFixedSphereMeshView() {
        float[] points = {
            0, -1, 0, // p0
            0, 0, -1, // p1
            1, 0, 0, //  p2
            0, 0, 1, //  p3
            -1, 0, 0, // p4
            0, 1, 0 //   p5
        };
        float[] texCoords = {
            1, 1, // index t0
            1, 0, // index t1
            0, 1, // index t2
            0, 0 //  index t3
        };
        int[] faces = {
            0, 0, 1, 1, 2, 2, // p0 t0 p1 t1 p2 t2
            0, 0, 2, 2, 3, 3, // p0 t0 p2 t2 p3 t3
            0, 0, 3, 1, 4, 2, // p0 t0 p3 t1 p4 t2
            0, 0, 4, 2, 1, 3, // p0 t0 p4 t2 p1 t3
            5, 0, 2, 0, 1, 0, // p5 t0 p2 t0 p1 t0
            5, 0, 3, 0, 2, 0, // p5 t0 p3 t0 p2 t0
            5, 0, 4, 0, 3, 0, // p5 t0 p4 t0 p3 t0
            5, 0, 1, 0, 4, 0 //  p5 t0 p1 t0 p4 t0
        };

        TriangleMesh mesh = new TriangleMesh();
        mesh.getPoints().setAll(points);
        mesh.getTexCoords().setAll(texCoords);
        mesh.getFaces().setAll(faces);

        return new MeshView(mesh);
    }

    private MeshView loadProceeduralSphereMeshView() {
        SphereMesh sphereMesh = MeshBuilder.buildOctosphereMesh(0);
        float[] points = sphereMesh.getPoints();
        float[] texCoords = {
            1, 1, // index t0
            1, 0, // index t1
            0, 1, // index t2
            0, 0 //  index t3
        };
        int[] faces = sphereMesh.getFaces();

        TriangleMesh mesh = new TriangleMesh();
        mesh.getPoints().setAll(points);
        mesh.getTexCoords().setAll(texCoords);
        mesh.getFaces().setAll(faces);

        return new MeshView(mesh);
    }

    private Group buildScene() {
        Box box = new Box(1, 1, 1);
        box.setTranslateX(0);
        box.setTranslateY(0);
        box.setTranslateZ(0);
        box.setMaterial(greenMaterial);
        proceeduralSphereMeshView.setTranslateX(-2);
        proceeduralSphereMeshView.setTranslateY(0);
        proceeduralSphereMeshView.setTranslateZ(0);
        proceeduralSphereMeshView.setMaterial(blueMaterial);
        fixedSphereMeshView.setTranslateX(2);
        fixedSphereMeshView.setTranslateY(0);
        fixedSphereMeshView.setTranslateZ(0);
        fixedSphereMeshView.setMaterial(redMaterial);
        Group group = new Group(proceeduralSphereMeshView, fixedSphereMeshView, box);
        group.setTranslateZ(10);
        return group;
    }

    private SubScene createScene3D(Group group) {
        SubScene scene3d = new SubScene(group, VIEWPORT_SIZE, VIEWPORT_SIZE * 9.0 / 16, true, SceneAntialiasing.BALANCED);
        scene3d.setFill(Color.LIGHTGRAY);
        PerspectiveCamera camera = new PerspectiveCamera(true);
        scene3d.setCamera(camera);
        return scene3d;
    }

    private VBox createControls(RotateTransition rotateTransition) {

        CheckBox cull = new CheckBox("Cull Back");
        proceeduralSphereMeshView.cullFaceProperty().bind(
            Bindings.when(
                    cull.selectedProperty())
                    .then(CullFace.BACK)
                    .otherwise(CullFace.NONE)
        );
        fixedSphereMeshView.cullFaceProperty().bind(
            Bindings.when(
                    cull.selectedProperty())
                    .then(CullFace.BACK)
                    .otherwise(CullFace.NONE)
        );

        CheckBox wireframe = new CheckBox("Wireframe");
        proceeduralSphereMeshView.drawModeProperty().bind(
            Bindings.when(
                    wireframe.selectedProperty())
                    .then(DrawMode.LINE)
                    .otherwise(DrawMode.FILL)
        );
        fixedSphereMeshView.drawModeProperty().bind(
            Bindings.when(
                    wireframe.selectedProperty())
                    .then(DrawMode.LINE)
                    .otherwise(DrawMode.FILL)
        );

        CheckBox texture = new CheckBox("Texture");
        proceeduralSphereMeshView.materialProperty().bind(
            Bindings.when(
                    texture.selectedProperty())
                    .then(texturedMaterial)
                    .otherwise((PhongMaterial) blueMaterial)
        );
        fixedSphereMeshView.materialProperty().bind(
            Bindings.when(
                    texture.selectedProperty())
                    .then(texturedMaterial)
                    .otherwise((PhongMaterial) redMaterial)
        );

        CheckBox rotate = new CheckBox("Rotate");
        rotate.selectedProperty().addListener(observable -> {
            if (rotate.isSelected()) {
                rotateTransition.play();
            } else {
                rotateTransition.pause();
            }
        });

        VBox controls = new VBox(10, rotate, texture, cull, wireframe);
        controls.setPadding(new Insets(10));
        return controls;
    }

    private RotateTransition rotate3dGroup(Group group) {
        RotateTransition rotate = new RotateTransition(Duration.seconds(10), group);
        rotate.setAxis(Rotate.Y_AXIS);
        rotate.setFromAngle(0);
        rotate.setToAngle(360);
        rotate.setInterpolator(Interpolator.LINEAR);
        rotate.setCycleCount(RotateTransition.INDEFINITE);

        return rotate;
    }

}

0 个答案:

没有答案