Windows 8 Directx 開發學習筆記(五)山峯河谷模型的簡單實現

通過之前對DirectX示例程序代碼的研究,基本瞭解DirectX最簡單的工作過程,爲了更好的理解整個過程,基於示例程序做一個山峯河谷的簡單模型。首先還是根據模板創建正方體的示例程序,Visual C++ -〉Windows應用商店 -〉DirectX3D應用程序,如圖1。設置好名稱後完成創建。

程序顯示一個類似山峯河谷的模型,只要將正方體的數據替換成模型數據即可。在不改變示例程序其他部分的前提下,要提供的模型數據只需包括頂點座標和顏色,索引數組兩部分,其中最重要的部分就是頂點座標的生成。

在DirectX的右手座標系中,y方向爲垂直方向,表示高度,x和z方向定義水平面。DirectX只繪製三角形,如果將山峯河谷模型投影在xz平面,那麼xz平面就是由許多三角形組成的網格。假設相鄰的兩個三角形能構成一個正方形,如圖2,頂點的x和z座標就很容易生成。獲得xz座標之後,將其代入高度計算公式即可算出y。爲表現出山峯河谷的效果,不同的高度範圍應該有不同的顏色,可以使用條件判斷進行設置。


首先找到CubeRenderer.cpp中的CreateDeviceResources方法,刪除裏面定義正方體頂點的代碼。設x和z的變化範圍爲0-127,間隔均爲1,定義常量和顏色如下:

const int xRange = 128;
const int zRange = 128;
const float dx = 1.0f;
const XMFLOAT3 WHITE(1.0f,1.0f, 1.0f);
const XMFLOAT3BEACH_SAND(1.0f, 0.96f, 0.62f);
const XMFLOAT3LIGHT_YELLOW_GREEN(0.48f, 0.77f, 0.46f);
const XMFLOAT3DARK_YELLOW_GREEN(0.1f, 0.48f, 0.19f);
const XMFLOAT3DARKBROWN(0.45f, 0.39f, 0.34f);

接着創建一個xRange*zRange大小的數組存儲頂點信息。生成頂點座標時,從原點開始按行掃描,獲得xz座標後代入上面的公式計算出y座標。然後根據y座標進行判斷,不同的高度值對應的不同顏色,模擬山峯效果。

VertexPositionColorVertices[xRange*zRange];
 
for(int row=0;row<zRange; ++row)
{
    float zPos = row*dx;
 
    for(int col=0;col<xRange; ++col)
    {
         float xPos = col*dx;
         float yPos = 0.3f *(zPos*sinf(0.1f*xPos) + xPos*cosf(0.1*zPos));
         Vertices[xRange*row + col].pos = XMFLOAT3(xPos, yPos,zPos);
 
         if(yPos <-10.0f)
             Vertices[xRange*row + col].color =BEACH_SAND;
         else if (yPos <5.0f)
             Vertices[xRange*row + col].color =LIGHT_YELLOW_GREEN;
         else if (yPos <10.0f)
             Vertices[xRange*row + col].color =DARK_YELLOW_GREEN;
         else if (yPos <12.0f)
             Vertices[xRange*row+ col].color = DARKBROWN;
         else
             Vertices[xRange*row + col].color =WHITE;
    }
}

然後就是創建索引數組。每個正方形由兩個三角形組成,所以索引數組的大小爲3*2*(xRange-1)*(zRange-1)。與上面生成頂點相同,生成索引時也從原點開始,不過每次存儲的是兩個三角形的頂點序號。

unsigned shortIndices[3*2*(xRange-1)*(zRange-1)];
 
int tempIndice = 0;
for(int row=0;row<(zRange-1); ++row)
{
    for(int col=0;col<(xRange-1); ++col)
    {
         Indices[tempIndice] = xRange*row + col;
         Indices[tempIndice+1] = xRange*row +col + 1;
         Indices[tempIndice+2] = xRange*(row+1)+ col;
 
         Indices[tempIndice+3] = xRange*(row+1)+ col;
         Indices[tempIndice+4] = xRange*row +col + 1;
         Indices[tempIndice+5] = xRange*(row+1)+ col + 1;
                 
         tempIndice += 6;
    }
}

模型生成後還有工作要做,因爲生成的模型比正方體大很多,爲了顯示模型全貌,需要調整可視距離。將CreateWindowSizeDependentResourcesXMMatrixPerspectiveFovRH方法的參數由100.0f改成1000.0f

另外,在Update方法中,攝像機的位置和焦點也要調整,而且這次不需要模型隨時間旋轉,所以固定旋轉角度爲0度,代碼如下。

XMVECTOR eye =XMVectorSet(0, 30.0f, 0, 0.0f);
XMVECTOR at =XMVectorSet(50.0f, -0.1f, 50.0f, 0.0f);
XMVECTOR up =XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
 
XMStoreFloat4x4(&m_constantBufferData.view,XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up)));
XMStoreFloat4x4(&m_constantBufferData.model,XMMatrixTranspose(XMMatrixRotationY(0.0f)));

按F5運行查看效果,如圖3。


靜態的模型看上去沒什麼感覺,可以通過移動攝像機的位置,簡單模擬飛過整個區域的效果,這樣感覺好些。只需要添加一個隨時間變化的變量flyPos來更新攝像機的位置,焦點座標同時改變是爲了保持視線方向不變。

float flyPos = timeTotal * 5;
XMVECTOR eye =XMVectorSet(flyPos, 30.0f, flyPos, 0.0f);
XMVECTOR at =XMVectorSet(50.0f + flyPos, -0.1f, 50.0f + flyPos, 0.0f);

雖然只是一個簡單粗糙的山峯河谷模型實現,在編寫過程中還是遇到點問題,尤其是尋找一個合適的攝像機位置和焦點。不過通過實現這個模型,對DirectX的三維空間和工作原理有了更深的體會。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章