2017-01-26 6 views
0

各面に異なるイメージを使用するキューブはどのように作成できますか?JavaFXで異なるテクスチャを使用してキューブを作成

ユーザーの入力を使用して、動的に使用するイメージを選択したいと考えています。

明白な解決策は、6つの別々の矩形を作成することです(これはパフォーマンスが悪くないでしょうか?)が、既存のBox機能を使用する方法がありますか?(Java3DのTextureCubeMapなど)これまでのところ私が見つけたすべては全体キューブのテクスチャとして一つの画像を使用したソリューションです

(例:。this

答えて

2

私は、WritableImageを使用して画像を結合して、基本的なテクスチャアトラスクラスを作成しました。私は現在読んでいるビンパッキングアルゴリズムを使用する方が効率的かもしれませんが、すべての画像が同じ幅である私の特別なケースでは、これはうまく動作します。画像を垂直方向に並べるだけです。しかし、現在の構造は、異なるレイアウトのアトラス実装に容易に拡張可能でなければなりません。

アトラス:

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の領域を表します。

+0

よくできました。それはあなたの質問に答えたときの私の心にあったものです。私は明示的にキーワード "テクスチャアトラス"を述べておくべきです:-)。 – mipa

1

あなただけの単一のものに別々の画像をコピーしていないのはなぜ?キャンバスとそのスナップショットを使ってプログラム内で行うこともできます。

関連する問題