[HOME] [J3Wの紹介]

J3W ver.5.60 のテクスチャ解説

2008/11/01
Copyright (c) Jun Mizutani 2008

J3Wのテクスチャ

J3W ver. 5.60 でポリゴンにテクスチャを貼ることができます。 テクスチャ専用の命令を10種類追加しました。 ここではテクスチャの使い方をサンプルプログラムで解説します。(すべてJ3W 5.60 に含まれています。) 同じコードが何度もリストに出てきて冗長ですが、それぞれ実行できる完全なソースとなっています。

テクスチャの形式

テクスチャはビットマップファイル(拡張子が .bmp)形式で保存された画像ファイルを使用します。 ビットマップファイルは モノクロ(1bit)、16bit(X1R5G5B5)、24ビット(R8G8B8)、32ビット(X8R8G8B8)の形式が使えます。 ビットマップファイルの大きさは最大4MBで 1024x1024ドットが可能です。 テクスチャはプログラム中最大128枚使用することができます。

テクスチャを貼り付ける方法は平面マッピングと球面マッピングの2種類をサポートしています。 また頂点のUV座標を指定することも可能です。

ビットマップファイルはコンパイルされた「???.j3d」と同じディレクトリにおいて下さい。パスを指定すれば別ディレクトリに置くこともできます。ファイル名を変更しなければ画像の内容を書き換えても再コンパイルする必要はありません。

平面テクスチャマッッピング

図中で緑で示される数値をTextureAxis組み込み関数に渡すことでテクスチャを張り付ける方向を指定できます。スライドでテクスチャを投影したような形で物体に貼り付けられます。物体の裏側も物体を透過したようにテクスチャが貼られます。

TextureAxis.png

テクスチャのUV座標は貼りつける方向によって、オブジェクトのローカル座標系の対応する軸の座標の値をビットマップのサイズで除した値がそのまま渡されます。大きいポリゴンの場合はテクスチャを拡大して貼る必要があります。例えばローカル座標系で512x512の大きさのポリゴンに対して256x256ドットのビットマップをテクスチャとして貼り付けた場合、縦横2枚、合計4枚分のテクスチャが貼られます。2倍に拡大すると1枚分のテクスチャとなります。

球面テクスチャマッピング

球面テクスチャマッピングは物体のローカル座標系の原点を中心としてオブジェクトを手前から奥に包み込むようにマッピングします。 UV座標は物体のローカル座標系の原点原点から見た頂点座標の経度、緯度から自動的に計算されます。

TextureMap.png

球面マッピングを使うとどのような大きさ、形の物体に対してもテクスチャをゴムの膜で包み込むように貼ることができます。中心(物体の原点)から離れるほどテクスチャは拡大され、上下に中心軸に近づくほど縮小されます。北極、南極に相当する部分は縮小され、下地のポリゴンの形や大きさを工夫しないと歪が目立つため、テクスチャの上下の端には均一な色を使うようにします。TextureAxis組み込み関数によってマッピングの中心軸をX軸(1)、Y軸(2)、Z軸(3)のように指定できます。原点を通る面に対しては正常にマッピングできないため平面マッピングを使う必要があります。

テクスチャ関連命令の使い方

テクスチャを使う場合は、命令を使う場所に注意する必要があります。 以下の表に示す順序でテクスチャを設定します。それぞれデフォルトの値が設定されているため、TextureFile と TextureSet の2命令でテクスチャを物体に設定できます。それ以外の命令は、テクスチャをより細かくコントロールする場合に使用します。

 実行順序デフォルト値説明
共通GraphMode() テクスチャ操作はグラフィックモード必須
TextureAlpha() 100 必要ならテクスチャファイル指定前
TextureFile()  ビットマップファイルからテクスチャを生成
物体初期化物体生成 NewObject または Child
TextureMap() 0 (球面マッッピング)TextureMap, TextureAxis, TextureBias,
TextureSetは物体生成後、
頂点登録前なら任意の順序でよい
TextureAxis() 3 (Z軸中心)
TextureBias() (0, 0)
TextureSet() -1 (テクスチャ無効)平面マップの場合のみ頂点登録前
頂点登録 Point, DefPoint, PointUV, DefPointUV
TextureSet() -1 (テクスチャ無効)テクスチャ番号を指定
ポリゴン登録Plane, DefPlane
動的に変更可能 TextureChange() TextureSet=TextureFile変更しなければ不要
TextureScale() (100, 100)

テクスチャ用の命令

テクスチャ専用の命令が以下の10種類あります。テクスチャを使う場合 TextureFile と TextureSet の2命令は最低でも必要です。 テクスチャはビットマップファイルと結びついて、オブジェクト間で共通に使用するテクスチャファイル番号と 頂点やポリゴンを登録するときに使用するテクスチャ番号の2種類の番号で管理されます。


TextureFile(テクスチャファイル番号, "ファイル名")
  • ビットマップファイルをテクスチャとして読み込む
  • ビットマップファイルはモノクロ、16, 24, 32 bitが使用可
  • オブジェクト間で共通のテクスチャファイル番号を使用
  • テクスチャファイル番号は 0 から 127 の範囲を使用します。
  • グラフィックモードに切り替えた後に実行すること

TextureSet(テクスチャ番号")
  • オブジェクトで使用するテクスチャ番号を指定します。
  • テクスチャ番号は 0 から 127 の範囲を使用します。
  • テクスチャ番号が -1の時はテクスチャは貼られません(デフォルト)
  • テクスチャ番号はオブジェクト毎に独立しています。
  • オブジェクト生成(NewObject または Child)後に実行すること。
  • テクスチャを使用するオブジェクトの場合、頂点登録前に実行すること。
    平面マッピングでUV算出する場合、テクスチャサイズが必要となるため。

TextureAxis(軸指定数値)
  • 1:x, 2:y, 3:z が中心軸になります。
  • -1:x, -2:y, -3:z の場合は逆方向からテクスチャが貼られます。
  • 0 を指定するとz 軸を指定することと同じ。
  • 頂点毎に指定可能
  • オブジェクト生成 (New または Child) の後で、頂点登録(Point または DefPoint)前に実行すること。

TextureAlpha(透明度%)
  • テクスチャの透明度を0から100の範囲で指定する。100で不透明
  • 値が大きいほどテクスチャは不透明となる
  • TextureFileの前に実行すること

TextureScale(横の拡大率, 縦の拡大率)
  • テクスチャの拡大率の指定
  • 200とすると頂点のUまたはV座標を0.5倍します。この場合テクスチャの見かけの大きさは2倍になります。
  • いつでも実行して拡大率を動的に変更できます。

TextureChange(テクスチャ番号, テクスチャファイル番号)
  • テクスチャ番号に対応するテクスチャファイル番号を変更することでテクスチャを動的に変更できます。
  • テクスチャファイル番号に -1 を指定するとテクスチャマッピングを解除できます。
  • テクスチャファイル番号は TxtureFile関数で指定された番号
  • テクスチャ番号は頂点またはポリゴン登録時にTextureSetで指定された番号

TextureMap(マッピング方法)
  • テクスチャマッピングの方法を指定します
  • デフォルトは0で球面マップ、1:は平面マップ
  • オブジェクト生成(New または Child)後で、頂点登録
    (DefPoint または Point)前に実行すること
  • ポリゴン毎に指定可能

TextureBias(U座標, V座標)
  • 頂点登録時の頂点座標に対してTextureAxisの設定に対応した座標にオフセットを加えます。
  • 平面マッピングに対してのみ動作。球面マッピングには影響なし。
  • オブジェクト毎に指定し、その後に登録されたポリゴンに対して影響します。
  • ポリゴン登録後はそのポリゴンのオフセットは変更できません。

PointUV( )
  • UV座標を明示的に指定して頂点を登録する場合に使用します。
  • TextureAxis、TextureMap による影響は受けません。
  • 「物体」頂点座標の定義(レジスタRX,RY,RZにより指定)
  • 「物体」頂点のU座標をレジスタRH、V座標をレジスタRPに指定
  • DefPointUVと同じだが, 実行時に計算した頂点座標を定義可能
  • SetOffset, ClearOffset によるオフセットが加算されます。

DefPointUV(x, y, z, u, v)
  • プロセス所有の「物体」にUV座標付きの頂点座標を追加します。
  • UV座標を明示的に指定して頂点を登録する場合に使用します。
  • TextureAxis、TextureMap による影響は受けません。
  • 定数を指定, 実行時に指定するためにはPointUVを用います。
  • SetOffset, ClearOffset によるオフセットが加算されます。

テクスチャを使ったサンプルプログラム

j3c言語を使ったテクスチャのサンプルプログラムです。 テクスチャ以外の解説はJ3Cプログラミング入門J3C 組み込み関数の解説J3C言語の概要を参照してください。

サンプルで使用するテクスチャ

サンプルでテクスチャとして使用しているビットマップファイルは横256ドット、 縦256ドット、16ビットの次の画像です。

num256.png

他にもモノクロの画像を4枚使っていますが、省略します。

tex_01.j3c 3角形への単純な平面マッピング

表裏のある1枚の3角形に平面マッピングしたサンプルです。元の3角形は表側が白、 裏側がオレンジ色です。 白いポリゴンにテクスチャを貼り付けた場合は光源によって陰影はつきますが、 テクスチャの色はそのままポリゴンの色となります。元のポリゴンに色が付いていた 場合はRGBの各色の強度とテクスチャのRGB各色の強度が乗算されます。 またオレンジ側は表から貼ったテクスチャが逆に写っているのが分かります。

tex01.png

tex01b.png

三角形の原点位置がテクスチャの左上の角になっていることが確認できます

//---------------------------------------------------------------------
// tex_01.j3c  3角形への単純な平面マッピング
//---------------------------------------------------------------------

// 視点用オブジェクト
class eye {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        See();                     // このオブジェクトが見る
        ClearRegisters();
        RX = -1000;
        SetPosition();             // 位置と角度を視点に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// [ESC] キーで終了
class esc_key {
    volatile int key;
    int INIT() {}
    int RUN() {
        key = InKey();             // キ−コ−ド入力
        if (key == 0x1B) Stop();   // 全インスタンスの終了
    }
    int EVENT() {}
}

// 回転する3角形
class Triangle {
    final int color1 = 6;          // 面の色指定
    final int color2 =14;
    int INIT() {
        NewObject(6, 2);           // オブジェクトの生成 6頂点 2面
        Specular(0);
        TextureMap(1);             // 平面マッピング
        TextureAxis(1);            // X 軸方向にマッピング
        // 三角形の頂点座標を登録
        TextureSet(0);             // テクスチャ番号0
        DefPoint(0, 0,   250);     // 頂点0
        DefPoint(0, 250,-250);     // 頂点1
        DefPoint(0,-250,-250);     // 頂点2
        DefPoint(0, 0,   250);     // 頂点3 頂点0と同じ
        DefPoint(0, 250,-250);     // 頂点4 頂点1と同じ
        DefPoint(0,-250,-250);     // 頂点5 頂点2と同じ
        // 三角形の面を登録
        DefPlane( 7, 3, 0, 1, 2);  // 面の定義 表から見て左回り(白)
        DefPlane(14, 3, 2, 1, 0);  // 面の定義 表から見て左回り(オレンジ)
        ClearRegisters();          // RX - RBに0を代入
        SetPosition();             // 原点に置く
    }
    int RUN() {
        RotHead(12000, 360*8);       // 12秒間で360度回転
    }
    int EVENT() {}
}

// メインクラス
class main {
    int INIT() {
        GraphMode();               // グラフィックモードに変更
        Zoom(1);
        TextureFile(0, "num256.bmp");
        new(Triangle, 50);         // 3角柱のインスタンスを生成
        new(eye, 50);
        new(esc_key, 50);          // ESCキーで終了させるインスタンス
        BackgroundColor(0x559);    // 背景色を青系に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

上のリストは今回のサンプルプログラムの基本的な形です。リスト中で赤く表示されている4つのクラスが同時に動作しています。それぞれの動作は以下のようになります。

main
プログラムが起動したら必ず最初に実行されるインスタンス(プロセス)です。
  1. グラフィック画面を表示。
  2. 視角をZoomで指定。
  3. テクスチャとなる num256.bmp というビットマップファイルを読み込み。
  4. Triangleクラスを実体化。
  5. eyeクラスを実体化して視点を生成。
  6. esc_keyクラスを実体化して「ESC」キーで終了する準備。
  7. 背景色を黒に設定。
  8. 後は何もしない。
Triangle
三角形からなる物体です。INIT()内で6頂点を登録して2面のポリゴンを登録しています。INIT()を実行した後、RUN()で回転を続けます。
eye
視点となる物体です。形状を持つ必要はないのでワールド座標系で原点にある物体(回転する三角形)の方向を向いてじっとしています。視点となるため See() を実行しています。
esc_key
[ESC]キーが押されるまで待ち続けるインスタンスです。[ESC]キーが押されたらすべてのプロセスを終了(プログラムの終了)します。

三角形の頂点座標を登録する前に TextureSet(0) を実行しています。平面マッピングする場合は内部的にJ3Wがテクスチャのサイズを知る必要があるため TextureSet(0) 等としてテクスチャを指定する必要があります。後述の球面マッピングでは頂点登録の前にテクスチャを指定する必要はありません。

tex_02.j3c 平面マッピング、片面にテクスチャを貼らない

このサンプルではサンプル1と同様に平面マッピングしますが、オレンジ色の裏側には テクスチャを貼っていません。テクスチャを貼らないポリゴンを登録する前に TextureSet(-1) を実行します。一度TextureSet() を実行すると次にTextureSet() が実行されてテクスチャ番号を変更しない限り、その後のポリゴンの登録では設定されたテクスチャ番号が使用されます。

tex02.png

//---------------------------------------------------------------------
// tex_02.j3c  平面マッピング、片面にテクスチャを貼らない
//---------------------------------------------------------------------

// 視点用オブジェクト
class eye {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        See();                     // このオブジェクトが見る
        ClearRegisters();
        RX = -1000;
        SetPosition();             // 位置と角度を視点に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// [ESC] キーで終了
class esc_key {
    volatile int key;
    int INIT() {}
    int RUN() {
        key = InKey();             // キ−コ−ド入力
        if (key == 0x1B) Stop();   // 全インスタンスの終了
    }
    int EVENT() {}
}

// 回転する3角形
class Triangle {
    int INIT() {
        NewObject(6, 2);           // オブジェクトの生成 6頂点 2面
        Specular(0);
        TextureMap(1);             // 平面マッピング
        TextureAxis(1);            // X 軸方向にマッピング
        TextureSet(0);             // テクスチャ番号0
        // 三角形の頂点座標を登録
        DefPoint(0, 0,   250);     // 頂点0
        DefPoint(0, 250,-250);     // 頂点1
        DefPoint(0,-250,-250);     // 頂点2
        DefPoint(0, 0,   250);     // 頂点3 頂点0と同じ
        DefPoint(0, 250,-250);     // 頂点4 頂点1と同じ
        DefPoint(0,-250,-250);     // 頂点5 頂点2と同じ
        // 三角形の面を登録
        DefPlane( 7, 3, 0, 1, 2);  // 面の定義 表から見て左回り(白)
        TextureSet(-1);            // テクスチャ無効
        DefPlane(14, 3, 5, 4, 3);  // 面の定義 表から見て左回り
        ClearRegisters();          // RX - RBに0を代入
        SetPosition();             // 原点に置く
    }
    int RUN() {
        RotHead(12000, 360*8);       // 12秒間で360度回転
    }
    int EVENT() {}
}

// メインクラス
class main {
    int INIT() {
        GraphMode();               // グラフィックモードに変更
        Zoom(1);
        TextureAlpha(100);
        TextureFile(0, "num256.bmp");
        new(Triangle, 50);         // 3角柱のインスタンスを生成
        new(eye, 50);
        new(esc_key, 50);          // ESCキーで終了させるインスタンス
        BackgroundColor(0x559);    // 背景色を青系に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

tex_03.j3c 平面マッピング、両側から貼る

このサンプルではサンプル1と同様に平面マッピングしますが、オレンジ色の裏側にも正面からテクスチャを貼ります。頂点登録前にTextureAxis(-1) を実行してX軸の反対側からテクスチャを貼ります。このとき上下方向は同じで左右のみ逆転することで裏側も正常に数字が読めることが確認できます。

tex03.png

//---------------------------------------------------------------------
// tex_03.j3c  平面マッピング、両側から貼る
//---------------------------------------------------------------------

// 視点用オブジェクト
class eye {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        See();                     // このオブジェクトが見る
        ClearRegisters();
        RX = -1000;
        SetPosition();             // 位置と角度を視点に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// [ESC] キーで終了
class esc_key {
    volatile int key;
    int INIT() {}
    int RUN() {
        key = InKey();             // キ−コ−ド入力
        if (key == 0x1B) Stop();   // 全インスタンスの終了
    }
    int EVENT() {}
}

// 回転する3角形
class Triangle {
    final int color1 = 6;          // 面の色指定
    final int color2 =14;
    int INIT() {
        NewObject(6, 2);           // オブジェクトの生成 6頂点 2面
        TextureSet(0);             // テクスチャ番号0
        TextureMap(1);             // 平面マッピング
        TextureAxis(1);            // X 軸方向にマッピング
        // 三角形の頂点座標を登録
        DefPoint(0, 0,   250);     // 頂点0
        DefPoint(0, 250,-250);     // 頂点1
        DefPoint(0,-250,-250);     // 頂点2
        TextureAxis(-1);           // X 軸の逆方向からマッピング
        DefPoint(0, 0,   250);     // 頂点3 頂点0と同じ
        DefPoint(0, 250,-250);     // 頂点4 頂点1と同じ
        DefPoint(0,-250,-250);     // 頂点5 頂点2と同じ
        TextureSet(0);             // テクスチャ番号0
        // 三角形の面を登録
        DefPlane( 7, 3, 0, 1, 2);  // 面の定義 表から見て左回り(白)
        DefPlane(14, 3, 5, 4, 3);  // 面の定義 表から見て左回り
        TextureSet(0);             // テクスチャ番号0
        ClearRegisters();          // RX - RBに0を代入
        SetPosition();             // 原点に置く
        Specular(0);
    }
    int RUN() {
        RotHead(12000, 360*8);       // 12秒間で360度回転
    }
    int EVENT() {}
}

// メインクラス
class main {
    int INIT() {
        GraphMode();               // グラフィックモードに変更
        Zoom(1);
        TextureAlpha(100);
        TextureFile(0, "num256.bmp");
        new(Triangle, 50);         // 3角柱のインスタンスを生成
        new(eye, 50);
        new(esc_key, 50);          // ESCキーで終了させるインスタンス
        BackgroundColor(0x559);    // 背景色を青系に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

tex_04.j3c テクスチャの拡大と貼り付け位置の変更

平面マッピングではローカル座標系の座標値がそのままテクスチャの大きさに反映されるため、大きなポリゴンではテクスチャがタイル状に何枚も貼られることになります。TextureScaleを実行するとテクスチャを拡大縮小できます。100を指定した場合はテクスチャサイズそのまま、200とした場合は2倍に拡大されます。50とするとテクスチャのドット数と同じ領域に2枚分のテクスチャが貼られます。TextureScaleは頂点やポリゴンの登録後も何度でも実行できるため、動的にテクスチャの拡大縮小が可能です。

tex04.png

tex_04b.j3c では3角形の左上の座標が(0, -250, -250)とテクスチャの原点(左上)とあわせるため、頂点の登録前に TextureBias(-250, -250) を実行しています。

tex04b.png
//---------------------------------------------------------------------
// tex_04b.j3c テクスチャの位置にオフセットを加える
//---------------------------------------------------------------------

// 視点用オブジェクト
class eye {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        See();                     // このオブジェクトが見る
        ClearRegisters();
        RX = -1000;
        SetPosition();             // 位置と角度を視点に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// [ESC] キーで終了
class esc_key {
    volatile int key;
    int INIT() {}
    int RUN() {
        key = InKey();             // キ−コ−ド入力
        if (key == 0x1B) Stop();   // 全インスタンスの終了
    }
    int EVENT() {}
}

// 回転する3角形
class Triangle {
    final int color1 = 6;          // 面の色指定
    final int color2 =14;
    int INIT() {
        NewObject(6, 2);           // オブジェクトの生成 6頂点 2面
        TextureSet(0);             // テクスチャ番号0
        TextureMap(1);             // 平面マッピング
        TextureAxis(1);            // X 軸方向にマッピング
        TextureScale(200, 200);
        TextureBias(-250, -250);
        // 三角形の頂点座標を登録
        DefPoint(0, 0,   250);     // 頂点0
        DefPoint(0, 250,-250);     // 頂点1
        DefPoint(0,-250,-250);     // 頂点2
        TextureAxis(-1);           // X 軸方向にマッピング
        DefPoint(0, 0,   250);     // 頂点3 頂点0と同じ
        DefPoint(0, 250,-250);     // 頂点4 頂点1と同じ
        DefPoint(0,-250,-250);     // 頂点5 頂点2と同じ
        TextureSet(0);             // テクスチャ番号0
        // 三角形の面を登録
        DefPlane( 7, 3, 0, 1, 2);  // 面の定義 表から見て左回り(白)
        DefPlane(14, 3, 5, 4, 3);  // 面の定義 表から見て左回り
        TextureSet(0);             // テクスチャ番号0
        ClearRegisters();          // RX - RBに0を代入
        SetPosition();             // 原点に置く
        Specular(0);
    }
    int RUN() {
        RotHead(12000, 360*8);       // 12秒間で360度回転
    }
    int EVENT() {}
}

// メインクラス
class main {
    int INIT() {
        GraphMode();               // グラフィックモードに変更
        Zoom(1);
        TextureAlpha(100);
        TextureFile(0, "num256.bmp");
        new(Triangle, 50);         // 3角柱のインスタンスを生成
        new(eye, 50);
        new(esc_key, 50);          // ESCキーで終了させるインスタンス
        BackgroundColor(0x559);    // 背景色を青系に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

tex_05.j3c オブジェクト内で複数テクスチャの使用と動的変更

このサンプルではオブジェクト内で複数のテクスチャを使用し、またテクスチャの拡大率を動的に変化させます。画面中央で回転する4角形は表裏各2枚のポリゴンで構成されています。片面を構成する2枚のポリゴンはテクスチャ番号 0 と 1 が指定されており、モノクロ画像とカラー画像を割り当てています。TextureChange と TextureScale を実行することでテクスチャと拡大率を動的に変更します。

tex05.png
//---------------------------------------------------------------------
// tex_05.j3c  オブジェクト内で複数テクスチャの使用と動的変更
//---------------------------------------------------------------------

// 視点用オブジェクト
class eye {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        See();                     // このオブジェクトが見る
        ClearRegisters();
        RX = -1000;
        SetPosition();             // 位置と角度を視点に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// [ESC] キーで終了
class esc_key {
    volatile int key;
    int INIT() {}
    int RUN() {
        key = InKey();             // キ−コ−ド入力
        if (key == 0x1B) Stop();   // 全インスタンスの終了
    }
    int EVENT() {}
}

// 回転する四角形
class Rectangle {
    volatile int sc;
    int INIT() {
        NewObject(8, 4);           // オブジェクトの生成 6頂点 2面
        Specular(0);
        TextureMap(1);             // 平面マッピング
        TextureScale(200, 200);
        // 四角形の頂点座標を登録
        TextureAxis(1);            // X 軸方向にマッピング
        TextureSet(0);             // テクスチャ番号0
        DefPoint(0,-250, 250);     // 頂点0
        DefPoint(0,-250,-250);     // 頂点1
        DefPoint(0, 250,-250);     // 頂点2
        DefPoint(0, 250, 250);     // 頂点3
        TextureAxis(-1);           // X 軸方向にマッピング
        TextureSet(1);             // テクスチャ番号1
        DefPoint(0,-250, 250);     // 頂点4
        DefPoint(0,-250,-250);     // 頂点5
        DefPoint(0, 250,-250);     // 頂点6
        DefPoint(0, 250, 250);     // 頂点7
        // 四角形の面を登録
        TextureSet(0);
        DefPlane( 7, 3, 0, 2, 1);  // 面の定義 表から見て左回り(白)
        TextureSet(1);
        DefPlane( 7, 3, 3, 2, 0);  // 面の定義 表から見て左回り(白)
        TextureSet(0);
        DefPlane(14, 3, 4, 5, 6);  // 面の定義 表から見て左回り(白)
        TextureSet(1);
        DefPlane(14, 3, 4, 6, 7);  // 面の定義 表から見て左回り
        ClearRegisters();          // RX - RBに0を代入
        SetPosition();             // 原点に置く
        sc = 200;
    }
    int RUN() {
        TextureChange(0,0);
        TextureChange(1,1);
        RotHead(2000, 880);       // 8秒間で360度回転
        TextureChange(0,1);
        TextureChange(1,0);
        RotHead(2000, 880);       // 8秒間で360度回転
        TextureChange(0,-1);
        TextureChange(1,0);
        RotHead(2000, 880);       // 8秒間で360度回転
        sc = sc + 50;
        if (sc > 300) sc = 200;
        TextureScale(sc, sc);
    }
    int EVENT() {}
}

// メインクラス
class main {
    int INIT() {
        GraphMode();               // グラフィックモードに変更
        Zoom(1);
        TextureAlpha(100);
        TextureFile(0, "num256.bmp");
        TextureFile(1, "mononum.bmp");
        new(Rectangle, 50);         // 3角柱のインスタンスを生成
        new(eye, 50);
        new(esc_key, 50);          // ESCキーで終了させるインスタンス
        BackgroundColor(0x559);    // 背景色を青系に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

tex_06.j3c 球面マッピングとテクスチャのスケーリング

球体をプログラムで作成し、テクスチャを球面マッピングで貼り付けています。球の中央部 (赤道部分) に比べて上下 (極部分) は縮小されていることが確認できます。正方形の画像を球面マッピングすると横方向に拡大されます。最初は TextureScale(50,100) として横方法を50%に縮小してテクスチャを横に2枚設定し、その後100%に戻しています。

tex06.png

tex06b.pngフラットシェイディングされた下地の色

//---------------------------------------------------------------------
// tex_06.j3c  球面マッピングとテクスチャのスケーリング
//---------------------------------------------------------------------

// 視点用オブジェクト
class eye {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        See();                     // このオブジェクトが見る
        ClearRegisters();
        RX = -1000;
        SetPosition();             // 位置と角度を視点に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// [ESC] キーで終了
class esc_key {
    volatile int key;
    int INIT() {}
    int RUN() {
        key = InKey();             // キ−コ−ド入力
        if (key == 0x1B) Stop();   // 全インスタンスの終了
    }
    int EVENT() {}
}

//----------------------------------------------------------------------
// 回転体を生成する
//----------------------------------------------------------------------
class CRevolution {
    final int MAX = 30;
    volatile int vx[MAX];                   // 頂点のX座標
    volatile int vy[MAX];                   // 頂点のY座標
    volatile int vColor[MAX];               // 面の色
    volatile int vWork[6];                  // 作業用配列
    volatile int T, m, i, j;

    int Vertex(int x, int y, int z) {       // 頂点の登録
        RX = x; RY = y; RZ = z;
        Point();
    }

    //--------------------------------------
    // 面と頂点を登録
    // n は頂点数-2, m は円周の分割数
    //--------------------------------------
    int Setup(int n, int m) {
        for(i = 0; i <= n+1; i=i+1)         // 初期頂点 (n+2個) の登録
            Vertex(vx[i], vy[i], 0);

        // 頂点座標を計算して、頂点を登録
        T = 360*8 / m;                       // 1ステップの角度
        for(j=1; j<m; j=j+1)                // j=0の座標は初期値で登録済み
            for(i=2; i<=n+1; i=i+1)
                Vertex(vx[i], vy[i] * cos(T*j)/10000, vy[i] * sin(T*j)/10000);

        // 面を登録
        if (n > 1) {               // 上下の錐体を除いた面の定義
            vWork[1] = 4;                   // 4角形
            for(j=0; j<=m-2; j=j+1)         // 経線毎
               for(i=2; i<=n; i=i+1) {      // 緯線毎
                   vWork[0] = vColor[i];    // 面の色を指定
                   vWork[2] = j*n+i;        // 頂点番号指定
                   vWork[3] = j*n+i+1;
                   vWork[4] = (j+1)*n+i+1;
                   vWork[5] = (j+1)*n+i;
                   Plane(vWork);            // 面の登録
                }

            for(i=2; i<=n; i=i+1) {         // m-1 から 0 への戻り
                vWork[0] = vColor[i];       // 面の色を指定
                vWork[2] = (m-1)*n+i;       // 頂点番号指定
                vWork[3] = (m-1)*n+i+1;
                vWork[4] = i + 1;
                vWork[5] = i;
                Plane(vWork);               // 面の登録
            }
        }

                                        // 上部 (X大) の錐体
        vWork[1] = 3;                       // 3角形
        vWork[0] = vColor[0];               // 面の色を指定
        for(j=0; j<=m-2; j=j+1) {
            vWork[2] = 0;                   // 頂点番号指定
            vWork[3] = j*n+2;
            vWork[4] = (j+1)*n+2;
            Plane(vWork);                   // 面の登録
        }
                                            // m-1 から 0 への戻り
        vWork[2] = 0;                       // 頂点番号指定
        vWork[3] = (m-1)*n+2;
        vWork[4] = 2;
        Plane(vWork);                       // 面の登録

                                        // 下部 (X小) の錐体
        vWork[0] = vColor[1];               // 面の色を指定
        for(j=0; j<=m-2; j=j+1) {
             vWork[2] = 1;                  // 頂点番号指定
             vWork[3] = (j+2)*n+1;
             vWork[4] = (j+1)*n+1;
             Plane(vWork);
        }
                                            // m-1 から 0 への戻り
        vWork[2] = 1;                       // 頂点番号指定
        vWork[3] = n +1;
        vWork[4] = m*n+1;
        Plane(vWork);                       // 面の登録
    }

    int INIT() { }
    int RUN() { }
    int EVENT() {  }
}

//----------------------------------------------------------------------
// 球体のクラス RH:色、RP:環境光強度、RB:スペキュラー強度を指定してNEW
//----------------------------------------------------------------------
class sphere extends CRevolution {
    int sphere(int radius, int div, int color) {
        volatile int i;
        vx[ 0] =  radius;       //   頂点0
        vy[ 0] =  0;
        vx[ 1] = -radius;       //   頂点1
        vy[ 1] =  0;
        for (i=0; i<div-1 ; i=i+1) {
            vColor[i] = color;
        }
        for (i=1; i<div-1 ; i=i+1) {
            vx[i+1] = radius * cos(i*1440/(div-1)) / 10000;
            vy[i+1] = radius * sin(i*1440/(div-1)) / 10000;
        }
    }

    int INIT() {
        volatile int div;

        div = 24;                  // 球体の分割数
        NewObject(1000,1000);
        ClearRegisters();          // 位置と姿勢をすべて0に
        RP = 90 * 8;               // 90度立てる
        SetPosition();             // 位置と姿勢を指定
        Ambient(10);
        Specular(100);             // スペキュラー100%
        TextureMap(0);             // 球面マッピング
        TextureAxis(1);            // X 軸方向にマッピング
        TextureSet(0);             // テクスチャ番号0
        sphere(250, div, 7);       // 半径250の白の球体
        vColor[div/2]   = 1;       // 赤道位置に帯状の青
        vColor[div/2+1] = 1;
        vColor[div/2+2] = 4;       // 赤道位置に帯状の赤
        vColor[div/2+3] = 4;
        Setup(div - 2, div);       // 頂点と面を登録
    }
    int RUN() {
        RotPitch(8000, 360*8);     // 8秒間で1周
        RotBank(8000, 360*8);      // 8秒間で1周
        TextureScale(50,100);      // 横(U)方向にテクスチャを2枚
        RotPitch(8000, 360*8);     // 8秒間で1周
        RotHead(8000, 360*8);      // 8秒間で1周
        TextureScale(100,100);     // 元に戻す
        TextureChange(0, -1);
        RotHead(8000, 360*8);      // 8秒間で1周
        TextureChange(0, 0);
    }
}

// メインクラス
class main {
    int INIT() {
        GraphMode();               // グラフィックモードに変更
        Zoom(1);                   // 視野角53度
        TextureAlpha(100);         // テクスチャを不透明
        TextureFile(0, "num256.bmp");
        TextureFile(1, "mononum.bmp");
        new(sphere, 1000)          // 球のインスタンスを生成
        new(eye, 50);              // 視点生成
        new(esc_key, 50);          // ESCキーで終了させるインスタンス
        BackgroundColor(0x559);    // 背景色を青系に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

tex_07.j3c 非球面への球面マッピングとテクスチャのスケーリング

このサンプルでは球体ではない回転体に球面マッピングします。球面マッピングではどのような大きさ、形の物体に対してもテクスチャを貼ることができます。中心(物体の原点)から離れるほどテクスチャは拡大され、上下に中心軸に近づくほど縮小されます。ただし原点を通る平面では正常にマッピングできないため平面マッピングを使ってください。

tex07.png
//---------------------------------------------------------------------
// tex_07.j3c  非球面への球面マッピングとテクスチャのスケーリング
//---------------------------------------------------------------------

// 視点用オブジェクト
class eye {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        See();                     // このオブジェクトが見る
        ClearRegisters();
        RX = -2000;
        SetPosition();             // 位置と角度を視点に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// [ESC] キーで終了
class esc_key {
    volatile int key;
    int INIT() {}
    int RUN() {
        key = InKey();             // キ−コ−ド入力
        if (key == 0x1B) Stop();   // 全インスタンスの終了
    }
    int EVENT() {}
}

//----------------------------------------------------------------------
// 回転体を生成する
//----------------------------------------------------------------------
class CRevolution {
    final int MAX = 30;
    volatile int vx[MAX];                   // 頂点のX座標
    volatile int vy[MAX];                   // 頂点のY座標
    volatile int vColor[MAX];               // 面の色
    volatile int vWork[6];                  // 作業用配列
    volatile int T, m, i, j;

    int Vertex(int x, int y, int z) {       // 頂点の登録
        RX = x; RY = y; RZ = z;
        Point();
    }

    //--------------------------------------
    // 面と頂点を登録
    // n は頂点数-2, m は円周の分割数
    //--------------------------------------
    int Setup(int n, int m) {
        for(i = 0; i <= n+1; i=i+1)         // 初期頂点 (n+2個) の登録
            Vertex(vx[i], vy[i], 0);

        // 頂点座標を計算して、頂点を登録
        T = 360*8 / m;                       // 1ステップの角度
        for(j=1; j<m; j=j+1)                // j=0の座標は初期値で登録済み
            for(i=2; i<=n+1; i=i+1)
                Vertex(vx[i], vy[i] * cos(T*j)/10000, vy[i] * sin(T*j)/10000);

        // 面を登録
        if (n > 1) {               // 上下の錐体を除いた面の定義
            vWork[1] = 4;                   // 4角形
            for(j=0; j<=m-2; j=j+1)         // 経線毎
               for(i=2; i<=n; i=i+1) {      // 緯線毎
                   vWork[0] = vColor[i];    // 面の色を指定
                   vWork[2] = j*n+i;        // 頂点番号指定
                   vWork[3] = j*n+i+1;
                   vWork[4] = (j+1)*n+i+1;
                   vWork[5] = (j+1)*n+i;
                   Plane(vWork);            // 面の登録
                }

            for(i=2; i<=n; i=i+1) {         // m-1 から 0 への戻り
                vWork[0] = vColor[i];       // 面の色を指定
                vWork[2] = (m-1)*n+i;       // 頂点番号指定
                vWork[3] = (m-1)*n+i+1;
                vWork[4] = i + 1;
                vWork[5] = i;
                Plane(vWork);               // 面の登録
            }
        }

                                        // 上部 (X大) の錐体
        vWork[1] = 3;                       // 3角形
        vWork[0] = vColor[0];               // 面の色を指定
        for(j=0; j<=m-2; j=j+1) {
            vWork[2] = 0;                   // 頂点番号指定
            vWork[3] = j*n+2;
            vWork[4] = (j+1)*n+2;
            Plane(vWork);                   // 面の登録
        }
                                            // m-1 から 0 への戻り
        vWork[2] = 0;                       // 頂点番号指定
        vWork[3] = (m-1)*n+2;
        vWork[4] = 2;
        Plane(vWork);                       // 面の登録

                                        // 下部 (X小) の錐体
        vWork[0] = vColor[1];               // 面の色を指定
        for(j=0; j<=m-2; j=j+1) {
             vWork[2] = 1;                  // 頂点番号指定
             vWork[3] = (j+2)*n+1;
             vWork[4] = (j+1)*n+1;
             Plane(vWork);
        }
                                            // m-1 から 0 への戻り
        vWork[2] = 1;                       // 頂点番号指定
        vWork[3] = n +1;
        vWork[4] = m*n+1;
        Plane(vWork);                       // 面の登録
    }

    int INIT() { }
    int RUN() { }
    int EVENT() {  }
}

//----------------------------------------------------------------------
// 球体のクラス RH:色、RP:環境光強度、RB:スペキュラー強度を指定してNEW
//----------------------------------------------------------------------
class revo extends CRevolution {
    int shape(int color) {
        volatile int i;
        vx[ 0] =  300;  vy[ 0] =  0;
        vx[ 1] = -300;  vy[ 1] =  0;

        vx[ 2] =  250;  vy[ 2] =   50;
        vx[ 3] =  200;  vy[ 3] =  200;
        vx[ 4] =  150;  vy[ 4] =  300;
        vx[ 5] =  100;  vy[ 5] =  300;
        vx[ 6] =   50;  vy[ 6] =  270;
        vx[ 7] =    0;  vy[ 7] =  170;
        vx[ 8] =  -50;  vy[ 8] =  100;
        vx[ 9] = -100;  vy[ 9] =   80;
        vx[10] = -150;  vy[10] =  100;
        vx[11] = -200;  vy[11] =  150;
        vx[12] = -250;  vy[12] =  100;
        for (i=0; i<12 ; i=i+1) {
            vColor[i] = color;
        }
    }

    int INIT() {
        volatile int div;

        div = 24;                  // 球体の分割数
        NewObject(1000,1000);
        ClearRegisters();          // 位置と姿勢をすべて0に
        RP = 90 * 8;               // 90度立てる
        RX = -800;
        SetPosition();             // 位置と姿勢を指定
        Ambient(10);
        Specular(100);             // スペキュラー100%
        TextureMap(0);             // 球面マッピング
        TextureAxis(1);            // X 軸方向にマッピング
        TextureSet(0);             // テクスチャ番号0
        shape(13);                 // 回転体用の頂点を登録(ピンク)
        Setup(10, 24);             // 頂点と面を登録
    }
    int RUN() {
        TextureScale(50,100);      // テクスチャを横2枚、縦1枚
        RotPitch(8000, 360*8);     // 8秒間で1周
        RotBank(8000, 360*8);      // 8秒間で1周
        TextureScale(25,50);       // テクスチャを横4枚、縦2枚
        RotPitch(8000, 360*8);     // 8秒間で1周
        RotHead(8000, 360*8);      // 8秒間で1周
        TextureScale(50,100);     // 元に戻す
        TextureChange(0, -1);      // テクスチャを無効に
        RotHead(8000, 360*8);      // 8秒間で1周
        TextureChange(0, 0);
    }
}

// メインクラス
class main {
    int INIT() {
        GraphMode();               // グラフィックモードに変更
        Zoom(1);                   // 視野角53度
        TextureAlpha(100);          // テクスチャの不透明100%
        TextureFile(0, "num256.bmp");
        TextureFile(1, "mononum.bmp");
        new(revo, 1000)            // 回転体のインスタンスを生成
        new(eye, 50);              // 視点生成
        new(esc_key, 50);          // ESCキーで終了させるインスタンス
        BackgroundColor(0x559);    // 背景色を青系に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

tex_08.j3c 不透明度が40%と100%のテクスチャ

このサンプルでは同じ画像ファイルを2回読み込みますが、それぞれ TextureAlha(40) と TextureAlha(100) を直前に実行し、テクスチャの透明度を変更しています。透明度は100で不透明、40は40%不透明(60%透明) を示します。テクスチャが100%不透明でも下地の色の影響を受けます。テクスチャの色をそのまま使いたい場合は下地を白にする必要があります。

tex08.pngTextureAlha(40)

tex08b.pngTextureAlha(100)

//---------------------------------------------------------------------
// tex_08.j3c  不透明度が40%と100%のテクスチャ
//---------------------------------------------------------------------

// 視点用オブジェクト
class eye {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        See();                     // このオブジェクトが見る
        ClearRegisters();
        RX = -2000;
        SetPosition();             // 位置と角度を視点に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// [ESC] キーで終了
class esc_key {
    volatile int key;
    int INIT() {}
    int RUN() {
        key = InKey();             // キ−コ−ド入力
        if (key == 0x1B) Stop();   // 全インスタンスの終了
    }
    int EVENT() {}
}

//----------------------------------------------------------------------
// 回転体を生成する
//----------------------------------------------------------------------
class CRevolution {
    final int MAX = 30;
    volatile int vx[MAX];                   // 頂点のX座標
    volatile int vy[MAX];                   // 頂点のY座標
    volatile int vColor[MAX];               // 面の色
    volatile int vWork[6];                  // 作業用配列
    volatile int T, m, i, j;

    int Vertex(int x, int y, int z) {       // 頂点の登録
        RX = x; RY = y; RZ = z;
        Point();
    }

    //--------------------------------------
    // 面と頂点を登録
    // n は頂点数-2, m は円周の分割数
    //--------------------------------------
    int Setup(int n, int m) {
        for(i = 0; i <= n+1; i=i+1)         // 初期頂点 (n+2個) の登録
            Vertex(vx[i], vy[i], 0);

        // 頂点座標を計算して、頂点を登録
        T = 360*8 / m;                       // 1ステップの角度
        for(j=1; j<m; j=j+1)                // j=0の座標は初期値で登録済み
            for(i=2; i<=n+1; i=i+1)
                Vertex(vx[i], vy[i] * cos(T*j)/10000, vy[i] * sin(T*j)/10000);

        // 面を登録
        if (n > 1) {               // 上下の錐体を除いた面の定義
            vWork[1] = 4;                   // 4角形
            for(j=0; j<=m-2; j=j+1)         // 経線毎
               for(i=2; i<=n; i=i+1) {      // 緯線毎
                   vWork[0] = vColor[i];    // 面の色を指定
                   vWork[2] = j*n+i;        // 頂点番号指定
                   vWork[3] = j*n+i+1;
                   vWork[4] = (j+1)*n+i+1;
                   vWork[5] = (j+1)*n+i;
                   Plane(vWork);            // 面の登録
                }

            for(i=2; i<=n; i=i+1) {         // m-1 から 0 への戻り
                vWork[0] = vColor[i];       // 面の色を指定
                vWork[2] = (m-1)*n+i;       // 頂点番号指定
                vWork[3] = (m-1)*n+i+1;
                vWork[4] = i + 1;
                vWork[5] = i;
                Plane(vWork);               // 面の登録
            }
        }

                                        // 上部 (X大) の錐体
        vWork[1] = 3;                       // 3角形
        vWork[0] = vColor[0];               // 面の色を指定
        for(j=0; j<=m-2; j=j+1) {
            vWork[2] = 0;                   // 頂点番号指定
            vWork[3] = j*n+2;
            vWork[4] = (j+1)*n+2;
            Plane(vWork);                   // 面の登録
        }
                                            // m-1 から 0 への戻り
        vWork[2] = 0;                       // 頂点番号指定
        vWork[3] = (m-1)*n+2;
        vWork[4] = 2;
        Plane(vWork);                       // 面の登録

                                        // 下部 (X小) の錐体
        vWork[0] = vColor[1];               // 面の色を指定
        for(j=0; j<=m-2; j=j+1) {
             vWork[2] = 1;                  // 頂点番号指定
             vWork[3] = (j+2)*n+1;
             vWork[4] = (j+1)*n+1;
             Plane(vWork);
        }
                                            // m-1 から 0 への戻り
        vWork[2] = 1;                       // 頂点番号指定
        vWork[3] = n +1;
        vWork[4] = m*n+1;
        Plane(vWork);                       // 面の登録
    }

    int INIT() { }
    int RUN() { }
    int EVENT() {  }
}

//----------------------------------------------------------------------
// 球体のクラス RH:色、RP:環境光強度、RB:スペキュラー強度を指定してNEW
//----------------------------------------------------------------------
class revo extends CRevolution {
    int shape(int color) {
        volatile int i;
        vx[ 0] =  300;  vy[ 0] =  0;
        vx[ 1] = -300;  vy[ 1] =  0;

        vx[ 2] =  250;  vy[ 2] =   50;
        vx[ 3] =  200;  vy[ 3] =  200;
        vx[ 4] =  150;  vy[ 4] =  300;
        vx[ 5] =  100;  vy[ 5] =  300;
        vx[ 6] =   50;  vy[ 6] =  270;
        vx[ 7] =    0;  vy[ 7] =  170;
        vx[ 8] =  -50;  vy[ 8] =  100;
        vx[ 9] = -100;  vy[ 9] =   80;
        vx[10] = -150;  vy[10] =  100;
        vx[11] = -200;  vy[11] =  150;
        vx[12] = -250;  vy[12] =  100;
        for (i=0; i<12 ; i=i+1) {
            vColor[i] = color;
        }
    }

    int INIT() {
        volatile int div;

        div = 24;                  // 球体の分割数
        NewObject(1000,1000);
        ClearRegisters();          // 位置と姿勢をすべて0に
        RP = 90 * 8;               // 90度立てる
        RX = -800;
        SetPosition();             // 位置と姿勢を指定
        Ambient(10);
        Specular(100);             // スペキュラー100%
        TextureMap(0);             // 球面マッピング
        TextureAxis(1);            // X 軸方向にマッピング
        TextureSet(0);             // テクスチャ番号0
        shape(11);                 // 回転体用の頂点を登録(薄緑)
        Setup(10, 24);             // 頂点と面を登録
    }
    int RUN() {
        TextureScale(50, 100);     // テクスチャを横2枚、縦1枚
        RotPitch(8000, 360*8);     // 8秒間で1周
        RotBank(8000, 360*8);      // 8秒間で1周
        TextureScale(25,50);       // テクスチャを横4枚、縦2枚
        RotPitch(8000, 360*8);     // 8秒間で1周
        RotHead(8000, 360*8);      // 8秒間で1周
        TextureScale(50,100);      // 元に戻す
        TextureChange(0, -1);      // テクスチャを無効に
        RotHead(8000, 360*8);      // 8秒間で1周
        TextureChange(0, 1);
    }
}

// メインクラス
class main {
    int INIT() {
        GraphMode();               // グラフィックモードに変更
        Zoom(1);                   // 視野角53度
        TextureAlpha(40);          // テクスチャの不透明40%
        TextureFile(0, "num256.bmp");
        TextureAlpha(100);          // テクスチャの不透明100%
        TextureFile(1, "num256.bmp");
        new(revo, 1000)            // 回転体のインスタンスを生成
        new(eye, 50);              // 視点生成
        new(esc_key, 50);          // ESCキーで終了させるインスタンス
        BackgroundColor(0x559);    // 背景色を青系に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

tex_09.j3c テクスチャアニメーション

このサンプルでは球体に貼ったテクスチャを切り替えてアニメーションします。 モノクロビットマップを3枚用意し、適当な時間で切り替えることで「まばたき」します。 光源を右上に配置しています。ポリゴンはすべて TextureSet(0) でテクスチャ番号を0で登録し、0.3秒程度で TextureChange(0, 1) などと実行することでテクスチャ番号の 0 をテクスチャファイル番号 0 から 2に切り替えています。

tex09.png
tex09c.png
//---------------------------------------------------------------------
//   tex_09.j3c  テクスチャアニメーション
//---------------------------------------------------------------------

// 視点用オブジェクト
class eye {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        See();                     // このオブジェクトが見る
        ClearRegisters();
        RX = -1000;
        SetPosition();             // 位置と角度を視点に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// 光源用オブジェクト
class Lamp {
    int INIT() {
        NewObject(0, 0);           // オブジェクトの生成  頂点も面も不要
        RX = -2000; RY = 2000; RZ = -2000;
        RP = -300; RH = -360; RB = 0;
        SetPosition();             // 位置と角度を視点に設定
        Emit(1);                   // 光源として発行
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

// [ESC] キーで終了
class esc_key {
    volatile int key;
    int INIT() {}
    int RUN() {
        key = InKey();             // キ−コ−ド入力
        if (key == 0x1B) Stop();   // 全インスタンスの終了
    }
    int EVENT() {}
}

//----------------------------------------------------------------------
// 回転体を生成する
//----------------------------------------------------------------------
class CRevolution {
    final int MAX = 30;
    volatile int vx[MAX];                   // 頂点のX座標
    volatile int vy[MAX];                   // 頂点のY座標
    volatile int vColor[MAX];               // 面の色
    volatile int vWork[6];                  // 作業用配列
    volatile int T, m, i, j;

    int Vertex(int x, int y, int z) {       // 頂点の登録
        RX = x; RY = y; RZ = z;
        Point();
    }

    //--------------------------------------
    // 面と頂点を登録
    // n は頂点数-2, m は円周の分割数
    //--------------------------------------
    int Setup(int n, int m) {
        for(i = 0; i <= n+1; i=i+1)         // 初期頂点 (n+2個) の登録
            Vertex(vx[i], vy[i], 0);

        // 頂点座標を計算して、頂点を登録
        T = 360*8 / m;                       // 1ステップの角度
        for(j=1; j<m; j=j+1)                // j=0の座標は初期値で登録済み
            for(i=2; i<=n+1; i=i+1)
                Vertex(vx[i], vy[i] * cos(T*j)/10000, vy[i] * sin(T*j)/10000);

        // 面を登録
        if (n > 1) {               // 上下の錐体を除いた面の定義
            vWork[1] = 4;                   // 4角形
            for(j=0; j<=m-2; j=j+1)         // 経線毎
               for(i=2; i<=n; i=i+1) {      // 緯線毎
                   vWork[0] = vColor[i];    // 面の色を指定
                   vWork[2] = j*n+i;        // 頂点番号指定
                   vWork[3] = j*n+i+1;
                   vWork[4] = (j+1)*n+i+1;
                   vWork[5] = (j+1)*n+i;
                   Plane(vWork);            // 面の登録
                }

            for(i=2; i<=n; i=i+1) {         // m-1 から 0 への戻り
                vWork[0] = vColor[i];       // 面の色を指定
                vWork[2] = (m-1)*n+i;       // 頂点番号指定
                vWork[3] = (m-1)*n+i+1;
                vWork[4] = i + 1;
                vWork[5] = i;
                Plane(vWork);               // 面の登録
            }
        }

                                        // 上部 (X大) の錐体
        vWork[1] = 3;                       // 3角形
        vWork[0] = vColor[0];               // 面の色を指定
        for(j=0; j<=m-2; j=j+1) {
            vWork[2] = 0;                   // 頂点番号指定
            vWork[3] = j*n+2;
            vWork[4] = (j+1)*n+2;
            Plane(vWork);                   // 面の登録
        }
                                            // m-1 から 0 への戻り
        vWork[2] = 0;                       // 頂点番号指定
        vWork[3] = (m-1)*n+2;
        vWork[4] = 2;
        Plane(vWork);                       // 面の登録

                                        // 下部 (X小) の錐体
        vWork[0] = vColor[1];               // 面の色を指定
        for(j=0; j<=m-2; j=j+1) {
             vWork[2] = 1;                  // 頂点番号指定
             vWork[3] = (j+2)*n+1;
             vWork[4] = (j+1)*n+1;
             Plane(vWork);
        }
                                            // m-1 から 0 への戻り
        vWork[2] = 1;                       // 頂点番号指定
        vWork[3] = n +1;
        vWork[4] = m*n+1;
        Plane(vWork);                       // 面の登録
    }

    int INIT() { }
    int RUN() { }
    int EVENT() {  }
}

//----------------------------------------------------------------------
// 球体のクラス RH:色、RP:環境光強度、RB:スペキュラー強度を指定してNEW
//----------------------------------------------------------------------
class sphere extends CRevolution {
    int sphere(int radius, int div, int color) {
        volatile int i;
        vx[ 0] =  radius;       //   頂点0
        vy[ 0] =  0;
        vx[ 1] = -radius;       //   頂点1
        vy[ 1] =  0;
        for (i=0; i<div-1 ; i=i+1) {
            vColor[i] = color;
        }
        for (i=1; i<div-1 ; i=i+1) {
            vx[i+1] = radius * cos(i*1440/(div-1)) / 10000;
            vy[i+1] = radius * sin(i*1440/(div-1)) / 10000;
        }
    }

    int INIT() {
        volatile int div;

        div = 24;                  // 球体の分割数
        NewObject(1000,1000);
        ClearRegisters();          // 位置と姿勢をすべて0に
        RZ = 100;                  // ちょっと下
        RP = 90 * 8;               // 90度立てる
        SetPosition();             // 位置と姿勢を指定
        Ambient(50);
        Specular(50);              // スペキュラー50%
        TextureMap(0);             // 球面マッピング
        TextureAxis(1);            // X 軸方向にマッピング
        TextureSet(0);             // テクスチャ番号0
        sphere(250, div, 13);      // 半径250の球体
        Setup(div - 2, div);       // 頂点と面を登録
    }
    int RUN() {
        Pause(1500);               // 1.5秒
        TextureChange(0, 1);
        Pause(200);                // 0.2秒
        TextureChange(0, 2);
        Pause(200);                // 0.2秒
        TextureChange(0, 1);
        Pause(200);                // 0.2秒
        TextureChange(0, 0);
        Pause(300);                // 0.3秒
        TextureChange(0, 1);
        Pause(100);                // 0.1秒
        TextureChange(0, 2);
        Pause(100);                // 0.1秒
        TextureChange(0, 1);
        Pause(100);                // 0.1秒
        TextureChange(0, 0);    // 以上を繰り返す
    }
}

// メインクラス
class main {
    int INIT() {
        GraphMode();               // グラフィックモードに変更
        Zoom(1);                   // 視野角53度
        TextureAlpha(100);         // テクスチャを不透明
        TextureFile(0, "face00.bmp");
        TextureFile(1, "face01.bmp");
        TextureFile(2, "face02.bmp");
        new(sphere, 1000)          // 球のインスタンスを生成
        new(eye, 50);              // 視点生成
        new(Lamp, 50);             // 光源生成
        new(esc_key, 50);          // ESCキーで終了させるインスタンス
        BackgroundColor(0x559);    // 背景色を青系に設定
    }
    int RUN() { Wait(); }
    int EVENT() {}
}

たった3枚のテクスチャでも、まばたきしているように見えるのは不思議です。


[INDEX]
ご意見・ご感想は,水谷 純 <mizutani.jun@nifty.ne.jp>まで.