Решение 1. Text3D
Нет встроенного узла JavaFX 3D Text.Однако вы можете использовать узел Text3DMesh
из библиотеки FXyz .
Примерно так:
build.gradle
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.7'
}
repositories {
jcenter()
mavenCentral()
}
dependencies {
implementation 'org.fxyz3d:fxyz3d:0.4.0'
}
javafx {
version = "12"
modules = [ 'javafx.controls' ]
}
mainClassName = 'text3d.Text3D'
text3d.Text3D.java
public class Text3D extends Application {
private final Rotate rotateX = new Rotate(10, Rotate.X_AXIS);
private final Rotate rotateY = new Rotate(-10, Rotate.Y_AXIS);
private double mousePosX, mousePosY, mouseOldX, mouseOldY;
@Override
public void start(Stage stage) throws Exception {
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.getTransforms().addAll (rotateX, rotateY, new Translate(-100, 100, -1000));
Text3DMesh text3D = new Text3DMesh("Text3D");
text3D.setFont(Font.getFamilies().get(new Random().nextInt(Font.getFamilies().size())));
text3D.setFontSize(200);
text3D.setTextureModeVertices3D(1530, p -> p.y);
Bounds bounds = text3D.getBoundsInParent();
text3D.setTranslateX(- bounds.getWidth() / 2d);
text3D.setTranslateY(bounds.getHeight() / 2d);
text3D.setTranslateZ(-bounds.getDepth());
double radius = Math.max(bounds.getWidth(), bounds.getHeight()) * 1.2;
SpheroidMesh spheroid = new SpheroidMesh(radius);
spheroid.setTextureModeVertices3D(1530, p -> p.x * p.y);
spheroid.setTranslateZ(radius);
Group group = new Group(spheroid, text3D);
Scene scene = new Scene(group, 400, 300, true, SceneAntialiasing.BALANCED);
scene.setFill(Color.BISQUE);
scene.setCamera(camera);
scene.setOnMousePressed(event -> {
mousePosX = event.getSceneX();
mousePosY = event.getSceneY();
});
scene.setOnMouseDragged(event -> {
mousePosX = event.getSceneX();
mousePosY = event.getSceneY();
rotateX.setAngle(rotateX.getAngle() - (mousePosY - mouseOldY));
rotateY.setAngle(rotateY.getAngle() + (mousePosX - mouseOldX));
mouseOldX = mousePosX;
mouseOldY = mousePosY;
});
stage.setScene(scene);
stage.setTitle("FXyz3D Sample");
stage.show();
}
}
Решение 2. Изображение
Другой подход можно сделать, добавив изображение в виде карты рассеянной сферы,Опять же, это можно сделать с помощью FXyz.
Сначала вам нужно визуализировать обычный Text
2D узел на сцене и сделать его снимок для генерации изображения.
text3d.Image3D
public class Image3D extends Application {
private final Rotate rotateX = new Rotate(10, Rotate.X_AXIS);
private final Rotate rotateY = new Rotate(-10, Rotate.Y_AXIS);
private double mousePosX;
private double mousePosY;
private double mouseOldX;
private double mouseOldY;
@Override
public void start(Stage stage) throws Exception {
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setFieldOfView(20);
camera.getTransforms().addAll (rotateX, rotateY, new Translate(-100, 100, -2000));
Text text = new Text(" Text3D ");
text.setStroke(Color.DARKGOLDENROD);
text.setFill(Color.DARKGOLDENROD);
text.setFont(Font.font(Font.getFamilies().get(new Random().nextInt(Font.getFamilies().size())), 30));
Group root = new Group(text);
Scene sceneAux = new Scene(root, root.getBoundsInLocal().getWidth(), root.getBoundsInLocal().getHeight());
SnapshotParameters sp = new SnapshotParameters();
double s = Screen.getPrimary().getOutputScaleX();
sp.setTransform(new Scale(s, s));
sp.setFill(Color.DARKMAGENTA);
Image image = root.snapshot(sp, null);
double radius = 400;
SpheroidMesh spheroid = new SpheroidMesh(radius);
((PhongMaterial) spheroid.getMaterial()).setDiffuseMap(image);
Group group = new Group(spheroid);
Scene scene = new Scene(group, 400, 300, true, SceneAntialiasing.BALANCED);
scene.setFill(Color.BISQUE);
scene.setCamera(camera);
scene.setOnMousePressed(event -> {
mousePosX = event.getSceneX();
mousePosY = event.getSceneY();
});
scene.setOnMouseDragged(event -> {
mousePosX = event.getSceneX();
mousePosY = event.getSceneY();
rotateX.setAngle(rotateX.getAngle() - (mousePosY - mouseOldY));
rotateY.setAngle(rotateY.getAngle() + (mousePosX - mouseOldX));
mouseOldX = mousePosX;
mouseOldY = mousePosY;
});
stage.setScene(scene);
stage.setTitle("FXyz3D Sample");
stage.show();
}
}
РЕДАКТИРОВАТЬ
Решение 3
Хотя это не является частью FXyz, вы также можете применить некоторые преобразования, чтобы обернуть Text3DMesh
вокруг сферы.
Каждая буква в основном представляет собой TriangleMesh
с переводомпреобразовать в X (offset
).
Итак, мы берем все точки для каждой буквы, удаляем преобразование и применяем смещение, поэтому у нас есть абсолютные координаты:
x = x + offset;
Затем мы вычисляем угол изгиба на основе заданногожелаемая длина дуги и фактическая ширина w
текстового узла.
t = (x - w/2) / (w/2) * Pi/2;
Тогда для каждой точки ее новые координаты будут:
x = (R + z) * cos(t);
z = (R + z) * Sin(t);
text3d.CurvedText3D.java
public class CurvedText3D extends Application {
private final Rotate rotateX = new Rotate(10, Rotate.X_AXIS);
private final Rotate rotateY = new Rotate(-10, Rotate.Y_AXIS);
private double mousePosX, mousePosY, mouseOldX, mouseOldY;
@Override
public void start(Stage stage) throws Exception {
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setFieldOfView(40);
camera.getTransforms().addAll (rotateX, rotateY, new Translate(-100, 100, -2000));
Text3DMesh text3D = new Text3DMesh("Round Text3D",
Font.getFamilies().get(new Random().nextInt(Font.getFamilies().size())), 100, true);
text3D.setHeight(30);
text3D.setTextureModeNone(Color.CRIMSON);
Bounds bounds = text3D.getBoundsInParent();
double width = bounds.getWidth();
double radius = Math.max(width, bounds.getHeight());
text3D.getMeshes().stream()
.forEach(m -> {
ObservableFloatArray points = ((TriangleMesh) m.getMesh()).getPoints();
float[] v = new float[points.size()];
points.toArray(v);
double offset = m.getTransforms().get(0).getTx();
m.getTransforms().clear();
for (int i = 0; i < v.length; i += 3) {
v[i] += offset;
double t0 = (v[i] - width / 2d) / (width / 2d) * Math.PI / 2;
double t1 = (radius + v[i + 2]) * Math.cos(t0);
double t2 = (radius + v[i + 2]) * Math.sin(t0);
v[i] = (float) t1;
v[i + 2] = (float) t2;
}
((TriangleMesh) m.getMesh()).getPoints().setAll(v);
});
SpheroidMesh spheroid = new SpheroidMesh(radius * 0.9);
spheroid.setTextureModeVertices3D(1530, p -> p.x * p.y);
Group group = new Group(spheroid, text3D);
Scene scene = new Scene(group, 400, 300, true, SceneAntialiasing.BALANCED);
scene.setFill(Color.BISQUE);
scene.setCamera(camera);
scene.setOnMousePressed(event -> {
mousePosX = event.getSceneX();
mousePosY = event.getSceneY();
});
scene.setOnMouseDragged(event -> {
mousePosX = event.getSceneX();
mousePosY = event.getSceneY();
rotateX.setAngle(rotateX.getAngle() - (mousePosY - mouseOldY));
rotateY.setAngle(rotateY.getAngle() + (mousePosX - mouseOldX));
mouseOldX = mousePosX;
mouseOldY = mousePosY;
});
stage.setScene(scene);
stage.setTitle("FXyz3D Sample");
stage.show();
}
}