Решено
Решение, связанное с группами сглаживания.
В методе 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 отрисовываются со странной темнотой«тени», тогда как стандартная коробка отлично отрисовывается.Я пытаюсь понять, что я делаю неправильно, когда я строю октаэдры.
Пожалуйста, быстро взгляните на изображение и короткое видео, которое я включил, поскольку они иллюстрируют визуальный артефакт, который я пытаюсь понять.
Изображение, иллюстрирующее рендеринг
Короткое видео, иллюстрирующее рендеринг
Система координат, на которую я ссылаюсь
Я работаю над небольшим приложением, которое будет отображать сферическую трехмерную сетку, созданную MeshBuilder - классом в другом проекте.Отправной точкой для этой сферической сетки является простой октаэдр.Приведенный ниже код представляет собой небольшое приложение, предназначенное для меня, чтобы понять, как работает JavaFX 3D, поскольку я новичок в нем.
Программа отображает стандартный зеленый прямоугольник JavaFX в центре, красный октаэдр справа ивторой синий октаэдр слева.Есть флажки, которые изменяют рендеринг октаэдров во время работы программы.
Красный октаэдр создается «вручную» в методе loadFixedSphereMeshView (), а синий октаэдр создается с использованием MeshBuilder в loadProceeduralSphereMeshView ().Код в MeshBuilder тестируется модулем на жестко закодированном октаэдре, чтобы убедиться, что он строит тот же октаэдр.
Я настроил все так, чтобы я мог:
- См.как визуализировать сетки, ссылаясь на поле
- Измените код для красного октаэдра, чтобы заставить его правильно отображаться
- Проведите модульное тестирование MeshBuilder против данных красного октаэдра, как только правильно отобразится
Я сосредоточен на попытках понять, что я делаю неправильно, когда я вручную строю красный октаэдр, что приводит к его рендерингу с этими «теневыми» артефактами.
Рывок видеопрограммное обеспечение захвата не программа.
Спасибо за чтение.
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;
}
}