在2DFX中使用2D文本到3D场景会导致文本模糊 [英] Use 2D Text into 3D scenes in JavaFX results in blurry texts

查看:183
本文介绍了在2DFX中使用2D文本到3D场景会导致文本模糊的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在3D场景中显示各种Text对象



问题是,当我缩放到文本附近时,它看起来非常模糊。



这是我的应用程序的屏幕截图





问题:如何改善屏幕上文字的图像质量?



我'尝试设置缓存,如



卡片看起来很暗,但是在环境光线下我们可以摆脱它的黑暗背景。



让我们生成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);
}

最后设置subScene:

  subScene.setFill(Color.WHITESMOKE); 
subSceneRoot.getChildren()。add(new AmbientLight(Color.WHITE));

并运行它:





并使用相机进行缩放:





文字看起来不再模糊了。如果您仍然需要更高的分辨率,则可以创建更大的快照,但这会带来内存成本。



还有一个小问题,因为卡片不透明并覆盖在它们后面(我试图尽可能减少它们的高度)。


I'm trying to display various Text objects inside a 3D scene

The problem is that when i zoom close to the text it looks very blurry.

Here's a screenshot from my app

Question: how can i improve the graphic quality of the text on the screen?

I've tried setting cache as in JavaFX 2D text with background in 3D scene because it seemed to improve graphics quality on the answer screenshots but it did not help me in my case.

Below is a compileable example stripped down form my app. It just create some random Text objects with positions and provides you a way to move around. Notice how the texts displays horribly when you zoom close.

You F10 and F11 to zoom in and out and mouse drag to move the camera.

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);
    }

}

解决方案

The main difference between what you are trying to do and the referred question is the camera movement: cache worked in that question because while rotating the node, the camera remained at the same position.

But in your case, you render the Text nodes at a given position, and with a given quality, and when you start translating the camera, these nodes are not rendered differently (with different size or quality), thus they become blurry.

If cache won't work, there is another possibility, as suggested in this other question: using 3D nodes.

This has the obvious cost of dealing with 3D objects, more heavy weight than the 2D text nodes.

The main idea is: for a given text, we'll write the text into an image, and we'll use this image as the diffuse map of a 3D cuboid. Then we'll add the cuboid to the sub scene and translate to the x,y,z coordinates.

We need the CuboidMesh from FXyz3D library, as the built-in 3D Box places the same image into every face, so that wouldn't work. We can implement a 3D prism with a custom TriangleMesh as well, but the cuboid already provides that.

Then we can generate a net image for the cuboid, and set it so we have the desired card:

private CuboidMesh generateCard(String message) {

    Text text5 = new Text(message);
    text5.setFont(Font.font("Arial", FontWeight.BLACK, FontPosture.REGULAR, 60));
    GridPane grid = new GridPane();
    grid.setAlignment(Pos.CENTER);

    CuboidMesh contentShape = new CuboidMesh(40, 8, 0.01);
    PhongMaterial shader = new PhongMaterial();

    GridPane.setHalignment(text5, HPos.CENTER);

    grid.add(text5, 3, 1);

    double w = contentShape.getWidth() * 10; // more resolution
    double h = contentShape.getHeight() * 10;
    double d = contentShape.getDepth() * 10;
    final double W = 2 * d + 2 * w;
    final double H = 2 * d + h;

    ColumnConstraints col1 = new ColumnConstraints();
    col1.setPercentWidth(d * 100 / W);
    ColumnConstraints col2 = new ColumnConstraints();
    col2.setPercentWidth(w * 100 / W);
    ColumnConstraints col3 = new ColumnConstraints();
    col3.setPercentWidth(d * 100 / W);
    ColumnConstraints col4 = new ColumnConstraints();
    col4.setPercentWidth(w * 100 / W);
    grid.getColumnConstraints().addAll(col1, col2, col3, col4);

    RowConstraints row1 = new RowConstraints();
    row1.setPercentHeight(d * 100 / H);
    RowConstraints row2 = new RowConstraints();
    row2.setPercentHeight(h * 100 / H);
    RowConstraints row3 = new RowConstraints();
    row3.setPercentHeight(d * 100 / H);
    grid.getRowConstraints().addAll(row1, row2, row3);
    grid.setPrefSize(W, H);
    grid.setBackground(new Background(new BackgroundFill(Color.WHITESMOKE, CornerRadii.EMPTY, Insets.EMPTY)));
    new Scene(grid);
    WritableImage image = grid.snapshot(null, null);
    shader.setDiffuseMap(image);
    contentShape.setMaterial(shader);
    return contentShape;
}    

The card looks dark, but with ambient light we can get rid of its dark background.

Let's generate the 100 cards:

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);
}

Finally set the subScene:

subScene.setFill(Color.WHITESMOKE);
subSceneRoot.getChildren().add(new AmbientLight(Color.WHITE));

and run it:

and zoom with the camera:

The text doesn't look blur anymore. If you still want more resolution you can create bigger snapshots, but that comes with a memory cost.

There is still a small issue, as the cards are not transparent and cover those behind them (I've tried to reduce their height as much as possible).

这篇关于在2DFX中使用2D文本到3D场景会导致文本模糊的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆