サイトのトップへ戻る

libGDX ドキュメント 日本語訳

サイト内検索

Material と Environment

実際、描写時にあなたは何を描写するのか(形状)とどうやって描写するのか(マテリアル)を指定しています。 形状は、Mesh (またはより一般的な MeshPart)を使って指定されます。Mesh ではシェーダーの頂点属性を定義しています。 マテリアルとは、シェーダーのユニフォーム値を指定するのに最もよく使用されるものです。

ユニフォームは、model 固有のユニフォーム変数(例えば、適用されるテクスチャや、ブレンド処理を使用するかどうか)と環境ユニフォーム変数(例えば、適用される光源やキューブ環境マッピング)に分けることができます。同様に、3D api を使うことで material と environmentを設定できます。



Material

Materialはmodel (または modelinstance) 固有のものです。インデックス指定model.materials.get(0)や名前指定 model.getMaterial("material3")やnodepart指定 model.nodes.get(0).parts(0).materialを使ってアクセスできます。 ModelInstanceを作成した時Materialはコピーされます、つまり、ModelInstance のマテリアルを変更しても元のModel やその他ModelInstancesには影響を与えません。

Material クラスは Attribute クラスを継承しています。Attributeの詳細については後述する内容を参照してください。



Environment

Environment には場所に対するユニフォーム変数が含まれています。 例えば、照明(lights)は Environmentの一部です。 単純なアプリケーションではEnvironmentを1つだけ使用し、より複雑なアプリケーションではModelInstanceの位置に応じた複数のEnvironmentを使用しているかもしれません。 1つのModelInstance (または Renderable) は1つの Environment しか保持することができないにもかかわらずです。

Environment クラスは Attribute クラスを継承しています。Attributeの詳細については後述する内容を参照してください。



Lights

バージョン 1.5.7 から、lights は attributesへ移行されました。つまり、environment や materialにlight を取り付けることができます。 environment.add(light)メソッドを使用してenvironment にlight を追加する方法は今でも行うことができます。 しかし、 DirectionalLightsAttribute属性とPointLightsAttribute属性と SpotLightsAttribute属性を使用することもできます(下記参照)。 これらの各属性には、1つ以上のlightを取り付けるのに使用できる配列を持っています。 ただし、通常はどちらか一方しか使用できないので注意してください。 light をenvironment のPointLightsAttribute に追加して、それから別のlight をmaterialのPointLightsAttributeに追加した場合、 DefaultShaderはenvironmentに追加されたpoint lightを無視します。 Light は常に参照によって使用されます。

Lightは重要度によって並べ替える必要があります。通常これは、 lightsは距離によって並べ替える必要があるということを意味します。 例えば、既定では DefaultShader(設定可能)は、シェーダーライティングに最初の5個のpoint lightを使用します。残りの照明は周囲のキューブマップに追加されますが、これは正確な処理とは言えません。



Attribute

Environmentクラスと Material クラスは両方とも Attributeクラスを継承しています。 最も一般的には、Attributeクラスはユニフォーム値を設定するのに使用されます。 For example a TextureAttribute can be used to specify an uniform to bound for a shader. However, attributes don't have to be uniforms, for example DepthTestAttribute is used to alter the opengl state and doesn't set an uniform.

Attributeクラスは Setに最も似ています。 ユニフォーム変数に1つの値しか設定できないように、Attributeクラスでは各属性ごとに最大でも1つの値しか持つことができません。 理論的にはMaterial とEnvironment は両方とも同じ属性を持つことができ、この場合の実際の動きがどうなるかは使用するシェーダーに依存します。 ですが、大抵の場合はEnvironment の属性ではなくMaterialの属性が使用されるでしょう。



属性タイプ

全ての属性はlong 型の値 type を持っており、これは属性を識別するのに使用されるビットマスクです。 したがって、完成したmaterial やenvironment は1つのlong値を使って表すことができます。long値の各ビットが属性を表します。 いくつかのattribute クラスは単一のタイプの値(bit)専用です。 それ以外のattribute クラスは複数のタイプの値(bits)のために使用され、この場合コンストラクターでタイプを指定する必要があります。 例えば:

Attribute attribute = new ColorAttribute(ColorAttribute.Diffuse, Color.RED);

ColorAttribute クラスには同じことを行える便利なメソッドが実装されているので覚えておいてください:

Attribute attribute = ColorAttribute.createDiffuse(Color.RED);


属性を使用する

属性で行う最も一般的なアクションは、 sethasremovegetです。

set メソッドを使うと属性の追加や変更を行うことができます。If there is already an attribute of the same type if will be first removed, after which the new attribute is added. 例: material.set(FloatAttribute.createAlphaTest(0.25f));

has メソッドを使用すると、特定の属性タイプが設定されているかを確認できます。 例えば: material.has(FloatAttribute.AlphaTest);。 また、複数の属性を確認することもできます。例: material.has(FloatAttribute.AlphaTest | ColorAttribute.Diffuse);。 この場合、has メソッドは全ての属性が設定されている場合のみtrue を返します。 hasメソッドはビットマスクを使用しているため非常に高速なので、例えば removeを呼び出す前にその属性が実際に設定されているかどうかを確認するのに使えます。覚えておいてください。

remove メソッドを使うことで、特定のタイプの属性を削除することができます。例:material.remove(FloatAttribute.AlphaTest);。 また一度に複数の属性を削除することもできます。例: material.remove(FloatAttribute.AlphaTest | ColorAttribute.Diffuse);

get メソッドを使って特定のタイプの属性を取得することができます。例: material.get(FloatAttribute.AlphaTest);。 その属性が設定されていなかった場合、get メソッドは nullを返します。 タイプはクラスを示しているので、型の確認をしなくても安全に戻り値をキャストできます: (FloatAttribute)material.get(FloatAttribute.AlphaTest);。 便宜上、テンプレートメソッドもあります: material.get(FloatAttribute.class, FloatAttribute.AlphaTest);

それ以外にも、clear(全ての属性を削除する)を使ったり、反復処理(Iterable<Attribute>を実装しています)を行ったり、属性の比較を行ったり (Comparator<Attribute>を実装していますが、sameメソッドでは追加のオブションがあります)もできます。 getMask() メソッドを使うと、全ての属性を含むマスクにアクセスできます。例えば material.getMask() & FloatAttribute.AlphaTest == FloatAttribute.AlphaTestmaterial.has(FloatAttribute.AlphaTest) と同じです。



カスタム属性タイプ

新たなカスタムタイプに標準のattribute クラスを使用することが可能です。 例えば、ColorAttribute クラスを使って色のカスタムタイプを設定したい場合です。 この場合、考慮しなければならないことが三つあります:

  1. 属性タイプに名前を付けてください。各属性タイプは一意の エイリアス (名前)を持たなければなりません。 これには統一した名前を使った方が良いかもしれません(しかし必須ではありません)。 このエイリアスはデバッグにも使用されます。例えば、attribute.toString()を呼び出す時。
  2. 属性タイプを登録してください。これは各ビットごとに1つの属性タイプしか存在しないようにするためです。 これはAttribute クラスかそのサブクラス内からのみ行うことができます。
  3. ColorAttribute がカスタムタイプを受け入れるようにしてください。 ColorAttribute クラスとその他大部分の attribute クラスでは、構築時にタイプの確認を行います。これにより、タイプ以外を確認せずに属性をキャストすることができます。 例えば、ColorAttribute はColorAttribute.Diffuseタイプのみを受け入れるので、(ColorAttribute)material.get(ColorAttribute.Diffuse) は問題なく動作します。

ステップ 2とステップ3のために、Attribute クラスを拡張してカスタム属性タイプを追加する必要があります。:

public class CustomColorTypes extends ColorAttribute {
    public final static String AlbedoColorAlias = "AlbedoColor"; // step 1: name the type
    public final static long AlbedoColor = register(AlbedoColorAlias); // step 2: register the type
    static {
        Mask |= AlbedoColor; // step 3: Make ColorAttribute accept the type
    }
    /** Prevent instantiating this class */
    private CustomColorTypes() {
        super(0);
    }
}

カスタム属性タイプを作成するには以下のようにします:

Attribute attribute = new ColorAttribute(CustomColorTypes.AlbedoColor, Color.RED);


カスタム属性

カスタム属性を作成することが可能です。この場合の手順は上記のものとあまり変わりません。 Attribute クラスを継承し、少なくとも1つのタイプを登録し、そしてもちろんシェーダーに渡すいくつかのデータを追加する必要があります。 例えば、シェーダーにdouble 値を渡すための属性を追加するには:

public class DoubleAttribute extends Attribute {
    public final static String MyDouble1Alias = "myDouble1";
    public final static long MyDouble1 = register(MyDouble1Alias);
    public final static String MyDouble2Alias = "myDouble2";
    public final static long MyDouble2 = register(MyDouble2Alias);
    protected static long Mask = MyDouble1 | MyDouble2;
    /** Method to check whether the specified type is a valid DoubleAttribute type */
    public static Boolean is(final long type) {
        return (type & Mask) != 0;
    }

    public double value;

    public DoubleAttribute (final long type) {
        super(type);
        if (!is(type))
            throw new GdxRuntimeException("Invalid type specified");
    }

    public DoubleAttribute (final long type, final double value) {
        this(type);
        this.value = value;
    }

    /** copy constructor */
    public DoubleAttribute (DoubleAttribute other) {
        this(other.type, other.value);
    }

    @Override
    public Attribute copy () {
        return new DoubleAttribute(this);
    }

    @Override
    public int hashCode () {
        final int prime = /* pick a prime number and use it here */;
        final long v = NumberUtils.doubleToLongBits(value);
        return prime * super.hashCode() + (int)(v^(v>>>32));
    }

    @Override
    public int compareTo (Attribute o) {
        if (type != o.type) return type < o.type ? -1 : 1;
        double otherValue = ((DoubleAttribute)o).value;
        return value == otherValue ? 0 : (value < otherValue ? -1 : 1);
    }
}

もちろん、 MyDouble1AliasMyDouble1"myDouble1"MyDouble2AliasMyDouble2"myDouble2" はより意味のある名前に変えたほうが良いでしょう。

例えば、 ModelModelInstanceを作成した時にはcopy()メソッドが呼び出されるので注意してください。 このメソッドではコピーされる属性に関わらず、編集可能な同一の属性インスタンスを返すべきです。 必須ではありませんが、 一般的にコピーコンストラクタはこれを実装するための良い方法です。

属性とマテリアルの比較に使用されるので、hashCode()メソッドを実装する必要があります。 例えば、二つのマテリアルが同じ属性(タイプ)を持ち、 equals()メソッドが属性タイプの各組み合わせごとにtrue を返した場合、それらは同じものと見なされます。 既定では、この場合 Attribute クラスのequals()メソッドは両方の属性の hashCode()を比較します。

マテリアルに基づいてrender 呼び出しを並び替えるために、compareTo(Attribute)メソッドを実装しなければなりません。 一般的にこの実装では常に最初にif (type != o.type) return type < o.type ? -1 : 1;の行を記述し、確実に同じタイプの属性を比較するようにします。

Attribute クラスは小さく自己完結型であるようにする必要があり、したがって常に Attributeクラスを直接継承するのがベストです。 Attribute クラスのサブクラスを継承して追加情報を追加するのは避けるようにしてください。



使用可能な属性

上記のようにカスタム属性を作成することは可能です。しかし既に用意されている属性がいくつかあります。それらを以下に一覧表記します。



BlendingAttribute

既定では、 3D api は全てのものが不透明であると想定しています。BlendingAttributeはマテリアルで最も一般的に使用されるもので (environmentの場合は既定動作が変わります。)、そのマテリアルにブレンド処理を行うかどうかを指定するのに使います。 BlendingAttributeでは作成時にタイプを指定する必要はなく、拡張していなければそのタイプは常にBlendingAttribute.Typeとなります。 BlendingAttributeは設定可能な四つのプロパティを持っています:

  • blendedはこのマテリアルをブレンド物として扱うかどうかを示します。これは主に並び替えで使用されます。例えば、透明なオブジェクトを描写するより前に不透明なオブジェクトの描写が行われます。
  • sourceFunctionは OpenGL の列挙体です。 赤、緑、青、透明度といったソースブレンドファクター(新たに描写するもの)をどのように計算するのかを設定します。 既定では GL_SRC_ALPHAが設定されています。
  • destFunction は OpenGL の列挙体です。赤、緑、青、透明度といったデスティネーションブレンドファクター(既に描写されているもの)をどのように計算するのかを設定します。 既定では GL_ONE_MINUS_SRC_ALPHAが設定されています。 加算ブレンド処理の場合はGL_ONEを設定した方がいいでしょう。
  • opacity は透明度の値です(ソースのアルファ値)。範囲は0(完全に透明)から1(完全に不透明)になります。


ColorAttribute

ColorAttribute を使うとシェーダーに色を渡すことができます。そのため、これは1つのプロパティ: .colorを持っているだけです。 インスタンス作成時(値で設定します)、もしくは.color.set(...)メソッドを使用して色を設定できます。 ColorAttribute では属性タイプを設定する必要があります、既定では以下のタイプが使用できます:

  • ColorAttribute.Diffuse
  • ColorAttribute.Specular
  • ColorAttribute.Ambient
  • ColorAttribute.Emissive
  • ColorAttribute.Reflection
  • ColorAttribute.AmbientLight
  • ColorAttribute.Fog

最後の二つはEnvironmentで最もよく使用され、他はMaterialで最もよく使用されます。



CubemapAttribute

Cubemapをシェーダーに渡すためには、CubemapAttributeが使用できます。 textureDescription メンバを使って、Cubemapと一緒にテクスチャ関連値を設定します。 CubemapAttribute では属性タイプを設定する必要があります、既定ではCubemapAttribute.EnvironmentMapのみが使用できます:



DepthTestAttribute

BlendingAttributeと同じ様に、DepthTestAttribute では属性タイプを必要としません。 属性タイプは常にDepthTestAttribute.Typeとなります。DepthTestAttribute は深度テストや深度バッファへの書き込みを指定するのに使われます。 以下のプロパティが使用できます。:

  • depthFunc は深度テスト機能を表し、 0 (もしくは GL_NONE)の場合は深度テストは無効になります。既定では GL20.GL_LEQUALとなっています。
  • depthRangeNear はニアクリッププレーンとウィンドウ座標との紐付けで、既定は0.0です。
  • depthRangeFar はファークリッププレーンとウィンドウ座標との紐付けで、既定は 1.0です。
  • depthMask は深度バッファ への書き込みを行うかどうかで、既定では有効となっています。


DirectionalLightsAttribute

DirectionalLightsAttribute は属性タイプを必要としません。属性タイプは常にDirectionalLightsAttribute.Typeとなります。 DirectionalLightsAttribute を使用してDirectionalLightインスタンスの配列を設定できます。 以下のプロパティを使って設定します。:

  • lights :lightの配列。重要度に応じて並べられる必要があります。


FloatAttribute

1つの浮動小数点値をシェーダーへ渡すためには、FloatAttribute を使用できます。 この値はインスタンス作成時か、もしくは .valueメンバを使って設定できます。 FloatAttribute では属性タイプが必要で、既定では以下が設定できます:

  • FloatAttribute.Shininess は面鏡照明に使用されます。
  • FloatAttribute.AlphaTest はアルファ値が指定した値以下だった場合にピクセルを破棄するために使用されます。


IntAttribute

FloatAttribute クラスと同様に、 IntAttribute を使うと整数値をシェーダーに渡すことができます。 同様に .value メンバを使用したり、インスタンス作成時に値を設定したりできます。 IntAttribute では属性タイプが必要で、既定では以下が設定できます:

  • IntAttribute.CullFace はOpenGL の列挙体で、GL_NONE (カリング処理はしない)か GL_FRONT (背面のみ描写する) か GL_BACK (前面のみ描写する)で面カリングを設定します。 既定値はシェーダーによって変わり、デフォルトシェーダーでは既定ではGL_BACKを使用します。


PointLightsAttribute

PointLightsAttribute は属性タイプを必要としません。属性タイプは常にPointLightsAttribute.Typeとなります。 PointLightsAttributeを使用してPointLight インスタンスの配列を設定できます。 以下のプロパティを使って設定します:

  • lights :lightの配列。重要度に応じて並べられる必要があります。


SpotLightsAttribute

デフォルトシェーダーではサポートされていません。SpotLightsAttribute は属性タイプを必要としません。 属性タイプは常に SpotLightsAttribute.Typeとなります。 SpotLightsAttributeを使ってSpotLightインスタンスの配列を設定できます。以下のプロパティを使って設定します:

  • lights :lightの配列。重要度に応じて並べられる必要があります。


TextureAttribute

TextureAttributeを使用して Texture をシェーダーへ渡すことができます。 CubemapAttribute と同様に、TextureAttributetextureDescriptionメンバを持っています。 これを使ってTextureと一緒に repeat や filterのようなテクスチャ関連値を設定できます。 さらに、使用するテクスチャの領域(テクスチャ座標変換)を設定するのに使用できるoffsetUメンバと offsetVメンバと scaleU メンバと scaleYメンバを持っています。 また、どのテクスチャ座標を使用するのかを設定するのに使用できる uvIndexメンバ(既定値は0)も持っています。 現時点では、デフォルトシェーダーはこのuvIndexメンバを無視して常に最初のテクスチャ座標を使用するので注意してください。

TextureAttribute は属性タイプが必要で、既定では以下のうち1つを設定できます:

  • TextureAttribute.Diffuse
  • TextureAttribute.Specular
  • TextureAttribute.Bump
  • TextureAttribute.Normal



エンジェル戦記