TriangleMesh - видны задние грани
Хорошего дня! У меня есть следующая проблема. Графическая модель отображается неправильно: некоторые задние грани модели, которые должны быть скрыты передней стороной, остаются видимыми. Вот несколько примеров для пояснения: (изометрия)
(Выпуск)
Эта проблема особенно заметна при использовании света и материалов. Таким образом, вопрос в том, как это можно решить для JavaFX?
UPD:
public class VertexTest extends Application {
PerspectiveCamera camera;
Cam cam = new Cam();
double mouseOldX, mouseOldY, mousePosX, mousePosY, mouseDeltaX, mouseDeltaY;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
TriangleMesh mesh = new Shape3DRectangle(100, 100, 100);
MeshView view = new MeshView(mesh);
view.setDrawMode(DrawMode.LINE);
view.setMaterial(new PhongMaterial(Color.RED));
cam.getChildren().add(view);
Scene scene = new Scene(cam, 1000, 1000, true);
addEvents(view, scene);
camera = new PerspectiveCamera();
camera.setTranslateX(-500);
camera.setTranslateY(-500);
camera.setTranslateZ(1000);
scene.setCamera(camera);
primaryStage.setScene(scene);
primaryStage.show();
}
private void addEvents(MeshView view, Scene s) {
s.setOnMouseDragged(new EventHandler<MouseEvent>() {
public void handle(MouseEvent me) {
mouseOldX = mousePosX;
mouseOldY = mousePosY;
mousePosX = me.getX();
mousePosY = me.getY();
mouseDeltaX = mousePosX - mouseOldX;
mouseDeltaY = mousePosY - mouseOldY;
cam.ry.setAngle(cam.ry.getAngle() - mouseDeltaX);
cam.rx.setAngle(cam.rx.getAngle() + mouseDeltaY);
}
});
}
class Cam extends Group {
Translate t = new Translate();
Translate p = new Translate();
Translate ip = new Translate();
Rotate rx = new Rotate();
{
rx.setAxis(Rotate.X_AXIS);
}
Rotate ry = new Rotate();
{
ry.setAxis(Rotate.Y_AXIS);
}
Rotate rz = new Rotate();
{
rz.setAxis(Rotate.Z_AXIS);
}
Scale s = new Scale();
public Cam() {
super();
getTransforms().addAll(t, p, rx, rz, ry, s, ip);
}
}
public class Shape3DRectangle extends TriangleMesh {
public Shape3DRectangle(float Width, float Height, float deep) {
this.getPoints().setAll(-Width / 2, Height / 2, deep / 2, // idx p0
Width / 2, Height / 2, deep / 2, // idx p1
-Width / 2, -Height / 2, deep / 2, // idx p2
Width / 2, -Height / 2, deep / 2, // idx p3
-Width / 2, Height / 2, -deep / 2, // idx p4
Width / 2, Height / 2, -deep / 2, // idx p5
-Width / 2, -Height / 2, -deep / 2, // idx p6
Width, -Height / 2, -deep / 2 // idx p7
);
this.getTexCoords().addAll(0.0f, 0.0f);
this.getFaces().addAll(5, 0, 4, 0, 0, 0 // P5,T1 ,P4,T0 ,P0,T3
, 5, 0, 0, 0, 1, 0 // P5,T1 ,P0,T3 ,P1,T4
, 0, 0, 4, 0, 6, 0 // P0,T3 ,P4,T2 ,P6,T7
, 0, 0, 6, 0, 2, 0 // P0,T3 ,P6,T7 ,P2,T8
, 1, 0, 0, 0, 2, 0 // P1,T4 ,P0,T3 ,P2,T8
, 1, 0, 2, 0, 3, 0 // P1,T4 ,P2,T8 ,P3,T9
, 5, 0, 1, 0, 3, 0 // P5,T5 ,P1,T4 ,P3,T9
, 5, 0, 3, 0, 7, 0 // P5,T5 ,P3,T9 ,P7,T10
, 4, 0, 5, 0, 7, 0 // P4,T6 ,P5,T5 ,P7,T10
, 4, 0, 7, 0, 6, 0 // P4,T6 ,P7,T10 ,P6,T11
, 3, 0, 2, 0, 6, 0 // P3,T9 ,P2,T8 ,P6,T12
, 3, 0, 6, 0, 7, 0 // P3,T9 ,P6,T12 ,P7,T13
);
}
}
}
3 ответа
Я играл с твоим образцом и думаю, что выяснил причину твоих проблем.
Сначала я проверил извилистость лица. Все они против часовой стрелки, поэтому все их нормали выходят наружу, как и должно быть.
Затем я изменил другие вершины вместо последней. В некоторых случаях проблем не было, в других проблема все еще была.
В основном, проблема возникает, когда есть "вогнутые" поверхности, то есть две грани имеют нормали, которые будут пересекаться. И это не происходит, когда все поверхности "выпуклые", то есть их нормали направлены наружу и не пересекаются.
Это четкое изображение обоих типов мешей, взятых отсюда:
Возвращаясь к вашему примеру, вы определяете вогнутую сетку:
Но если вместо изменения вершины № 7 мы увеличим размер № 5, у нас будет выпуклая сетка без проблем рендеринга:
Очевидно, что, хотя это решает проблему рендеринга, оно меняет вашу первоначальную форму.
Если вы хотите сохранить исходную геометрию, другим возможным решением является изменение граней, поэтому у вас нет вогнутых областей.
Давайте посмотрим на грани 5-1-3 и 5-3-7, и предположим, что мы хотим теперь переместить вершину #1.
Если мы сохраним ваши треугольники, грани 5-1-3 и 5-3-7 будут определять вогнутую поверхность для рендеринга (их нормали будут пересекаться), в то время как если мы изменим эти треугольники на 5-1-7 и 1-3-7, тогда поверхность будет выпуклой (их нормали не будут пересекаться):
Возвращаясь к исходной форме, это изменение этих двух граней решит проблемы рендеринга.
Хотя вершины одинаковы, геометрия немного отличается. Так что это требует некоторой доработки (больше элементов). Добавление этих элементов должно быть сделано с учетом этой выпуклой концепции. Однако проблема не является тривиальной, как вы можете видеть здесь.
Хороший анализ Хосе, но мне кажется, что ОП только что забыл разделить ширину на 2 в этой строке своего кода.
Width, -Height / 2, -deep / 2 // idx p7
должно быть
Width / 2, -Height / 2, -deep / 2 // idx p7
Класс называется Shape3DRectangle, но с этой ошибкой геометрия больше не является прямоугольной.
Вы можете установить cullFaceProperty для каждого Shape3D. Я думаю, это то, что вам нужно, но я не уверен, правильно ли я понял ваш вопрос.