在JavaFX中将2D文本用于3D场景会导致文本模糊
我试图在3D场景中显示各种文本对象 问题是,当我放大文本时,它看起来非常模糊 这是我的应用程序的截图 问题:如何提高屏幕上文本的图形质量 我曾尝试将缓存设置为中,因为它似乎可以提高答案屏幕截图上的图形质量,但对我的情况没有帮助 下面是一个可编译的示例,从我的应用程序中剥离出来。它只是创建一些随机的文本对象和位置,并为您提供了一种移动的方式。请注意,当您缩小时,文本显示得非常糟糕 您可以F10和F11进行放大和缩小,并拖动鼠标来移动相机在JavaFX中将2D文本用于3D场景会导致文本模糊,javafx,javafx-3d,Javafx,Javafx 3d,我试图在3D场景中显示各种文本对象 问题是,当我放大文本时,它看起来非常模糊 这是我的应用程序的截图 问题:如何提高屏幕上文本的图形质量 我曾尝试将缓存设置为中,因为它似乎可以提高答案屏幕截图上的图形质量,但对我的情况没有帮助 下面是一个可编译的示例,从我的应用程序中剥离出来。它只是创建一些随机的文本对象和位置,并为您提供了一种移动的方式。请注意,当您缩小时,文本显示得非常糟糕 您可以F10和F11进行放大和缩小,并拖动鼠标来移动相机 package timelinefx; import s
package timelinefx;
import static javafx.application.Application.launch;
import java.util.Random;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.scene.CacheHint;
public class TextInto3DScene extends Application {
static Stage stage;
static Scene scene;
static Group root;
static Group subSceneRoot;
static PerspectiveCamera camera;
static SubScene subScene;
static boolean cached = true;
static int width = 1000;
static int height = width;
@Override
public void start(Stage primaryStage) throws Exception {
createWindow();
}
protected static void createWindow(){
stage = new Stage();
root = new Group();
root.setCache(cached);
root.setCacheHint(CacheHint.QUALITY); //doesn't work
scene = new Scene(root, 1500, 700, true, SceneAntialiasing.BALANCED);
//Initialize the camera
camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(5000);
camera.setTranslateZ(-200);
//creates the SubScene and add the camera to it!
subSceneRoot = new Group();
subSceneRoot.setCache(cached); //doesn't work
subScene = new SubScene(subSceneRoot, 1800, 700, true, SceneAntialiasing.BALANCED);
subScene.setCache(cached);
root.getChildren().add(subScene);
subScene.setFill(Color.WHITE);
subScene.setCamera(camera);
//Create random texts
for( int i = 0;i<=100;++i){
Text text = new Text(Math.random()* width-width/2, Math.random()*height-height/2, randomText() );
text.setFill( Color.BLACK );
text.setTranslateZ( Math.random()*750 );
text.setCache(cached); //doesn't work
text.setCacheHint(CacheHint.QUALITY);
subSceneRoot.getChildren().add(text);
}
stage.setScene(scene);
setEventHandlers();
stage.show();
}
static void setEventHandlers() {
scene.setOnMouseDragged((event) -> {
//camera.setRotate(event.getX());
double translateX = (event.getSceneX() - 0) / stage.getWidth();
translateX = translateX * width - width/2;
double translateY = (event.getSceneY() - 0) / stage.getHeight();
translateY = translateY * height - height/2;
double tz;
if(!camera.getTransforms().isEmpty()){
tz = camera.getTransforms().get(0).getTz();
} else {
tz = camera.getTranslateZ();
}
camera.getTransforms().clear();
camera.getTransforms().addAll( new Translate(translateX, translateY, tz) );
});
//KEY PRESSED
scene.setOnKeyPressed((event) -> {
switch (event.getCode().toString()) {
case "F10":
double amt = event.isControlDown() ? 100 : 30;
camera.setTranslateZ(camera.getTranslateZ() + amt);
break;
case "F11":
amt = event.isControlDown() ? -100 : -30;
camera.setTranslateZ(camera.getTranslateZ() + amt);
break;
}
});
}
static String randomText(){
String out = "";
Random r = new Random();
for(int i = 0;i<=10;++i){
char c = (char) (r.nextInt(26) + 'a');
out += c;
}
return out;
}
public static void main(String[] args) {
launch(args);
}
}
package timelinefx;
导入静态javafx.application.application.launch;
导入java.util.Random;
导入javafx.application.application;
导入javafx.scene.Group;
导入javafx.scene.PerspectiveCamera;
导入javafx.scene.scene;
导入javafx.scene.sceneatialiasing;
导入javafx.scene.SubScene;
导入javafx.scene.paint.Color;
导入javafx.scene.text.text;
导入javafx.scene.transform.Translate;
导入javafx.stage.stage;
导入javafx.scene.CacheHint;
公共类textinoto3dsecene扩展应用程序{
静态阶段;
静态场景;
静态群根;
静态群次塞诺;
静态透视照相机;
静态亚新统;
静态布尔缓存=真;
静态整数宽度=1000;
静态整数高度=宽度;
@凌驾
public void start(Stage primaryStage)引发异常{
createWindow();
}
受保护的静态void createWindow(){
阶段=新阶段();
root=新组();
setCache(缓存);
root.setCacheHint(CacheHint.QUALITY);//不起作用
场景=新场景(root,1500700,true,sceneatialiasing.BALANCED);
//初始化相机
摄像头=新透视摄像头(正确);
摄像头。setNearClip(0.1);
相机。setFarClip(5000);
照相机.setTranslateZ(-200);
//创建子场景并将摄影机添加到其中!
subSceneRoot=新组();
subSceneRoot.setCache(缓存);//不工作
亚新世=新亚新世(亚新世,1800,700,真实,场景化。平衡);
subScene.setCache(缓存);
root.getChildren().add(子场景);
亚新世。刚毛填充(颜色。白色);
亚场景设置摄像机(摄像机);
//创建随机文本
对于(int i=0;i而言,您尝试执行的操作与引用的操作之间的主要区别在于摄影机移动:缓存在该问题中起作用,因为在旋转节点时,摄影机保持在相同的位置
但在本例中,您在给定的位置以给定的质量渲染文本节点,当您开始平移摄影机时,这些节点的渲染方式不同(大小或质量不同),因此它们变得模糊
如果缓存不起作用,那么还有另一种可能性,正如本文中所建议的:使用3D节点
这显然需要处理3D对象,比2D文本节点更重
其主要思想是:对于给定的文本,我们将文本写入一幅图像,并将该图像用作三维长方体的漫反射贴图。然后我们将长方体添加到子场景中,并转换为x、y、z坐标
我们需要FXyz3D中的长方体网格
,因为内置的3D框
将相同的图像放置到每个面中,所以这不起作用。我们也可以使用自定义的三角形网格
实现3D棱镜,但长方体已经提供了这一功能
然后,我们可以生成长方体的净图像,并将其设置为获得所需的卡:
这张卡片看起来很暗,但是有了环境光,我们可以去掉它的暗背景
让我们生成100张卡片:
for (int i = 0; i <= 100; i++) {
CuboidMesh card = generateCard(randomText());
card.setTranslateX(Math.random() * width - width / 2);
card.setTranslateY(Math.random() * height - height / 2);
card.setTranslateZ(Math.random() * 750);
subSceneRoot.getChildren().add(card);
}
然后运行它:
并使用相机进行缩放:
文本看起来不再模糊。如果你仍然想要更高的分辨率,你可以创建更大的快照,但这需要内存成本
还有一个小问题,因为卡片不透明,并且覆盖了后面的卡片(我已经尽量降低了它们的高度).非常感谢您解决了这个问题,并提供了一个示例!出于好奇,为什么不使用ImageView而不是长方体?我刚刚做了一些测试,它工作了。我还做了一个小例程,检查图像上的白色像素(对于ex,R、G和B>=0.8)我没有尝试ImageView,但是很明显,如果你要创建一个快照并显示一个高分辨率的图像,它应该可以工作(并且允许透明,正如你提到的)。每当我必须使用3D时,我宁愿只使用3D节点,正如您所经历的那样,2D和3D并没有很好的混合。
for (int i = 0; i <= 100; i++) {
CuboidMesh card = generateCard(randomText());
card.setTranslateX(Math.random() * width - width / 2);
card.setTranslateY(Math.random() * height - height / 2);
card.setTranslateZ(Math.random() * 750);
subSceneRoot.getChildren().add(card);
}
subScene.setFill(Color.WHITESMOKE);
subSceneRoot.getChildren().add(new AmbientLight(Color.WHITE));