程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 在游戲中充分利用可編程的GPU

在游戲中充分利用可編程的GPU

編輯:關於.NET

在文章開始之前,借此園地真誠向我最親愛的咪寶道歉,我謹記自己嚴重的錯誤,以此為 訓,所有朋友作證,我將克己自重,痛改前非。我充分意識到GPU海量的吞吐和強悍的浮點計 算能力,將極高提高程序性能,也能讓充分發揮顯卡的價值,GPU作為電腦上2個可編程的高 性能芯片之一,長期以來都沒得到普通程序員應有的重視,主要因為其編程麻煩,資料工具 欠缺。這裡我將敘述我的游戲編程中盡可能多的使用GPU做事的一些經驗,主要是想表達一種 合理使用計算機資源的一種思想吧。

我對DX10和SM3.0都不熟悉,所以更有用的GS數據輸出,甚至於更強大的CUDA都不在本文 敘述范圍之內,這裡更多討論SM2.0和DX9,相信大部分朋友都應該具備實踐的條件。專業的 GPGPU都利用科學計算作為實例,我覺得不妥,還是簡單點好,在這裡我說說如何將公告板的 所有幾何計算都放到GPU裡去。

公告板對於圖形程序員都再熟悉不過,就是讓幾何體(通常是四邊形)總是面對相機,其 實就是一個旋轉過程,最簡單的就是雪花,草叢等等,在這裡我要講一個稍微復雜點的例子 ,比如魔獸中的鎖鏈魔法,或者天空中的分形閃電,其實這些都是鏈接在2個點之間的一條或 多條幾何體面片,一段可能是一個四邊形,也可能是多個四邊形,如下圖:

如果一段不是一個面片就用不著旋轉了,所以我們主要說上面那種情況。法師對一個或多 個目標發送帶鏈接的魔法,其實就是在目標之間生成鏈接的面片,並且面片上進行相關的紋 理動畫,當目標之間方位不斷改變時還要進行幾何變換等操作。原理很簡單,就是讓所有面 片都能面對觀眾,這樣在特定方向觀看時才不會有嚴重失真的表現,我們主要看如何把所有 計算都塞到GPU中去。

首先我們 必須在CPU中生成所有需要的頂點,因為沒有GS的GPU不能生成頂點。比如我們要從A點生成一 條幾何條帶到B點,我們生成8個中間點,共10個點。通過相鄰的2個點,我們可以求出2個點 的中間點,Pmid= (Pi + Pi+1) / 2,我們為第一個段 生成4個頂點,後續的段因為共用前一個段的後2個頂點,所以後面的每段只需要2個頂點,每 個頂點的幾何坐標設置為本段的中間點坐標Pmid,這樣每個段的頂點都是窩在一 起的,我們需要在VS裡將其擴展成四邊形,但我們需要信息,當前頂點該如何擴展,如下圖 :

 

我們可 以用UV坐標做標識,UV坐標y分量為0的都向後擴展,y分量!=0的都向前擴展,而x==0的向左 ,x==1的向右。因為一般的鎖鏈上的紋理都是U向CLAMP,V向WRAP的,所以UV正好給我們提供 了如何擴展幾何體的信息,但擴展多少呢?我們需要再利用一個數據流送入信息,我們就利 用TEXCOORD1吧,X方向和Y方向擴展數量正好用2個FLOAT送入。之後是旋轉,其實就是擴展, 我們需要2個軸,一個是X方向的,一個是Y方向的,Y方向的其實就是LeashY = Pi+1 - Pi,至於原理就是公告板旋轉,只是約束軸不同,而X方向 LeashX = Cross( LeashY, (CameraPos - VertexPos) ),所以我們還需要一個流送入LeashY ,而LeashX可以通過頂點原始坐標和LeashY在VS中計算出來,不用在CPU裡做。所以唯一要在 CPU裡做的就是生成頂點和UV,而這2個計算量非常小,頂點真實坐標的計算,公告板的旋轉 等都放到VS裡來了。現在我們看看VS大概是什麼樣子。

float3 g_CameraPos;
float4x4 g_WorldMatrix;
float4x4 g_ViewProjMatrix;

struct VS_INPUT
{
float3 VertexPos : POSITION0;
float2 UV0    : TEXCOORD0;
float3 LeashY  : TEXCOORD1;
float2 Size    : TEXCOORD2;
};

struct VS_OUTPUT
{
float3 ProjPos : POSITION0;
float2 UV0  : TEXCOORD0;

};


VS_OUTPUT VS_Main( VS_INPUT In )
{
VS_OUTPUT Out;
float4 VertexWorldPos = mul(float4(In.VertexPos, 1.f), g_WorldMatrix);
float3x3 WorldRotateMatrix;
WorldRotateMatrix[0] = float3(g_WorldMatrix[0][0], g_WorldMatrix[0][1], g_WorldMatrix[0][2]);
WorldRotateMatrix[1] = float3(g_WorldMatrix[1][0], g_WorldMatrix[1][1], g_WorldMatrix[1][2]);
WorldRotateMatrix[2] = float3(g_WorldMatrix[2][0], g_WorldMatrix[2][1], g_WorldMatrix[2][2]);
//注意旋轉軸需要被旋轉否則不對
float3 RotatedLeashY = normalize(mul(In.LeashY, WorldRotateMatrix ));
float3 LeashX = normalize(cross(g_CameraPos-VertexWorldPos, RotatedLeashY));
//開始旋轉了
float3 DealedPos = float3(0,0,0);
float3 ExtendY = In.Size.y*RotatedLeashY;
float3 ExtendX = In.Size.x*LeashX;
if(In.UV0.y == 0 )
{
if(In.UV0.x == 0 )
{
DealedPos = -ExtendY-ExtendX;
} else {
DealedPos = -ExtendY+ExtendX;
}
} else {
if(In.UV0.x == 0 )
{
DealedPos = ExtendY-ExtendX;
} else {
DealedPos = ExtendY+ExtendX;
}
}
Out.ProjPos = mul(float4(VertexWorldPos.xyz+DealedPos, 1.0f), g_ViewProjMatrix);
Out.UV0 = In.UV0;
 

}

怎麼樣?CPU既不用計算頂點坐標,又不用旋轉公告板,做一些改進後,甚至可以完成鎖 鏈的拉伸變形,完全不用CPU管。在可編程的GPU出現以前,很多計算工作是在CPU中完成,現 在有了SM2.0和SM3.0都可以移植到GPU中來,大家多多發現吧。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved