在JavaFX中使用不同的纹理创建一个立方体

时间:2017-01-26 19:59:05

标签: java javafx javafx-8

如何为每一面创建一个使用不同图像的立方体?

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

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

到目前为止,我发现只有使用一个图像作为整个立方体的纹理的解决方案(例如:TextureCubeMap。)

2 个答案:

答案 0 :(得分:2)

我最终编写了一个原始纹理图集类,使用WritableImage组合图像。使用bin打包算法可能更有效,我目前正在阅读,但在我的特殊情况下,所有图像都是相同的宽度,这对我来说很好。它只是垂直放置图像。但是,它目前的结构应该可以轻松扩展到不同布局的地图集实施。

阿特拉斯:

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代表地图集的某个区域,getImage返回一个代表整个地区的延迟初始化Image

答案 1 :(得分:1)

为什么不将单独的图像复制到一个图像中?您甚至可以通过画布和快照在程序中执行此操作。