Platform SDK: DirectX

キューブ環境マップへのレンダリング

キューブ環境マップを DDSCAPS_3DDEVICE で作成する場合、その他のレンダリング ターゲット サーフェスと同様に、キューブ マップの個々のサーフェスにレンダリングすることができる。このレンダリングを行う前に実行する最も大切なことは、カメラを正しく配置し、そのサーフェスに対して正しい方向を向くようにトランスフォーム行列を設定することである。正しい方向とは、前方 (+z)、後方 (-z)、左 (-x)、右 (+x)、上方 (+y)、または下方 (-y) である。

[C++]

次の C++ コードは、レンダリングするサーフェスに応じてビュー行列を用意して設定する。

//
// ppddsFaces 変数は、各サーフェスに対して 1 つある
// IDirectDrawSurface7 インターフェイス ポインタの配列のアドレスである。
//
void RenderFaces(LPDIRECTDRAWSURFACE7* ppddsFaces)
{
// キューブ マップの 6 つのサーフェスに対してループ処理を実行する。
for( DWORD i=0; i<6; i++ )
    {
DDSCAPS2 ddsc;
ZeroMemory( (LPVOID)&ddsc, sizeof(DDSCAPS2) );

// サーフェス能力を取得する (これにより、どのサーフェスであるかを把握する)。
ppddsFaces[i]->GetCaps( &ddsc );

// 以下のように、標準ビューを置き換える。
D3DVECTOR vEnvEyePt = D3DVECTOR( 0.0f, 0.0f, 0.0f );
D3DVECTOR vLookatPt, vUpVec;

switch( ddsc.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES )
        {
case DDSCAPS2_CUBEMAP_POSITIVEX:
vLookatPt = D3DVECTOR( 1.0f, 0.0f, 0.0f );
vUpVec    = D3DVECTOR( 0.0f, 1.0f, 0.0f );
break;
case DDSCAPS2_CUBEMAP_NEGATIVEX:
vLookatPt = D3DVECTOR(-1.0f, 0.0f, 0.0f );
vUpVec    = D3DVECTOR( 0.0f, 1.0f, 0.0f );
break;
case DDSCAPS2_CUBEMAP_POSITIVEY:
vLookatPt = D3DVECTOR( 0.0f, 1.0f, 0.0f );
vUpVec    = D3DVECTOR( 0.0f, 0.0f,-1.0f );
break;
case DDSCAPS2_CUBEMAP_NEGATIVEY:
vLookatPt = D3DVECTOR( 0.0f,-1.0f, 0.0f );
vUpVec    = D3DVECTOR( 0.0f, 0.0f, 1.0f );
break;
case DDSCAPS2_CUBEMAP_POSITIVEZ:
vLookatPt = D3DVECTOR( 0.0f, 0.0f, 1.0f );
vUpVec    = D3DVECTOR( 0.0f, 1.0f, 0.0f );
break;
case DDSCAPS2_CUBEMAP_NEGATIVEZ:
vLookatPt = D3DVECTOR( 0.0f, 0.0f,-1.0f );
vUpVec    = D3DVECTOR( 0.0f, 1.0f, 0.0f );
break;
        }

D3DMATRIX matView;
D3DUtil_SetViewMatrix( matView, vEnvEyePt, vLookatPt, vUpVec );
g_pd3dDevice->SetTransform( D3DTRANSFORMSTATE_VIEW, &matView );
 

キューブ環境マップの各サーフェスには 90°の視界が含まれることを思い出すこと。アプリケーションで特殊効果などのために視界の角度を変更しない限り、この角度に応じて射影行列を設定するよう注意が必要である。

次のコードは、最も一般的に使用する射影行列を作成および設定する。

// 90°の視界を射影に使用する。
D3DMATRIX matProj;
D3DUtil_SetProjectionMatrix( matProj, g_PI/2, 1.0f, 0.5f, 1000.0f );
g_pd3dDevice->SetTransform( D3DTRANSFORMSTATE_PROJECTION, &matProj );
 

カメラを正しく配置し、射影行列を設定すると、シーンをレンダリングできる。シーンの各オブジェクトは、通常配置するとおりに配置する。次のコードでは、処理を完全に示すために、このタスクについては大まかに示す。

        // 
// シーンのレンダリング
        // 

// 深度バッファをサーフェスに入れ替え、レンダリング ターゲットして設定する。
// この関数については、後で詳しく説明する。
ChangeRenderTarget( ppddsFaces[i] );

// z バッファをクリアする。
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_ZBUFFER, 0x000000ff, 1.0f, 0L );

// アンチエイリアシングを有効する。これにより、環境マップの見た目がきれいになる。
g_pd3dDevice->SetRenderState( D3DRENDERSTATE_ANTIALIAS, 
D3DANTIALIAS_TRANSLUCENTSORTINDEPENDENT );

// シーンを開始する。
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
        {
// シーンのジオメトリを通常どおりに配置する。
// このためには、レンダリングする各オブジェクトのワールド行列を設定する。

            g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST,
D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0),
lpVertices, VERTEX_COUNT, 0);

// シーンを終了する。
g_pd3dDevice->EndScene();
        }
    }
}

 :  キューブ環境マップへのレンダリングを実行する際は、ほとんどのアプリケーションでアンチエイリアシングを有効にする必要がある。各サーフェスは比較的小さなものであるため、そのサーフェスへのレンダリングの際にアンチエイリアシングを有効にしておくと、見た目が非常にきれいな環境マップを生成できる。

ChangeRenderTarget 関数の呼び出しには注意すること。キューブ マップ サーフェスにレンダリングするときは、そのサーフェスをカレント レンダリング ターゲット サーフェスとして割り当てる必要がある。深度バッファを使用するアプリケーションでは、そのレンダリング ターゲットに明示的に深度バッファを作成したり、既存の深度バッファをレンダリング ターゲット サーフェスに再割り当てすることができる。次のコードは、後者の方法を使用する。

HRESULT ChangeRenderTarget( LPDIRECTDRAWSURFACE7 pddsNewTarget)
{
LPDIRECTDRAWSURFACE7 pddsOldRenderTarget = NULL;
g_pd3dDevice->GetRenderTarget( &pddsOldRenderTarget );

if( pddsOldRenderTarget )
    {
LPDIRECTDRAWSURFACE7 pddsZBuffer = NULL;
DDSCAPS2 ddscaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
pddsOldRenderTarget->GetAttachedSurface( &ddscaps, &pddsZBuffer );

if( pddsZBuffer )
        {
pddsOldRenderTarget->DeleteAttachedSurface( 0, pddsZBuffer );
pddsNewRenderTarget->AddAttachedSurface( pddsZBuffer );
pddsZBuffer->Release();
        }
        pddsOldRenderTarget->Release();
    }

g_pd3dDevice->SetRenderTarget( pddsNewRenderTarget, 0 );
    return S_OK;
}
[Visual Basic]

次の Visual Basic コードは、レンダリングするサーフェスに応じてビュー行列を用意して設定する。

'
' ddsFaces 変数は、各サーフェスに対して 1 つある
' DirectDrawSurface7 オブジェクトの配列のアドレスである。
'
Sub RenderFaces(ddsFaces() As DirectDrawSurface7)
Dim i As Integer
    
' キューブ マップの 6 つのサーフェスに対してループ処理を実行する。
For i = 0 To UBound(ddsFaces)
Dim ddsc As DDSCAPS2
Dim vEnvEyePt As D3DVECTOR, _
vLookatPt As D3DVECTOR, _
vUpVec As D3DVECTOR
        
' サーフェス能力を取得する (これにより、どのサーフェスであるかを把握する)。
Call ddsFaces(i).GetCaps(ddsc)

Select Case (ddsc.dwCaps2 And DDSCAPS2_CUBEMAP_ALLFACES)
Case DDSCAPS2_CUBEMAP_POSITIVEX:
vLookatPt.x = 1#:vUpVec.y = 1#
                
Case DDSCAPS2_CUBEMAP_NEGATIVEX:
vLookatPt.x = -1#:vUpVec = 1#

Case DDSCAPS2_CUBEMAP_POSITIVEY:
vLookatPt.y = 1#:vUpVec.z = -1#
                
Case DDSCAPS2_CUBEMAP_NEGATIVEY:
vLookatPt.y = -1#:vUpVec.z = 1#

Case DDSCAPS2_CUBEMAP_POSITIVEZ:
vLookatPt.z = 1#:vUpVec.y = 1#
                
Case DDSCAPS2_CUBEMAP_NEGATIVEZ:
vLookatPt.z = -1#:vUpVec.y = 1#
                
End Select

Dim matView As D3DMATRIX
Call g_dx.ViewMatrix(matView, vEnvEyePt, vLookatPt, vUpVec)
Call g_pd3dDevice.SetTransform(D3DTRANSFORMSTATE_VIEW, matView)
 

キューブ環境マップの各サーフェスには 90°の視界が含まれることを思い出すこと。アプリケーションで特殊効果などのために視界の角度を変更しない限り、この角度に応じて射影行列を設定するよう注意が必要である。

次のコードは、最も一般的に使用する射影行列を作成および設定する。

' 90°の視界を射影に使用する。
Dim matProj As D3DMATRIX
Call g_dx.ProjectionMatrix(matProj, 0.5, 1000#, 3.1415926535 / 2)
Call g_d3dDevice.SetTransform(D3DTRANSFORMSTATE_PROJECTION, matProj)
 

カメラを正しく配置し、射影行列を設定すると、シーンをレンダリングできる。シーンの各オブジェクトは、通常配置するとおりに配置する。次のコードでは、処理を完全に示すために、このタスクについては大まかに示す。

        '
' シーンのレンダリング
        '

' 深度バッファをサーフェスに入れ替え、レンダリング ターゲットして設定する。
' この関数については、後で詳しく説明する。
Call ChangeRenderTarget(ddsFaces(i))

Dim rec(1) As RECT
rec.Top = 0:rec.Left = 0
        
' サーフェスの大きさは 64x64 であるとする。
rec.Bottom = 64:rec.Right = 64

' z バッファをクリアする。
Call g_d3dDevice.Clear(0, rec(), D3DCLEAR_ZBUFFER, _
g_dx.CreateColorRGBA(0, 0, 256, 0), 1#, 0)

' アンチエイリアシングを有効する。これにより、環境マップの見た目がきれいになる。
Call g_d3dDevice.SetRenderState(D3DRENDERSTATE_ANTIALIAS, _
D3DANTIALIAS_TRANSLUCENTSORTINDEPENDENT)

' シーンを開始する。
Call g_d3dDevice.BeginScene
If Err.Number = DD_OK Then
' シーンのジオメトリを通常どおりに配置する。
' このためには、レンダリングする各オブジェクトのワールド行列を設定する。

Call g_pd3dDevice.DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_XYZ Or D3DFVF_NORMAL Or _
D3DFVF_TEX1 Or D3DFVF_TEXCOORDSIZE3(0), _
g_Vertices(0), VERTEX_COUNT, 0)

// シーンを終了する。
Call g_d3dDevice.EndScene
End If
Next i
End Sub

 :  キューブ環境マップへのレンダリングを実行する際は、ほとんどのアプリケーションでアンチエイリアシングを有効にする必要がある。各サーフェスは比較的小さなものであるため、そのサーフェスへのレンダリングの際にアンチエイリアシングを有効にしておくと、見た目が非常にきれいな環境マップを生成できる。

ChangeRenderTarget サブルーチンの呼び出しには注意すること。キューブ マップ サーフェスにレンダリングするときは、そのサーフェスをカレント レンダリング ターゲット サーフェスとして割り当てる必要がある。深度バッファを使用するアプリケーションでは、そのレンダリング ターゲットに明示的に深度バッファを作成したり、既存の深度バッファをレンダリング ターゲット サーフェスに再割り当てすることができる。次のコードは、後者の方法を使用する。

Sub ChangeRenderTarget(ddsNewTarget As DirectDrawSurface7)
Dim ddsOldRenderTarget As DirectDrawSurface7
    
Set ddsOldRenderTarget = g_pd3dDevice.GetRenderTarget

If (ddsOldRenderTarget Is Not Nothing) Then
Dim ddsZBuffer As DirectDrawSurface7
Dim ddscaps As DDSCAPS2
        
ddscaps.lCaps = DDSCAPS_ZBUFFER
Set ddsZBuffer = ddsOldRenderTarget.GetAttachedSurface

If (ddsZBuffer Is Not Nothing) Then
Call ddsOldRenderTarget.DeleteAttachedSurface(ddsZBuffer)
Call ddsNewRenderTarget.AddAttachedSurface(ddsZBuffer)
End If
End If

Call g_pd3dDevice.SetRenderTarget(pddsNewRenderTarget)
End Sub