球にテクスチャーを張り視点を回転させる(DirectX9 32/64bit)

icon 項目のみ表示/展開表示の切り替え

概要

Direct X 9を用い、球にテクスチャーを張り視点を回転させます

ソースコードのダウンロード Sphere_Texture.zip

ソースコードの説明

WinMain

最初に実行される関数です。
最初にウィンドウを作成し、Init3DDev関数でDirect Xの初期化を行います。
その後通常のWinMain関数と同じ様にメッセージループを構成しますが、メッセージの取り出しにGetMessage関数ではなく、PeekMessage関数を使用し、メッセージがないときもループが回るようにします。メッセージがないときにDraw関数を呼び出し描画を行います。

convert

メッシュの頂点座標(x,y,z)をテクスチャ座標(u,v)に変換します。テクスチャ座標は、uが横方向で、vが縦方向となります。
テクスチャは、下図のとおりで、0~1.0の範囲に正規化します。正規化の方法は、地図なので使われるメルカトル図法と同様です。

Init3DDev

Direct Xの初期化をおよび球の作成を行います。

D3DxCreateSphere

球のメッシュを作成します。この関数により球のx,y,zの頂点が作成されます。

CloneMeshFVF

x,y,zの座標にテクスチャ座標を追加した構造体()を作成し、先ほどの球のメッシュのx,yzをコピーします。

テクスチャ座標の書き込み

x,yzよりテクスチャ座標をconvert関数により算定し、構造体TLVERTEXに設定します。
頂点の数は、GetNumVertices()で取得できます。構造体への書き込み中はLock()によりロックします。

D3DXCreateTextureFromFile

テクスチャに使うTexture.jpg.ファイルを読み込みます。使用するjpegファイルは下記のサイトより入手しました
テクスチャのつなぎ目(画像の左右端)に色等があるとうまくつながらないので消します。(枠等)

http://www.sekaichizu.jp/

SetupMatrices

draw関数から呼び出されます。
球をみる視点の位置の設定等を設定しています。

視点の設定 D3DXMatrixLookAtLh

デバイスにワールド座標への変換方法を設定する SetTransform

D3DXMatrixPerspectiveFovLH

ワールド座標をビュー座標に変換する。ワールド座標のどの方向からどの範囲を見るか(描画するか)を設定する。この関数は、左手座標(Xが右、Yが上、Zが奥行方向で奥 左手で手のひらを上側がにし人差し指をX方向に向けた時における親指のさしている方向がZ値が増える方向である。)においてワールド座標をビュー座標に変換する。
描画する遠近それぞれのZ値、画面の縦横比(アスペクト)、Y方向の視野角を指定する。

ビュー座標への変換行列を設定する SetTransform

レンタリングステートの設定 SetRenderState

カーニング方法 反時計周りの面を消去
ライディングをしない
Zバッファを使わない

draw

画面のクリア Clear

レンタリング開始 BeginScene

テクスチャを設定する SetTexture

メッシュの描画 DrawSubset

レンタリング終了 EndScene

バッファの内容を表示 Present

Cleanup

Init3DDevで作成したデバイスとメッシュ・テクスチャを開放します。

WndProc

ウィンドウプロシージャーです。ウィンドウ関係のメッセージを処理します。通常WM_PAINTメッセージにより再描画を行いますが、スピードが要求される場合は、前期のとおり別の場所で処理しています。

コンパイル方法

Visual C++ 2008
Microsoft DirectX SDK June 2010をインストールをあらかじめ行っておく
プロジェクトに下記のパスを追加(64bit Windowsで64bitの実行ファイルを作成する場合)
includeパスにC:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Include
LibパスにC:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Lib\x64
を追加

ソースコード


//      Direct X 9 Sample Program 
//  球を固定し、ビュー座標(視点)側をY軸中心に回転させる
//  球にテクスチャーを張る
//      32bit/64bit マルチバイト/Unicode対応 Visual C++ 2008   2011/3/17

#define     szClassName        TEXT("Sphere Texture")

#define TIME_SET 1000.0f


#define R 50.0f //      球半径
#define VIEW_R 200.0f // カメラ位置

#include <windows.h>
#include <d3dx9.h>
#include <tchar.h>

#pragma once
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")

#define SAFE_RELEASE(p)         { if (p) { (p)->Release();  (p)=NULL; } }
#define FVF_TLVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)


HWND                    hWnd;
LPDIRECT3D9             pD3D;
LPDIRECT3DDEVICE9       pDev;
D3DPRESENT_PARAMETERS   D3DPPWin;
D3DLIGHT9               Light;
D3DMATERIAL9            Material;

LPD3DXMESH              pMeshApp = NULL;
LPD3DXMESH              pMeshApp2 = NULL;
LPDIRECT3DTEXTURE9      g_pTextures;

DWORD start;    //      プログラム開始時のシステム時刻

HRESULT InitDevices(void);
void  SetupMatrices(void);
void Draw(void);
void Cleanup(void);
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);

// 頂点フォーマットの定義
struct  TLVERTEX{
        float       x,y,z;
    float       tu,tv;
};



int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int){
        MSG     msg;

    WNDCLASSEX wc = {
                sizeof(WNDCLASSEX),CS_CLASSDC,WndProc,0L,0L,hInst,
                NULL,NULL,NULL,NULL,szClassName,NULL
        };
    if (RegisterClassEx(&wc)==0)
                return FALSE;
    hWnd = CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,
                            CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
                            NULL,NULL,hInst,NULL);
    if (FAILED(InitDevices()))
                return FALSE;
        start=timeGetTime();

    ShowWindow(hWnd,SW_SHOWDEFAULT);
    UpdateWindow(hWnd);
    ZeroMemory(&msg,sizeof(msg));
    while(msg.message!=WM_QUIT){
                if (PeekMessage(&msg,NULL,0U,0U,PM_REMOVE)){
                        TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else{
            Draw();
        }
    }
    Cleanup();
    UnregisterClass(szClassName,wc.hInstance);
    return 0;
}

void convert(float x,float y,float z,float r,float& u,float& v){
        float q;
        float q2;
        q=atan2(z,x);

        u=q / (2.0f * 3.1415f);
        q2=asin(y/r);
        v=(1.0f-q2/(3.1415f/2.0f))/2.0f;
        if(u>1.0)
                u=1.0;
}

//デバイス/モード等の初期化
HRESULT InitDevices(void){
    pD3D= NULL;
    pDev= NULL;

        HRESULT     hr;

        D3DDISPLAYMODE  dmode;

        // デバイス/モード等の初期化
        if(pD3D==NULL)
                pD3D = Direct3DCreate9(D3D_SDK_VERSION);
        if(pD3D==NULL)
                return E_FAIL;
        //現在のディスプレイモードを得る
        if(FAILED(pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&dmode)))
                return E_FAIL;

        // D3DDeviceオブジェクトの作成
        ZeroMemory(&D3DPPWin, sizeof(D3DPPWin));
        D3DPPWin.BackBufferFormat           = dmode.Format;
        D3DPPWin.BackBufferCount            = 1;
        D3DPPWin.SwapEffect                 = D3DSWAPEFFECT_DISCARD;
        D3DPPWin.Windowed                   = TRUE;
        D3DPPWin.EnableAutoDepthStencil     = TRUE;
        D3DPPWin.AutoDepthStencilFormat     = D3DFMT_D16;
        D3DPPWin.Flags                      = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

        hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                D3DCREATE_HARDWARE_VERTEXPROCESSING, &D3DPPWin, &pDev);
        if (FAILED(hr)){
                hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3DPPWin, &pDev);
                if (FAILED(hr)){
                        hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd,
                                D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3DPPWin, &pDev);
                        if (FAILED(hr)){
                                MessageBox(NULL,TEXT("Create Device Error"),TEXT("Surface Error"),MB_OK);
                                return E_FAIL;
                        }
                }
        }
    //球メッシュの生成
    D3DXCreateSphere(pDev,R,32,32,&pMeshApp,NULL);

        pMeshApp->CloneMeshFVF(NULL, FVF_TLVERTEX,pDev,&pMeshApp2);
        LPDIRECT3DVERTEXBUFFER9 pVB=NULL;
        TLVERTEX* pVer=NULL;
        pMeshApp2->GetVertexBuffer(&pVB);
        pVB->Lock(0,0,(VOID**)&pVer,0);
        DWORD n;
        for(n=0;n<pMeshApp2->GetNumVertices();n++){ //頂点の数を取得する
                float u,v;
                convert(pVer[n].x,pVer[n].y,pVer[n].z,R,u,v);
                pVer[n].tu=u;
                pVer[n].tv=v;
        }
        pVB->Unlock();

        hr=D3DXCreateTextureFromFile(pDev,TEXT("Texture.jpg"),&g_pTextures);
        if (FAILED(hr)){
        MessageBox(NULL,TEXT("Texture Load Error"),TEXT("Error"),MB_OK);
            return E_FAIL; 
    }

        
    return  S_OK;
}

//描画環境の設定
void  SetupMatrices(void){
    D3DXMATRIX      matView;
    D3DXMATRIX      matProj;
        D3DXVECTOR3     ViewForm;       //(0.0f,0.0f,-200.0f);  //      目の位置を保存

        float rt=(float(timeGetTime()-start)/10.0f);    //      システムタイムより回転角を算出する
        ViewForm.x= (float)(VIEW_R*cos(rt/180*3.14));
        ViewForm.y= 0.0f;
        ViewForm.z= (float)(VIEW_R*sin(rt/180*3.14));

    //View 座標の設定 ViewFormが目の位置 &D3DXVECTOR3(0.0f,0.0f,0.0f)が目の向く方向 すなわちy軸から距離200位置から原点を見ることになる
    D3DXMatrixLookAtLH(&matView,&ViewForm,
                       &D3DXVECTOR3(0.0f,0.0f,0.0f),&D3DXVECTOR3(0.0f,1.0f,0.0f));
    pDev->SetTransform(D3DTS_VIEW,&matView);
    //透視変換の設定 Y方向の視野角45度 Z座標 100~1000の範囲を射影する
    D3DXMatrixPerspectiveFovLH(&matProj,D3DXToRadian(45.0f),1.0f,100,1000); // 視野に基づいて、左手座標系パースペクティブ射影行列を作成する
    pDev->SetTransform(D3DTS_PROJECTION,&matProj);

        pDev->SetRenderState(D3DRS_WRAP0,D3DWRAPCOORD_0);

        pDev->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);            //反時計回りの面を消去
    pDev->SetRenderState(D3DRS_LIGHTING,FALSE);              //ライティングしない
    pDev->SetRenderState(D3DRS_ZENABLE,D3DZB_FALSE);         //Zバッファ使わない

}

//描画処理
void Draw(void){
    //黒で塗りつぶして消去
    pDev->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);
    if (SUCCEEDED(pDev->BeginScene())){
            pDev->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_TEXTURE);
        SetupMatrices();
                pDev->SetFVF(FVF_TLVERTEX);

                pDev->SetTexture(0,g_pTextures);
        pMeshApp2->DrawSubset(0);
        pDev->EndScene();
    }
    pDev->Present(NULL,NULL,NULL,NULL);
}

//オブジェクトの開放
void Cleanup(void){
        SAFE_RELEASE(g_pTextures);
    SAFE_RELEASE(pMeshApp);
    SAFE_RELEASE(pMeshApp2);
        SAFE_RELEASE(pDev);
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam){
    switch(msg){
           case WM_CLOSE:
       case WM_DESTROY:
            PostQuitMessage(0);
            return 0L;
    }
    return DefWindowProc(hWnd,msg,wParam,lParam);
}