Есть несколько способов создать трехмерную фигуру, подобную той, которую вы опубликовали.
3D-моделирование
Вероятно, самый простой способ - использовать 3D-редактор, например Blender (с открытым исходным кодом), а затем экспортировать модель в файл .OBJ. В этом файле OBJ вы получите список вершин, текстур и граней. Однако формат не читается напрямую, поэтому вы не можете просто передать его в JavaFX MeshView
. Однако есть импортеры этого формата, которые создадут TriangleMesh
, например one .
JCSG
Не имея дело с точкой , вершины и грани, но при подходе Java другой вариант - использовать JCSG : вы можете просто создать два куба и выполнить логическую операцию, чтобы получить желаемую форму (вычесть куб 20x20x60 из 60x20x100 куб). Существует также способ конвертировать объект CSG в TriangleMesh
.
FXyz3D
С точки зрения чистого JavaFX вы также можете использовать библиотеку FXyz3D
и ее TriangulatedMesh
. Is основан на плоской поверхности со списком трехмерных точек ({x, y, 0}), которые определяют его периметр, который триангулирован и выдавлен до заданной высоты. Внутренне он использует Poly2Tri , что в точности равно a 2D constrained Delaunay triangulation library
.
Поскольку вам нужна плоская поверхность на XY, я перепишу ваш список точек в:
private final List<Point3D> points = new ArrayList<>(Arrays.asList(
new Point3D(0, 0, 0),
new Point3D(0, 100, 0), new Point3D(60, 100, 0),
new Point3D(60, 60, 0), new Point3D(40, 60, 0),
new Point3D(40, 0, 0), new Point3D( 0, 0, 0)));
, а затем форму можно сгенерировать с помощью:
TriangulatedMesh customShape = new TriangulatedMesh(points, 20);
customShape.setLevel(0);
customShape.setCullFace(CullFace.NONE);
customShape.getTransforms().addAll(new Rotate(-90, Rotate.X_AXIS));
(обратите внимание, что вращение поместит плоскую поверхность из плоскости XY в плоскость XZ, как на вашем рисунке)
Теперь вы можете проверить сгенерированное мной sh, и вы увидите все сгенерированные треугольники:
так что вы можете использовать эту информацию, чтобы "заполнить" ваши точки, текстуры и массивы граней, и выяснить, как это работает.
TriangleMe sh
Наконец Начиная с нуля, но исходя из вышеуказанной триангуляции, это обязательные массивы:
Вершины
float[] vertices = {
0.0, 0.0, 0.0, // 0
0.0, 0.0, 100.0, // 1
60.0, 0.0, 100.0,
60.0, 0.0, 60.0,
40.0, 0.0, 60.0,
40.0, 0.0, 0.0,
0.0, 20.0, 0.0,
0.0, 20.0, 100.0,
60.0, 20.0, 100.0,
60.0, 20.0, 60.0,
40.0, 20.0, 60.0,
40.0, 20.0, 0.0}; // 11
Координаты текстуры
Они могут быть сгенерированы, например, на основе 2D-поверхности с размером 1x1, поэтому координаты вершин Их можно легко сопоставить с помощью этого выражения: {x / (MaxX-MinX), y /(MaxY-MinY)}
.
float[] texture = {
0.00, 0.00, // 0
0.00, 1.00, // 1
1.00, 1.00,
1.00, 0.60,
0.67, 0.60,
0.67, 0.00,
0.00, 0.00,
0.00, 1.00,
1.00, 1.00,
1.00, 0.60,
0.67, 0.60,
0.67, 0.00}; // 11
Лица
Мы добавим индексы 3 вершин и 3 координат текстуры для каждой грани три angular.
int[] faces = {
1, 1, 2, 2, 4, 4, // 0
4, 4, 2, 2, 3, 3, // 1
1, 1, 4, 4, 0, 0, // 2
0, 0, 4, 4, 5, 5,
7, 7, 10, 10, 8, 8,
10, 10, 9, 9, 8, 8,
7, 7, 6, 6, 10, 10,
6, 6, 11, 11, 10, 10,
0, 0, 1, 1, 7, 7,
0, 0, 7, 7, 6, 6,
1, 1, 2, 2, 8, 8,
1, 1, 8, 8, 7, 7,
2, 2, 3, 3, 9, 9,
2, 2, 9, 9, 8, 8,
3, 3, 4, 4, 10, 10,
3, 3, 10, 10, 9, 9,
4, 4, 5, 5, 11, 11,
4, 4, 11, 11, 10, 10,
5, 5, 0, 0, 6, 6,
5, 5, 6, 6, 11, 11}; // 19
Например, для верхней поверхности определены четыре треугольника, и первый (0) имеет вершины (1, 2, 4), второй (1) имеет вершины (4, 2, 3) и и так далее:
В этом случае текстуры координат имеют те же индексы, что и вершины (но это может отличаться). Обратите внимание на обмотку вершины или вращение против часовой стрелки.
РЕДАКТИРОВАТЬ
Если вы не используете нормали, удобно добавлять группы сглаживания граней: каждая группа содержит грани индексов, которые принадлежат одной плоской поверхности. Например, первые четыре индекса принадлежат верхней поверхности.
int[] smooth = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7};
И это весь код для создания вашего пользовательского MeshView
узла:
private final float[] vertices = {
0.0f, 0.0f, 0.0f, // 0
0.0f, 0.0f, 100.0f, // 1
60.0f, 0.0f, 100.0f,
60.0f, 0.0f, 60.0f,
40.0f, 0.0f, 60.0f,
40.0f, 0.0f, 0.0f,
0.0f, 20.0f, 0.0f,
0.0f, 20.0f, 100.0f,
60.0f, 20.0f, 100.0f,
60.0f, 20.0f, 60.0f,
40.0f, 20.0f, 60.0f,
40.0f, 20.0f, 0.0f}; // 11
private final float[] texture = {
0.00f, 0.00f, // 0
0.00f, 1.00f, // 1
1.00f, 1.00f,
1.00f, 0.60f,
0.67f, 0.60f,
0.67f, 0.00f,
0.00f, 0.00f,
0.00f, 1.00f,
1.00f, 1.00f,
1.00f, 0.60f,
0.67f, 0.60f,
0.67f, 0.00f}; // 11
private final int[] faces = {
1, 1, 2, 2, 4, 4, // 0
4, 4, 2, 2, 3, 3, // 1
1, 1, 4, 4, 0, 0, // 2
0, 0, 4, 4, 5, 5,
7, 7, 10, 10, 8, 8,
10, 10, 9, 9, 8, 8,
7, 7, 6, 6, 10, 10,
6, 6, 11, 11, 10, 10,
0, 0, 1, 1, 7, 7,
0, 0, 7, 7, 6, 6,
1, 1, 2, 2, 8, 8,
1, 1, 8, 8, 7, 7,
2, 2, 3, 3, 9, 9,
2, 2, 9, 9, 8, 8,
3, 3, 4, 4, 10, 10,
3, 3, 10, 10, 9, 9,
4, 4, 5, 5, 11, 11,
4, 4, 11, 11, 10, 10,
5, 5, 0, 0, 6, 6,
5, 5, 6, 6, 11, 11}; // 19
private final int[] smooth = {
0, 0, 0, 0, // top surface
1, 1, 1, 1, // bottom surface
2, 2,
3, 3,
4, 4,
5, 5,
6, 6,
7, 7};
public MeshView getMeshView() {
TriangleMesh mesh = new TriangleMesh();
mesh.getPoints().addAll(vertices);
mesh.getTexCoords().addAll(texture);
mesh.getFaces().addAll(faces);
mesh.getFaceSmoothingGroups().addAll(smooth);
MeshView meshView = new MeshView(mesh);
meshView.setMaterial(new PhongMaterial(Color.FIREBRICK));
meshView.setCullFace(CullFace.NONE);
return meshView;
}