在JavaFX中使用不同的纹理创建多维数据集 [英] Create a cube using different textures in JavaFX

查看:64
本文介绍了在JavaFX中使用不同的纹理创建多维数据集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何创建一个在每侧使用不同图像的多维数据集?

How can I create a cube that uses different images for each side?

我想使用用户的输入来选择要动态使用的图像.

I would like to choose the images to use dynamically, using the user's input.

显而易见的解决方案是创建六个单独的矩形(这在性能上会不会更差吗?),但是有一种方法可以利用现有的Box功能(例如,类似于

The obvious solution would be to create six separate rectangles (wouldn't this be worse performance-wise?), but is there a way that utilizes the existing Box functionality (e.g. something similar to TextureCubeMap in Java3D)?

到目前为止,我发现的所有解决方案都是使用一个图像作为整个多维数据集的纹理(例如:

So far all I've found are solutions using one image as a texture for the entire cube (example: this.)

推荐答案

我最终写了一个原始的纹理图集类,并使用WritableImage组合了图像.使用当前正在阅读的bin装箱算法可能会更有效,但是在我的特例中,所有图像都具有相同的宽度,这对我来说很好用.它只是垂直放置图像.但是,其当前结构应易于扩展到布局不同的地图集实施中.

I ended up writing a primitive texture atlas class, combining the images using a WritableImage. It could be more efficient using bin packing algorithms, which I am currently reading up on, but in my special case where all images are the same width this works fine for me. It just lays out the images vertically. However, its current structure should be easily extendable to a differently laid-out atlas implementation.

地图集:

public class TextureAtlas {

    private final Image image;

    private final Map<String, TextureRegion> regions;

    public TextureAtlas(Image image) {
        this.image = image;
        regions = new HashMap<>();
    }

    /**
     * Creates an extremely primitive texture atlas.
     * Could use bin packing eventually.
     */
    public TextureAtlas(Map<String, Image> images) {
        this.regions = new HashMap<>();
        int height = (int) Math.ceil(images.values().stream().mapToDouble(Image::getHeight).sum());
        OptionalDouble w = images.values().stream().mapToDouble(Image::getWidth).max();
        WritableImage i = new WritableImage(w.isPresent() ? (int) w.getAsDouble() : 0, height);
        int h = 0;
        PixelWriter writer = i.getPixelWriter();
        for(Map.Entry<String, Image> entry : images.entrySet()) {
            Image img = entry.getValue();
            PixelReader reader = img.getPixelReader();
            for(int x = 0; x < img.getWidth(); x++)
                for(int y = 0; y < img.getHeight(); y++)
                    writer.setColor(x, y + h, reader.getColor(x, y));
            createRegion(entry.getKey(), img, 0, h, (int) img.getWidth(), (int) img.getHeight());
            h += img.getHeight();
        } this.image = i;
    }

    public TextureRegion createRegion(String name, int x, int y, int width, int height) {
        TextureRegion reg;
        regions.put(name, reg = new TextureRegion(this, x, y, width, height));
        return reg;
    }

    private TextureRegion createRegion(String name, Image image, int x, int y, int width, int height) {
        TextureRegion reg;
        regions.put(name, reg = new TextureRegion(this, x, y, width, height));
        return reg;
    }

    public TextureRegion getRegion(String name) {
        return regions.get(name);
    }

    public Map<String, TextureRegion> getRegions() {
        return Collections.unmodifiableMap(regions);
    }

    public int getWidth() {
        return (int) image.getWidth();
    }

    public int getHeight() {
        return (int) image.getHeight();
    }

    public int getColorAt(int x, int y) {
        if(x >= image.getWidth() || y >= image.getHeight()) return -1;
        return image.getPixelReader().getArgb(x, y);
    }

    public Image getImage() {
        return image;
    }

}

纹理区域:

public class TextureRegion {

    public final TextureAtlas atlas;
    public final int x, y, width, height;
    private Image image;

    public TextureRegion(TextureAtlas atlas, int x, int y, int width, int height) {
        this.atlas = atlas;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    public TextureRegion(TextureAtlas atlas, Image image, int x, int y, int width, int height) {
        this.atlas = atlas;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.image = image;
    }

    public int getColorAt(int x, int y) {
        return atlas.getColorAt(this.x + x, this.y + y);
    }

    public double[] getTextureCoordinates(double x, double y) {
        return new double[] {getU(x), getV(y)};
    }

    public double[] scaleTextureCoordinates(double u, double v, double max) {
        return new double[] {scaleU(u, max), scaleV(v, max)};
    }

    public double getU(double x) {
        return (this.x + x) / atlas.getWidth();
    }

    public double getV(double y) {
        return (this.y + y) / atlas.getHeight();
    }

    public double scaleU(double u, double max) { //For conversion from UV systems using a different max value than 1.0
        return getU(u / max * this.width);
    }

    public double scaleV(double v, double max) {
        return getV(v / max * this.height);
    }

    public Image getImage() {
        if(image != null) return image; //Lazily initialize
        else {
            WritableImage img = new WritableImage(width, height);
            PixelWriter writer = img.getPixelWriter();
            PixelReader reader = atlas.getImage().getPixelReader();
            for(int x = 0; x < width; x++)
                for(int y = 0; y < height; y++)
                    writer.setArgb(x, y, reader.getArgb(x + this.x, y + this.y));
            return this.image = img;
        }
    }

}

TextureRegion s代表地图集的一个区域,getImage返回代表整个区域的延迟初始化的Image.

TextureRegions represent a region of the atlas and getImage returns a lazily-initialized Image representing the entire region.

这篇关于在JavaFX中使用不同的纹理创建多维数据集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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