2014年12月18日木曜日

7.5.MMD Open GL シャドウ(ステンシルバッファ)

7.4の動画は影をつけてしまっていました。
OpenGLのステンシルバッファを利用して影を表示しています。以下コード。

#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

#ifdef _DEBUG
#pragma comment(lib,"../../freeglut-2.8.1/lib/x86/Debug/freeglut.lib")
#pragma comment(lib,"../../glew-1.11.0/lib/Debug/Win32/glew32d.lib")
#pragma comment(lib,"../../bullet3-master/bin/BulletCollision_vs2010_debug.lib")
#pragma comment(lib,"../../bullet3-master/bin/BulletDynamics_vs2010_debug.lib")
#pragma comment(lib,"../../bullet3-master/bin/LinearMath_vs2010_debug.lib")
#else
#pragma comment(lib,"../../freeglut-2.8.1/lib/x86/freeglut.lib")
#pragma comment(lib,"../../glew-1.11.0/lib/Release/Win32/glew32.lib")
#pragma comment(lib,"../../bullet3-master/bin/BulletCollision_vs2010.lib")
#pragma comment(lib,"../../bullet3-master/bin/BulletDynamics_vs2010.lib")
#pragma comment(lib,"../../bullet3-master/bin/LinearMath_vs2010.lib")
#endif

#include <GL/glut.h>
#include "../BulletPhysics/BulletPhysics.h"
#include "../MMD/PMDModel.h"
#include "../MMD/VMDMotion.h"

extern cBulletPhysics g_clBulletPhysics;
static cPMDModel g_clPMDModel;
static cVMDMotion g_clVMDMotion;
static Matrix  g_matPlanarProjection;

//----------------------------------------------------
void Initialize(void)
{
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    glClearStencil( 0 ); // ステンシル用。
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_NORMALIZE);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_FRONT);
    const float fLightPos[] = { 0.45f, 0.55f, 1.0f, 0.0f };
    const float fLightDif[] = { 0.9f, 0.9f, 0.9f, 1.0f };
    const float fLightAmb[] = { 0.9f, 0.9f, 0.9f, 1.0f };
    glLightfv(GL_LIGHT0, GL_POSITION, fLightPos);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, fLightDif);
    glLightfv(GL_LIGHT0, GL_AMBIENT, fLightAmb);
    glLightfv(GL_LIGHT0, GL_SPECULAR, fLightAmb);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
    { // ステンシル用
        Vector4  vec4Plane = { 0.0f, 1.0f, 0.0f, 0.0f };
        Vector3  vec4LightPos = { 10.0f, 70.0f, -20.0f };
        MatrixPlanarProjection( g_matPlanarProjection, &vec4Plane, &vec4LightPos );
    }
    g_clBulletPhysics.initialize();

    SetCurrentDirectory("../models/xxx/");             // ファイルをアクセスためのパスを設定。Release/***.exeから考える。
    g_clPMDModel.load("xxx.pmd");              // PMDファイルを登録
    g_clVMDMotion.load("../motion/xxx.vmd");          // VMDファイルを登録
    g_clPMDModel.setMotion(&g_clVMDMotion, false); // モデルをモーションに紐付け
    g_clPMDModel.updateMotion(0.0f);               // プレイ時間を初期化
    g_clPMDModel.resetRigidBodyPos();              // モデルを初期化

    glClearColor(0.0, 1.0, 1.0, 1.0); //背景色
}
//----------------------------------------------------
static float lscalef = 1.0f;
void Display(void)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective( /* field of view in degree */ 40.0,/* aspect ratio */ 1.0,/* Z near */ 1.0, /* Z far */ 500.0);
    gluLookAt(0, 20, 50,  /* eye is at (0,0,5) */ 0.0, 10.0, 0.0, /* center is at (0,0,0) */ 0.0, 1.0, 0.); /* up is in positive Y direction */
    glEnable( GL_LIGHTING );
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_NORMALIZE);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
    {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glPushMatrix();
        glScalef(1.0f*lscalef, 1.0f*lscalef, -1.0f*lscalef); 
        g_clPMDModel.render();
        { // ステンシル用
            glDisable( GL_CULL_FACE );
            glDisable( GL_TEXTURE_2D );
            glDisable( GL_LIGHTING );
            glEnable( GL_STENCIL_TEST ); // ステンシルバッファに書き込むよ。
            glStencilFunc( GL_ALWAYS, 1, ~0 );
            glStencilOp( GL_REPLACE, GL_KEEP, GL_REPLACE );
            glColorMask( 0, 0, 0, 0 );   // カラーバッファに書き込むのを禁止
            glDepthMask(GL_FALSE);       // デプスバッファに書き込むのを禁止
            glMultMatrixf( (const float *)g_matPlanarProjection ); // 光源から見たようにキャンバスを設定。
            g_clPMDModel.renderForShadow();
            // ここから通常描画に戻る。
            glColorMask( 1, 1, 1, 1 );   // カラーに書き込み許可
            glDepthMask(GL_TRUE);        // デプスに書き込む許可
            float fWndW = glutGet( GLUT_WINDOW_WIDTH ),
                  fWndH = glutGet( GLUT_WINDOW_HEIGHT );
            glStencilFunc( GL_EQUAL, 1, ~0);          // デフォルトに戻す。
            glStencilOp( GL_KEEP, GL_KEEP ,GL_KEEP ); // ステンシルには書かない!
            // 正面から見たテクスチャを1枚貼る
            glMatrixMode( GL_PROJECTION );
            glLoadIdentity();
            gluOrtho2D( 0.0f, fWndW, 0.0f, fWndH );
            glMatrixMode( GL_MODELVIEW );
            glLoadIdentity();

            glColor4f( 1.0f, 0.2f, 0.2f, 0.5f );
            glBegin( GL_TRIANGLE_FAN );
            glVertex2f(  0.0f, fWndH );
            glVertex2f( fWndW, fWndH );
            glVertex2f( fWndW,  0.0f );
            glVertex2f(  0.0f,  0.0f );
            glEnd();
            glDisable( GL_STENCIL_TEST );
        }
        glPopMatrix();
    }
    glutSwapBuffers(); // ダブルバッファリング
}
//----------------------------------------------------
float getElapsedFrame(void)
{
    static int s_iPrevTime = 0;
    int   iTime = glutGet(GLUT_ELAPSED_TIME);
    float  fDiffTime;

    if (s_iPrevTime == 0) s_iPrevTime = iTime;
    fDiffTime = (float)(iTime - s_iPrevTime) * (30.0f / 1000.0f);
    s_iPrevTime = iTime;
    return fDiffTime;
}
void Idle(void)
{
    Vector3 vecCamPos;
    float  fElapsedFrame = getElapsedFrame();
    if (fElapsedFrame > 10.0f) fElapsedFrame = 10.0f;
    g_clPMDModel.updateMotion(fElapsedFrame);
    g_clPMDModel.updateNeckBone(&vecCamPos);
    g_clBulletPhysics.update(fElapsedFrame);
    g_clPMDModel.updateSkinning();
    glutPostRedisplay();
}
//----------------------------------------
void Visibility(int visible)
{
    if (visible == GLUT_VISIBLE) glutIdleFunc(Idle);
    else       glutIdleFunc(NULL);
}
//----------------------------------------------------
void Cleanup(void)
{
    g_clPMDModel.release();       // PMD,VMDが取得したメモリを解放
    g_clBulletPhysics.release();  // Bulletが取得したメモリを解放
}
//----------------------------------------------------
int main(int argc, char *argv[])
{
    glutInit(&argc, argv);               // glut の初期化
    glutInitWindowPosition( 100 , 100 ); // ウィンドウの位置
    glutInitWindowSize( 640, 480 );      // ウィンドウサイズ
    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_STENCIL ); // ディスプレイモード
    glutCreateWindow("MMDapr1");         // ウィンドウ作成
    glutDisplayFunc(Display);            // 描画時コールバック
    glutVisibilityFunc(Visibility);
    glutIdleFunc(Idle);                  // アイドル時コールバック
    atexit(Cleanup);                     // 終了時コールバック(メモリ解放など
    Initialize();                        // 初期設定
    glutMainLoop();
    return 0;
}

0 件のコメント:

コメントを投稿