解决
与平滑组相关的解决方案。
在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正在渲染完美。我在构建八面体时试图理解我做错了什么。
请快速浏览一下我所包含的图片和短片,因为这些图片说明了我想要了解的视觉神器。
Short Video Illustrating Rendering
The Coordinate System I am referencing
我正在开发一个小应用程序,它将显示由MeshBuilder生成的3D球形网格 - 另一个项目中的一个类。该球形网格的起点是一个简单的八面体。下面包含的代码是一个小应用程序,旨在让我了解JavaFX 3D如何工作,因为我是新手。
程序在中间显示一个标准的JavaFX绿色框,右边是红色八面体,左边是第二个蓝色八面体。在程序运行时,有一些复选框可以更改八面体的渲染。
红色八面体是在loadFixedSphereMeshView()方法中“手动”构造的,蓝色八面体是在loadProceeduralSphereMeshView()中使用MeshBuilder构造的。 MeshBuilder中的代码是针对硬编码的八面体进行单元测试的,以确保它构建相同的八面体。
我已经这样设置,以便我可以:
当我手动构造红色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;
}
}