トップページ
ひらく | たたむ | ページトップ
↓マウスで反転選択した文字を検索
OpenGL
   
ページ内検索 ページ外検索
検索したい文字を入力して
ENTERを押すと移動します。
\n
[ トップページ ]
[ ____CommandPrompt ] [ ____JScript ] [ ____MySQL ] [ ____Cygwin ] [ ____Java ] [ ____Emacs ] [ ____Make ] [ ____Perl ] [ ____Python ] [ ____OpenGL ] [ ____C# ] [ ____StyleSheet ] [ ____C++ ] [ ____Winsock ] [ ____Thread ] [ ____VisualStudio ] [ ____C ] [ ____Win32API ] [ ____Lua ] [ ____PhotoShop ]
ヘッダ検索
___

■ チュートリアル(Tutorial)





___

■ ApplicationFW

SAMPLE シンプルウィンドウ サンプル DESC OpenGL Application の フレームワークとして次のような構成を用意しておくと便利。 手間なら GLUT などが利用できる。

    // 1 回だけ
    virtual void App::onInit();

    // 毎 frame ( 描画毎 )
    virtual void App::onDraw();

    // マウスイベント
    virtual void App::onMouseEvent();

アプリケーション毎に具体的な処理をオーバーライドする。
    class TestApp : public App {}

    int main() {
      TestApp app;

      // メインループ
      app.run();
      return 0;
    }
REFERENCE 仮想関数でフレームワークをつくる
___

■ 下準備

POINT OpenGL は 現在のステート( 色、テクスチャ、変換行列 )を利用してプリミティブを描画する。 ステートを把握しておくことが大切。 変更のない設定は最初にまとめてする。
    void init() {

      // DepthTest ON
      glEnable( GL_DEPTH_TEST );

      // Texture なし
      glDisable( GL_TEXTURE_2D );

      // 画面の背景色を設定する。
      glClearColor( 0.5f, 0.5f, 0.5f, 1 );

    }

___

■ 描画毎の設定

描画するタイミングでは、画面をクリア、カメラを設定、図形を描画するという流れになる。
    

    void draw() {

      // 画面をクリアする。
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );


      // 現在の カメラ座標系( カメラから見た位置 )の設定をする
      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();

    
      // カメラの画角を設定する
      glMatrixMode( GL_PROJECTION );
      glFrustum();
    

      // この設定で三角形を描画
      glBegin( GL_TRIANGLES );
      glVertex3f( 0,0,0 );
      glVertex3f( 1,0,0 );
      glVertex3f( 1,1,0 );
      glEnd();

    }    
___

■ 三角形の描画

三角形を描画するには, glBegin() - glEnd() 間で頂点情報を OpenGL へ転送する。 頂点属性は以下のものがあるが、座標( Position )の指定は必須。

  Position   // 位置
  Normal     // 法線
  Texcoord   // テクスチャ座標
  Color      // 頂点カラー
  Fog
  Edge
指定した頂点列を組み立てる方法を glBegin() のパラメータとして渡す。

  GL_TRIANGLES
  GL_TRIANGLE_STRIP
  GL_TRIANGLE_FAN
  GL_POLYGON
  GL_POINTS
  GL_LINES
  GL_LINE_LOOP
  GL_LINE_STRIP
  GL_QUADS
  GL_QUAD_STRIP

___

■ glVertex

POINT OpenGL では座標は、行列変換のために同次座標 として扱われる。

  // glVertex4f( 1, 0, 0, 1 ) と同じ。
  glVertex3f( 1, 0, 0 );
  glVertex3f( 1, 1, 0 );
  glVertex3f( 0, 1, 0 );

他の頂点属性は glVertex をした時に Current の State から Copy される。


  glBegin();

  // Primary Color を赤にする ( w は 1 になる )
  glColor3f( 1, 0, 0 );

  // Normal , TexCoord も同じように Current が設定される
  glNormal3f( 0, 0, 1 );
  glTexCoord2f( 0, 0 );

  // 以降, Primary Color は赤として 各頂点属性に指定される
  glVertex3f( 1, 0, 0 );
  glVertex3f( 1, 1, 0 );
  glVertex3f( 0, 1, 0 );

  glEnd();

___

■ glNormal

SYNTAX glNormal( ); DESC glColor : 同様に glNormal() は定数設定処理が可能

void drawCube3()
{

  float s = 100;

  static float v[] = {
    -s, -s, s,
    s, -s, s,
    s, s, s,
    -s, s, s,

    -s, -s, -s,
    s, -s, -s,
    s, s, -s,
    -s, s, -s,
  };

  static float n[] = {
    0, 0, 1,    0, 0, -1,
    1, 0, 0,    -1, 0, 0,
    0, -1, 0,  0, 1, 0,
  };

  // 6 QUADS
  static unsigned short idx[] = {
    0, 1, 2, 3,    4, 5, 6, 7,
    1, 5, 6, 2,    4, 0, 3, 7,
    4, 5, 1, 0,    3, 2, 6, 7,
  };


  glBegin( GL_QUADS );
  for( int i=0; i< 6; i++ ){

    // glColor と同じように, 現在の State の影響をうける
    glNormal3fv( n + (3*i) );

    for( int j=0; j< 4; j++ ){
      int p = idx[ 4*i + j ];
      glVertex3fv( v + 3*p );
    }
  }
  glEnd();

  glDisable( GL_LIGHTING );

}

___

■ glColor

SYNTAX glColor DESC 頂点カラーを設定する。 glVertex() を call すると その時点の Color が設定される。

    // 1個のColorで描画
    glColor4f( 1,1,1,1 );
    glVertex3f();
    glVertex3f();
    glVertex3f();

    // 各頂点で変更
    glColor4f( 1,1,1,1 );
    glVertex3f();
    glColor4f( 1,0,0,1 );
    glVertex3f();
    glColor4f( 0,0,1,1 );
    glVertex3f();


___

■ REFERENCE(リファレンス)







___

■ glColorMask

SYNTAX glColorMask() DESC framebuffer の書き込み制御 TRUE : ON FALSE : 描画 OFF ( 黒が MASK )
    ■□■■
___

■ glRasterPos

SYNTAX void glRasterPos[234][sidf]( TYPE x, TYPE y, TYPE z, TYPE w ); DESC RaterPos( Screen 上に描画する bitmap の位置 ) を指定する POINT glRasterPos で指定した位置は VertexTransform の影響をうける 3D 空間での glVertex と同様に考えればいい RasterPos は次の変換をうける
    ObjectSpace ---> ClipSpace ---> WindowSpace

                    ClipingVolume 内にある場合のみ WindowSpace へ変換される

    // glVertex2f() と同じく Texcoord の影響をうける
    glRasterPos2f( 1, 1 );

    // z = 0, w = 1 としての扱われる
    glRasterPos4f( 1, 1, 0, 1 );
POINT 最も初期の FrameBuffer は HostMemory ( Application から直接参照できる Memory ) に格納されていた
___

■ glDrawPixels

SYNTAX void glDrawPixels( unsigned int w, unsigned int h, // Size int fmt, // format ( RGB ) int type, // 型 ( U8 ) void *data // Pixel Data ); DESC CPU memory から FrameBuffer の PixelData に data を転送 ( 読み込んだ画像を直接表示するときに利用する ) glRasterPos() で指定した位置に描画される RasterPos が無効なら描画されない POINT glDrawPixels は以下の State の影響をうける Pixel は 3D の描画と同じく Fragment の変換時に処理をうける そのため Texture が有効なら 影響をうける たいていは Default で問題なし

     ByteOrder
     行の Alignment
          Default では 各行 が 4 Byte Alignment であることを要求
          変更するには glPixelTranser() を使用

     ColorTable Lookup
     PixelZoom
表示されない時は次の State を指定する

    for( unsigned int i=0; i< 8; i++ ){
      glActiveTexture( GL_TEXTURE0 + i );
      glDisable( GL_TEXTURE_1D );
      glDisable( GL_TEXTURE_2D );
      glDisable( GL_TEXTURE_3D );
      glDisable( GL_TEXTURE_CUBE_MAP );
    }

    // Fragment へ変換する際の FOG Color の着色
    glDisable( GL_FOG );

    glDisable( GL_DEPTH_TEST );

さらに Window の一部 が 別の Window に隠されている時も問題になる OpenGL が 隠された 領域から Pixel Data を返せるかどうかは Window System に依存する


POINT
    format
      Pixel が何を表すか GL に伝える
      色なら GL_RGBA
      Depth なら GL_DEPTH_COMPONENT

    type
      Pixel の Data 型

    GL の立場で考えれば この情報は必然
      data の先頭は void * でもらうため

  App::init() {
    glClearColor( 1, 0.7f, 1, 1 );

    data = new unsigned char[ w*h * sizeof(char) * 4 ];

    for( unsigned int i=0; i< w*h; i++ ){
      data[4*i + 0] = 255;
      data[4*i + 1] = 255;
      data[4*i + 2] = 0;
      data[4*i + 3] = 255;
    }

    // 画面 size
    float W = 1024.0f;
    float H = W/2;

    // ModelView 変換はしない
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    // 画面 size の大きさになるように Frustum を作成
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho( 0, W, 0, H, 1, 1000 );


    // 影響のある TEST を OFF にする
    // Rasterize 後の FragmentTest で不合格にならないように
    glDisable( GL_DEPTH_TEST );

    // Fragment 変換時に 不要な色がつかないように
    glDisable( GL_TEXTURE_2D );
    glDisable( GL_FOG );

    glDisable( GL_BLEND );

  }

  void App::Draw() {

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    static int cnt = 900;
    float y = 100;

    // x <  0 になると消える
    glRasterPos3f( (--cnt), y, -1.5f );   // Z も Frustum にはいるように

    // RasterPos が有効かチェックする
    {
      GLboolean ret;
      glGetBooleanv( GL_CURRENT_RASTER_POSITION_VALID, &ret );
      psc( "raster pos vaiid %d", ret );
    }

    glDrawPixels( w, h, GL_RGBA, GL_UNSIGNED_BYTE, data );

  }



TIP TextureObject を利用した方が処理が早い EXT:GL_ARB_pixel_buffer_object により高速化可能 如何に処理負荷がかかるかわかる WARNING glRasterPos() は VertexTransform の影響をうける MV = UNIT, Frustum == Window の時に同一の場所になる. glWindowPos() VER1.4 で直接指定可能. Rasterize 時の State の影響もうける. Tex OFF DepthTest
___

■ glBitmap

SYNTAX void glBitmap( unsigned int w, unsigned int h, // 画像の大きさ float x, float y, // 開始位置 offset float xinc, float yinc,// 描画後 の RasterPos の移動量( WindowSpace ) byte *data ); DESC 大きさ w, h の bimap ( 1pixel 1 bit 画像 )を x, y の位置から 現在の RasterPos に data を描画 描画後 は xinc, yinc だけ RasterPos が移動する POINT 本来は txt を描画するために利用したが, RasterPos を移動するのに利用する

    // "有効な位置" を指定する
    glRasterPos( )

    // glBitmap() で RasterPos を移動して "有効な位置" からずれても問題なし
    glBitmap()


___

■ glWindowPos

SYNTAX void glWindowPos[23][sifd]( type x, type x, type z ); VER 1.4 DESC RasterPos を WindowSpace で指定する VertexTransform をバイパスする WARNING Symbol が見つからないため 中止
___

■ glClientActiveTexture

SYNTAX void glClientActiveTexture( GLenum unitTex ); DESC VertexArray の tc をわりあてる, UnitTex を指定する. TIP MultiTex && VertexArray の組あわせで使う
___

■ glDepthMask

SYNTAX void glDepthMask( bool flag ); DESC 指定した Buffer の書き込み Mask を設定する. はいってくる Fragment に対して, 指定した bit と && 操作する. なので, glDepthMask( true ); -> Depth 値が Buffer に書き込まれる. TIP glColorMask( bool red, bool, grn, bool blu, bool alp ); glStencilMask( int mask );
___

■ glFinish

SYNTAX void glFinish() DESC コマンドが完全に実行されるまで制御を返さない( BlockAPI ) 発行済みコマンドを強制実行し、グラフィックス ハードウェアやネットワークが コマンドの効果が現れた(描画を終了した)ことを保障した時点で制御が戻ります [GPU]---> おわったよ ----> [CPU] 処理の同期をとる際に利用する たとえば, 2D 表示を別の PostScript などでする場合. 先に 3次元処理を終了しておく. WARNING 同期まちをするので, 過度の使用は APP の処理速度をおとす( 特に Network 経由の場合 ) 基本的に glFlush() を利用すること。
___

■ glFlush

SYNTAX void glFlush() 発行した OpenGL コマンドの実行を強制するという方法が用いられます Flush == 送り出す. [ 有限時間内 ]に終了することが保障される 今の FW では CMyGL::flip() で SwapBuffers( hDC ); をしている App::Draw() の最後. もし Flush ならば, 処理待ちはしていないことになる. 消すとまったく表示されなくなる. しかし App::update() は正しい。 SwapBuffers の前に glFinish() を読んでも動作は OK の. コマンドを発行したからといって、サーバーが描画を終了しているとは限らないのです ClientServerModel だから, Newwork 経由で毎度命令データを送るわけではない. でも促したい場合もある そういう場合は, Flush する( 送り出す ) Graphics 処理は PIPELINE 方式である. POINT [CPU] : 描画CMD 発行. : ( 各 CMD の終了をまつ必要なし ) [GPU] : 専用の HW で処理.: CPU が送り出した 頂点を次々に処理する -> というわけで, CPU は 各 CMD ごとに GPU の処理を待つ必要はない. さて [CPU] < -> [GPU] が Network ではなれていた場合, 描画 CMD をひとつずつ送るのは、大変 OverHead がかかる. -> よって, NetworkProgram は CMD を NetworkPacket にまとめる。 しかし [ 1Frame の描画 CMD の発行が終了した ]際は, 強制的に送ってほしい. Network をはさまない場合は, CMD 発行と同時に即時処理される 次のケースでは glFlush() が有効. 各 Frame の最後で, 残りの CMD をすべて送り出す保障をする. SystemMemory に描画する SoftwareRenderer で 明示的に描画する際.
___

■ glClearColor

SYNTAX void glClearColor( float r, float g, float b, float a ); DESC glClear に使用する Color を設定する [0-1] に clamp される POINT 指定した Alpha 成分も, Clear() するとその値に FrameBuffer の Alpha 成分がなる Shader, glCopyTexImage2D, Blend 時はこの Alpha 成分を利用することになる FragmentShader で Fragment.w の値を指定すると Blend State で以下の影響をうける
    DST( FrameBuffer)  +  SRC( Fragment )
WARNING FrameBuffer に Alpha 成分がなければ Alpha 成分は無視される TIP Alpha も設定できることに注目 glCopyTexImage2D() では Alpha 成分も Copy できる
___

■ glClear

SYNTAX void glClear( GLbitfield mask ) DESC Frame Buffer をクリアする Application は 各 frame の最初に color Buffer と DepthBuffer をクリアする TIP 一度の 呼び出しで 複数の Buffer をクリアすると高速

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

___

■ 座標変換(VertexTransform)



  DESC
    プログラム内での関数名は次のように変換先の空間を指定する.

  WARNING
    スクリーンスペースでの原点は左下原点となるように指定する。


  WARNING 
    glFrustum, glOrtho をコールすると現在の行列に積算される。
    必ず glLoadIdentity() でクリアすること。
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();               // 必須
    glFrustum();
以下の方法では 現在の PROJECTION 行列に glFrustum() で生成した行列をかけることになる。
    glMatrixMode( GL_PROJECTION );
    glFrustum();
POINT 頂点を xyz を指定すると w 成分は 暗黙 で 1 になる POINT 転置する理由 行列は列行関係なく, 最後の 4 つに T がある  ( Memory 的には 4*3 がよいので, 転置する ) GL の仕様書で扱う行列は "列順" で表記される [ 0][ 4][ 8][12] [ 1][ 5][ 9][13] [ 2][ 6][10][14] [ 3][ 7][11][15] ベクトルは 列ベクトルとして扱う。 [ x ] [ y ] [ z ] [ w ] これは数式の表記の問題であって, 処理には関係ない。 POINT 守ることは次のことだけ 列順, 行順の混乱しないように, 1 次元配列で考えること。 LoadMatrix() をする際は, 最後の4成分 が移動成分である必要がある。
    X 軸  m[0] m[1] m[2]  Y 軸  m[4] m[5] m[6]  Z 軸  m[8] m[9] m[10]  原点  m[12] m[13] m[14]
例えば、Z 方向に -10 移動する行列は次のように指定する。
    float m[] = { 
            1, 0,   0, 0, 
            0, 1,   0, 0, 
            0, 0,   1, 0, 
            0, 0, -10, 0,   // 最後の4要素が移動成分
            };
    
    glLoadMatrixf( m );
    drawCube();

ProjectionSpace pos.w == ViewSpace pos.z
___

■ 行列積の順番

POINT 列順, 行順の表記に関係なく 行列変換の API は最後にコールされた順番に頂点が変換される。 T * R * v
    glLoadIdentity();
    glTranslatef( 1, 0, 0 );      // 横に1移動する
    glRotatef( 45, 0, 1, 0 );     // Y 軸に回転してから
    drawCube();
R * T * v
    glLoadIdentity();
    glRotatef( 45, 0, 1, 0 );     // Y 軸中心に 45 度を回転をする。
    glTranslatef( 1, 0, 0 );      // 横に1移動してから
    drawCube();
カメラ座標系への変換は最後にするので, コードとしては最初にかく。 C * T * R * v
    glLoadIdentity();

    convertCameraSpace();
    
    // 以下のコードで先ずはワールド空間に配置する。
    glTranslatef( 1, 0, 0 ); 
    glRotatef( 45, 0, 1, 0 );
    drawCube();
1次式の別表現( 定義 )が行列とベクトルの積
    x2 = a*x + b*y
    y2 = c*x + d*y
上の式を行列とベクトルの積として定義する
    V2 = ( a, b ) V
         ( c, d )
スケール変換を行列積であらわす
    x2 = sx*x
    y2 = sy*y
    V2 = ( sx,  0 ) V
         (  0, sy )
___

■ 行列とベクトルの積

行列とベクトルの積を OpenGL に計算させるには 行列同士の積を利用する。 2個目の行列の第一列をベクトルとみなして、 glMultMatrix() で計算する。
    glMatrixMode( GL_MODELVIEW );
    glLoadMatrixf( m );

    float mv[16] = {
      v[0], v[1], v[2], 0,
    };

    // ベクトルの代わりに
    glMultMatrixf( mv );
    // 結果をとりだす。
    glGetFloatv(GL_MODELVIEW_MATRIX, mv );

    // 結果
    v[0] = mv[0];
    v[1] = mv[1];
    v[2] = mv[2];
___

■ モデルビュー変換

POINT OpenGL にはカメラをここに置くという命令はない。 モデルのワールドでの位置はカメラが中心の座標系として指定する。 カメラの位置を原点とする右手座標系のため、カメラの正面に置くためには Z値がマイナスである必要がある。 行列の変換がわかりずらいならば、直接z値にマイナスの値を指定すれば良い。
    App::onDraw() {

      // 変換をしないように単位行列をロードしておく。
      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();

      
      // 直接マイナスの値を指定する。
      float z = -1.0f;
      
      glBegin( GL_TRIANGLES );
      glVertex3f( 0, 0, z );
      glVertex3f( 0, 1, z );
      glVertex3f( 1, 1, z );
      glEnd();

    }
移動行列を使って、カメラの正面に移動させる。


    App::onDraw() {
      glMatrixMode( GL_MODELVIEW );

      // 同一のモデルを複数の位置で描画する。
      glLoadIdentity();
      glTranslatef( 0, 0, -1.0f; );
      drawTriangle();

      glLoadIdentity();
      glTranslatef( 1.0f, 0, -1.0f; );
      drawTriangle();
    }

    void drawTriangle() {

      glBegin( GL_TRIANGLES );
      glVertex3f( 0, 0, 0 );
      glVertex3f( 0, 1, 0 );
      glVertex3f( 1, 1, 0 );
      glEnd();

    }
___

■ 回転とスケール

モデルを回転するには glRotate() を使う。 移動と回転の順番によって結果は異なる。 通常はモデルを回転してから、ワールド( カメラ原点 )の位置へ移動する( 置く )。
    [ 単位行列 ]  // glLoadIdentity() でカレントの行列は単位行列になる。

    [ 移動行列 ]  // glTranslatef()   で移動行列をかける  T * R
    [ 回転行列 ]  // glRotatef()      で回転行列となる。      R


    描画コールをした時点でこの行列によって頂点が変換される。
    行列操作のコマンドは現在の行列に対して右から掛けられる。
    先に回転 glRotate() をコールした後に glTranslate() をコールすると
    glRotate 後の座標系で移動することになる。
    ( または移動してから回転という操作になる。 )
    App::onDraw() {

      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();
      glTranslatef( 0, 0, -1 );     // Z=-1 の位置に置く。
      glRotatef( 45, 0, 1, 0 );     // Y軸を中心に45度回転してから
      
      drawTriangle();
    }

// DirectX の本では. --------------------------- 射影空間 ( ProjectionSpace ) ( z/w ) < -> [0:1] に正規化された NearPlane からの距離. ProjectionSpace の w は ViewSpace の z と等しい.
___

■ 投影変換

モデルを配置したら、カメラの位置を焦点として画面にモデルを投影させる。 この変換を投影変換といい、画面に投影することで遠くのものは小さく、 近くのものは大きく見えるようになる。 カメラでいうと画角の調整に相当する。 投影変換をするには glFrustum() を使う。 6つのパラメータで四角錐( 視錐台 )の形を定義する。 この範囲内のものが画面に描画される。 遠くのものほど, 小さく写すので x, y をカメラからの距離に応じて割る。
    X = x/z;
    Y = y/z;
z の値を変換する1次式
    Z = a*z + b
near のときに 0, far の時に 1 となるような係数を求める。
    0 = -n * a + b
    1 = -f * a + b
    // b を消す。
    1 = (n - f) * a

           1
    a = --------
          n-f

    // b = n*a だから
           n
    b = --------
          n-f
ハードウェアで透視変換をしてもらう。
    // 縦横比の調整
    X *= W/H;
    

    // 4 次元目に 範囲変換前の Z をセットしておく。これで XY が割られる。
    w = z;

    // Z の値は 0:1 の範囲に線形変換する
    Z =     

ハードに渡す頂点は次の条件をみたす必要がある。 自前で投影変換をした後の頂点は以下を満たす必要がある。
     X, Y は [ -1 : 1 ]    ( 範囲外は 画面に表示されない )
     w は xz(z) を割ってほしい値をいれる
     z は すでに変換すみなので, 先に z をかけておく
___

■ カメラを動かす

SAMPLE カメラを動かす 注視点を軸にカメラを回すには、 カメラのワールドの行列の逆行列を各モデルのワールド行列に掛ければよい。 というより、カメラから見た位置に変換するにはカメラの逆行列をかける。 例えば、回転だけで考えると カメラが右( X=1 の方向 )に90度向けた場合、 カメラを基準に見れば、すべてのモデルを左に−90度回したことと等しい。 移動に関しても同じで カメラを 右に10移動することと、すべてのモデルを左に−10移動させることは等しい。 以上のことからカメラのワールドの行列がわかれば、 その逆の変換をすればカメラから見た位置が決まる。 カメラのワールドでの位置と回転(向き)から逆の変換をする。
    void tranforrmCameraSpace( float tx, float ty, float tz, float rx, float ry ) {  

      // カメラ位置の逆の変換
      glTranslatef( -tx, -ty, -tz );

      // カメラの向きの逆の変換
      glRotatef( -rx, 1, 0, 0 );
      glRotatef( -ry, 0, 1, 0 );
    }
各モデルのワールドの位置をカメラから見た位置に変換する。

    glMatrixMode( GL_MODELVIEW );

    glLoadIdentity();
    glTranslatef( 0, 0, 10 );                  // モデルを 0, 0, 10 に置く
    tranforrmCameraSpace( 0, 10, 0, 30, 40 );  // 0, 10, 0 に置いたカメラから見た位置に変換する。
    drawCube();

    glLoadIdentity();
    glTranslatef( 1, 1, 1 );
    tranforrmCameraSpace( 0, 10, 0, 30, 40 );
    drawCube();

___

■ 行列の結果を取得する

行列の現在の値を取得するには glGet() で取得する。 POINT glTranslate はそのときの座標系の Local 方向へ移動する 今 移動 [Xx][Yx][Zx][Tx] [Xx][Yx][Zx][Tx] [Xx][Yx][Zx][Ty] [Xx][Yx][Zx][Ty] [Xx][Yx][Zx][Tz] [Xx][Yx][Zx][Tz] [ 0][ 0][ 0][ 1] [ 0][ 0][ 0][ 1] // 今の座標系のうち, X 方向へ寄与する量 + 元の X 位置 X = Xx * Tx + Yx * Ty + Zx * Tz + Tx( 元の位置 ) 結果をチェック

      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();
      glTranslatef( 1, 2, 3 );

      float m[16];
      glGetFloatv( GL_MODELVIEW_MATRIX, m );

      print( m );

      1.000000 0.000000 0.000000 1.000000
      0.000000 1.000000 0.000000 2.000000
      0.000000 0.000000 1.000000 3.000000
      0.000000 0.000000 0.000000 1.000000   // Translation に 1, 2, 3


0.707107 0.707107 0.000000 0.000000
-0.707107 0.707107 0.000000 0.000000
0.000000 0.000000 1.000000 0.000000
0.000000 0.000000 0.000000 1.000000

      glLoadIdentity();
      glRotatef( 45, 0, 0, 1 );


0.707107 0.707107 0.000000 0.000000
-0.707107 0.707107 0.000000 0.000000
0.000000 0.000000 1.000000 0.000000
0.707107 0.707107 0.000000 1.000000

      // 45 度回転して, そのときの X 軸方向{ 0.707107 0.707107, 0 }へ 1 の長さ移動
      glLoadIdentity();
      glRotatef( 45, 0, 0, 1 );
      glTranslatef( 1, 0, 0 );


0.707107 0.707107 0.000000 0.000000
-0.707107 0.707107 0.000000 0.000000
0.000000 0.000000 1.000000 0.000000
1.000000 0.000000 0.000000 1.000000

      // 移動した場所で回転
      glLoadIdentity();
      glTranslatef( 1, 0, 0 );
      glRotatef( 45, 0, 0, 1 );

回転と同じく Scale の影響もうける

      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();

      glScalef( 0.5, 0.5f, 0.5f );
      glTranslatef( 1, 0, 0 );

      0.500000 0.000000 0.000000 0.000000
      0.000000 0.500000 0.000000 0.000000
      0.000000 0.000000 0.500000 0.000000
      0.500000 0.000000 0.000000 1.000000

I * MT * MR
___

■ glMatrixMode

SYNTAX glMatrixMode DESC 行列操作をする行列スタックを選択する Texture Matrix は Texture Unit ごとにある。 TIP GL_TEXTURE の場合は, 操作するスタックは glActiveTexture() で選択している Unit になる DEFAULT 単位行列 ERROR GL_STACK_UNDERFLOW GL_STACK_OVERFLOW
    // UNIT 1 を選択
    glActiveTexture( GL_TEXTURE1 );

    // UNIT 1 の Texture Matrix を設定
    //  以後, Matrix 操作は この Stack が対象
    glMatrixMode( GL_TEXTURE );
    glLoadIdentity();
    glTranslatef( 1, 0, 0 );


    // ModelView Stack へ切り替え
    glMatrixMode( GL_MODELVIEW );



___

■ glMultMatrix

SYNTAX glMultMatrixf( const GLfloat *m ) DESC スタック最上位の行列に右からかける カレントの行列を C とすると
    C * v
glMultMatrix( M ) をコールすると, M を右から掛けることになる。
    C * M * v
___

■ glLoadMatrix

SYNTAX void glLoadMatrixf( const GLfloat *m); DESC 指定した行列に置き換える。 m は列優先の行列。
    m[0] m[4] m[ 8] m[12]   v[0]
    m[1] m[5] m[ 9] m[13]   v[1]
    m[2] m[6] m[10] m[14]   v[2]
    m[3] m[7] m[11] m[15]   v[3]
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glTranslatef( 1, 0, 0 );
    glTranslatef( 1, 0, 0 );   // この時点で x = 2 の行列

    float m[16] = {0};
    glLoadMatrixf(m);          // これをコールした時点で0行列
___

■ glRotate

SYNTAX glRotatef( float angle, float x, float y, float z ); DESC x, y, z で指定した軸を中心に r 度回転する行列を右からかける。 角度の単位はラジアンではなく、360度での設定。
___

■ glTranslate

DESC x, y, z 軸にそった平行移動をする行列を作成して 右からかける 次の行列を glMultMatrix() することと同じ
    1 0 0 x
    0 1 0 y
    0 0 1 z
    0 0 0 1
次の2つは同じ
    glTranslatef( 1, 2, 3 );

    float m[] = { 
        1, 0, 0, 0, 
        0, 1, 0, 0, 
        0, 0, 1, 0,
        1, 2, 3, 1,
    }
    glMultMatrixf( m );
___

■ glScale

DESC x, y, z 軸にそって拡大縮小をする行列を作成して 右からかける
___

■ 視点座標の定義

DESC GL の視点座標の定義は以下のもの。
     視点は原点 { 0, 0, 0 }

     右手座標系
       視線の方向( 正面 )は Z 軸のマイナスの方向
       +Y が上
       +X が右
POINT カメラに写るためにはモデルビュー変換後の Z 座標が - であることが必須になる。
___

■ glPushMatrix.glPopMatrix

DESC [ cur Mtx を cp ] したものを最上段に配置 POINT MtxTex は Unit ごとに設定する. ( 選択は glActiveTexture で ) 自前で mtx 計算をする場合は不要な処理のはず. 余計な Error を防ぐために使用を禁止する. DEFAULT Stk ごとに 1 つの MtxUnit をふくむ. EX GL_MAX_( MODELVIEW | PROJECTION | TEXTURE )_STACK_DEPTH
___

■ 座標変換 pipeline

次の流れで頂点座標がスクリーン上のピクセル位置まで変換される
    [ オブジェクト座標 ]
           |
      モデリング( ワールド )変換
           |
    [ ワールド座標  ]
           |
        視野変換( カメラから見た位置へ変換  )
           |
    [  視点座標  ]
           |
       投影変換 ( 投影面に写像する )
           |
    [  クリップ空間  ]
           |
       w 除算
           |
  [ NormalizedDeviceCoordinate ]
           |
      ビューポート変換( 印画紙に引き伸ばす )
           |
    [ スクリーン座標(画面) ]


___

■ クリップ座標

ModelViewProjection 行列の結果の座標 透視除算( w で割る ) ( 透視投影のみ有効 四角い箱にする ) 投影行列が w の値をきめる 平行投影なら w = 1 になる Clip 座標の点は 以下のようにある -w < [x,y,z] < w Frustum の外の Primitive はこの時点で除去 部分的にでる Primitive は, 範囲内だけが Rasterize される
___

■ 正規化された デバイス座標

-1.0 < [x,y,z] < 1.0 処理 透視除算 w 成分で x, y, z 成分をわる これによって 遠いものが 小さく見えるように変換される x : Window の SubPixel y : Window の SubPixel
___

■ window 座標

SAMPLE 複数のビューポート 処理 viewport 変換 ( WARNING, x, y だけでなく z も写像される ) 変換された z 値は DepthBuffer にはいり、デプステストで使われる。 DESC 左下原点 | | | | ----------------------------- ( [0,0] - [x,y] , Z: depth buf [0:1] ( 正規化された Depth 値 ) 0 : DepthBuffer の前面 1 : DepthBuffer の背面 WARNING: x,y,z は浮動小数点でもつ ラスタライズのため )
___

■ glViewport

SYNTAX void glViewport( GLInt x, y, // mapping 先の 原点位置 ( 負数も指定できる ) GLInt w, h, // 幅, 高さ ) DESC 最終的に写像される矩形領域を定義する。 x, y, w, h は Window 左下を原点とするスクリーン座標 DEFAULT 正規化 Device 座標を Window Size 全体に写像する。 Window Size が変更されないなら指定は不要 ^-------------------- | | H|------------ | | | | | | | --------------------> 0,0 W Normalized Device Coordinate -------- | | | | | | -------- メタファは印画紙 VertexTransform 後の 値は Film WARNING 指定した Buffer ( Color | Depth | Stencil )全体をクリアする 一部分ではない
    // Viewport 変換もステートのひとつなので
    // 好きなタイミングで変更できる

    float W = 1024;
    float H = 768;

    // 左半分 に表示
    glViewport( 0,  0, W, H );
    drawScene();

    // 右半分 に表示
    glViewport( 0, W/2, W, H );
    drawScene();

___

■ glFrustum

SYNTAX glFrustum( float l, float r, float b, float t, float n, float f // 視点からクリップ面までの距離 ( 正の値 ) ); DESC 投影変換( 遠くのものを小さく変換する )行列を作成してカレントの行列に掛ける。
    // 透視変換行列を指定する。
    glMatrixMode( GL_PROJECTION );

  WARNING
    // 乗算するので 初期化 しとく
  glLoadIdentity();

    // 通常は左右対称の投影するため, 
    // left   = -right
    // bottom = -top   の関係が成り立つ。

    さらに画面の縦横比(アスペクト)に合わせることで、ウィンドウ変換した際に歪まないようにする。

    そのため画面サイズ(アスペクト)と画角から r, l, t, b は決まる。

    n, f はニアクリップとファークリップの位置を指定する。
    n より手前と f より奥はすべてクリップされて表示されない。

    画角と n, f のクリップ面の距離から指定すると直感的にわかりやすい。
    
    

  WARNING
    n, f の値はデプスバッファの精度に影響を与えるためシーンのサイズに合わせる必要がある。
    n を小さくして、 f を大きくすれば良いというものではない。
    
    f/n  の値を大きくすればするほど、精度が落ちる。

    n を 0 に近づけると、 f/n は無限大に発散する。

    log2(f/n) bit の精度が失われる。


  float l = -0.75;
  float r = -l;
  float b = -l * h/w;
  float t = -b;
  glFrustum( l, r, b, t, 1, 1000.0f );

___

■ glOrtho

SYNTAX void glOrtho( GLDouble l, GLDouble r, GLDouble b, GLDouble t, GLDouble n, GLDouble f // カメラからの距離 ) DESC 平行な視体積の行列を作成する。 near , far は [ 正負0 ] 可能 視体積 の外の obj はクリップされる メタファーとしては, カメラから見た世界での BOX を定義 WARNING 行列スタック上で累積するので, glLoadIdentity(); 忘れないこと ERROR GL_INVALID_VALUE( l = r, b = t, n = f ) TIP 投影行列が ClipSpace へ変換する. ( Ortho の場合は常に w = 1.0f ) WARNING ortho proj mtx 内に obj が内包されていない カメラ座標系( カメラから見た )の点がボックス領域に入る必要がある
    glOrtho( 0, 800, 600, 0, 0, 1 );

    ERROR
      pnt A { -10.0f, 0.0f, 0.0f }
    OK
      pnt B { 10.0f, 10.0f, 0.0f }
___

■ gluPerspective

SYNTAX gluPerspective( GLDouble fovy, // 縦( Y )方向の角度 ( 単位 degree ) GLDouble aspect, // 縦横比 ( w/h ) GLDouble near, far // 視点からクリップ面までの距離 ( 正の値 ) ) DESC view frustum を定義する。 アスペクトはビューポートを同じ比率にするのが一般的。 glFrustum などと同じく、カレントの行列に乗算される。 上書きする場合は, glLoadIdentity() を先に呼ぶこと。 fovy/2 とあるので、縦方向半分ではなく, 縦全体の角度指定になる。

      /
     /
    /
  --------------------------  120 度の指定では縦方向はこの範囲が見れる。
    \
     \
      \
この計算と同じになる。

    float ang = angle/180.0f * 3.14f;
    float t = tan(ang/2) * n;
    float b = -t;

    float r = t * ratio;
    float l = -r;

    glFrustum( l, r, b, t, n, f );
___

■ gluLookAt

SYNTAX void gluLookAt( GLdouble eyeX, eyeY, eyeZ, GLdouble centerX, centerY, centerZ, GLdouble upX, GLdouble upY, GLdouble upZ); DESC カメラ座標系への変換行列を作成する。( カメラのワールド行列ではない ) この変換により、 注視点は Z軸のマイナスの値に, 視点は原点は移動する。 現在の行列を積算するかどうかは書いてないが, 行列を取得してみればわかる。 UPベクターは 視線ベクトルと平行になってはいけない。
___

■ DepthBuffer

非線形 ( /w ) 指数関数的 次の比率が 目安 16bit Depth Buffer -> far / near = 50 24bit Depth Buffer -> far / near = 10000
___

■ ProjectionSpace

DESC ProjectionSpace( 射影空間 ) とその変換について MEMO DirectX [-1,-1,0] < -> [1,1,1] の 箱に変換される W 除算前は ↑の範囲にはない OpenGL [-1,-1,-1] < -> [1,1,1] の 箱に変換される W 除算前は ↑の範囲にはない。 POINT 投影変換 した後の pos.w は ViewSpace における奥行値になる これは Projection Matrix の 3 行目から明らか
              (vpos.x)
              (vpos.y)
              (vpos.z)
      0,0-1,0  (vpos.w)  = -vpos.z  ( カメラの奥行 )

    ということは w 除算とは 奥行で xyz を割ること

    , VertexShader で出力する 位置( pos )情報は
    w 除算してない

    -> どうやら Pipeline の中で行われる



TIP ShadowMap で利用する Depth 値の算出方法

    // [ ModelSpace ] ---> [ ClipSpace ]
    float4 pos = mul( mvp, IN.pos );

    // POINT
    //  ここでは まだ w 除算しない
    //  理由は 線形補間では 補間式が異なるから
    //  この違いは shadowmap, priority shadowmap で明らかになる
    //
    OUT.depth = pos.zzzw;
    return OUT;


    // Fragment Shader で w 除算すること


    // POINT
    //    ここで [0:1] の範囲に おさまる
    //    逆に w 除算をする前は [0:1]  におさまってない
    //
    float4 col = IN.depth.z / IN.depth/w;



TIP 画面いっぱいに Quad をかく指定
    // でも考えてみると Z の指定が これでいい ?

    // 変換はしない
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    // W = 1 にすること
    glVertex3f(-1, -1, -0.3f, 1 );
    glVertex3f( 1, -1, -0.3f, 1 );
    glVertex3f( 1,  1, -0.3f, 1 );
    glVertex3f(-1,  1, -0.3f, 1 );
___

■ 行列操作

POINT 行列操作 の Command は 行列スタックの最上部につまれ右から乗算される
      // Code で記述した順番と反対になる
      [  glTranslate ]
      [  glRotate    ]

      {
        glRotate();    // 移動した後に回転
        glTranslate(); // 先に移動処理がかかる

        // 描画
        draw();
      }

      // 数式でかくと
      R * T * v

      // 言葉で言えば
      移動してから, 原点( 0,0,0 )を中心に回転
___

■ 頂点配列


___

■ VertexArray(頂点配列)

DESC 描画に使う頂点をひとまとめにして、OpenGL へ転送しておくことで 描画処理を高速化する機能。 頂点を配列として扱うことでまとまった処理ができ、 関数呼び出しの オーバーヘッドを減らすこともできる。 Application は index で頂点を指定する 共有頂点の処理の重複にも効果がある( Cashe )
    // 頂点の数だけ関数呼び出しのオーバーヘッドがかかる。
    float vtx[3*100][3];

    glBegin( GL_TRIANGLES );
    for( int i=0; i< 300; i++ ){
      glVertex3fv( vtx[i] );
    }
    glEnd();

    // 頂点の配列を指定して一度の描画コマンドで済ます。
    glVertexPointer( 3, GL_FLOAT, 0, vtx );
    glDrawArrays( GL_TRIANGLES, 0, 300 );
頂点配列を利用する場合は、glBegin() - glEnd() の部分のコードを置き換える。 頂点配列のデータを指定して、頂点配列の使用を有効化した後に描画コールをするだけ。

    App::onDraw() 
    {
      // 頂点データ
      // 描画コール毎に頂点データが転送されるため、アプリケーション側は描画コールまではデータを保持する必要がある。
      float vtx[] = {
        0, 0, 0,
        100, 0, 0,
        50, 200, 0,
      };

      // 使用する頂点属性を宣言する。( データを指定するだけでは描画に利用されない。)
      glEnableClientState( GL_VERTEX_ARRAY );

      // 頂点配列として使うデータを指定する。
      glVertexPointer( 3, GL_FLOAT, 0, vtx );

      // 描画する。
      glDrawArrays( GL_TRIANGLES, 0, 3 );
    }
SAMPLE 頂点配列 頂点配列には、単一のデータではなく複数の頂点属性を混ぜることができる。 実装によってはこちらの方が高速に処理できる。

    struct Vertex {
      float pos[3];
      float col[3];
    };

    Vertex v[] = {
      {  0, 0, 0, 1, 0, 0 },
      {  100, 0, 0, 1, 1, 1 },
      {  50, 100, 0, 0, 1, 0 },
    };

    // インターリーブ型にする場合は stride で間隔を指定する。
    glVertexPointer( 3, GL_FLOAT,  sizeof(Vertex),  v );
    glColorPointer ( 3, GL_FLOAT,  sizeof(Vertex), v[0].col );

    // カラーと座標を使う。
    glEnableClientState( GL_VERTEX_ARRAY );
    glEnableClientState( GL_COLOR_ARRAY );

    glDrawArrays( GL_TRIANGLES, 0, 3 );
void drawPrimitiveArray()
{
  // Texture の影響をうけないようにする
  glDisable( GL_TEXTURE_2D );

  const float s = 30;

  // Position
  static float vtx[] = {
    0, 0, 0,    s, 0, 0,    s, s, 0,
  };

  // Color
  static GLfloat col[] = {
    1.0f, 0.0f, 0.0f,    1.0f, 0.0f, 0.0f,    1.0f, 0.0f, 0.0f,
  };

  // Color , Positon の頂点配列を有効化
  //    ポインタは場所を指定するだけで使用するにはこの関数をよびだす
  //
  glEnableClientState( GL_COLOR_ARRAY );
  glEnableClientState( GL_VERTEX_ARRAY );

  // 頂点配列へののアドレスと要素数を指定する
  glColorPointer( 3, GL_FLOAT, 0, col );
  glVertexPointer( 3, GL_FLOAT, 0, vtx );

  static unsigned short idx[] = { 0, 1, 3,};
  // Triangle を描画
  glDrawElements( GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, idx );
  }
}
___

■ glVertexPointer

SYNTAX void glVertexPointer( GLint size, // 頂点座標の要素数 ( XYZ ならば3 ) GLenum type, // データ型 GLsizei stride, // 次の頂点の座標データまでのバイトサイズ。 const GLvoid *pointer // Dataへのポインタ ) DESC 描画に使う頂点配列のデータ( 場所、型、フォーマット )を指定する。 POINT stride, pointer パラメータはデータの指定方法によって異なる。 stride 0 : pointer で指定した配列には座標データが連続して並んでいるとみなされる。 N : pointer で指定するのはインターリーブ配列で, 次の座標データまでの間隔をバイトで指定する。 ( 実装によってはこちらの方が効率的 ) pointer VBO がバインドされている場合は VBO のバイトオフセットとして扱われる。 バインドされていない場合は、クライアント側のメモリアドレス。 WARNING Type にあう Alignment に各要素が配置されている必要がある
___

■ glTexCoordPointer

DESC 頂点配列のテクスチャ座標データを指定する。
___

■ glColorPointer

SYNTAX void glColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer ); DESC The glColorPointer function defines an array of colors. POINT pointer は VBO がバインドされている場合は VBO 内にあるカラーデータまでのオフセットを指定する。 VBO がバインドされていない場合は アプリケーションのメモリの値になる。 BLEND OFF == glDisable( GL_BLEND ); Fragment col.w = 1; の値が FrameBuffer に格納される. BLEND ON Fragment col.w = a; BlendExp にしたがって格納。 要は [ COLOR 成分 ]と同様にふるまう. と考えること。 POINT Alpha も設定できる。 glCopyTexImage2D() では Alpha 成分も Copy できる. !
___

■ glVertexAttribPointer

VERSION 2.0 SYNTAX void glVertexAttribPointer( GLuint index, // 頂点属性の番号 GLint size, // 要素数( 1−4 ) GLenum type, GLboolean normalized, // [ -1 : 1 ], [ 0 : 1 ] に正規化するかどうか GLsizei stride, const GLvoid * pointer); DESC 汎用型の頂点データを指定する。 おおまかには glVertexPointer() などと使い方は同じ。 シェーダで追加の頂点属性を指定する時などに利用する。
___

■ glDrawArrays

SYNTAX glDrawArrays( mode, // プリミティブモード offset, // 頂点配列の開始オフセット count // 描画に使う頂点数の数 ); DESC 格納した頂点バッファを描画する glDrawElements とは違い 頂点配列へのインデックスを指定しないので 頂点バッファのデータは描画順にならんでないとだめ [0]-- [3] | | | | [1]-- [2]
    // 四角形をひとつ
    //      0 番目から 4 個
    glDrawArrays( GL_QUADS, 0, 4 );

___

■ glDrawElements

SYNTAX void glDrawElements( GLenum mode, // Primitive 形式の指定 GLsizei count, // Rendering する頂点の個数 GLenum type,     // Index Data の型( GL_UNSIGNED_BYTE | GL_UNSIGNED_SHORT | GL_UNSIGNED_BYTE ) const GLvoid *idx // 頂点配列をさす Index ); DESC 頂点配列を使った描画コマンドのひとつ 指定した index 列がさす頂点で描画する glVertexPointer, glNormalPointer, glTexCoordPointer で指定した頂点配列から index を使ってとる TIP BufferObject に Bind されているときは indices は BufferObject への offset として解釈される
    // 頂点配列を指定
    static float vtx[] = {
      0, 0, 0,
      1, 0, 0,
      1, 1, 0,
    };

    // 頂点配列へのインデックス配列  0 1 2 を指定する
    static unsigned short idx[] = {
      0, 1, 2
    };

    glVertexPointer( 3, GL_FLOAT, 0, vtx );

    // BufferObject を Bind しているときは
    glBindBuffer( GL_ARRAY_BUFFER, id );

    // idx が指す先は BufferObject からの offset として扱われる
    glDrawElements( GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, idx );
___

■ glDrawRangeElements

SYNTAX glDrawRangeElements DESC glDrawElements を最適化したもので頂点 index の範囲を制限する
___

■ glEnableClientState

SYNTAX void glEnableClientState( GLenum array ) DESC 有効にする配列( VertexArray )を指定する VertexArray の Command を発行するとき, 有効になっている Data のみを利用する glEnable() と概念は同じだが Client 側の State を変更する glEnable() は サーバー側のステートを有効にする glEnableClientState という名前は displaylist に格納できないことに由来している ( data がクライアント側に残るから ) TIP MultiTexture の場合は. UnitActive Unit のみ影響をうける

    // 頂点と法線を使って描画することを宣言
    glEnableClientState( GL_VERTEX_ARRAY );
    glEnableClientState( GL_NORMAL_ARRAY );
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );

    // 描画
    draw();
___

■ 頂点バッファオブジェクト(VBO)


  SAMPLE
     VBO 

___

■ BufferObjectに頂点配列(VertexArray)を配置する

DESC 頂点データをビデオメモリに配置することで描画を高速化する機能のこと。 アプリケーション側のメモリを解放もでき、 また CPU < -> GPU 間での頻繁なデータの転送も不要になる。 DEP VERSION::1.5
    App::onInit() {   

      glGenBuffers =
        (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");      
      glBindBuffer =
        (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
      glBufferData =
        (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");      


      // BufferObject ID を確保
      glGenBuffers( n, bufs );

      // buffer をバインドして頂点データ, インデックスデータのどちらかを指定する。

      // Buffer Object を選択して初期化
      glBindBuffer( GL_ARRAY_BUFFER, id );


      // 頂点属性
      struct Vertex {
        float vtx[3];
        float col[3]
      };

      // OpenGL側に記憶領域を確保してもらいアプリケーション側のデータをコピーする
      Vertex vtx[] = { 
                      0, 0, 0, 1, 1, 1, 
                      1, 0, 0, 1, 1, 1,  
                      1, 1, 0, 1, 1, 1,  
                      0, 1, 0, 1, 1, 1, 
                      };

      glBufferData( GL_ARRAY_BUFFER, sizeof(vtx), vtx, GL_STATIC_DRAW );

      
      // 頂点と同じようにインデックス用のVBOを作成する。
      glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, id );

      // インデックスデータをコピーする。
      unsigned short idx[] = { 0, 1, 2, 3 };
      glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW );

    }

  App::onDraw() {

    // 描画に利用する VBO を指定する。
    glBindBuffer( GL_ARRAY_BUFFER, id );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, id );

    
    // VBO を利用するときは, 頂点データのポインタではなく VBO 内のオフセットを指定する。
    // インターリーブ型の配列のため stride は頂点ごとのバイト数を指定する。
    // pointer 引数には各頂点属性のオフセットを指定する。
    glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), 0  )
    glColorPointer ( 3, GL_FLOAT, sizeof(Vertex), sizeof( float )*3;  )


    // 頂点配列を使うときは OpenGL にどこから Data をとるか指定する
    // Data を直接送るときも, BufferObject を利用するときも同じ

    // 頂点データは既に転送済のため, 要素数、要素型 オフセットのみを指定する。
    // VBO の先頭から指定するため offset = 0
    //
    glVertexPointer( 3, GL_FLOAT, 0, (GLvoid *)( (char*)0 ) );
    glVertexPointer( 3, GL_FLOAT, 0, (void *)0 );
    
    
    // 描画する。
    // VBO を利用しているので pointer はメインメモリのアドレスではなく 
    // インデックス用のVBO内のオフセットを指定する。
    glDrawElements( GL_QUADS, 1, GL_UNSIGNED_SHORT, 0 );
  }


終了時はバッファオブジェクトを解放する。
    App::onQuit() {
      glDeleteBuffers( n, bufs );
    }
TIP id = 0; GL は VBO を使用しなくなる glBindBuffer() ではじめて Bind すると作成 -> 2度目からは, Bind ( glBindTexture とおなじ ) BufferObject , ClientMemory 共に指定する Interface は同一
___

■ glGenBuffers

SYNTAX glGenBuffers( GLsizei n, // 取得する BufferObject の個数 GLuint *buf ) DESC n 個の BufferObject の ID を取得する

  // Buffer Object の生成
  glGenBuffers( 1, (GLuint *)&id_src );

___

■ glBindBuffer

SYNTAX glBindBuffer( GLenum tgt, // BufferObject のタイプ GLuint id // glGenBuffers で作成した ID ) DESC カレントの BufferObject を選択する 新規の Buffer ならば初期化される( 空Data の Object が作成される )

    // 選択をはずすには 0 を指定する
    glBindBuffer( GL_ARRAY_BUFFER, 0 );

    // 頂点配列を格納するためのバッファを作成するには GL_ARRAY_BUFFER
    glBindBuffer( GL_ARRAY_BUFFER, id );

    // Index を格納するには GL_ELEMENT_ARRAY_BUFFER を指定する
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, id );

___

■ glBufferData

SYNTAX glBufferData( GLenum tgt, GLsizeiptr size, // バッファオブジェクト全体のサイズ const GLvoid *data, // コピー元のデータ GLenum usage ) DESC Client Memory から BufferObject へデータをコピーする。 転送先は glBindBuffer() で指定しておく データは glBufferData() をコールした時点で転送される。 Specifies the expected usage pattern of the data store. The symbolic constant must be GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, or GL_DYNAMIC_COPY. usage is a hint to the GL implementation as to how a buffer object's data store will be accessed. This enables the GL implementation to make more intelligent decisions that may significantly impact buffer object performance. It does not, however, constrain the actual usage of the data store. usage can be broken down into two parts: first, the frequency of access (modification and usage), and second, the nature of that access. The frequency of access may be one of these: STREAM The data store contents will be modified once and used at most a few times. STATIC The data store contents will be modified once and used many times. DYNAMIC The data store contents will be modified repeatedly and used many times. DRAW The data store contents are modified by the application, and used as the source for GL drawing and image specification commands. READ The data store contents are modified by reading data from the GL, and used to return that data when queried by the application. COPY The data store contents are modified by reading data from the GL, and used as the source for GL drawing and image specification commands.

    // buffer object 用の領域を確保と転送
    glBufferData( GL_ARRAY_BUFFER, 3*sizeof(float)*cnt, vtx, GL_STATIC_DRAW );



___

■ glDeleteBuffers

SYNTAX glDeleteBuffers( GLsizei n, GLuint *bufs ) DESC 指定 ID の BufferObject を解放する 不要になったら ServerMemory を解放すること
___

■ テクスチャ(Texture)


  SAMPLE
     シンプルテクスチャ 
     ドラックアンドドロップした 2冪サイズのbmp ファイルをテクスチャにする 


___

■ 処理の基本

DESC テクスチャ処理はフラグメント単位でされる。 UV値は rasterize の補間結果になる UV の値から画像のテクセル値を取得する 頂点毎の lighting 計算結果後 の fragment に適用される Fragment に適用される前は, Vertex 毎に tc を割り当てる ラスタライズ中に, 透視補正補間アルゴリズムを利用して, フラグメント毎に適用される TextureObject は高速な VideoMemory に配置される サイズはなるべく小さい方がいい
   map される texel は 左下原点( 0,0 )の直交座標系

   t
   |
   |
   |
   |-------- s

   glTexImage2D() で指定するピクセル列は以下のようになる

   (0,0) data の先頭
   (1,1) data の最後

  POINT
    Y 反転するのは
    画像 data は左上から始まるため

頂点のカラーを基本色として、テクスチャステージ0から順番に処理される。 ステージ1はステージ0と頂点カラーの混色の結果になる。 頂点カラーは glColor() またはライティングされた色で、 ラスタライズされた時点では各頂点で線形補間された色になる。 混色の方法は glTexEnv() で指定する。

    頂点カラー ---> [ ステージ0 ] ---> [ ステージ1 ] ---> ...
はみ出した部分を指定するときは, WRAP_S|T param を利用して mapping を制御する
___

■ 基本的な流れ

テクスチャオブジェクトはアプリケーションの初期化でする。

  unsigned int gId;

    void App::onInit()
    {

      // TextureObject を生成して、そのIDを取得する
      glGenTextures( 1, &gId );
      glBindTexture( GL_TEXTURE_2D, gId );     // タイプを指定してつくる( GL_TEXTURE_2D )

      typedef struct {
        unsigned char c[3];
      } col;

      col O = { 0xFF, 0x00, 0x00 };
      col I = { 0xFF, 0xFF, 0xFF };

        col img[] = {
          I, I, I, I, I, I, I, I,
          I, I, I, I, I, I, I, I,
          I, O, I, I, I, I, O, I,
          I, O, I, I, I, I, O, I,
          I, I, I, I, I, I, I, I,
          I, O, I, I, I, I, O, I,
          I, I, O, O, O, O, I, I,
          I, I, I, I, I, I, I, I,
        };

      // ピクセルデータを指定( ファイルから読んでもよい )
      glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0,
                    GL_RGB, GL_UNSIGNED_BYTE, img );


      // 貼り方の設定
      // 補間方法の設定
      glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
      glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

      // リピート設定
      glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
      glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);


      // 混ぜ方
      glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
    }

  void App::draw() {

    // 描画時に貼り付けるテクスチャを指定する    
    glBindTexture( GL_TEXTURE_2D, gId );

    // TextureMap を利用することを宣言する
    glEnable( GL_TEXTURE_2D );


    // UV座標を指定しながら、プリミティブを描画する
    float z = -1.0f, s = 200.0f;

    glBegin( GL_QUADS );
    glTexCoord2f( 0, 0 );
    glVertex3f( 0, 0, z );

    glTexCoord2f( 1, 0 );
    glVertex3f( s, 0, z );

    glTexCoord2f( 1, 1 );
    glVertex3f( s, s, z );

    glTexCoord2f( 0, 1 );
    glVertex3f( 0, s, z );
    glEnd();
  }
不要なテクスチャオブジェクトを破棄するには glDeleteTexture() を使う。
    App::onReset() {
      glDeleteTextures( 1, &id );
    }
    // 描画毎に Texture Object を指定する( 変更がないなら そのままで )
    App::update() {

      // id を指定して TextureObject を指定する.
      glBindTexture( id );

      // かく
      Draw();

    }
// 頂点毎に uv 座標を指定して GL に形状 data を送り出す( texture 領域を primitive に関連つける ) UV( 0,0 )は pixel[] の最初を指す -> BMP Format は 左下から格納されている TIP glTexImage2D() になぜ infmt, fmt の指定があるか ? infmt : 指定 data ptr を { fmt, type }のように読んでね. そしてそれを, infmt の形でもつ だから, texture から DEPTH_FORMAT がある MAX_SIZE = 2048 ( ifmt は考慮していないので注意 ) glGetIntegerv(GL_MAX_TEXTURE_UNITS, &n) // TexUnit 数取得. Format は MPEG2, AVI をはりつけることも可能. -> image がとれればよい.
___

■ glBindTexture

SYNTAX void glBindTexture( GLenum tgt, // テクスチャオブジェクトのタイプ GLuint id // バインドするテクスチャオブジェクトのID ); DESC TextureObject を選択する IDをはじめて渡す際に, TextureObject が生成される この時, TextureObject の param ( == State )は Default で初期化される ERROR GL_INVALID_OPERATION: 異なる tgt を指定して bind をする

    App::init() {
        // 初期化時にテクスチャオブジェクトを生成
        glBindTexture();
        glBindTexture( GL_TEXTURE_2D, id );
    }

    App::draw() {
        // 描画時に利用するテクスチャを指定する
        glBindTexture( GL_TEXTURE_2D, id );
    }

___

■ glDeleteTextures

SYNTAX void glDeleteTextures( GLsizei, GLint * ); DESC 指定したテクスチャオブジェクトを破棄する。
___

■ TextureCoordを指定する

SYNTAX void glTexCoord( TYPE ); DESC 各頂点がテクスチャをサンプルするテクセルの位置をきめる。 TextureCoord { 0, 0 } ならば 画像の左下の色を取得する
    // 各頂点を指定する前に、設定する。
    // glTexCoord で指定した値は glVertex で影響をうける
    // 
    glBegin( GL_TRIANGLES );

    glTexCoord2f( 0, 0 );
    glVertex3f( 1, 0, 0 );   // この頂点は UV { 0, 0 } を使う
    glTexCoord2f( 0, 0 );
    glVertex3f( 1, 0, 0 );
    glTexCoord2f( 0, 0 );
    glVertex3f( 1, 0, 0 );

    glEnd();

WARNING TextureCoord も頂点と同じく、テクセルをサンプルする前に TextureMatrix が乗算される 自動生成した場合もおなじ 利用しないならば、 TextureMatrix の使用をオフにすることで余計な変換がされることを回避できる。
    TextureCoord = M * [ TextureCoord ]

    // 頂点と同じように同次座標 であつかわれる

    // r = 0, q = 1 となる
    glTexCoord2f( 1, 1 );

    // q = 1
    glTexCoord2f( 1, 1, 1 );

    // 明示する
    glTexCoord2f( 1, 1, 0, 0 );

___

■ パラメータ設定

DESC テクスチャオブジェクトは各種パラメータをもつ テクスチャをサンプルする時はこの設定の影響をうけるため、 適切な初期設定をしておく。 サンプリング方法の指定 拡大フィルタ NEARENT : ピクセルに最も近い Texel をサンプル LINEAR : Pixel を囲む 2 * 2 Texel をサンプル 縮小フィルタ NEARENT LINEAR GL_NEAREST_MIPMAP_NEAREST : 画面上のテクスチャサイズに合うミップマップから GL_NEAREST でテクセルを決定 GL_LINEAR_MIPMAP_NEAREST : 画面上のテクスチャサイズに合うミップマップから GL_LINEAR でテクセルを決定 GL_LINEAR_MIPMAP_LINEAR : 画面上のテクスチャサイズに合う2つミップマップから GL_LINEAR でテクセルを決定 トリリニアサンプリング GL_NEAREST_MIPMAP_LINEAR : 2つのミップマップから取得した値の加重平均とをる。 範囲外を指定したときの設定 GL_REPEAT : 繰り返す GL_CLAMP : 0:1 の範囲に収める Texel の真ん中をサンプルすると, Texel の色そのものになる TIP Texel 格子上の点で Sample すれば均等に 4Texel の平均がとれる ぼかし効果をつくるなら [ Texel 幅の整数倍の場所をサンプルすること ] wrap parameter
    App::init() {

      // mipmap, 拡縮に対する, parameter
      // depth map parameter

      // ON
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  WARNING 
    GL_TEXTURE_MIN_FILTER は default で GL_NEAREST_MIPMAP_LINEAR
    ( mipmap を利用しない texture では正しく描画されない )
    GL_REPEAT は shadow map には不向き

      // OFF
      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    }

___

■ glTexPrameter

SYNTAX void glTexPrameter( GLenum tgt, GLenum name, // 設定するパラメータ名 TYPE prm // 設定する値 ) DESC TextureObject の 各種パラメータを設定する
    // 範囲外のリピート方法を指定する
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // 補間方法を指定する

// テクスチャの自動生成にも利用できる


3 種類のカテゴリ. 1. Rasterize 時の Fragment と Texel の対応関係の指定. Fragment が Texel より小さい場合: GL_TEXTURE_MAG_FILTER Fragment が Texel を覆う場合: GL_TEXTURE_MIN_FILTER WARNING: Default が Mipmap を利用する GL に自動生成させる( 画像を指定する前に ) VER:1.4 { glTexPrameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); glTexImage2D(); } tc の wrapping Param : はみだしたときどうするか ? texture image を指定する際は mipmap をすべて指定する必要あり glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); で自動生成 && 自動再生成 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); において, Default が MipMap のため, 必ず変更すること.
___

■ 画像を割り当てる

___

■ glTexImage2D

SYNTAX void glTexImage2D( GLenum tgt, // Texture Object の TYPE ( GL_TEXTURE_2D | CUBE_X ) GLint level, // ミップマップのレベル ( 利用しないならば 0 ) GLint internalFormat, // OpenGL 内部でどの成分(種類)にデータをもつか( RGBA, Depth, Luminance, Intensity ) GLsizei w, h, // 画像サイズ GLint border, GLenum format, // 設定する画像データのフォーマット GLenum type, // 各色要素のデータ型 void *texel // 画像データへのポインタ ) DESC バインドした TextureObject に画像データを設定する。 画像データは OpenGL に転送されるので アプリケーション側はメモリを保持しなくてもよい。 設定する画像データは, テクスチャの左下から右上に向かって割り当てられる。
    -----------------End
      
    
    Start-------------
format, type, のパラメータで, アプリケーションから転送する画像データの構成を OpenGL に知らせて internalFormat に従って OpenGL 内でもつ画像データ構造を決める。
    // GL_RGB を internalFormat で指定すると, alpha 成分は 1 として扱われる
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, data );

    // GL_RGBA を internalFormat で指定すると, alpha 成分は画像データの alpha が利用される。
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
GL_RGBA は 各要素を 32 bit でもつ. 説明としては, どの成分( 明るさ, Depth, RGBA )が Texel として利用するかを決める. TIP GL_RGBA : 4個の要素をもち、カラー画像として使われる。 GL_LUMINANCE : 1個の要素をもち、グレースケールとして使われる。 GL_LUMINANCE_ALPHA : 2個の要素をもち、グレースケールとして使われる。 GL_DEPTH_COMPONENT : 1 成分 -> ( shadow map はこれ )
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
          GL_RGB, GL_UNSIGNED_BYTE, image );

    // GL_DEPTH_COMPONENT は特定の解像度を要求しない
    //    要求に対して近い Format が選択される
    glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, w, h, 0,
          GL_RGB, GL_UNSIGNED_BYTE, image );
ミップマップ( あらかじめ縮小した画像のこと )の指定をする場合は、 レベルを変更しながらサイズが半分にした画像データを指定する。
    
    for( i=0; i< 3; i++ ){
      glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, w, h, i,
              GL_RGBA, GL_UNSIGNED_BYTE, image[i] );
    }
WARNING 各列は default で 4byte アラインメントになっている必要がある。 ( GL がそう解釈するから )
___

■ glTexImage3D

SYNTAX void glTexImage3D(); NOTE 3D Texture は Tool では作成できない そのため Program で動的に作成する POINT DirectX の場合 [0:1] で決めるが GL は [0:255] で決める 3 次元 texture は短い video clip が可能

      unsigned int i, j, k;

      for( i=0; i< 32; i++ ){
        for( j=0; j< 32; j++ ){
          for( k=0; k< 32; k++ ){
            texvol[i][j][k][0] = (unsigned char)( 255 * myRand() );
            texvol[i][j][k][1] = (unsigned char)( 255 * myRand() );
            texvol[i][j][k][2] = (unsigned char)( 255 * myRand() );
            texvol[i][j][k][3] = 255;
          }
        }
      }

      glGenTextures( 1, &idVol );

      glBindTexture( GL_TEXTURE_3D, idVol );
      glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP  );
      glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP  );
      glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP  );

      glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST  );
      glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST  );

      MyTex->load3dData( "noise3d.bmp", 32, 32, 32, texvol );
      glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );

___

■ glTexSubImage2D

SYNTAX void glTexSubImage2D( GLenum tgt, // Texture Object の TYPE ( GL_TEXTURE_2D | CUBE_X ) GLint level, // ミップマップレベル ( 利用しないならば 0 ) GLint x, y, // オフセット GLsizei w, h, GLint border, GLenum format, // 設定する画像のフォーマット GLenum type, // 各要素 の Data 型 // ( GL_BYTE | GL_UNSIGNED_BYTE | GL_SHORT | GL_UNSIGNED_SHORT ) // ( GL_INT | GL_FLOAT | GL_UNSIGNED_INT ) // ( GL_BITMAP ) void *texel ) DESC バインドした既存のテクスチャの一部( SubSet )を 別の画像で置き換える。 glTexImage2D の 部分集合版なので、パラメータもほぼ同じ。 ERROR GL_INVALID_ENUM target が GL_TEXTURE_2D でない場合 format が容認された定数でない type が型定数でない場合 GL_INVALID_VALUE width < 0 | height < 0 GL_INVALID_OPERATION type がGL_UNSIGNED_SHORT_5_6_5 で、format が GL_RGB でない場合
___

■ glTexSubImage1D

SYNTAX void glTexImage2D( GLenum tgt, // Texture Object の TYPE ( GL_TEXTURE_2D | CUBE_X ) GLint level, // Image の MipMap Level ( 利用しないならば 0 ) GLint x, y, // Offset GLsizei w, h, GLint border, GLenum format, // 設定元 Image の Format GLenum type, // 各要素 の Data 型 // ( GL_BYTE | GL_UNSIGNED_BYTE | GL_SHORT | GL_UNSIGNED_SHORT ) // ( GL_INT | GL_FLOAT | GL_UNSIGNED_INT ) // ( GL_BITMAP ) void *texel ) DESC 現在の Texture の一部を 別の Texel でおきかえる


    float texel[128];

    glTexImage1D( GL_TEXTURE_2D, 0, texel );

___

■ テクスチャのブレンド方法を指定する

SYNTAX void glTexEnv(if)( GLenum tgt, GLenum namePrm, TYPE prm ) DESC テクセルの色をフラグメントの色とのブレンド方法を指定する。 この設定は テクスチャユニットごとに設定される。 加算処理とかできる ライティングした色と乗算する。(デフォルト)
    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

    // 線形補間するには GL_COMBINE


    // tex0 * ( 1 - a )  +  tex1 * a
    //
    glActiveTexture( GL_TEXTURE0 );
    glActiveTexture( GL_TEXTURE1 );

    glTexEnvi( GL_TEXTURE_ENV_MODE, GL_COMBINE );
    glTexEnvi( GL_TEXTURE_ENV_MODE, GL_COMBINE );


GL_BLEND を指定したときは画像のアルファ値は使われないで かわりに画像の RGB 値が 別に設定した色と下地の色との混合比に使われる この色は glTexEnvf() の pname に GL_TEXTURE_ENV_COLOR を指定する この出力画像では テクスチャの暗い部分に下地の色(color: 赤)が現れ 明るい部分に別に定義した色 (blend: 緑) になる --- Rv, Gv, Bv, Av → テクスチャ環境関数の結果 Rt, Gt, Bt, At → テクスチャ色 Rf, Gf, Bf, Af → フラグメント色 Rc, Gc, Bc, Ac → テクスチャ環境色 (GL_TEXTURE_ENV_COLORを参照) --------------------------- // Multi Texture なら一番↓ ( TEXTURE0 ) から順に評価 [ ] < --- Texture [ ] < --- Texture [ ] < --- Texture [ ] < --- Fragment // 計算をするときは 次の 2 つが対象になる [ ] < ---- 新しく貼ろうとしている Texture ( 基本形式 はこの Texture が対象 ) [ ] < ---- 既に計算すみの Fragment 計算方法は 貼る対象の Texture の 内部フォーマットによって決まる Format は複数あるが 6 つの基本形式に分類される そして計算時は RGBA 形式に変換されて扱われる
    GL_ALPHA     0, 0, 0, A
    GL_LUMINANCE 0, 0, 0, 1
    GL_RGB       R, G, B, 1
    GL_RGBA      R, G, B, A
GL_RBGA : 基本 Texture 形式
___

■ GL_MODULATE

各成分をかける( Alpha も乗算される )。 ライティング結果と乗算される デフォルトの設定。
    out = src * texcol;

    Rv = Rf * Rt
    Gv = Gf * Gt
    Bv = Bf * Bt
    Av = Af * At
___

■ GL_DECAL

ステッカーを貼った効果を出す時に使う。 テクスチャのアルファ成分でマスクをする。 透明にしたい場所のアルファ値を 0 にしておく。 0ならば src の色となる。
    out = texcol * texcol.a  + ( 1 - texcol.a ) * src

    Rv = Rf * (1-At) + Rt * At
    Gv = Gf * (1-At) + Gt * At
    Bv = Bf * (1-At) + Bt * At
    Av = Af
___

■ GL_REPLACE

テクスチャの色で置き換える。 WARNING 利用すると, ライティング結果も無効になる。
    out = texcol;

    Rv = Rt
    Gv = Gt
    Bv = Bt
    Av = At
___

■ GL_ADD

    out = src + texcol
___

■ GL_COMBINE

演算子なども指定して細かく混色の方法を指定する。 次のような計算式を指定する。
    out = arg0  演算子  arg1
次の要素を指定する。
    // 算術演算子を指定する。
    

    // 1番目の引数を指定する。

    // 2番目の引数を指定する。

GL_RGB TIP 高速化のためには, Texture の内部 Format のサイズを小さくする 32bit -> 16bit におとす これをするには _EXT とつく 拡張フォーマットを使う // この式の [ 意.味 ] がわからん Rv = Rf * (1-Rt) + Rc * Rt Av = Af * At
___

■ 画像ファイルから読み込む


  SAMPLE
     png ファイルを読み込んでテクスチャにする 

  REFERENCE  ファイルダイアログ
  REFERENCE  nmake

___

■ raw

.raw 形式のファイルを読む raw 形式とはヘッダ情報がないデータだけのファイル
    void *readRawTexture( const char *path, int w, int h, int nrElement )
    {
      FILE *fp = fopen( path, "rb" );

      // 画像サイズ
      int sz = w * h * nrElement;

      // バッファ確保
      char *buf = new char [sz];

      // ヘッダ(余計な情報)がないため fread() のみで読める
      fread( buf, sz, 1, fp );

      fclose( fp );
      return buf;
    }

___

■ ppm

raw 形式と同様に ppm というシンプルなフォーマットも利用できる。 フォーマットは以下のとおり
    ファイル形式識別記号
    横ピクセル数   縦ピクセル数
    最大輝度
    画像データ(RGB順,左から右,上から下へ走査した順
POINT ヘッダ部分の改行コードは \n である必要がある。 そのため、必ずバイナリモードでオープンすること。
    P6
    1024 1024
    255
    ..........
ppm 形式として 24bit RGB で保存する。 保存した画像は gimp などで開くことができる。
    FILE *fp = fopen( "test.ppm", "wb" );

    int w = 256, h = 256;
    int nrElement = 3;

    // 画像サイズ
    int sz = w * h * nrElement;
    
    // ヘッダ
    fprintf( fp, "P6\n%d %d\n255\n", w, h );

    // バッファ確保
    char *buf = new char [sz];
  
    // 画像データ
    memset( buf, 0, sz );
    fwrite( buf, sz, 1, fp );

    fclose( fp );
___

■ bmp

ウィンドウズの標準画像フォーマットなので、ペイントでもつくれる。 フォーマットは先頭にヘッダがあり、その後にピクセルデータ列がある。
    -------------------
    ヘッダ
    INFOヘッダ
    -------------------
    ピクセルデータ
    -------------------
ピクセルデータ列は 青、緑, 赤 の順番。 左下から右上の順番にピクセルデータが格納されている。 ( ファイルの末尾は右上のピクセルデータ ) バイナリのテキストエディタで開くとわかる。 OpenGL のテクスチャの順番と同じため、 glTexImage2D() にそのまま渡すことができる。 WARNING png などは順番が異なるため 上下反転などの処理が必要になる。
    [B][G][R][B][G][R] ...


    --------------> エンド
    |                   |
    |                   |
    |                   |
    |                   |
    |                   |
    |                   |
    スタート ----------->
アルファがある時( 32bit )は BGRA の順番になる。
    [B][G][R][A][B][G][R][A] ...
WARNING 横のバイト数は 4バイトアラインメントされている必要がある。 4 で割り切れない時は, padding を考慮して読み書きする必要がある。 次の場合は 4 の倍数になるので padding は考えなくてもいい。
      横のサイズが 4 の倍数 ( 100 pixel とか )
      ピクセルあたりのサイズが 4byte( 32bit )
___

■ png

画像サイズを小さくしたい場合は png 形式を使う。 可逆圧縮なので、画像も劣化しない。 次の順番で画素データがつまっている。 先頭が左上で 最後が右下
    -------------------
    START --------->
                 /
                /
               /
              /
             /
            /
         ---------> END
    -------------------
ライブラリ libpng と zlib に依存するためネットから取得する。
    wget http://jaist.dl.sourceforge.net/project/libpng/libpng15/1.5.10/lpng1510.zip
    wget http://jaist.dl.sourceforge.net/project/libpng/zlib/1.2.7/zlib127.zip
解凍する。
    unzip lpng1510.zip
    unzip zlib127.zip
ビルドする時の makefile の記述にあわせてディレクトリ名を変更する。
    mv lpng1510      png
    mv zlib-1.2.7    zlib
たとえば次のディレクトリの状態になる
    d:/png
          /scripts
    d:/zlib
          /win32
VisualStudio 2008 のコマンドプロンプトを起動して namke を使ってビルドすれば完了。
    cd zlib
    nmake -f win32/Makefile.msc

    cd png
    nmake -f scripts/makefile.vcwin32
とりえあえず RGB 8bit を読む簡単なサンプル
   #include "png/png.h" 
   #include "zlib/zlib.h" 
   #include "zlib/zconf.h" 

   #pragma comment(lib,"png/libpng.lib")
   #pragma comment(lib,"zlib/zlib.lib")


    // PNG構造体の取得
    png_structp pPtr = NULL;
    pPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);

    // PNG情報構造体の取得
    png_infop info_ptr = NULL;
    info_ptr = png_create_info_struct(pPtr);

    png_bytep pData = 0;         //PNGからピクセルデータを受け取るバッファ
    png_bytepp row_pointers = 0;      //PNGから受け取った画像行の先頭ポインタ


    // fread を利用したデフォルトの読み方にまかせる。
    png_init_io( pPtr, fp );


    // 情報ヘッダの読み込み
    png_read_info( pPtr, info_ptr );

    png_uint_32 W, H;          // 横, 縦ピクセル数
    int bit_depth;              //ビット深度
    int color_type;             //PNG画像の形式
    png_get_IHDR(pPtr,info_ptr,&W,&H,&bit_depth,&color_type,NULL,NULL,NULL);


    //すべての設定を登録
    png_read_update_info( pPtr, info_ptr );

    //イメージを格納するメモリーを割り当てる為の情報を取得
    png_size_t rowbytes = png_get_rowbytes(pPtr,info_ptr);//行データのバイト数
    int channels = (int)png_get_channels(pPtr, info_ptr); //チャンネル数


    // 画像データをうけとるバッファ
    pData = new BYTE[ rowbytes * H ];
    row_pointers = new png_bytep[H];

    // 行配列にフラット領域のそれぞれの位置を設定します
    for (UINT i=0;i< H;i++) {
        row_pointers[i] = pData + i*rowbytes;
    }

    // イメージを読む
    png_read_image( pPtr, row_pointers );

    // 後始末
    delete[]row_pointers;
    png_read_end(pPtr,NULL);


    printf( "img W %d H %d  channels %d  rowbytes %d\n", W, H, channels, rowbytes );
    
    // raw データとして出力して確認
    {
      FILE *fp = fopen( "d:/test_png_out.raw", "wb" );
      fwrite( pData, H*rowbytes, 1, fp );
      fclose(fp);
    }
読み込み方法をカスタマイズするには png_set_read_fn() にコールバックとして渡す。 例えば、アーカイブ, リソースなどのメモリ上に読み込み済みの png ファイルから png イメージを取得するには次のようにする。
    struct ReadContext
    {
      // 読み込み元のデータの場所
      const char *ptr;

      // 現在の位置
      int i;

      ReadContext( const char *p, int _i)
        : ptr((char *)p), i(_i)
      {}
    };


png_init_io() の代わりにコールバックを指定する。
    void readPng( char *pSrc ) {
  #if 0
      png_init_io( pPtr, fp );
  #else
      ReadContext  ctx( pSrc, 0 );
      png_set_read_fn( pPtr, &ctx, pngReadProc );
  #endif
    }
コールバックされるので好きなように実装する。 ライブラリが指定する data という場所に length byte を読み込んであげる。
    void pngReadProc( png_structp png, png_bytep data, png_size_t length )
    {
        // png 構造体から png_set_read_fn() で渡したポインタを取得する。
        ReadContext *p = (ReadContext *)png_get_io_ptr(png);

        // png file を読みこみ済みなので memcpy をする。
        memcpy 
             // 書き込み先はシステムからもらう
             data, 

             // 読み込み元はこちらの指定
             p->ptr + p->i,
             length
             );

        p->i += length;
    }
先にpngファイルを読んでから、読み込み処理をする。
    FILE *fp = fopen("d:/test.png","rb");
    char *pSrc = new char[ filesz ];
    fread( pSrc, filesz, 1, fp );
    fclose( fp );

    readPng( pSrc );
___

■ nconvert

nconvert を利用すると、任意の形式に変換できる。
    nconvert -out bmp  test.ppm
    nconvert -out png  test.ppm
    nconvert -out jpg  test.ppm
    nconvert -out tga  test.jpg
raw 形式には変換できないらしい。
    nconvert -out raw  test.ppm
一覧をみるには help をつかう。
    nconvert  -help
windows icon も変換できる。 REFERENCE リソーススクリプトのかきかた
    nconvert -out ico  test.ico
上書きをする
    nconvert -overwrite -out ico  test.ico
出力ファイル名を指定する
    nconvert -out png -o d:/out.bmp  d:/src.cmp
サイズを変更する
    nconvert -out bmp  -resize 64px 64px  d:/src.bmp
比率を保持する
    nconvert -out png  -ratio -resize 1000px 0px  d:/test.bmp
ログをOFFにする
    nconvert -quiet -out png  d:/src.bmp
___

■ キューブマップ(CubeMap)


  SAMPLE
     キューブマップを利用した環境マップ 


  DESC
    キューブマップとはキューブ(箱)の各6面に2Dテクスチャを割り当て、3つの UV値でテクセルをサンプルする。
    UV値を反射ベクトルとみなして、環境マップになどとして利用できる。

  VER 1.3
    version 1.1 の header にはないため glext.h を利用する





  GL_REFLECTION_MAP
    視点と法線ベクトルから反射ベクトルを計算し
    その値でキューブマップテクスチャを参照する

  GL_NORMAL_MAP
    法線ベクトルからテクスチャを参照

    キューブマップ用のテクスチャは次の条件を満たすこと。
     w, h > 0
     6面がすべて同一サイズ && 正方形
     同一ボーダ幅

void App::init()
{

  // 作成するテクスチャオブジェクトはキューブマップ用を指定
  glGenTextures( 1, &id );
  glBindTexture( GL_TEXTURE_CUBE_MAP, id );


  // UVの自動生成方式は ReflectionMap 形式にする
  glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP );
  glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP );
  glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP );

  // Q の成分は計算する必要はない。

  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );

  // UV自動生成を有効にする
  glEnable( GL_TEXTURE_GEN_S );
  glEnable( GL_TEXTURE_GEN_T );
  glEnable( GL_TEXTURE_GEN_R );

  // CubeMap 画像
  glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );


  // 各6面にテクスチャを割り当てる
  // CubeMap 用の Texture は 縦横サイズが同じでないとだめ
  int sz = 64*2;
  void *img = readRawTexture( PATH_TEX"cube.raw", sz, sz*6 );
  for( int i=0; i< 6; i++ ){
    char *p = (char *)img;
    glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, sz, sz, 0,
                  GL_RGB, GL_UNSIGNED_BYTE, p + (sz*sz*3*i) );
  }

  // WARNING
  //    CubeMap も 2D と同じく補間方法を指定する
  glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR );


  // ここは CLAMP にしてもかわらない
  glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_REPEAT );
  glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_REPEAT );
  glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_REPEAT );


  // POINT
  //  OpenGL に テクスチャのサンプリング方法に CUBE_MAP を使うように指定する
  //  Shader なら 自分で tex2D() などの命令を明示するため不要
  //
  glEnable( GL_TEXTURE_CUBE_MAP );
}
WARNING テクスチャ座標の計算に法線と視線ベクトルの使うため、 法線を定義する。
    // 法線を定義して球を描画する。
    void drawSphere()
    {
      int n = 8*2;
      int s = 8*2;
      float r = 25;

      float dn = 360.0f / n; // 軽度
      float ds = 180.0f / s; // 緯度

      int i, j;

      glBegin( GL_QUADS );

      for( i=0; i< n; i++ ){ // 横
        for( j=0; j< s; j++ ){ // 縦 [ 0 - 180 度まで 
          float x0 = cosf( D2R( i*dn ) );
          float z0 = sinf( D2R( i*dn ) );
          float x1 = cosf( D2R( (i+1)*dn ) );
          float z1 = sinf( D2R( (i+1)*dn ) );

          float rs = r*sinf( D2R( j*ds ) );
          float y  = r*cosf( D2R( j*ds ) );  // Y 軸とのなす角

          float ss = sinf( D2R( j*ds ) );
          float yy = cosf( D2R( j*ds ) ); 

          glNormal3f( ss*x0, yy, ss*z0 );
          glVertex3f( rs*x0, y, rs*z0 );
          glNormal3f( ss*x1, yy, ss*z1 );
          glVertex3f( rs*x1, y, rs*z1 );


          // ひとつ下がる
          y = r*cosf( D2R( (j+1)*ds ) );
          rs = r*sinf( D2R( (j+1)*ds ) );
          ss = sinf( D2R( (j+1)*ds ) );
          yy = cosf( D2R( (j+1)*ds ) );

          glNormal3f( ss*x1, yy, ss*z1 );
          glVertex3f( rs*x1, y, rs*z1 );
          glNormal3f( ss*x0, yy, ss*z0 );
          glVertex3f( rs*x0, y, rs*z0 );
        } 
      } 
      glEnd();
    }
POINT GL_REFLECTION_MAP の結果が視点座標系と思うので カメラ自体を回す場合は、カメラのワールド行列をかけて反射ベクトルをワールド座標系に戻す。

    App::onDraw() {

      // オブジェクトをカメラから見た位置に置く。
      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();
      convertCameraSpace( 0, 0, 500 - czoom, cy, cx );


      // テクスチャマトリックスを使って、反射ベクトルをワールド座標系に戻す。
      glMatrixMode( GL_TEXTURE );
      glLoadIdentity();

      glRotatef( cx, 0, 1, 0 );
      glRotatef( cy, 1, 0, 0 );

      // 球を描画する。
      drawSphere();

      // 元に戻す。
      glMatrixMode( GL_TEXTURE );
      glLoadIdentity();
    }

___

■ Texcoordの自動生成

SAMPLE ワールド座標をテクスチャ座標にする テクスチャ座標は明示的に指定する以外に、オブジェクトの座標などから 動的に計算した結果を使うことができる。 環境マップ、投影マップといった動的な処理で使う。 このような場合は glTexcoord() ではなく glTexGen() で自動計算させる。 計算式は次のような 1次結合式をつかうため、計算の元となる x, y, z, w の値とその係数をそれぞれ指定する。
    s = a*x  + b*y  + c*z  + d*w
    u = a*x  + b*y  + c*z  + d*w
    r = a*x  + b*y  + c*z  + d*w
    t = a*x  + b*y  + c*z  + d*w
( s, t, r, q ) 毎に tc の自動生成を指定する. POINT 指定するパラメータは2つ 計算式と各係数 GL_EYE_LINEAR GL_OBJECT_LINEAR
    // 自動計算で求める Texcoord の成分{ s, t, r, q }を指定する。
    glEnable( GL_TEXTURE_GEN_S );
    glEnable( GL_TEXTURE_GEN_T );
    glEnable( GL_TEXTURE_GEN_R );


    線形結合での各 x, y, z, w の値で利用する座標系を指定する。
    // オブジェクト座標系で計算式を利用するには OBJECT


    // 視線座標系の値を計算式に利用するには  EYE_LINEAR
    //
    POINT
      ModelView 変換後の座標を使う
      空間全体で TexCoord が共有されるので 投影マッピングなどはこれを利用する


    // 各係数を指定する

    // その線形結合の結果が UV 値の値になる
    // a*x + b*y + c*z + d = S となる
オブジェクトのワールド座標をテクスチャ座標として使うには オブジェクトのワールド座標を計算式を再現すればいいだけ。 オブジェクト座標を使う場合は、 GL_OBJECT_LINEAR を使う。 下の式でいうと x, y, z, w がオブジェクト座標として使われる。 これをワールド座標に変換する行列をかけるだけ。
    u = X = ( m00  m01  m02 m03 ) x
    v = Y = ( m10  m11  m12 m13 ) y
        Z = ( m20  m21  m22 m23 ) z
        W = ( m30  m31  m32 m33 ) w


    u = X =  m00*x  + m01*y +  m02*z +  m03*w
    v = Y =  m10*x  + m11*y +  m12*z +  m13*w

    void App::onDraw() {

      // 自動生成を有効化する
      glEnable( GL_TEXTURE_GEN_S );
      glEnable( GL_TEXTURE_GEN_T );


      // 計算式の右辺の x,y,z,w をオブジェクト座標に指定する
      glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
      glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );  


      // オブジェクトのワールドの位置
      float x = 100;
      float z = 100;

      float m[16];
      {
        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();
        // uv を 1 の範囲におさめるために適当にスケールをかける
        glScalef( 1.0/1000, 1.0f/1000, 1.0f );
        // ワールドの位置に移動した後に
        glTranslatef( x, z, 0 );
        glGetFloatv(GL_MODELVIEW_MATRIX, m);
      }

      // テクスチャ座標をワールドに変換する行列の係数をセットする
      float vs[] = { m[0], m[4], m[8],  m[12] };
      float vt[] = { m[1], m[5], m[9],  m[13] };
      glTexGenfv( GL_S, GL_OBJECT_PLANE, vs ); 
      glTexGenfv( GL_T, GL_OBJECT_PLANE, vt ); 


      // 後は通常のオブジェクトを描画する。
      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();
      convertCameraSpace( 0, 0, 2000 - czoom, cy, cx );
      glTranslatef(  x, 0, z );


      // ハコを描画( UV は明示する必要はない )
      drawCube();
    }
  




___

■ テクスチャ行列

DESC UV値は利用される前にテクスチャ行列が積算される。 自動生成. 明示的な指定に関係なく適用される。 Default 単位行列 TIP Unit ごとにもつ. 利用しない場合は処理がスキップされる POINT uv animation とかに使用する
    // 利用しない場合は以下をコールしておくと安全
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
___

■ マルチテクスチャ(MultiTexture)


  SAMPLE
     マルチテクスチャ     

___

■ 全体の流れ

DEP glext.h VER 1.3 DESC ひとつの物( Primitive )に絵( Texture )をたくさん貼り付ける [0][1][2][3][4][5][6][7] テクスチャユニット( サンプラー )は8つあり、テクスチャオブジェクトを設定することで 一度の描画で複数のテクスチャを参照できる。 ペイントソフトのレイヤーと同じ概念。 POINT TextureObject を 各 Unit に bind する OpenGL は GL_TEXTURE0 から順にフラグメントに適用する テクスチャマトリックスは ユニットごとに持つ POINT テクスチャユニットの設定に関連したAPIは以下のもの。 現在のユニットの影響を受けるため、把握しておくこと。 ユニットをサンプラーとして考えると必要な設定が理解しやすい。
     glTexGen();                     // tc 自動生成 Param
     glEnable( GEN_S );              // UV 自動生成の各成分ごとの ON/OFF
     glEnable( GL_TEXTURE_2D );      // サンプリング処理の ON/OFF
     Texture Enviroment ( glTexEnv )
     TextureMatrix
     バインドするテクスチャオブジェクトの指定
DEFAULT GL_TEXTURE0
    #include < GL/glext.h> 

    void App::init() {

      PFNGLACTIVETEXTUREPROC glActiveTexture =
        (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");

      // 操作するテクスチャユニットを指定する      
      //    一枚のみを利用しているときはこれが暗黙の指定になっている。
      glActiveTexture( GL_TEXTURE0 );

      // UNIT0 にテクスチャオブジェクトをセットする
      glBindTexture( GL_TEXTURE_2D, id );

      // ブレンド方法の指定
      // 次の設定が最も simple blend 方法 ( 各 unit にすること )
      glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

      // 2D Texure をサンプリング処理を有効化する。
      glEnable( GL_TEXTURE_2D );


      // 2 番目のユニットを指定
      glActiveTexture( GL_TEXTURE1 );

      //  上と同じように設定するだけ
      glBindTexture( GL_TEXTURE_2D, id2 );
      glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    }
    

    // 描画時は各UNITごとに Texture座標を指定する

    App::draw() {


    }


glClientActiveTexture(); で texture 座標を割り当てる texture unit を選択 glTexCoordPointer(); で texture 座標配列を ( 明示的 | buffer object ) から指定 glEnableClientState( GL_TEXTURE_COORD_ARRAY ); WARNING 描画毎に Unit は使い回すので state の管理は必要 glTexEnv(); の計算は texture object の intenral format にも依存 && alpha 成分も計算の対象 ( glTexImage(), TexParamter(), TexEnv(), BindTexture() ) はカレントに対して有効

    // 単一の tex unit に戻す
    glActiveTexture( GL_TEXTURE1 );
    glDisable( GL_TEXTURE_2D );
    glActiveTexture( GL_TEXTURE0 );

MultiTexture 用に複数の TextureCoord を指定する方法は3つある。

     glMultiTexCoord();
     glTexCoordPointer();    // 頂点配列を指定する
     glTexGen();

次のように使い分ける. MultiTex && VertexArray -> glTexCoordPointer(); MultiTex && Scratch -> glMultiTexCoord(); MultiTex && 自動生成. -> glTexGen(); // ( Shader 利用するなら不要 )
    / / Multi tc の指定方法.
    // Server 側の Unit ( State ) を選択する

    glActiveTexture();


    // 複数の tc を VertexArray に指定する.

    // VertexArray の tc を割り当てる [ U.n.i.t ] を指定する.
    glClientActiveTexture();

    // Client 側の UnitTex を指定する.
    glEnableClientState( );

    // TexCoord を指定
    glTexCoordPointer( 2, GL_FLOAT, 0, buf );


    複数の TexCoord を指定する
    glClientActiveTexture( GL_TEXTUREn );
    glTexCoordPointer():
    glClientActiveTexture() が指す TexUnit に TexCoord を割り当てる.

   glEnableClientState( GL_TEXTURE_COORD_ARRAY );
   も指定している, TexUnit が利用される.

WARNING glBegin() - glEnd() では指定できない POINT Texcoord.w の成分により w 除算される glTexCoord2f( 1, 0 ); == glTexCoord4f( 1, 0, 0, 1 ); glTexGen をした時も, Texture Matrix の影響をうける WARNING 部分的に glTexGen はできない ? GL_TEXTURE_2D && glTexGen は併用できない ? -> それはないはず

void drawCube()
{
  float s = 30;

  // 8 頂点
  static float v[] = {
    -s, -s, s,    s, -s, s,    s, s, s,    -s, s, s,
    -s, -s, -s,    s, -s, -s,    s, s, -s,    -s, s, -s,
  };


  // 6 QUADS の index
  static unsigned short idx[] = {
    0, 1, 2, 3,    4, 5, 6, 7,
    1, 5, 6, 2,    4, 0, 3, 7,
    4, 5, 1, 0,    3, 2, 6, 7,
  };

  // 各面の Normal
  static float n[] = {
    0, 0, 1,    0, 0, -1,
    1, 0, 0,    -1, 0, 0,
    0, -1, 0,    0, 1, 0,
  };

  // 各面の Texcoord
  static float t[] = {
    0, 0,    1, 0,    1, 1,    0, 1,
  };


  glBegin( GL_QUADS );
  for( int i=0; i< 6; i++ ){
    // 法線を設定

    // ここの影響をうける
    glNormal3fv( n + (3*i) );

    //    world となるように normal を指定する ?
    //    先ほどの見え方から推測すると,
    //    ここで指定した normal が , 視線空間上で mapping される
    //glNormal3fv( n );



    for( int j=0; j< 4; j++ ){
      // 現在の idx
      int p = idx[ 4*i + j ];
      glMultiTexCoord2f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1] );

      // z も指定してみる
      //glMultiTexCoord3f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], t[2*j + 1] );
      // w も指定してみる
      //glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], t[2*j + 1], 1 );


      // 前言撤回 -> ここも影響をうける
      glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, -1 );
      glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, -100 );

      // w 除算される -> 頂点処理 と同じ流れ
      //glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, 0.5f );
      glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, 2 );
      //glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, 1 );

      // Z 値はなんでもいい
      glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], 10000, 1 );
      glVertex3fv( v + 3*p );

    }

  }
  glEnd();
}
___

■ glMultiTexCoord

SYNTAX void glMultiTexCoord( GLenum unitTex, TYPE tc ); DESC 指定したテクスチャユニットに Texcoord をセットする POINT glTexCoord(); は実は. glMultiTexCoord( GL_TEXTURE0, ); と同じ.


  // ユニット1 に UV を指定する
  float t = { 0, 0, 1 };
  glMultiTexCoord3fv( GL_TEXTURE0, t );

  float t = { 0, 0, 1 };
  glMultiTexCoord3fv( GL_TEXTURE1, t );

  glBegin( GL_QUADS );
  for( int i=0; i< 4; i++ ){
    glVertex3fv( vtx );
  }
  glEnd();


拡張機能のため 関数ポインタを取得しておく

  PFNGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv;
  PFNGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv;

  glMultiTexCoord2dv =
    (PFNGLMULTITEXCOORD2DVPROC)wglGetProcAddress("glMultiTexCoord2dv");

  glMultiTexCoord3fv =
    (PFNGLMULTITEXCOORD3FVPROC)wglGetProcAddress("glMultiTexCoord3fv");

より複雑に指定するには GL_COMBINE mode を使う ( Shader を使った方が簡単だけど )
        {
          // Preset の補間( GL_ADD, GL_MODULATE )ではなく, CUSTOM の補間を使う
          glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );

          // 線形補間 を指定
          //    ここも複数指定できる
          //    { GL_COMBINE_RGB }
          //    { GL_COMBINE_A }
          //
          //    GL_REPLACE     a0
          //    GL_MODULATE    a0a1
          //    GL_ADD        a0 + a1
          //    GL_ADD_SIGNED  a0 + a1 - 0.5f
          //    GL_SUBSTRACT   a0 - a1
          //    GL_INTERPOLATE a1 * ( 1 - a2 ) + a0 * a2;
          //
          glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
          ///glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE );
          glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD_SIGNED );

          // 補間する 係数 を指定する ( Alpha 成分のみが使われる )
          static const float c[] = { 1, 1, 1, 0.5f };
          //glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, c );

          // 次のような計算をすることになる

          // GL_INTERPOLATE
          //  V1 * ( 1 - V2 ) + V0 * V2;

          // POINT
          //  V2 も Vector 扱い
          //  rgb, a を別途指定できる

          // f.r = ( 1 - a2.r ) + a0.r * a2.r;
          // f.g = ( 1 - a2.g ) + a0.g * a2.g;
          // f.b = ( 1 - a2.b ) + a0.b * a2.b;
          // f.a = ( 1 - a2.a ) + a0.a * a2.a;


          // Document からの仮定( この順番 )
          //
          //   a0 : 今 処理中の UNIT がサンプルする Texture 色
          //   a1 : 前の Texture UNIT の結果
          //

          // 今 Alpha にしているのは UNIT1 の結果の RGB の値
          // CubeMap が明るい -> a0 が優先

          // 変数 a2 に何を使うか 決める
          // GL_PREVIOUS == 前の UNIT の結果
          glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS );
          //glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE );
          //glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA );


          // a2.rgb にどの値を使うか決める
          //
          // a2.r = TexUnit1.r
          // a2.g = TexUnit1.g
          // a2.b = TexUnit1.b
          //

          // WARNING
          //    GL_SRC_RGB という 定数 はなし

          // a2.rgb に 前の Unit の結果のどの成分を使うか ?
          //  GL_SRC_COLOR なので
          //    a2.rgb = UnitPrev.rgb
          //
          glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR );
          //glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_RGB );
          //glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_ONE_MINUS_SRC_ALPHA );

          //glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT );

          // Primary Color( 頂点色 )を指定すれば Texture の色は無視される
          //
          glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR );
          glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR );

          glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
          glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );

        }
___

■ glActiveTexture

SYNTAX PFNGLACTIVETEXTUREPROC glActiveTexture;
#if defined(WIN32)
  glActiveTexture =
    (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
#endif
___

■ ProxyTexure

DESC proxy texture は GL に texture のサポートを問い合わるもの 圧縮 texture も対応している
___

■ 投影マップ(ProjectionMap)


  SAMPLE
     投影マップ 


    画面に投影されるようなテクスチャ座標を計算するには
    通常のオブジェクトの変換と同じ工程を使う。

    モデルビュー、プロジェクション、w除算された頂点座標は 
    画面に対して [ -1 1 ] の範囲に収まる。
    これをさらに [ 0 1 ] の範囲にずらせば画面に投影されるテクスチャ座標が求まる。

  POINT
    2次元テクスチャ座標は u, v の2つを指定するが、
    投影マップの場合はw除算の処理が必要なため、w成分( GL_Q )も求めて置く必要がある。
    Z成分( GL_T )の値は求める必要はない。


  #define W  1024
  #define H  512

  App::onDraw() {

    // UVの変換行列を合成する
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.5f, 0.5f, 0.5f);
    glScalef(0.5f, 0.5f, 0.5f);
    gluPerspective(60.0, (float)W/H, 1.0, 2000.0);
    gluLookAt( n, n, n, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);  

    
    // 合成された変換行列を取得する。
    float m[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, m );

    // UVの自動生成を有効化する。
    glEnable( GL_TEXTURE_GEN_S );
    glEnable( GL_TEXTURE_GEN_T );
    glEnable( GL_TEXTURE_GEN_R );  // おまけ
    glEnable( GL_TEXTURE_GEN_Q );

    // 自動生成の計算式にオブジェクト空間の頂点座標を使う。
    glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    
    // 線形結合する式の係数を並べておく。
    float vs[] = { m[0], m[4], m[8],  m[12] };
    float vt[] = { m[1], m[5], m[9],  m[13] };
    float vr[] = { m[2], m[6], m[10], m[14] };
    float vq[] = { m[3], m[7], m[11], m[15] };
    

    // 合成した変換行列をオブジェクトの頂点に掛ければ画面を覆うようにUVが計算される。
    glTexGenfv( GL_S, GL_OBJECT_PLANE, vs ); 
    glTexGenfv( GL_T, GL_OBJECT_PLANE, vt ); 
    glTexGenfv( GL_R, GL_OBJECT_PLANE, vr );
    glTexGenfv( GL_Q, GL_OBJECT_PLANE, vq );


    // 投影したいテクスチャをバインドする
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, id );

    // モデルビュープロジェクション変換を設定する。
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluPerspective(60.0, (float)W/H, 1.0, 2000.0);
    gluLookAt( n, n, n, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);  
    

    // 平面を描画する。
    // UVは自動で計算されるので座標は明示( glTexCoord() )しない。    
    drawPlane();
  }
___

■ シャドウマップ(ShadowMap)


  SAMPLE
     シャドウマップ 
    

  DESC
    影を落とすはライトから投影したデプステクスチャを利用する。
    そのため影を落としたい範囲にフラスタムがはいるようにする。


  #define W 1024
  #define H 1024

void App::onInit()
{

    // シャドウマップ用のテクスチャオブジェクトを生成
    glGenTextures( 1, &idShd );
    glBindTexture( GL_TEXTURE_2D, idShd );


    // シャドウマップ用のテクスチャオブジェクトを生成。
    // 後でデプスバッファの値を格納するため ピクセルデータは設定しないでおく
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, W, H, 0,
                 GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );
    

    // 拡大縮小、リピート設定
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);


    // フラグメントの tc.R( Z )成分と シャドウマップテクスチャの値を比較する
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE );
    
    // 比較関数の指定( より小さい == より暗い == より手前 )
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL );


    // 比較の結果を輝度値として適用する
    glTexParameteri( GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE );


}
ライトの位置からシャドウマップを投影するため、 投影マップと同じようにテクスチャ座標を動的に計算する。 今度はカメラではなくライトの位置から投影するのでライトの場所にカメラを置く。
void App::onDraw()
{
    float n = 500;

    {

      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();

      glTranslatef(0.5f, 0.5f, 0.5f);
      glScalef(0.5f, 0.5f, 0.5f);
      gluPerspective(60.0, (float)W/H, 1.0, 2000.0);
      gluLookAt( n, n, n, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);  // ライトの位置

      // 合成された変換行列を取得する。
      float m[16];
      glGetFloatv(GL_MODELVIEW_MATRIX, m);

      {
        float vs[] = { m[0], m[4], m[8],  m[12] };
        float vt[] = { m[1], m[5], m[9],  m[13] };
        float vr[] = { m[2], m[6], m[10], m[14] };
        float vq[] = { m[3], m[7], m[11], m[15] };

        // 合成した変換行列をオブジェクトの頂点に掛ければ画面を覆うようにUVが自動計算される。
        glTexGenfv( GL_S, GL_OBJECT_PLANE, vs ); 
        glTexGenfv( GL_T, GL_OBJECT_PLANE, vt ); 
        glTexGenfv( GL_R, GL_OBJECT_PLANE, vr );
        glTexGenfv( GL_Q, GL_OBJECT_PLANE, vq );
      }

      // UVの自動生成を有効化する。
      glEnable( GL_TEXTURE_GEN_S );
      glEnable( GL_TEXTURE_GEN_T );
      glEnable( GL_TEXTURE_GEN_R );
      glEnable( GL_TEXTURE_GEN_Q );

      // 自動生成の計算式にオブジェクト空間の頂点座標を使う。
      glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
      glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
      glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
      glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    }



    // デプステクスチャを作成するためライトの位置にカメラを置いてレンダリング。
    // 前面を描いてしまうと、奥行きの判定の時に光のあたる面にも影が落ちてしまう。
    // そこで裏面のみを描画する。
    glEnable( GL_CULL_FACE );
    glCullFace( GL_FRONT );

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    // ライトの位置にカメラを置く。
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective(60.0, (float)W/H, 1.0, 2000.0);

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    gluLookAt( n, n, n, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);  

    drawCube();

    // レンダリングされたデプスバッファの値をデプステクスチャへセットする。
    glBindTexture( GL_TEXTURE_2D, idShd );
    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, W, H );



    // 描画面を前面に戻して、2パス目の描画をする。
    glEnable( GL_CULL_FACE );
    glCullFace( GL_BACK );

    // 画面をクリアする。
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    // 適当な位置にカメラを置いて物体を描画する。
    {
      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();
      gluLookAt( -n, n, -n, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);  

      // 影を落とすために、シャドウマップをバインドする。
      // テクスチャ座標は自動計算される設定になっている。
      glEnable( GL_TEXTURE_2D );
      glBindTexture( GL_TEXTURE_2D, idShd );

      drawCube();
      drawPlane();
    }
}

___

■ アニメーション(Animation)


  SAMPLE
     アニメーション 



___

■ Debug ( Tex に関連する )

TextureObject の State と UnitTex の State を混合していませんか ? glTexParameter(); が文字通り. TextureObject の Param を設定する MAG|MIN_FILTER WRAP_(S|T|R) GENERATE_MIPMAP Tex が完全( 次の要件を満たすか Check ) Tex が不完全だと, ActiveUnit が無効であるような振る舞いをする. -> Tex なしのような効果になる. 要件 w, h > 0 if ( GL_TEXTURE_MIN_FILTER ) Mipmap Mipmap 前提の MIN_FILTER なのに, Mipmap なしの画像を渡していないか ? よくある間違い. TextureObject と同一タイプを tgt に指定すること glEnable( GL_TEXTURE_2D|CUBE_MAP ); 異なる TYPE を OFF にする. -> 実は優先度を指定したりする.
___

■ ブレンディング(Blending)


  SAMPLE
     加算ブレンド 
     ブレンドを利用した残像エフェクト 


  DESC
    ブレンディングを指定することで、フレームバッファとフラグメントの色を混色できる。
    半透明のオブジェクトを描画したり、特殊なエフェクトを追加できる。

  POINT
    半透明を描画するときは, Blend ステートを設定すること。


    ブレンド処理はフラグメントの色が決定した後にフレームバッファにある色とされる。
      頂点処理 ---> フラグメント処理 ---> ブレンド処理 ---> ピクセルの色が決定
ブレンド方法は1次式の内容を指定するだけ。
    合成色 = Fragment * sFactor  +  FrameBuffer * dFactor
NOTE 係数は [0:1] の範囲であることが前提 合成結果 は [0:1] にクランプされる アルファ成分も計算される POINT ブレンド係数の指定は複数あるが、意味のある組み合わせは以下のような内容。
    // アルファブレンド
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // 加算
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    // 上書き ( デフォルト )
    glBlendFunc(GL_ONE, GL_ZERO);

    // 光学フィルター
    //    色成分 の割合を調整する
    //
    glBlendFunc( GL_ZERO, GL_SRC_COLOR );
___

■ ブレンド処理による残像

前のフレームの画像と現在のフレームの描画結果を混色することで残像のような効果をだせる。 前のフレームの結果をテクスチャに保持しておき、現在のフレームとアルファブレンドする。

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );


    // シーンを描画する。この時点でフレームバッファは現在のフレームの結果になる。
    setProjection( 60/1, 1.0f*W/(float)H, 1, 1000 );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    convertCameraSpace();
    drawCube();


    // テクスチャとして、とっておいた前のフレームとブレンドする。

    // 前のフレームをバインド
    glBindTexture( GL_TEXTURE_2D, id );

    // ブレンド指定    
    glEnable( GL_BLEND );
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // 画面いっぱいに矩形を描くための変換
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glDisable( GL_DEPTH_TEST );

    // 頂点カラーのアルファ成分を使って、フラグメントのアルファを指定する。
    glColor4f( 1, 1, 1, 0.99f )
    {
      glBegin( GL_QUADS );
      float s = 1;
      float z = -1;
      glTexCoord2f( 0, 0 );      glVertex3f( -s, -s, z );
      glTexCoord2f( 1, 0 );      glVertex3f(  s, -s, z );
      glTexCoord2f( 1, 1 );      glVertex3f(  s,  s, z );
      glTexCoord2f( 0, 1 );      glVertex3f( -s,  s, z );
      glEnd();
    }

    // 合成結果を次のフレームに使うため、とっておく。
    glBindTexture( GL_TEXTURE_2D, id );
    glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, W, H, 0 );

___

■ glBlendFunc

SYNTAX void glBlendFunc( GLenum s, // フラグメントの重み GLenum d // フレームバッファの重み ); DESC 合成するときのブレンド率を指定する。 DEFAULT GL_ONE GL_ZERO
___

■ glBlendEquation

SYNTAX void glBlendEquation( unsigned int ) DESC Fragment, FrameBuffer の合成方法( 計算式 )を指定する DEFAULT GL_FUNC_ADD
    // 加算
    //   S + D
    glBlendEquation( GL_FUNC_ADD );

    // 減算
    //   S - D
    glBlendEquation( GL_FUNC_SUBSTRACT );

    // 減算
    //   D - S
    glBlendEquation( GL_FUNC_REVERSE_SUBSTRACT );

    // min, max
    //    min( S, D )
    //    max( S, D )
    glBlendEquation( GL_MIN );
    glBlendEquation( GL_MAX );


POINT Alpha 成分の指定もすることになる


    GL_ZERO
        RGB          A
        ( 0, 0, 0 )  0

    GL_ONE
        RGB          A
        ( 1, 1, 1 )  1

    GL_SRC_ALPHA
        RGB             A
        ( As, As, As )  As

    GL_SRC_COLOR
        RGB             A
        ( Rs, Gs, Bs )  As

sfactor specifies which of nine methods is used to scale the source color components. dfactor specifies which of eight methods is used to scale the destination color components. The eleven possible methods are described in the following table. Each method defines four scale factors, one each for red, green, blue, and alpha. In the table and in subsequent equations, source and destination color components are referred to as ( Rs, Gs, Bs, As ) and ( Rd, Gd, Bd, Ad ). They are understood to have integer values between 0 and ( kR, kG, kB, kA ), where kc = 2mc - 1 TIP 半透明の面を正しく描画するにはアプリケーションは次の順番で描画をする。 1. 不透明な面をかく 2. 半透明を 視点から遠い順にかく

    // 不透明 Object を描画
    drawOpaqueObject();


    // depth かきこみ OFF
     glDepthMask( GL_FALSE );


    // ブレンド機能を有効にする。
      glEnable( GL_BLEND );


    // ブレンド方法を指定する。
      glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );


    // Fragment の Alpha を透明にする
    // 画面奥から順番に描画
    //
    // Alpha を 1 以下に
    //  Texture のアルファ値も乗算されるはず
    float a = 0.5f;
    float s = 100.0f;
    glColor4f( 1, 1, 1, a );
    glBegin( GL_QUADS );
    glVertex4f( 0, 0, z, 1 );
    glVertex4f( s, 0, z, 1 );
    glVertex4f( s, s, z, 1 );
    glVertex4f( 0, s, z, 1 );
    glEnd();

    SRC = fragment col, DST = buf col

    // blend 処理 ON
    glEnable( GL_BLEND );

    // blend の計算式を選ぶ
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    // 加算する場合
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);

___

■ アルファテスト

DESC 指定した条件に合格したフラグメントのみがフレームバッファへ更新される。 適用する、しないの2値の処理のため、ブレンド処理の方が柔軟に制御できる。
    glEnable( GL_ALPHA_TEST );

    // > 0.1 なら合格
    glAlphaFunc( GL_GREATER, 0.1f ); 
___

■ カリング(Culling)


  DESC
    Primitive の裏側を破棄する機能
    デフォルトではポリゴンは両面が描画される。
    これによって Rasterize 処理が不要になるため処理が軽減される

    閉じた Object は通常この設定を ON にする。
    表は 頂点 が半時計まわり

    // Culling 機能 ON
    //    Default : OFF
    glEnable( GL_CULL_FACE );


    // Culling する面の向きを指定
    glCullFace( GL_FRONT );

    // 面を描画して確認
    drawQuad();
___

■ 描画モード


    描画方法を変更するには glPolygonMode() を使う。
    ラスタライズ方法が変更されて、塗り、ライン、点に変更できる。

glShadeModel(GLenum mode)

___

■ glPolygonMode

SYNTAX glPolygonMode(GLenum face, GLenum mode)

    // 前面をラインで背面をポリゴンで描画する。
    glPolygonMode(GL_FRONT, GL_LINE);

___

■ glShadeModel

SYNTAX glShadeModel( GLenum face, GLenum mode )
    glShadeModel( GL_SMOOTH );
___

■ Debug(デバッグ)


  POINT
     簡単なものから順番にして, 正しく Rendeing されているか確認すること
     追加して問題がおきれば, そこが原因

  DESC
    OpenGL のエラーを取得するには glGetError() を利用する。


  POINT
    OpenGL はエラーを起こすような命令がくると、その処理を実行しないでエラーフラグを立てる。
    アプリケーションは継続するためアプリケーション側はチェックをする必要がある。
    


  WARNING 
    コンパイルエラーにはならないが、OpenGL への命令としてはエラーになるケースがあるため
    エラーチェックをする必要がある。
    無効なマクロ定数の指定はコンパイルエラーにならないが、
    OpenGL はエラーを発生させて命令を実行しない。
    // これは Compile ERROR ではないが、OpenGL への命令としてはエラー
    glTexEnvi( GL_S, GL_TEXTURE_ENV_MODE, GL_OBJECT_PLANE );
POINT 常に Error Check する習慣をつけること ただし Cost は 0 ではないので , Release 時は消す。 Error の仕様は変更されるため, Error 内容に依存した Code はかかない Error が発生する場合, GL は Command を無視する マクロを利用して, リリース時はオフになる仕組みを用意しておく。
    #ifdef _DEBUG
    # define   CHECK_ERROR checkError()
    #else
    # define   CHECK_ERROR
    #endif
    
    void checkError() {
      GLenum err = glGetError();


      if ( err != GL_NO_ERROR ) {
        printf( "OpenGL ERROR code %d: %s\n", err, (const char *)gluErrorString( err ) );
      }
    }

App::init() 時に一度. App::onDraw() の最後でするのがコツ。 正しく描画されない場合は, エラーが発生している可能性があるので チェックをしておくの無難。
    App::init() {
        // 初期化時に 1 度チェック

      // Error は Debug のみ有効にする
      assert( glGetError() == GL_NO_ERROR );

    }

    App::update() {
      // 各フレームでも 一度処理をする
      assert( glGetError() == GL_NO_ERROR );
    }
      // もうはいらない.
    行列スタックが一杯のときに, glPushMatrix が呼ばれる場合、GL_STACK_OVERFLOW が発生

      // もう空っぽ.
    行列スタックがひとつのときに, glPopMatrix が呼ばれる場合、GL_STACK_UNDERFLOW が発生.

    // ここで補足する
    {
      static struct Tbl{
        int id;
        char *msg;
      }tbl[]=
        {
          GL_NO_ERROR, "エラーなし",
          GL_INVALID_ENUM, "Enum 型の引数が範囲外"
          GL_INVALID_VALUE, "数値の引数が範囲外"

                // size が同じでない Cube Texture
                glTexImage2D( GL_CUBE, 32, 64 )

          GL_INVALID_OPERATION, "カレントのステートではできない Command を発行した"

          GL_OUT_OF_MEMORY, "コマンドを実行するメモリが不足",

          GL_STACK_OVERFLOW, "コマンドがスタックのオーバーフローをおこしている"
          GL_STACK_UNDERFLOW, "コマンドがスタックのアンダーフローをおこしている"

               Stack の Push, Pop がペアになってない
               Stack Size の最大数を超えた Push


      };

      unsigned int err = glGetError();

      for( int i=0; i< NROF(tbl); i++ ){
        if ( err == tbl[i].id ) {
          printf( "ERROR CHECK: %s\n", tbl[i].msg );
          break;
        }
      }


      assert( err == GL_NO_ERROR );
    }
___

■ glGetError

SYNTAX GLenum glGetError(); DESC エラーコードを返す。 POINT glGetError() で取得するまで, 新たな ErrorCode は記録されない。 また, glGetError() で取得すると, エラー状態は GL_NO_ERROR にリセットされる。 glGetError() は glBegin() - glEnd() 内でコールするとエラー扱いになる。( GL_INVALID_OPERATION )
___

■ gluErrorString

SYNTAX const GLubyte * gluErrorString( GLenum error); DESC GL, GLU エラーコードからエラー文字列を取得する。
___

■ Error

___

■ デバッグツール

DESC OpenGL Command 列 の Capture , State をチェックできる "OpenGL Debugger", "OpenGL Tool" で検索すること
___

■ ErrorCode

DESC
   GL_INVALID_ENUM  0x0500  GLenum型引数が範囲外
   GL_INVALID_VALUE  0x0501  数値の引数が範囲外
   GL_INVALID_OPERATION  0x0502  カレントのステートでの操作が不適切

   // StkMtx の問題.
   GL_STACK_OVERFLOW  0x0503  コマンドがスタックのオーバーフローを起こしている
   GL_STACK_UNDERFLOW  0x0504  コマンドがスタックのアンダーフローを起こしている


   GL_OUT_OF_MEMORY  0x0505  コマンドを実行するメモリが不足
___

■ glBegin(); glEnd(); の不一致

#if 0 glBegin(); ... #endif glEnd();
___

■ texture 初期設定の不一致

初期値が環境によって異なる 初期化のときにすべてのパラメータを明示すること

    // mipmap を利用しないことを明示する    


    // ON
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    // OFF
      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

___

■ ライティング(Lighting)


  SAMPLE
     ライティング計算 
     カメラの移動とライティング計算 
     ワールド座標指定のライティング 



___

■ Lighting

DESC ライティング結果は ライトの設定である glLight() と オブジェクトの材質設定の glMaterial() によって決まる。 計算結果は各頂点の色(プライマリーカラー)となり、 照明がオフの場合は glColor() で指定したカラーが適用される。 テクスチャなどのフラグメント処理は頂点カラーの決定後にされる。 POINT ライトの位置( 向き )の指定も頂点変換と同じように、モデルビュー変換の影響を受ける。 glLight( GL_POSITION ); をコールした時点で指定した座標が変換される。 常に正面から照らす設定は以下になる。
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    float dir[] = { 0, 0, 1, 0 };
    glLightfv( GL_LIGHT0, GL_POSITION, dir );
ワールド座標で指定するにはカメラ座標系から変換する。
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    convertCameraSpace( 0, 0, 500, cy, cx );

    // ワールド座標の 0 0 1 の方向から照らす。
    float dir[] = { 0, 0, 1, 0 };
    glLightfv( GL_LIGHT0, GL_POSITION, dir );
ライティング計算のための初期化をする。
    App::onInit() {

      // Lighting 処理を有効化( DEFAULT : オフ )
      glEnable( GL_LIGHTING );

      // ライト数は 少なくとも 8 つ
      // 個別に ON/OFF できる。
      glEnable( GL_LIGHT0 );

      
      // ライトの位置を設定する
      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();
      float dir [] = { -0.3f, 0, 1, 0 };
      glLightfv( GL_LIGHT0, GL_POSITION, dir );
    }

描画時は法線( glNormal )を設定したモデルを描画する。
    App::onDraw() {    

      // 法線をもつプリミティブを描画
      //    残りの Light の parameter はすべてデフォルトを使う
      drawNormalCube();

      // WARNING
      //  Lighting ON は 不要ならばオフにする。
      //  以下の 頂点処理に影響をうける
      glDisable( GL_LIGHTING );
    }
___

■ ライトの色

ライティングは次の3つの要素で近似する。
    環境光 : 間接光
    拡散光 : 面に対して均等に拡散する面
    鏡面光 : 光沢のある面
ライティングの内部計算。 L : ライト M : マテリアル
     Env * aM +
    aL * aM +
    dL * dM * ( N.L ) +
    sL * sM + ( N.R )
___

■ 法線(Normal)

DESC OpenGL は Normal を見て面の向きを決める。 ライティング計算をするためには、面の向きを指定する必要がある。 WARNING 頂点と同じくモデルビュー行列の影響をうけるため Scale 成分の影響をうける。

    // Normalize を ON
    glEnable( GL_NORMALIZE );

    // Scaling のみの調整をする
    //    Scale Matrix が 等しいなら これで十分
    glEnable( GL_RESCALE_NORMAL );


    // 最も効率的なのは init 時に normal を再計算すること
    recalcNormal();

___

■ LightParameter


    GLInt nr;
    glGetIntegerv( GL_MAX_LIGHTS, &nr );

    // 各 Light を有効化 ( GL_LIGHTi )
    glEnable( GL_LIGHT0 );

    // 各 Light の parameter 設定
    glLightfv( GL_LIGHT0, GL_DIFFUSE, col );
    glLightfv( GL_LIGHT0, GL_POSITION, pos );

___

■ glLight

SYNTAX glLight( GLenum light, GLenum pramName, // GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_POSITION TYPE *val // color | position ) DESC ライトのパラメータ( 色、位置 )を設定する。 DEFAULT GL_AMBIENT : 0, 0, 0 // Ambient とは 間接光 ( N 回 Bounce ) の近似 GL_LIGHT0 GL_DIFFUSE : 1, 1, 1 GL_SPECULAR : 1, 1, 1 GL_LIGHT1 - N GL_DIFFUSE : 0, 0, 0 GL_SPECULAR : 0, 0, 0 DESC ライトの位置の設定も頂点と同じく、glLight() をコールした時点での モデルビュー行列変換の影響を受ける。 平行光( DirectionLight )を利用するには, 位置指定のw成分を 0 にする。 無限遠の 0, 0, 1 の位置に置いたことになり 0, 0, -1 方向への平行光として計算される。
    // 平行光
    float dir [] = { 0, 0, 1, 0 };
    glLightfv( GL_LIGHT0, GL_POSITION, dir );

    // 位置で指定
    float pos [] = { 0, 0, 1, 1 };
    glLightfv( GL_LIGHT0, GL_POSITION, pos );
___

■ glMaterial

SYNTAX glMaterial( GLenum face, // 表裏の指定 GLenum pramName, // GL_AMBIENT | GL_DIFFUSE | GL_SPECULAR | GL_SHININESS const TYPE *val ) DESC オブジェクトの色を指定する。 ライトの各成分と乗算される。 POINT アルファ成分は GL_DIFFUSE で指定したアルファ成分が頂点のアルファ色になる。 GL_AMBIENT, GL_SPECULAR の指定は無視される。
    float col[] = { 0, 1, 0, 1 };
    glMaterialfv( GL_FRONT, GL_AMBIENT, col );
    glMaterialfv( GL_FRONT, GL_DIFFUSE, col );
    glMaterialfv( GL_FRONT, GL_SPECULAR, col );


    // GL_SHININESS [0:128] DEFAULT 0
    glMaterialf( GL_FRONT, GL_SHININESS, 128 );
___

■ レイトレース(RayTrace)

物が見えるのは、レンズに光(レイ)が飛びこんでくる結果なのでこれを逆からトレースするという考え方。 Direct 1 Bound : 通常のライティングモデル ( ) 2 Bound : 照り返し 画素の数だけ、このトレースを繰り返す 2 バウンド
    光源からライトがでる ---> 赤い壁にあたる ---> 白い布を照らす  ---> カメラのレンズに届く 
カメラから画素へ向かってレイをとばす。 何かにあたる その何かは、全方向からの光の影響をうけるので、全方向にライトをとばす これを N 階の深さまで繰り返す。 光源方のみに絞ったは 1 バウンドは、直接の光源のみなので、反対領域は黒くなる。 そこで、1バウンドに限定して、暗い部分は適当にバイアスを足しておく( アンビエント ) 1バウンドも、ライトという光源方向のみに限定する。 これで画素数だけの計算回数になる。 明るさは 面積あたりの光の粒の数( 密度 )なので、距離の2乗に比例する。 しかし、太陽などの十分に長い距離に対しては、100m などは 0m として近似できるため 距離の減衰を無視できる。 反射の割合( 分布 ) ある方向からきた光は、必ず一定方向にだけ反射するわけではない。 そうだとしたら見る方向をかえると、黒く見えてしまう。 そこで、全方向に一様に反射すると仮定する。 これを計算式として表現すると、ディフューズモデルができる
      I = I0 * R * cos(theta),  cos(theta) =  dot(L , N)

      L  : 頂点から光源へのベクトル
      N  : 頂点の法線ベクトル
      I0 : 光源の色
      R  : 反射する割合
___

■ ライティング計算を自前でする

OpenGL にはライティング計算をするための API があるが 自前で計算式から明るさを求めて、頂点カラーとして渡すこともできる。 テクスチャを貼るときは、 GL_MODULATE をつかえばいい。 REFERENCE テクスチャのブレンド方法を指定する
___

■ PipeLine


  POINT
    大まかには 頂点処理, Fragment 処理にわかれる


  [ VertexTransform ]
         |
  [ FragmentTest ]    // FrameBuffer に入る前に Test

  TIP
    Triangle 単位で Pipeline が進行する.
    ひとつの DrawCall 内でも, DepthTest, DepthWrite が有効になる



___

■ Fragment ごとの処理

次の順番で処理される

   // Application が定義した Window 座標の外の領域の Fragment を破棄
   1: シザー

   // Application で指定した Alpha 値より Fragment の Alpha 値が小さいなら破棄
   2: アルファ

   // FrameBuffer の Stencil 値と比較して 一定の処理をする
   3: ステンシル

   // Fragment の Depth 値と FrameBuffer の Depth 値と比較して 小さければ破棄
   4: デプス

   //
   5: 混合処理
   6: ディザ
   7: 論理


___

■ シェーダ(Shader)



___

■ shader の対応について

DESC glview によれば ... Vertex Program extension found.( DX8 Vertex Shader ) Fragment Program extension found.( DX9 Pixel Shader ) No OpenGL Shading Language support( GLSL は不可 )
___

■ 基本的なれ流

SAMPLE フラグメントシェーダ

  #include "Cg/cg.h"
  #include "Cg/cgGL.h"

  #pragma comment (lib, "cg.lib")
  #pragma comment  (lib, "cgGL.lib")

    App::init() {

      CGprofile  pfV = CG_PROFILE_ARBVP1;
      CGprofile  pfF = CG_PROFILE_ARBFP1;
      CGprogram  shdV, shdF;

      CGcontext ctx = cgCreateContext();


      // Shader は使えるか確認
      cgGLIsProfileSupported();

      // shader code を読んで Program を作成
      shdV = cgCreateProgramFromFile( ctx, CG_SOURCE, ".\\vertex.cg", pfV, NULL, NULL);
      shdF = cgCreateProgramFromFile( ctx, CG_SOURCE, ".\\fragment.cg", pfF, NULL, NULL);

      // または文字列バッファから作成
      shdF = cgCreateProgram( ctx, CG_SOURCE, "...", pfF, NULL, NULL);



      // あげる
      cgGLLoadProgram(shdV);
      cgGLLoadProgram(shdF);

      // Shader 有効化
      cgGLEnableProfile( pfV );
      cgGLEnableProfile( pfF );

      cgGLBindProgram( shdV );
      cgGLBindProgram( shdF );

    }


    App::draw() {

      // Shader の指定
      //  Texture Object の指定と同じ
      cgGLBindProgram();

      // 描画
      draw();
    }

フラグメントの色を単色にするだけのフラグメントシェーダ
    float4 main() : COLOR
    {
      return float4( 0, 0, 1, 1 ); 
    }
___

■ cgGLEnableProfile

SYNTAX void cgGLEnableProfile( CGprofile profile ) DESC プロファイルを有効化する。 有効化した後の OpenGL の描画コールではシェーダが利用される。
___

■ cgGLDisableProfile

SYNTAX void cgGLDisableProfile( CGprofile profile )

    // 固定機能の描画に戻す。
    cgGLDisableProfile( pfV );
    cgGLDisableProfile( pfF );

    // 描画
    drawCube();
___

■ 頂点シェーダ

SAMPLE 頂点シェーダ とりあえず、固定機能と同じように描画してみる。
    App::onDraw() {

      // 変換行列を設定。
      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();

      glMatrixMode( GL_PROJECTION );
      glLoadIdentity();
      glFrustum();


      // シェーダから変数 "mvp" のハンドルを取得する。
      CGparameter param = cgGetNamedParameter( shdV, "mvp");

      // OpenGL のステートである ModelViewProjection 行列をセットする。
      // これをコールした時点の ModelViewProjection 行列がセットされるため
      // 先に行列を設定しておく必要がある。
      cgGLSetStateMatrixParameter( param,
                                CG_GL_MODELVIEW_PROJECTION_MATRIX,
                                CG_GL_MATRIX_IDENTITY );


      // この設定でプリミティブを描画
      drawCube();
    }
頂点シェーダ
    struct app {
      float4 pos : POSITION;   // 頂点データ
    };
    struct v2f {
      float4 pos : POSITION;   // 頂点データ
    };

    v2f main( 
            app IN,
            uniform float4x4 mvp
            ) {

      v2f OUT;          

      // 頂点を変換してフラグメントシェーダへ渡す。
      OUT.pos = mul( mvp, IN.pos );

      return OUT;
    }
頂点シェーダ側では任意の頂点アトリビュートをフラグメントシェーダへレジスタ経由で渡す ことができる。 法線の値をフラグメントの色に指定してみる。
    struct app {
      float4 pos : POSITION;   // 頂点データ
      float4 nrm : NORMAL;     // 法線データ
    };
    struct v2f {
      float4 pos : POSITION;   // 頂点データ
      float4 nrm : TEXCOORD0;  // フラグメントシェーダへ法線の値を渡す。
    };

    v2f main( 
            app IN,
            uniform float4x4 mvp
            ) {

      v2f OUT;

      // 頂点を変換してフラグメントシェーダへ渡す。
      OUT.pos = mul( mvp, IN.pos );

      OUT.nrm = IN.nrm;

      return OUT;
    }
フラグメントシェーダでは頂点シェーダから渡された法線の値を出力する。
    float4 main( v2f IN ) : COLOR
    {
      return float4( 0.5f * IN.nrm.xyz + 0.5f, 1 ); 
    }
___

■ フラグメントシェーダからテクスチャをサンプルする

SAMPLE シェーダへテクスチャをわたす サンプラー変数のハンドルを取得して、 利用したいテクスチャオブジェクトの id を指定する。
      
  App::onInit() {
    glGenTextures( 1, &id );
  }


  App::onDraw() {

    CGparameter p = cgGetNamedParameter( shdF, "decal");
    cgGLSetTextureParameter( p, id );    
    cgGLEnableTextureParameter( p );
  }
フラグメントシェーダではサンプラー型の変数を宣言しておく
    float4 main(
              v2f IN,
              uniform sampler2D decal
    ) : COLOR
    {
      return tex2D( decal, IN.tc.xy );
    }
___

■ cgGLSetTextureParameter

SYNTAX void cgGLSetTextureParameter( CGparameter param, GLuint texobj ); DESC param で指定したテクスチャユニットにテクスチャオブジェクトをバインドする。 glBindTexture() に相当する処理。
___

■ cgGLEnableTextureParameter

SYNTAX cgGLEnableTextureParameter( CGparameter ) DESC 指定したテクスチャパラメータ(ユニット == サンプラー)を有効化する。 この処理は, テクスチャを利用して描画する前にコールしておく必要がある。 とあったが, あってもなくても動く? テクスチャの適用を解除するときは cgGLDisableTextureParameter() をコールする。
___

■ フラグメント単位のライティング

SAMPLE フラグメント単位のライティング アプリケーション側では視線の位置を頂点シェーダにわたす。
  {
    CGparameter param = cgGetNamedParameter( shdV, "eyepos");
    cgGLSetStateMatrixParameter( param,
                                 CG_GL_MODELVIEW_MATRIX,
                                 CG_GL_MATRIX_INVERSE
                                 );
  }
頂点シェーダ側ではフラグメントシェーダに渡す。
    uniform float4x4 eyepos;

    OUT.nrm = IN.nrm;
    OUT.E = float4( eyepos[0][3],eyepos[1][3],eyepos[2][3],eyepos[3][3] ) - IN.pos;
頂点シェーダから視線ベクトルと法線ベクトルをフラグメントシェーダへ渡す。 フラグメントでのそれらの値は頂点間で線形補間されるため、 Normalize() が必要。
    struct v2f {
      // 頂点データ
      float4 pos : POSITION;   
      float4 nrm : TEXCOORD0;  
      float4 E   : TEXCOORD3;   // 視線ベクトル
    };


    float3 E = normalize( IN.E.xyz );
    float3 N = normalize( IN.nrm.xyz );
    // ライトベクトル
    float3 L = float3( 0, 0, 1 );
    // ハーフベクトル
    float3 H = normalize( (L + E)/2 );


    // ディフューズ成分
    float d = max( dot( L, N ), 0 );

    // スペキュラー成分
    float s = max( 0, pow( dot( H, N ), 30 ) );

    d += s;    
    return float4( d, d, d, 1 ); 
ToonShader はライティング結果を階調化して表現してみる。
    s = step( 0.5, s );

    float n = 3;
    d = floor ( d * n ) / n;

    d += s;    
    return float4( d, d, d, 1 ); 
WARNING 頂点シェーダで受け取る頂点属性は必ずアプリケーション側から渡すこと。
    struct app {
      float4 pos : POSITION;
      float4 nrm : NORMAL;
      float2  tc : TEXCOORD0;
    };

    glBegin( GL_TRIANGLES );
    // この2つは必須
    glNormal3f( 0, 1, 0 );
    glTexCoord2f( 0, 0 );

    glVertex3f();
    glVertex3f();
    glVertex3f();

    glEnd();
___

■ ノーマルマップ(NormalMap)

SAMPLE ノーマルマップ ノーマルマップとライティング カラーのテクスチャからノーマルマップに変換する

    float3 calcNormalMap( sampler2D decal, float2 tc) 
    {

      // 1テクセルの大きさ
      // 1024×1024のテクスチャを利用する場合
      float du = 1 / 1024.0f;
      float dv = 1 / 1024.0f;

      // 隣接テクセルの値
      float2 tx = tc + float2( du, 0 );
      float2 ty = tc + float2(  0, dv );


      // 元のテクスチャがカラーのため、明度のみの色に変更
      float cx = convMono( tex2D( decal, tx ).xyz );
      float cy = convMono( tex2D( decal, ty ).xyz );

      tx = tc - float2( du, 0 );
      float cx2 = convMono( tex2D( decal, tx ).xyz );

      ty = tc - float2(  0, dv );
      float cy2 = convMono( tex2D( decal, ty ).xyz );

      float scl = 1;

      // X, Y 方向の傾きを計算する
      float3 vu = normalize( float3( 1, 0, scl*(cx - cx2) ) );
      float3 vv = normalize( float3( 0, 1, scl*(cy - cy2) ) );

      // 2つの軸に直交するz軸を計算する
      float3 N = cross( vu, vv );

      return N;
    }

    float4 main( 
                v2f IN,
                uniform sampler2D decal
                ) : COLOR
    {
      // -1 : 1 の範囲の値を 0 : 1 に変換する
      return float4( 0.5f * calcNormalMap( decal, IN.tc.xy) + 0.5f, 1 );
    }
___

■ ポストエフェクト(PostEffect)


  SAMPLE

     ポストエフェクト モザイク 
     ポストエフェクト エッジ抽出 

     ポストエフェクト ぼかしを加算 


    ポストエフェクトをするには、描画した画面をフラグメントシェーダを利用して
    再処理をする。

    // 適当にシーンを描画
    drawScene();
    

    // 画面をテクスチャへコピー
    glBindTexture( GL_TEXTURE_2D, id );
    glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
                          0, 0, W, H, 0 );

    // ポストエフェクト用の頂点シェーダとフラグメントシェーダをバインドする。                          
    cgGLBindProgram( shdV );
    cgGLBindProgram( shdF );


    // フラグメントシェーダで利用するテクスチャを渡す。
    CGparameter p = cgGetNamedParameter( shdF2, "decal");
    cgGLSetTextureParameter( p, id );    
    cgGLEnableTextureParameter( p );


    // テクスチャを画面を覆う四画形ポリゴンにはりつけて描画する。
    glBegin( GL_QUADS );
    glTexCoord2f( 0, 0 );
    glVertex3f( -1, -1, z );
    glTexCoord2f( 1, 0 );
    glVertex3f( 1, -1, z );
    glTexCoord2f( 1, 1 );
    glVertex3f( 1, 1, z );
    glTexCoord2f( 0, 1 );
    glVertex3f( -1, 1, z );    
    glEnd();

頂点シェーダでは正規化デバイス座標系で -1 : 1 の範囲を覆うように変換しておく。 四画形の各頂点を -1 1 にしておき、モデルビュー変換、プロジェクション変換をしないでスルーさせる。

    struct app {
         // 頂点データ
      float4 pos : POSITION;
      float4 tc : TEXCOORD0;     
    };
    struct v2f {
      float4 pos : POSITION;   
      float4 tc  : TEXCOORD1;  
    };

    v2f main( 
                app IN
                ) 
    {
      v2f OUT;

      // -1 1 の範囲になるようにスルーさせる。
      OUT.pos = float4( IN.pos.xy, -0.9f, 1 );
      OUT.tc = IN.tc;

      return OUT;
    }
フラグメントシェーダでは描画した画面に対して適当な処理をする。
    float4 main( 
                v2f IN,
                uniform sampler2D decal
                ) : COLOR
    {
      return float4( tex2D( decal, floor( IN.tc.xy * 100 ) / 100.0f ).xyz, 1 );
    }
___

■ 基本事項


___

■ GL の原則

一度設定した 内容は 変更されるまで有効 State を保存する場所を Rendering Context という WARNING State の状態を正しく管理しないと, 想定しない動作に悩まされる 以下の方法をとる init 時に 頻繁に利用する State にする State を変更するときは 属性 Stack ( Push, Pop ) で囲む

     Module 設計, Object 指向 と合性が良い
        変更する Code が責任をもって元の State に戻す

     Code が前提にしているものを取り除く

        特定の State を前提にしている Code は他の Code を追加すると破壊されてしまう

     Code の再利用が簡単になる

___

■ 描画命令の順

DESC Command の発行順に描画される Primitive 単位でも同じこと glDrawElements();
    clearcolor -> drawtri
    drawtri -> clearcolor では 上塗りされる
TIP matrix の順番も特に指定する必要なし( 現在のstate が描画時に反映 ) 描画時とは begin() - end() の間

  glMatrixMode( MV );
  glMatrixMode( PROJ );
  draw

  glMatrixMode( PROJ );
  glMatrixMode( MV );
  draw

  glMatrixMode( PROJ ); // これは既に有効ではない

透明に関しては以下の3種類 1. 不透明( 手前から, 塗りを減らすため ) 3. クリップ( 奥から描画, αテストの部分が補間の関係でマージンができる為 ) 2. 半透明( 奥から描画 )
___

■ glPushAttrib

SYNTAX void glPushAttrib( GLbitfield ); DESC 指定した Group の属性を Stack に Push 利用してみたが, かなり効果的 1 Primitive 描画毎に Push, Pop してもいい
    // 全部 保存
    glPushAttrb( GL_ALL_ATTRIB_BITS );

___

■ glPopAttrib

___

■ glPushClientAttrib

___

■ glPopClientAttrib

___

■ State の設定 クエリ

___

■ glIsEnabled()

SYNTAX bool glIsEnabled( GLenum val ); DESC test whether a capability is enabled
___

■ glGet

DESC OpenGL の実装依存の情報を取得する ( init 時にする ) 問い合わせる型にあった関数を利用する
  float m[16];
  glGetFloatv( GL_MODELVIEW_MATRIX, m );


___

■ Stack を使って管理する

State の変更を管理するための stack( 属性スタック ) が Server, Client 側にある
___

■ glPushAttrb

SYNTAX glPushAttrb( GLbitfield mask ) glPopAttrb();

    // Material, Light 属性のみを Push する
    glPushAttrb( GL_LIGHTING_BIT );

    // そして元に戻す
    glPopAttrb();

    // Stack のサイズをしらべる
    int nr;
    glGetIntegerv( GL_MAX_ATTRIB_STACK_DEPTH, &nr );

___

■ 開発環境

以下の Header, library が必要 OpenGL Header, library Window System の Header, library visualstudio.net には OpenGL 1.1 の Header と Export StubLibrary がふくまれる // version 1.1 以降の機能, 拡張機能 を利用するには glext.h が必要 #include "GL/glext.h" Microsoft Compiler は glu1.2 の header, StubLibrary を含む
___

■ 用語

___

■ Primitive

DESC Primitive とは 1 つ以上の 頂点のグループ 線の Primitive は 2 つ以上の頂点が必要。 プリミティブは頂点を組み立てることで生成される。
___

■ Profile(プロファイル)


  DESC
    自分の OpenGL 環境をしる

___

■ GL version

GL のバージョンとは固有の機能拡張 == 新API の追加のこと 機能拡張は各vendor からリリースされている 2.0対応( OpenGL Extensions Viewerで確認 ) 2.0対応ということは2.0の拡張機能を利用しているということ 表示可能な画面解像度も備えている
___

■ glGetString

DESC OpenGL の実装情報を 文字列でえる init 時に GL_VERSION, GL_EXTENSIONS をしらべて support する機能をしらべる glEnable() < -> glIsEnable() glGetXXX() : state 値の問い合わせ( perf が必要な部分での使用は禁止 )

  bool profile() {
    bool ret = false;

    version = (char *)glGetString( GL_VERSION );

    printf( "GL_EXTENSIONS: %s\n", glGetString( GL_EXTENSIONS ) );
    printf( "GL_VERSION: %s\n", glGetString( GL_VERSION ) );
    printf( "GL_REBDER: %s\n", glGetString( GL_RENDERER ) );
    printf( "GL_VENDOR: %s\n", glGetString( GL_VENDOR ) );

    return ret;
  }
DESC openGL は [ call した順 ]にすべての処理がされる( 描画順も制御可能 ) 1. .ピクセル系の処理 glReadBufferやglReadPixelなどの処理は負荷が高い VRAM ではなく MEMORY に転送するので
___

■ cgGl




___

■ cgDestroyEffect

SYNTAX void cgDestroyEffect( CGeffect effect ); DESC Effect object を破棄する Effect を破棄すると それに関連する Techinique Pass も無効になる
___

■ cgIsEffect

SYNTAX CGbool cgIsEffect( CGeffect effect ); DESC determine if an effect handle references a valid effect
___

■ cgGetLastListing

SYNTAX const char * cgGetLastListing( CGcontext context ); RET NULL: 空だった DESC get the current listing text Cg Compiler , CG_ERROR の情報が取得できる cgGetLastListing(); POINT Context には Error 情報とかもはいっている
___

■ cgGetFirstStateAssignment

SYNTAX cgGetFirstStateAssignment( CGpass pass ) DESC get the first state assignment in a pass // 描画 pass Pass { State } POINT Nest 構造をたどっていく
___

■ cgCreateProgramFromFile

SYNTAX cgCreateProgramFromFile DESC 指定した cg ソースコード, コンパイル済みのオブジェクトから CgProgram を生成する。
    // 相対パスで指定する
    shdV = cgCreateProgramFromFile( ctx, CG_SOURCE, "data/shader/test.vsh", pf, NULL, NULL);

    // 絶対パスで指定する
    shdF = cgCreateProgramFromFile( ctx, CG_SOURCE, "d:/data/shader/test.vsh", pf, NULL, NULL);
___

■ エラーチェック

___

■ cgGetError

SYNTAX CGerror cgGetError( void ); DESC エラーステートを取得する。 cgGetError() をコールするとエラー状態はリセットされる。
    CGerror err = cgGetError();
    assert( err == CG_NO_ERROR );
___

■ cgSetErrorCallback

SYNTAX typedef void (*CGerrorCallbackFunc)( void ); void cgSetErrorCallback( CGerrorCallbackFunc func ); DESC Cg ランタイムエラーが発生した時にコールバックされる関数を設定する。
    void MyErrorCallback() {
      const char* s = cgGetErrorString( cgGetError() );
      printf( "ERROR: Cg Runtime msg = %s\n", s );
    }
    cgSetErrorCallback( MyErrorCallback );
___

■ cgGetErrorString

SYNTAX const char * cgGetErrorString( CGerror error ); DESC エラーコード値からエラー文字列を返す。
___

■ cgGetNamedParameterAnnotation

SYNTAX CGannotation cgGetNamedParameterAnnotation( CGparameter param,const char * name ); RET NULL : なかった CG_INVALID_PARAM_HANDLE_ERROR is generated if param is not a valid parameter. DESC 名前, parameter を指定して CGannotation をえる
___

■ cgGetFirstTechnique

SYNTAX CGtechnique cgGetFirstTechnique( CGeffect effect ); RET CG_INVALID_EFFECT_HANDLE_ERROR( if effect is not a valid effect ) DESC Effect の最初の Techinique をえる
    // effect 内の すべての Technique を Iterate するときに使う
    CGeffect effect = cgCreateEffectFromFile(context, cgfx_filename, NULL);
    CGtechnique technique = cgGetFirstTechnique(effect);

    while (technique) {
      // Do something with each technique

      // 有効かを調べる
      // CGbool cgValidateTechnique( CGtechnique tech );
      if ( cgValidateTechnique(tech) ) {
        // 名前をえる
        printf("ERR: %s", cgGetTechniqueName(tech) );
      }


      // 次の Tech へ
      technique = cgGetNextTechnique(technique);
    }
___

■ cgGetNamedParameter

SYNTAX CGparameter cgGetNamedParameter( CGprogram, const char *name ) DESC 指定 shader Program から uniform data へのハンドルを取得 RET null : 指定した Parameter がない !null : ParameterHandle TIP RetVal で Shader 内に, どの UniParam があるか確認可能.
    // Vertex Program から ModelViewProj を取得してセット
    param = cgGetNamedParameter( vp, "ModelViewProj")

    Matrix m;
    cgGLSetMatrixParameterfr( param, m.f );

___

■ cgGLSetMatrixParameter

SYNTAX DESC uniform 型行列( 4 X 4 行列 )パラメータの設定をする。 r 接尾辞 行優先の順序で配置されていることを想定 c 接尾辞 行列が列優先の順序で配置されていることを想定する
___

■ cgGLSetStateMatrixParameter

SYNTAX void cgGLSetStateMatrixParameter( CGparameter param, GLenum type, // 行列の種類 GLenum transform // 追加の変換処理 ); DESC OpenGL の行列を直接わたす。 POINT 列, 行の指定はなく、Cg 側では列優先として行列が設定される。 つまり、位置を取得するには 第3列の値をとる。
  cgGLSetStateMatrixParameter( 
                              param,
                              CG_GL_MODELVIEW_MATRIX,
                              CG_GL_MATRIX_INVERSE
                              );
    uniform float4x4 eyepos;

    // 視線ベクトル
    E = float4( eyepos[0][3], eyepos[1][3], eyepos[2][3], eyepos[3][3] ) - IN.pos;
合成行列 CG_GL_MODELVIEW_PROJECTION_MATRIX モデルビュー行列 CG_GL_MODELVIEW_MATRIX 射影行列 CG_GL_PROJECTION_MATRIX 現在のテクスチャ CG_GL_TEXTURE_MATRIX パラメータ値の設定に使用する前にステートの行列に適用する変換を指定 変換を適用しない CG_GL_MATRIX_IDENTITY 行列を転置する CG_GL_MATRIX_TRANSPOSE 行列を逆にする CG_GL_MATRIX_INVERSE 行列に逆と転置の両方する CG_GL_MATRIX_INVERSE_TRANSPOSE cgGLGetParameter1f(CGparameter parameter, float* array); cgGLGetParameter1d(CGparameter parameter, double* array); cgGLGetParameter2f(CGparameter parameter, float* array); cgGLGetParameter2d(CGparameter parameter, double* array); cgGLGetParameter3f(CGparameter parameter, float* array); cgGLGetParameter3d(CGparameter parameter, double* array); cgGLGetParameter4f(CGparameter parameter, double* array); cgGLGetParameter4d(CGparameter parameter, type* array); void cgGLSetMatrixParameterfr(CGparameter parameter, const float* matrix); void cgGLSetMatrixParameterfc(CGparameter parameter, const float* matrix); void cgGLSetMatrixParameterdr(CGparameter parameter, const double* matrix); void cgGLSetMatrixParameterdc(CGparameter parameter, const double* matrix); void cgGLSetMatrixParameterArray{fd}{rc}( CGparameter param, long offset, long nelements, const TYPE * v ); cgGLSetParameterArray
___

■ パラメータ(parameter)

___

■ cgGLSetParameterArray4

SYNTAX cgGLSetParameterArray4( CGparameter param, long offset, // 配列 v の開始オフセット( 先頭からなら 0 ) long nr, // float4 型配列の要素数 const float * v // データ ); DESC 配列型パラメータに値をセットする。
    // スキニング行列を設定する。

    float m[] = {
          1, 0, 0, 200, 
          0, 1, 0, 0, 
          0, 0, 1, 0, 
          0, 0, 0, 1, 
          1, 0, 0, -400, 
          0, 1, 0, 0, 
          0, 0, 1, 0, 
          0, 0, 0, 1, 
    }

    param = cgGetNamedParameter( shdV, "m");
    cgGLSetParameterArray4f( param, 0, 2*4, m );
    v2f main(
            app IN,
            uniform float4 m[4*2]
            )
    {
      float4x4 mtx = float4x4( m[0],
                               m[1],
                               m[2],
                               m[3] );

      float4 pos = mul( mtx, IN.pos );
    }
___

■ cgGLSetParameter4fv

SYNTAX void cgGetNamedParameter( CGparameter, float *) DESC float N 型値をセットする
___

■ cgGLSetParameter

SYNTAX cgGLSetParameter

      CGparameter p = cgGetNamedParameter( db.createShd( "pe_dof.fsh" ), "testparam" );
      cgGLSetParameter4f( p, 1, 1, 0, 1 );

___

■ cgGetArraySize

SYNTAX int cgGetArrayDimension(CGparameter parameter); int cgGetArraySize( CGparameter p, int d ); CGparameter cgGetArrayParameter(CGparameter p, int idx ); DESC case CG_ARRAY: { // 0 次元目の 要素数 をかえす // // // // int arraySize = cgGetArraySize(p, 0); myas( 0, "not impl Array size %d", arraySize );
___

■ Cg


___

■ Profile.別性能表

DESC Profile とは Graphics 命令セットの種類のこと C, C++ で Target Machine を指定するのと同じ Cg Compiler にこの Hardware 用に Compile しろというのと同じ WARNING GPU によって利用できる命令セット, インストラクション数に限界がある コンパイルができても Load で失敗する可能性がある
    // foo.fsh(133) : error C5051: profile does not support conditional returns
    cgc -arbfp1 foo.fsh

    // vertex shader は tex2D 命令は support しない
    // foo.fsh(176) : error C3004: function "tex2D" not supported in this profile
    cgc -arbvp1 foo.fsh
___

■ 行列の積(mul)

POINT Cg の mul は次の順番で処理される。 mul( m, v ) は以下の計算結果になる。

  m00 m01 m02  vx      m00*vx + m01*vy + m02*vz
  m10 m11 m12  vy  ==  m10*vx + m11*vy + m12*vz
  m20 m21 m22  vz      m20*vx + m21*vy + m22*vz

WARNING // 可換ではない mul( v, m ) != mul( m, v )
    // Fragment Shader で確認できる

    float3x3 m = {
    { 1, 1, 1 },
    { 0, 0, 0 },
    { 0, 0, 0 },
    };

    {
      float3x3 m = {
        { 1, 0, 0 },
        { 1, 0, 0 },
        { 1, 0, 0 },
      };

      // 結果は白 ( 1, 1, 1 )になる。
      return float4( mul( m, float3(1,1,1) ), 1 );
    }
行列の変換がよく理解できなくなるため, 正解をかいておく Application::Mtx -> transpose -> Mul( mtx, vtx );

    Model -> World -> View -> Projection
      mul(m, IN.pos) mul(v, posW) mul( p, posV )

法線の変換 POINT N, T の関係から N の変換行列を求める。 T の変換は 位置の変換と同じ処理をする N.T = 0; Nw.Tw = Nw . (W*Tl) = (Wt * Nw) . Tl (a)bc (Nx) (Tl) (a)bc (Ny) = (Tl) (a)bc (Nz) (Tl) Nw . ( W[0].Tx, W[1].Ty, W[2].Tz ) ( Nx, Ny, Nz ) . ( W[0].Tx, W[1].Ty, W[2].Tz ) Nx には W[0] の成分がかかるから 左から 行列をかけるときは 転置して W[0] を縦に配置する Wt*Nw = Nl が成り立つ ( ) // 転置の逆行列 Nw = (Wt)-1 * Nl
___

■ shader.コツ

Constant Register 数に気をつける Matrix の積ではなく, dot ( 内積 )で代用する 命令数に気をつける
___

■ SYNTAX

POINT global 変数として定義しても良い。 この方が, 関数の引数よりもテストしやすいので利用すること

    // インクルード
    #include "common.h"

    // global として定義
    uniform float scl = 1;



    float4 main(
       // 仮引数として定義
       uniform float scl;
    )

マクロも使える
    // #define 
    #define  LIGHT_NUM  7


    #ifdef  _MAYA_

    #else

    #endif

    // 引き数つきマクロ
    #define  LIGHT_DECLARE( N )  float4  light_ ## N


    // C と同じく \ で複数行を連結する。
    #define  LIGHT_DECLARE( N )  float  normalmap_scale ## N \
    <  \
      UIName = "Nomalmap Scale" \
    > = {0.1f}

___

■ 行列

  // 成分のとり方
  float3 v = m._m03_m13_m23;

  // 1行目を取得。
  float3 v = m[0];
Cg 内の Matrix と 成分を調査 守ること. Application -> Cg に渡す際に transpose すること
      かける順番
      mul( m, v );

      次のように構成だと考えられる
      Ax  Ay  Az   T
     [00][01][02][03] (x)  = (Xnew + Tx)
     [10][11][12][13] (y)    (yNew + Ty)
     [20][21][22][23] (z)    (zNew + Tz)
     [30][31][32][33] (1)    (1)


  POINT
    mul( m, v )は 次の計算

    v.x = 0行目 ( m[0] ) * v
    v.y = 1行目 ( m[1] ) * v
    v.z = 2行目 ( m[2] ) * v
    v.w = 3行目 ( m[3] ) * v
[] 演算子は行列の行を取得する。 次の計算で確認できる。
  float4x4 m;

  m[0] = float4(1,1,0,0);
  m[1] = float4(0,1,0,0);
  m[2] = float4(0,0,1,0);
  m[3] = float4(0,0,0,1);

  //  { 1, 0.5, 0, 1 } == オレンジ色
  float s = 0.5f;
  OUT.col = mul( m, float4(s,s,0,1) );

  //  { 0.5, 1, 0, 1 } == ライトグリーン
  m[0] = float4(1,0,0,0);
  m[1] = float4(1,1,0,0);
  m[2] = float4(0,0,1,0);
  m[3] = float4(0,0,0,1);
  OUT.col = mul( m, float4(s,s,0,1) );

  // 成分指定 がどこを指すかチェック

  m[0] = float4(1,0,0,0);
  m[1] = float4(1,1,0,0);
  m[2] = float4(0,0,1,0);
  m[3] = float4(0,0,0,1);

  m._m10 = 0;    //  1行, 0 列
  m._m11 = 0;

  //    { 0.5, 0, 0, 1 }  Dark Red
  float s = 0.5f;
  OUT.col = mul( m, float4(s,s,0,1) );



  行列スウィズル演算子

  < type>< rows>x< columns> という形式の行列型の場合、

  matrix._m< row>< col>
  matrix._m< row>< col>[_m< row>< col>][...]


  という表記法を使用して、個々の行列要素にアクセスしたり(< row>< col>ペアが1つのみの場合)
  行列の要素からベクトルを構成したり(< row>< col>ペアが複数存在する場合)することができる。

  行と列の番号は0 から始まる


  // 連続で指定できる
  // Assign the main diagonal of myMatrix to myFloatVec4.
  fvec4 = myMatrix.m_00_m11_m22_m33;



  float4x4 a と宣言したとすると、a[3] は a._m30_m31_m32_m33 に等しくなる
  どちらの式も、行列の3 行目を取り出す



   // Az 成分( 列 )をとる
   float3 Az = m._m02_m12_m22;

   // Cg Reference より抜粋

   mul() は 3 つの使用方法がある。

   行列 × 列ベクトル
   mul(M, v);

   行ベクトル × 行列  
   mul(v, M);

   行列 × 行列  
   mul(M, N);


   // 次のような 記述になる 
   (m11 m21 m31 m41) (v1)
   (m12 m22 m32 m42) (v2)
   (m13 m23 m33 m43) (v3)
   (m14 m24 m34 m44) (v4)


  float3 eyevec_w = viewI._m03_m13_m23 - pos_w;
  OUT.test = float4( viewI._m03_m13_m23, 1.0f );

  float3x3 nmatrix = float3x3( tan, bin, nml );
  nmatrix[0] = tan;
  nmatrix[1] = bin;
  nmatrix[2] = nml;

  float4 a = float4( 1.236812, -0.714074, -0.866025, -0.577350 );
  float4 b = float4( 0.000000, 1.428148, -0.866025, -0.577350 );
  float4 c = float4( -1.236812, -0.714074, -0.866025, -0.577350 );
  float4 d = float4( 1.785185, 0.507938, -68.817703, 120.788200 );

  // float4 から matrix 生成
  float4x4 mtxLit = float4x4( a, b, c, d );

  float4 a = float4(1,2,3,1);
  return float4(a[0], a[1], a[2], 1 );

  // 要素をえる( 0 行 0 列 )
  float4x4 m;
  float f = m[0][0];

___

■ Reference(Cg)

___

■ floor

SYNTAX floor( f ) DESC f 以下の最大の整数 浮動小数点 の 整数部 をとりだす
___

■ frac

SYNTAX frac( f ) DESC f の小数部
___

■ cross

SYNTAX cross(float3 a, float3 b) DESC ベクトル a と b の外積 a から b への外積 a = 1, 0, 0 b = 0, 1, 0 0 0 1 0 0 1 ----- 0 0 1 0 1 0 1 0 0 ----- 0 0 0 1 0 0 0 1 0 ----- 0 0 1 0 0 1 ------ -1 c = a * b の定義 ( aからbまで回す右ねじの進む向き) a.y*b.z + a.z * b.x + a.x + b.y - b.y*a.z + b.z*a.x + + b.x*a.y
    float3 cross(float3 a, float3 b)
    {
      return a.yzx * b.zxy - a.zxy * b.yzx;
    }

    // fragment shader で試すと 青
    return float4( cross( float3(1,0,0), float3(0,1,0) ), 1 );

    // 黒
    return float4( cross( float3(0,1,0), float3(1,0,0) ), 1 );
___

■ lerp

SYNTAX lerp(a, b, f) DESC (1-f)*a + f*b TIP WARNING 描画結果が正しくない現象が見られる 自前で計算した方が無難
___

■ reflect

SYNTAX floatN reflect( floatN i, floatN n); DESC param n: Normal ( 要 normalize ) param i: IncidentVector WARNING i は VtxPos - EyePos Lighting 時とは逆向き の Vector PROFILE fp20
___

■ tex2Dproj

SYNTAX tex2Dproj (sampler2D tex, float4 sq); DESC Texture 座標を W=1 の空間に変換後に sampling する PROFILE PS20 シャドウマップルックアップ: テクスチャ座標のz 成分が、シャドウマップと比較する深度値を保持 シャドウマップルックアップでは 深度比較テクスチャリングのためにアプリケーションにより構成された関連テクスチャのユニットが必要 これがないと、深度比較は実際に実行されない
___

■ clamp

SYNTAX clamp(x, a, b) DESC x < a = x = a x > b = x = b else x;
___

■ abs

SYNTAX abs(x) DESC abs(x) x の絶対値
___

■ length

SYNTAX float length( floatN vec ) DESC vec の長さ( ノルム )を返す
    float length( float3 vec ) {
      return sqrt( dot(vec, vec) );
    }
___

■ exp

SYNTAX exp(x) DESC Euler ^ x
___

■ exp2

SYNTAX exp2(x) DESC 2^x
___

■ step

SYNTAX floatN step( floatN a, floatN x) DESC x >= a となる階段関数で変換した値を返す。
___

■ normalize

SYNTAX normalize(x) DESC N次元ベクトルを正規化する
___

■ 高速化


___

■ 頂点共有をする

GL_LINE_LOOP GL_LINE_STRIP 頂点を共有するため, 頂点変換の Pipeline を軽減できる GL_QUADS : 8 頂点 GL_QUAD_STRIP : 6 頂点
___

■ グラフィックカードのメモリを利用する

グラフィック用のハードは専用のメモリをもつ。 メインメモリからグラフィック用のメモリへの転送はとても時間がかかるので 初期化のタイミングでグラフィックメモリに形状、テクスチャを転送しておく。 REFERENCE 頂点バッファオブジェクト
___

■ GPUの終了まちを避ける

GPU と CPU は独立したハードウェアのため、CPU から GPU へ投げた仕事を CPU 側が待つ時間を有効に使う。
___

■ ライティングを高速化する

Cg シェーダを使うときは 、コンパイルしたアセンブラをみて、命令数をチェックしてみる。 ライティングについては、各頂点をワールド、視線空間へ変換せずにローカル座標にもっていく。 こうすると、 N 頂点の変換ではなく、1 個のライトベクトルの変換ですむ。
___

■ デプステスト(DepthTest)


___

■ DepthBuffer(デプスバッファ)

DESC OpenGL は DepthBuffer による陰面消去アルゴリズムをサポートする。 DepthBuffer とは画素ごとに Z 座標を記録する領域のこと。 利用するには Window を作成時に DepthBuffer を用意する Window 空間での z 値より小さい Fragment は破棄される Application が DepthTest を OFF にすると 後でかいた Primitive によって上書きされる DEFAULT OFF
h

    // ON ( DEFAULT: OFF )
    glEnable( GL_DEPTH_TEST );

    // Detph Test を指定 ( DEFAULT: GL_LESS )
    glDepthFunc( GL_LEQUAL );
Z 値の変換式
          1 
    -------------
      n - f
___

■ 半透明の描画

___

■ Performance


  POINT
    Tuning 前に 自分の環境の 期待できるか知っておくこと
    速さは十分かどうか 知ること


  POINT
    OpenGL は ClinetServer 型のため Command を内部で Buffering する
     実行前に, App に制御がもどる

    測定時にはこの動作は困る

    そこで glFinish() ですべての glCommnd の終了待ちをする
    ( glFinish == GL との同期処理 )


    const int s = glutGet( GLUT_ELAPSED_TIME );

    // N Frame 描画
    Render();
    glFinish();

    const int e = glutGet( GLUT_ELAPSED_TIME );

___

■ PipeLine の限界を測定する

POINT OpenGL は PipeLine Architecture 頂点 Pass と Fragment Pass がある POINT 先ずは 不要な処理をしてないかチェックする。 以下は Fill 限界に影響する GL_ALL_TEST GL_DITHER GL_MULTISAMPLE POINT 幾何形状限界 頂点を PipeLine に送らないようにする Frustum Culling GL_CULL_FACE Fill 限界 Texture Size を小さくして VRAM にのせる Texture Addressing を Mipmap Nearest に変更して Fetch 回数を減らす 上書きする Pixel 量を減らす ( 手前からかく ) State 変更 不要な State の変更は避ける
___

■ FrameBuffer



___

■ 画面をキャプチャする

glReadPixels() を利用して画面をClientMemoryにコピーする

    void App::draw() {
    
    // 何か FrameBuffer に描く
      draw();

      // 適当なイベントで実行する
      if ( mouseEvent )
      {

        const int sz = 800 * 600 * 4;
        byte[] buf = new byte[ sz ];

        // サイズ 800, 600 の画面を buf へコピーする
        glReadPixels( 0, 0, 800, 600, GL_RGBA, GL_UNSIGNED_BYTE, buf );               

        // Fileに出力する
        FILE *fp = fopen( "capture.raw", "wb" );
        fwrite( buf, sz, 1, fp );
        fclose(fp);

        delete[] buf;
      }
    }
___

■ glReadPixels

SYNTAX void glReadPixels( int x, int y //読み取る領域の左下隅の Window空間の x, y座標 unsigned int width, height //読み取る領域の幅, 高さ GL_BGRA, //取得したい色情報の形式() GL_UNSIGNED_BYTE, //読み取ったデータを保存する配列の型 void *buf //データを保存する配列へのポインタ ); DESC Framebuffer の内容をクライアントメモリへ Copy する WARNING この処理は、かなりの負荷がかかる Default は BackBuffer から得る この Command は 終了するまで制御を返さない そして GL の Pipeline をすべて Flush する
    App::init() {


    //画像(読み取る領域)のピクセル数
    int nr = w * h;

    // 1 Pixel 要素数 ( RGB 3  RGBA 4 )
    int format = 4; //rgba

    // バッファから読み取ったデータを格納する配列
    byte[] buf = new byte[nr * format];


    //読み取るバッファを指定
    //バックバッファを読み取る
    //フロントバッファを読み取りたい GL_FRONT を指定
    glReadBuffer( GL_BACK );


    // ClientMemory への Pack ( 詰め込み )方法の指定
    //  Defalut ( GL_RGBA, GL_UNSIGNED_BYTE )は 密にセットする
    //
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );


    // FrameBuffer image を使う Texture Object
    glGenTextures( 1, &gId );
    glBindTexture( GL_TEXTURE_2D, gId );

    }

    App::draw() {

        // Scene を描画
        drawScene();

        // FrameBuffer から Pixel Data 取得
        glReadPixels(
                     500,                 //読み取る領域の左下隅のx座標
                     500,                 //読み取る領域の左下隅のy座標
                     SW,             //読み取る領域の幅
                     SH,            //読み取る領域の高さ
                     GL_RGBA,           //取得したい色情報の形式()
                     GL_UNSIGNED_BYTE,  //読み取ったデータを保存する配列の型
                     gBuf     //読み取ったデータを保存する配列
                     );


        // Image の更新
        glBindTexture( GL_TEXTURE_2D, gId );
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, SW, SH, 0,
                      GL_RGBA, GL_UNSIGNED_BYTE, gBuf );


        // 一度かいた絵を利用して何かする
        draw();
    }
___

■ glReadBuffer

SYNTAX void glReadBuffer( GLenum target ) DESC 読み取るバッファを指定 glReadPixels() などに影響する

    // 最初の 1 回目の描画は FrontBuffer には未初期化の画像があることがわかる
    glReadPixels( GL_FRONT );

___

■ glPixelStorei

SYNTAX void glPixelStorei(GLenum pname, GLint val) DESC set pixel storage modes Main Memory と OpenGL 側の Memory でデータを転送するときに Data がどのように配置( Alignment )されているか教える 1, 2, 4, 8 を指定できる 初期値は 4 この数が 大きいほど 効率的に Data を転送できる DEFAULT 4 POINT unpack とは Application が GL に Pixel Data を送り出す時の指定方法 "store" 命令 と考えれば OK GL_UNPACK_ALIGNMENT Specifies the alignment requirements for the start of each pixel row in memory. The allowable values are 1 (byte-alignment), 2 (rows aligned to even-numbered bytes), 4 (word-alignment), 8 (rows start on double-word boundaries). The initial value is 4. // ClientMemory から Read する方法を指定する // だから glTexImage2D() にとってとても重要



  // バッファの読み取り方を指定する
  // Alignment を指定する
  // glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );


  WARNING
  //  1 Pixel 3 byte の raw format を利用するときは必須

  glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
  void *img = readRawTexture( "./test.raw" );

___

■ glCopyPixels

SYNTAX glCopyPixels( int x, y, // 読み取り位置 unsigned int w, h, // 大きさ int type // Copy する Buffer の指定 ( GL_COLOR | GL_DEPTH | GL_STENCIL ) ); DESC 指定した Buffer を RasterPos の位置に Copy
___

■ glCopyTexImage2D

SYNTAX void glCopyTexImage2D( int tgt, int lvl, int ifmt, // Copy すべき対象を指定する // GL_LUMINANCE : 輝度値のみ // TextureObject にも DepthBuffer がある int x,y,w,h, // Copy する FrameBuffer の矩形 // FrameBuffer( ReadBuffer ) の 左下.w, h は, FrameBuffer の左下からの サイズ. // 小さい値をセットすれば当然きれる ( 観測すみ. ) int border ); DESC FrameBuffer( BackBuffer )から 画像data を TextureObject に Copy する MultiPath には必須の API TIP parameter は glTexImage2D() と同じ pixel data の転送元が異なるだけ ARG3 : ReadBuffer からどの値をとるよーという宣言. -> BackBuffer は, RGB + DEPTH だったから別々にとることも可能. -> Texture も Buffer だから どんな内部構成( ifmt )にするかの指定が可能 WARNING w, h は 2冪.(VER:2.0 ) 画面全体を copy するならば, 2 冪でないとだめ ?

    // Depth 値もとれる
    glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16,
                        0, 0, vpW, vpH, 0 );


    // Copy 先の Texture Object を選択
    glBindTexture( GL_TEXTURE_2D, id );


        if ( 0 ) {
          glReadPixels(
                       500,                 //読み取る領域の左下隅のx座標
                       500,                 //読み取る領域の左下隅のy座標
                       SW,             //読み取る領域の幅
                       SH,            //読み取る領域の高さ
                       GL_RGBA,           //取得したい色情報の形式()
                       GL_UNSIGNED_BYTE,  //読み取ったデータを保存する配列の型
                       gBuf     //読み取ったデータを保存する配列
                       );


          // Image の更新
          glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, SW, SH, 0,
                        GL_RGBA, GL_UNSIGNED_BYTE, gBuf );

        }
        else {
          // こちらの方が高速
          glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
                            500, 500, SW, SH, 0 );
        }
___

■ glCopyTexSubImage2D

SYNTAX glCopyTexSubImage2D( GLenum target, GLint level, GLint x, y, // Copy 先の Texture の位置 GLint x, y, // Copy 元の FrameBuffer の位置と大きさ GLsizei w, h ) WARNING CubeMap には 裏側から利用するため Texture を反転する
___

■ スプライト(Sprite)


  SAMPLE
     スプライト 
     加算処理のスプライト 
     . 

  POINT
    再利用性を高めるためにクラスにまとめること


    #define W  1024
    #define H  512 

    App::onDraw() {
      
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

      // 3Dシーンの描画
      draw3D();

      // デプステストを無効にする。
      glDisable( GL_DEPTH_TEST );

      // テクスチャの透明色の部分を透過させるためブレンディングを有効にする
      glEnable( GL_BLEND );
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

      // 2Dを描画するための変換行列を設定する
      // 画面サイズと同じ大きさの等角投影を設定しておくと、スプライト位置の指定が簡単になる。
      // 奥行きは適当。
      glMatrixMode( GL_PROJECTION );
      glLoadIdentity();
      glOrtho( 0, W, 0, H, 0, 1 );
      
      // モデルビュー変換は不要
      glMatrixMode( GL_MODELVIEW );
      glLoadIdentity();

      // スプライトテクスチャを描画して FPS を描画
      glEnable( GL_TEXTURE_2D );
      glBindTexture( GL_TEXTURE_2D, id );

    }



___

■ スプライトを利用したGUIボタン

SAMPLE GUIボタン
___

■ 頂点スキニング


  SAMPLE
     頂点スキニング 
     頂点スキニングを使ったバネモデル 





    App::onDraw() {

      float m0[16], m1[16];

      // 現在の骨の位置に移動する。
      glLoadIdentity();
      glTranslatef( 0, 50, 0 );

      // 回転する。
      glRotatef( m_timer, 0,0,1 );
      
      // 骨の位置を基準(Pivot)にして回転するため、逆行列をかけて原点に移動する。
      glTranslatef( 0, -50, 0 );

      glGetFloatv( GL_MODELVIEW_MATRIX, mb0 );


      // 2番目の骨も同じように計算      
      glLoadIdentity();
      glTranslatef( 100, 50, 0 );
      glRotatef( m_timer, 0,0,1 );
      glTranslatef( -100, -50, 0 );
      glGetFloatv( GL_MODELVIEW_MATRIX, mb1 );


      {
        CGparameter param;

      // 頂点シェーダで変形させるため、骨の行列をシェーダに渡す。
        float m[] = {
          m0[0], m0[4], m0[ 8], m0[12],
          m0[1], m0[5], m0[ 9], m0[13],
          m0[2], m0[6], m0[10], m0[14],
          m0[3], m0[7], m0[11], m0[15],

          m1[0], m1[4], m1[ 8], m1[12],
          m1[1], m1[5], m1[ 9], m1[13],
          m1[2], m1[6], m1[10], m1[14],
          m1[3], m1[7], m1[11], m1[15],
        };

      param = cgGetNamedParameter( shdV, "m");
      cgGLSetParameterArray4f( param, 0, 2*4, m );

      
      // モデルビュー, プロジェクションを渡す。
      glMatrixMode( GL_MODELVIEW_MATRIX );
      glLoadIdentity();
      convertCameraSpace();

      param = cgGetNamedParameter( shdV, "mvp");
      cgGLSetStateMatrixParameter( param,
                                   CG_GL_MODELVIEW_PROJECTION_MATRIX,
                                   CG_GL_MATRIX_IDENTITY
                                   );
      }

      // 描画する。( ウェイトの値は glNormal で指定しておく。 )
      glBegin( GL_TRIANGLE_STRIP );
      {
        glColor4f(1,1,1,1);
        for( int j=0; j< 2*7; j++ ){

          // ウェイト値
          float w0 = 1 - 1/7.0f*(j/2);
          float w1 = 1 - w0;
          glNormal3f( w0, w1, 1 );


          float x = 2*(w1 - 0.5f) * 100;
          float y = 100 * (j%2);
          glVertex3f( x, y, 0 );
        } 
      }      
      glEnd();            
    }
頂点シェーダで頂点を変形する

  float4x4 mtx0 = float4x4( m[0], m[1], m[2], m[3] );
  float4x4 mtx1 = float4x4( m[4], m[5], m[6], m[7] );

  // ウェイト
  float w0 = IN.nrm.x;
  float w1 = IN.nrm.y;

  // 変形
  float4 p = w0 * mul( mtx0, IN.pos ) + w1 * mul( mtx1, IN.pos );

  // モデルビュープロジェクション変換
  OUT.pos = mul( mvp, pt );
___

■ CPUで変形する

CPUで計算するには頂点座標を指定する( glVertex() )前に変換をしておく。
    float v[2*7*3];

    for( int j=0; j< 2*7; j++ ){
      // ウェイト値
      float w0 = 1 - 1/7.0f*(j/2);
      float w1 = 1 - w0;

      float x = 2*(w1 - 0.5f) * 100;
      float y = 100 * (j%2);


      // 行列とベクトルの積
      multiMatrix( mb0, v0, v0 );
      multiMatrix( mb1, v1, v1 );
          
      // ウェイトをかけてブレンドする
      v[3*j+0] = w0*v0[0] + w1*v1[0];
      v[3*j+1] = w0*v0[1] + w1*v1[1];
      v[3*j+2] = 0;
    }

    glBegin( GL_TRIANGLE_STRIP );
    glColor4f(1,1,1,1);
    for( int j=0; j< 2*7; j++ ){
      // 事前計算した頂点を指定する
      glVertex3fv( v + 3*j );
    }      
    glEnd();            
行列とベクトルの積には glMultMatrix() を利用する。
    void multiMatrix( const float *m, float *v, float *vout ) {

      glMatrixMode( GL_MODELVIEW );
      glLoadMatrixf( m );

      float mt[16] = {
        v[0], v[1], v[2], 1, // 第1列をベクトル扱いにする。
        0, 0, 0, 0,          // 残りの3列は仮
        0, 0, 0, 0,
        0, 0, 0, 0,
        };

      // 右からかける
      glMultMatrixf( mt );  

      // 計算結果として行列同士の積の結果の第一列を取得する
      glGetFloatv(GL_MODELVIEW_MATRIX, mt );
      vout[0] = mt[0];  
      vout[1] = mt[1];
      vout[2] = mt[2];
    }
___

■ 頂点配列でウェイトを指定する

頂点の属性としてウェイトを指定するには glVertexAttribPointer() を利用して 汎用型の属性のひとつとして指定する。

    App::onInit() {
      glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");
    }

    #define ATTR1   1

    App::onDraw() {

        struct Vertex {
          float pos[3];
          float col[3];
          float weight[4];
        };

       Vertex v[2*NR];

       {
         for( int i=0; i< 2*NR; i++ ){
           float w0 = 1 - 1.0f/(NR-1)*(i/2);
           float w1 = 1 - w0;
           float x = 2*(w1 - 0.5f) * 100;
           float y = 100 * (i%2);

           v[i].pos[0] = x;
           v[i].pos[1] = y;
           v[i].pos[2] = 0;

           v[i].col[0] = 1;
           v[i].col[1] = 0;
           v[i].col[2] = 0;

           v[i].weight[0] = w0;
         } 
       }

      glEnableClientState( GL_VERTEX_ARRAY );
      glEnableClientState( GL_COLOR_ARRAY );
      glEnableVertexAttribArray( ATTR1 );

      glVertexPointer( 3, GL_FLOAT, sizeof(Vertex),  v );
      glColorPointer ( 3, GL_FLOAT,  sizeof(Vertex), v[0].col );
      glVertexAttribPointer( ATTR1, 1, GL_FLOAT, false, sizeof(Vertex), v[0].weight );

      // シェーダを有効にする。
      cgGLEnableProfile( pfV );

      glDrawArrays( GL_TRIANGLE_STRIP, 0, m_nr*2 );
    }
頂点シェーダではアプリケーションで指定した頂点インデックスからウェイトを取得する。
   struct app {
     float4 pos     : POSITION;
     float4 weight  : ATTR1;
   };
    
  float4x4 mtx0 = float4x4( m[0], m[1], m[2], m[3] );
  float4x4 mtx1 = float4x4( m[4], m[5], m[6], m[7] );

  // ウェイト
  float w0 = IN.weight[0]
  float w1 = 1 - w0;

  // 変形
  float4 p = w0 * mul( mtx0, IN.pos ) + w1 * mul( mtx1, IN.pos );

  // モデルビュープロジェクション変換
  OUT.pos = mul( mvp, p );
___

■ ステンシル(Stencil)


  SAMPLE
     ステンシル 

  DESC
    ステンシルバッファを使うと輪郭の切り出しなどの、特殊エフェクトができる。


    ステンシルバッファを設定する。
      // 8 bit サイズで指定する。    
      pfd.cStencilBits = 8;

      int fmt = ChoosePixelFormat( hDC, &pfd );
      SetPixelFormat( hDC, fmt, &pfd );

最初にステンシル(型)をつくるため、輪郭にしたいオブジェクトを描画する。 次に 作成したステンシルとテストをして、描画する画面を切り抜く。

    glEnable( GL_STENCIL_TEST );

    glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE  );
    glStencilFunc( GL_ALWAYS, 0xff, 0xff );

    // 型紙をつくるにはオブジェクトを描画する
    drawPlane();

    
    // ステンシルで切り抜く。( 0xff と同じ値のピクセルが描画される。 )
    glStencilFunc( GL_EQUAL, 0xff, 0xff );
    glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP  );

    // 移りこみを表現するため、ワールド座標でY軸反転する。
    glScalef( 1, -1, 1 );
    glTranslatef( 0, 100, 0 );
    drawCube();
    
    
    // 通常のオブジェクトを描画する。
    glDisable( GL_STENCIL_TEST ); 
    drawCube();
___

■ glStencilOp

SYNTAX void glStencilOp( GLenum sfail, // ステンシルテストが失敗したピクセルに対する処理 GLenum dpfail, // ステンシルテストに合格したが デプステストに失敗したピクセルに対する処理 GLenum dppass // デプステストまで合格した( またはデプステスト無効 )ピクセルに対する処理。 ) DESC ステンシルバッファへの処理を指定する。 3つの引数で、各テストに合格、不合格したピクセルごとに処理を設定できる。 set front and back stencil test actions Stenciling, like depth-buffering, enables and disables drawing on a per-pixel basis. You draw into the stencil planes using GL drawing primitives, then render geometry and images, using the stencil planes to mask out portions of the screen. Stenciling is typically used in multipass rendering algorithms to achieve special effects, such as decals, outlining, and constructive solid geometry rendering. 次の8つの処理ができる。 GL_KEEP : 何もしない。 GL_REPLACE : glStencilFunc() の ref で指定した値で置き換える。
___

■ glStencilFunc

SYNTAX void glStencilFunc( GLenum func, // テスト演算子の指定 GLint ref, // テストで比較する値 GLuint mask // テスト実行前にステンシル値と ref の両方に bit mask する値 ) DESC ステンシルテストの方法を設定する。 Specifies the test function. Eight symbolic constants are valid: GL_NEVER, GL_LESS, GL_LEQUAL, GL_GREATER, GL_GEQUAL, GL_EQUAL, GL_NOTEQUAL, and GL_ALWAYS. The initial value is GL_ALWAYS.
___

■ glClearStencil

SYNTAX void glClearStencil( GLint s) // Specifies the index used when the stencil buffer is cleared. The initial value is 0. DESC ステンシルバッファのクリアする値を指定する。 glClearStencil specifies the index used by glClear to clear the stencil buffer. s is masked with m 2 - 1 , where m is the number of bits in the stencil buffer.
___

■ FrameBufferObject(FBO)


  SAMPLE
     フレームバッファオブジェクト 



    初期化時に FrameBufferObject を作成する
    App::onInit() {
      
      // フレームバッファオブジェクトを作成する
      glGenFramebuffersEXT( 1, idFbo );

      // fbo にアタッチするテクスチャオブジェクトを作成する                            
      glGenTextures( 1, idTex );
      glGenTextures( 1, idDepth );

      // カラーバッファ
      glBindTexture( GL_TEXTURE_2D, idTex );
      glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );

  WARNING 
      // fbo に利用するテクスチャも 初期化の設定を正しく設定しないと
      // 2パス目の描画でバインドしたときに正しく描画されない
      {
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexEnvf ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
      }

       // 深度バッファを作成
       glBindTexture( GL_TEXTURE_2D, idDepth );
       glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL );

       // テクスチャをフレームバッファオブジェクトにバインド
       glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, idFbo );
       glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, idTex, 0 );
       glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D,  idDepth, 0 );

       // デフォルトのレンダーターゲットに戻す
       glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
    }
1パス目の描画で FrameBufferObject に描画する。 2パス目でその結果をバインドしたテクスチャを利用する。

    App::onDraw() {

      // バッファを変更
      glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, idfbo );
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

      // ハコを描画
      drawCube();
      

      // 描画した結果を利用して 2 パス目を描画

      // デフォルトのレンダーターゲットに戻し、ディスプレイに描画
      glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
      
      glBindTexture( GL_TEXTURE_2D, idTex );

      drawCube();
    }
___

■ glBindFramebufferEXT

SYNTAX void glBindFramebuffer( GLenum target, // GL_DRAW_FRAMEBUFFER | GL_READ_FRAMEBUFFER | GL_FRAMEBUFFER GLuint framebuffer // FrameBufferObject の ID ); DESC FrameBuffer で指定した fbo を target に設定する。 target は 3つのいずれかひとつ。 GL_DRAW_FRAMEBUFFER 描画の対象になる GL_READ_FRAMEBUFFER テクスチャへの読み込み処理の対象にする
    // target に GL_FRAMEBUFFER を指定すると, 描画( draw ) と テクスチャへの読み込み( read )の両対応になる
    


    // fbo オブジェクトは glGenFramebuffers() で作成する

  POINT
    // 0 を指定すると fbo オブジェクトの設定を解除する
    // デフォルトに戻すときは必ずコールすること
    glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
___

■ glGenFramebuffers

SYNTAX void glGenFramebuffers( GLenum target, // GL_DRAW_FRAMEBUFFER | GL_READ_FRAMEBUFFER | GL_FRAMEBUFFER GLuint framebuffer // FrameBufferObject の ID );
___

■ glFramebufferTexture

void glFramebufferTexture2D( GLenum target, GLenum attachment, // FrameBufferObject へバインドする場所 GLenum textarget, // アタッチするテクスチャオブジェクトのタイプ GLuint texture, // Specifies the texture object to attach to the framebuffer attachment point named by attachment. // アタッチ(設定)する TextureObject GLint level // アタッチする TextureObject のミップマップレベルの指定 ); DESC attach a level of a texture object as a logical buffer to the currently bound framebuffer object glFramebufferTexture, glFramebufferTexture1D, glFramebufferTexture2D, attach a selected mipmap level or image of a texture object as one of the logical buffers of the framebuffer object currently bound to target. target must be GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, or GL_FRAMEBUFFER. GL_FRAMEBUFFER is equivalent to GL_DRAW_FRAMEBUFFER. attachment で FrameBufferObject のどこにテクスチャをバインドするか指定する 次のいずれか GL_COLOR_ATTACHMENTi, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT GL_DEPTH_STENCIL_ATTACHMMENT. i in GL_COLOR_ATTACHMENTi は以下の範囲 [ 0 : GL_MAX_COLOR_ATTACHMENTS - 1 ] Attaching a level of a texture to GL_DEPTH_STENCIL_ATTACHMENT is equivalent to attaching that level to both the GL_DEPTH_ATTACHMENT and the GL_STENCIL_ATTACHMENT attachment points simultaneously. textarget specifies what type of texture is named by texture, and for cube map textures, specifies the face that is to be attached. If texture is not zero, it must be the name of an existing texture with type textarget, // cubemap でなければ unless it is a cube map texture, in which case textarget must be GL_TEXTURE_CUBE_MAP_POSITIVE_X GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z. texture If texture is non-zero, the specified level of the texture object named texture is attached to the framebfufer attachment point named by attachment. For glFramebufferTexture1D, glFramebufferTexture2D, and glFramebufferTexture3D, texture must be zero or the name of an existing texture with a target of textarget, or texture must be the name of an existing cube-map texture and textarget must be one of GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z.
___

■ 衝突判定


___

■ OBB.OBB

SAMPLE OBB 同士の衝突判定
___

■ 空間分割

SAMPLE 空間分割 固定サイズの配列を用意して、点の場所ごとに仕分けをする。 各ボックス内にある点同士で判定をする。 総当りの数を減らす。 1000 個ならば 1000 * 1000 で 100 万回の判定をする。 4 分割して 250 個ならば (* 250 250 4) 250.000 16 分割して 62 個ならば, 6 万回の判定をする。 (* 62 62 16) 61.500 1/4 ずつに減っていく 処理の順番 当たるなら動かない 1. 動く予定をしらべる 1. 当たった場合は動かない 3. あたる方向の成分をなくして 当たらない方向だけ移動する ( これをしないと 斜めに入力したときに, 完全に動かなくなる ) ( 重力がある場合も同じ ) ---- | | ----> ------------------------------ | v 直方体どうしのあたり判定では , 斜めの表現はできない
___

■ k-dTree

均等分割は 一様に分布していないと性能が落ちる。 k-dTree は2分木で空間を分割する。 再帰的に空間を2つに分割していく。
___

■ sort

ソートする場合は 右から左に順番に検索していく。
    ---------        ----------
        ----------------
                ----

左側にマッチしたら リストに追加 右側にマッチしたら リストから削除( 領域から抜けたということ ) リスト内にあるものを判定する 動くもの同士の総当りを高速化する。 N*log(N) * N
___

■ 箱どうし

SAMPLE 箱どうしの衝突判定 矩形どうしが当たる場合は XY 軸ともに重なっている必要がある。 当たらない条件を考えると
    A                B
    =========        ===========
    A.right    <      B.left
    
    または

    B                A
    =========        ===========
    B.right    <      A.left

    A.right <  B.left  ||  B.right <  A.left
これの偽だから
    A.right >= B.left  &&  B.right >= A.left

                    A
                   ===========
            ============    
            B
    bool testBoxBox( Box &a, Box &b ) ) 
    {
      if ( a.right >= b.left  &&  b.right >= a.left ) {
        if ( a.top >= b.bottom  &&  b.top >= a.bottom ) {
          return true;
        }
      }
      return false;
    }
当たった場合の処理として 動かないという対応がある。 この場合、移動するスピードが十分に小さければ、 隙間も目立たないので補正が不要という考えもある。 移動速度をあげると隙間が目立つ。 速度を上下するとわかる。 SAMPLE 衝突結果として動かない この場合、斜めに移動をして衝突した場合も動けなくなる。 Y 方向の移動が 重力などの場合は 一切動けなくなる。
___

■ 位置の補正

SAMPLE 位置の補正 あたる直前の位置に補正するには、当たった後に重なった長さ分だけ元に戻す。 WARNING XY 2軸同時に移動をする場合は、各軸独立して移動してから2回補正をする必要がある。 そうしないと横、縦方向にはじかれることになる。
___

■ 移動と速度

SAMPLE 移動と速度 最初に速度を変更して、それから位置を更新する。
    vy += 0.1f;
    ty += vy;
___

■ 球球

2 点の中心の距離をもとめる
___

■ 三角形と線分

地面などに立つ場合につかう POINT あるフレームでの移動において使うことがポイント こうすることで貫通が起きない 球と三角形では抜ける可能性がある 線分上のある点と 三角形上のある 点が一致するパラメータを求めればいい a + t*b = c + u*X * v*Y 求めたい 未知数は 3 つ 3つの式が必要 無限平面でかんがえる p = a + t*b となる p が平面にあれば (p - c) は N と垂直である N, c は定数としてもとまるので, パラメータ t だけが求まる 内積をつかうと n.( c - p ) = 0 n . ( c - a + t*b ) = 0 n.c - n.a + t*n.b = 0 // 1次方程式 n.c - n.a t = ------------- // t が求まる. 0:1 であるかチェックをする n.b n.b = 0 とならないようにチェックすること 幾何学的な意味は N と b が平行なので当然、 交わらないということ p = c + u*d + v*e ベクタをスカラに変換するために 内積 を使える // 1 次連立方程式 g.d = u*d.d + v*d.e g.e = u*d.e + v*e.e 地道にとく u を消すような 係数を 2 つの式にかける v = ---------------






金利比較.COM
NINJAIDX 9