トップ 差分 一覧 ソース 検索 ヘルプ RSS ログイン

unity_script_create_texture2d

テクスチャの作成

スクリプト内でテクスチャを作成して独自描画を行います。

Texture2D m_texture;
m_texture = new Texture2D(128, 128, TextureFormat.ARGB32, false);

Texture2Dコンストラクタの第一引数はテクスチャの幅、第二引数はテクスチャの高さ、第三引数はテクスチャフォーマット、第四引数はミップマップを作成するか、になります。

 テクスチャの色の指定

Color col = new Color(1.0f, 0.0f, 0.0f, 1.0f);   // Red/Green/Blue/Alphaの順に色指定.
for (int y = 0; y < m_texture.height; y++) {
  for (int x = 0; x < m_texture.width; x++) {
    m_texture.SetPixel(x, y, col);
  }
}
m_texture.Apply();

のようにすると、1ピクセルごとに色指定します。
SetPixel()で色指定、Apply()で確定します。

 注意事項

Texture2Dへのピクセル描画は速度的には重い部分になりますので、インタラクティブな処理時にはピクセル色格納をしないほうがよいかもしれません。
また、2のべき乗サイズでないと内部的なサイズ変換処理が走るため速度低下につながります。

 まとめてテクスチャ色を指定

複数のピクセル色を配列で用意し、まとめてピクセル色を更新します。

Color [] cols = new Color[256];
for (int i = 0; i < 256; i++) cols[i] =  Color.green;
m_texture.SetPixels(0, 0, 16, 16, cols);
m_texture.Apply();

この場合は、テクスチャ上の(0, 0)の位置から幅16 x 高さ16の範囲に緑色を指定します。

 GameObjectにテクスチャを割り当て

シーンに配置されているGameObjectにテクスチャを割り当てるには、GameObjectの「renderer.material.mainTexture」に作成したTexture2Dを指定します。

GameObject.Find("Plane").renderer.material.mainTexture = m_texture;

この場合は、GameObject名が「Plane」のものを探してテクスチャを割り当ててます。
もしくは、

GameObject.Find("Plane").renderer.material.SetTexture("_MainTex", m_texture);

も同義です。
シェーダーで「BumpedDiffuse」を指定している場合は、法線マップテクスチャは

GameObject.Find("Plane").renderer.material.SetTexture("_BumpMap", m_textureNormal);

のように指定することになります。

private Texture2D m_texture;

void Start () {
  // テクスチャの生成.
  m_texture = new Texture2D(128, 128, TextureFormat.ARGB32, false);

  // テクスチャ模様の指定.
  for (int y = 0; y < m_texture.height; y++) {
    for (int x = 0; x < m_texture.width; x++) {
      if ((x & 1) != 0 && (y & 1) == 0) m_texture.SetPixel(x, y, Color.red);
      else m_texture.SetPixel(x, y, Color.white);
    }
  }

  // テクスチャ模様を確定.
  m_texture.Apply();

  // GameObjectのPlaneにテクスチャ割り当て.
  GameObject.Find("Plane").renderer.material.mainTexture = m_texture;
}

これで、後は自動的にPlaneのテクスチャが指定のTexture2Dのものになります。


 法線マップを持つマテリアルかどうか

Material nMat = GameObject.Find("Plane").renderer.material;
if (nMat.HasProperty("_BumpMap")) {   // 法線マップを指定できるマテリアルか判定.
    nMat.SetTexture("_BumpMap", m_textureNormal);
}

のように「HasProperty」で判定できる。

 Assetからのテクスチャの使用

スクリプトのpublicとして

public Texture2D m_icon;

のような変数指定を行い、一度Unityの画面に戻ります。
すると、スクリプトを使用しているGameObjectのInspectorウィンドウに
Iconというものが列挙されています。ここにAssetからのイメージを割り当てると、
自動的にm_iconにTexture2Dのイメージが読み込まれます。


 アルファを持つテクスチャ


アルファ値として0.0を指定した場合、そのピクセルは透過になります。
しかし、そのままでは透過を行うことはできません。

Texture2D m_texture;
m_texture = new Texture2D(128, 128, TextureFormat.ARGB32, false);

のように「TextureFormat.ARGB32」指定に加えて

GameObject.Find("Plane").renderer.material.mainTexture = m_texture;

のようにテクスチャを割り当てる形状のマテリアルのシェーダーが「Transparent/Diffuse」などになっている必要があります。


以下のように、透過でテクスチャが描画されます。

影をシャドウマップで落とす場合は「Transparent/Cutout/Diffuse」シェーダーを指定すると、影が有効になります。

 法線マップの作成


GameObjectとしては以下のように割り当てます。

Material nMat = GameObject.Find("Plane").renderer.material;
if (nMat.HasProperty("_BumpMap")) {   // 法線マップを指定できるマテリアルか判定.
    nMat.SetTexture("_BumpMap", m_textureNormal);
}

int m_width  = 512;
int m_height = 512;
m_textureNormal = new Texture2D(m_width, m_height, TextureFormat.ARGB32, false);

法線マップとしての凸凹のない状態は(0.5, 0.5, 1.0)になる(Z要素が上方向)。
AndroidとPCでの実行では挙動が違う模様。

// 凸凹の濃淡をバンプマップとして保持.
float [][] bumps = new float[m_height][];
for (int y = 0; y < m_height; y++) {
  bumps[y] = new float[m_height];
  for (int x = 0; x < m_width; x++) {
    bumps[y][x] = 0.0f;
  }
}
// 各ピクセルの濃度をピクセルごとに指定(0.0 - 1.0)。.
// ...

// バンプを法線として格納.
float strength = 0.01f;
float left_p, right_p, top_p, bottom_p;
for (int y = 0; y < m_height; y++) {
  for (int x = 0; x < m_width; x++) {
    left_p = right_p = top_p = bottom_p = bumps[y][x];
    if (x - 1 >= 0) left_p = bumps[y][x - 1];
    if (x + 1 < m_width) right_p = bumps[y][x + 1];
    if (y - 1 >= 0) top_p =  bumps[y - 1][x];
    if (y + 1 < m_height) bottom_p =  bumps[y + 1][x];
    Vector3 vv = Vector3.zero;
    vv.x = right_p - left_p;
    vv.y = bottom_p - top_p;
    vv.z = strength;
    vv.Normalize();
    float x_delta = vv.x * 0.5f + 0.5f;
    float y_delta = vv.y * 0.5f + 0.5f;
    float z_delta = vv.z * 0.5f + 0.5f;

    // PCでの法線マップの格納値.
    Color col2 = new Color(y_delta, y_delta, y_delta, x_delta);

    m_textureNormal.SetPixel(x, y, col2);
  }
}

PCでの実行は上のようにすると、法線マップの凸凹がつきます。Colorとしては、
(y_delta, y_delta, y_delta, x_delta)として格納している点に注意してください。

androidでの実行時は、以下のように指定すると反映されるようです(ごく一般的な法線マップ指定)。

 Color col2 = new Color(x_delta, y_delta, z_delta);