創作內容

1 GP

【程式】Direct3D11小試(2)

作者:Shark│2016-09-08 03:23:41│巴幣:2│人氣:527
接下來根據做Cyber Sprite的經驗,把會用到的功能一個一個加上去

(程式碼的框框裡黑字是C++,綠字是shader)

艾莉兒,檢查一下你身上的功能,看有哪些要做的。
艾莉兒:我看看哦……
艾莉兒:第一個是blend。


OpenGL裡是呼叫glBlendFunc設定,D3D11裡要建立ID3D11BlendState物件。
艾莉兒裝備了5種blend mode:normal、add、screen、multiply、copy,所以要建立5個物件,畫圖時套用其一個。
D3D11_BLEND_DESC blendDesc;
D3D11_RENDER_TARGET_BLEND_DESC* blendDesc2=blendDesc.RenderTarget;
…………
blendDesc2->SrcBlend=D3D11_BLEND_ONE;
blendDesc2->SrcBlendAlpha=D3D11_BLEND_ONE;
blendDesc2->DestBlend=D3D11_BLEND_ZERO;
blendDesc2->DestBlendAlpha=D3D11_BLEND_ZERO;
device->CreateBlendState(&blendDesc, & copyBlendState);

艾莉兒:還要改culling設定。

polygon正對鏡頭時才畫出來,背對時就不畫的功能。畫2D物體的時候要關閉culling,3D時再打開。
查查看怎麼做……,要用ID3D11RasterizerState物件
D3D11_RASTERIZER_DESC rsState;
ZeroMemory(&rsState, sizeof(D3D11_RASTERIZER_DESC));
rsState.FillMode=D3D11_FILL_SOLID;
rsState.CullMode=D3D11_CULL_NONE;
device->CreateRasterizerState(&rsState, &_2dState);

艾莉兒:還有quad和fan,D3D11沒有直接支援quad和fan了。

想了一下解法,決定用index array模擬。
用兩個ID3D11Buffer,quad是012,023,456,467……,fan是012,023,034……,建好之後就不需要更動,不過好像buffer建好後就不能更改大小,想擴大buffer要把物件刪除重建。


第二階段測試,既然加上fan的功能,就畫一個矩形看看
const float rectVertex[]={0,-0.2, -0.4,-0.2, -0.4,0.4, 0,0.4};
const int16_t rectTexCoord[]={0,0,1,0,1,1,0,1};

格式和上篇的particle不同,particle把頂點和貼圖坐標放在同一個陣列,矩形則是兩者分開,也要寫個對應的vertex shader和layout。
同時測試blend功能,用加法模式,為了能看出加法的效果把shader裡的顏色改成float4(0,0.5,0.5,1);。

加法blend有變亮的效果,所以矩形蓋到的部分會比較亮。



下一步是貼圖和載入矩陣做坐標轉換
測試用的貼圖不是讀取圖檔,而是用程式產生
for(int i=0;i<TEX_H;i++){
 int gValue=i*255/TEX_H;
 for(int j=0;j<TEX_W;j++){
  int bValue=j*255/TEX_W;
  *pixel=0xff000000|bValue|(gValue<<8);
  pixel++;
 }
}

艾莉兒:我解析看看……,這是藍色和綠色的漸層。


shader裡讀取貼圖的方法……,跟D3D9和OpenGL很不一樣,要先定義一個sampler
sampler defaultSampler{
 Filter=MIN_MAG_MIP_LINEAR;
 AddressU=Wrap;
 AddressV=Wrap;
};
然後用texture.Sample(defaultSampler, 坐標)讀取。

矩陣的話,找找看有沒有矩陣stack的功能,發現要建一個ID3DXMatrixStack物件。
然後建一個正投影矩陣,讓螢幕坐標以像素為單位,而不是0~1,因為2D遊戲比較常以像素為單位。
D3DXMatrixOrthoOffCenterLH((D3DXMATRIX*)mat, 0,screenW,screenH,0,0,1);
matrixStack->LoadMatrix((D3DXMATRIX*)mat);

再來要把這些參數從C++傳給shader了。
D3D10以後就沒有D3D9的uniform變數了,要用constant buffer,配置一塊記憶體,裡面可以包含很多變數。

艾莉兒:globalColor和貼圖寬高也一起做吧。

shader裡這樣宣告
uniform float4x4 modelViewMatrix :register(b1);
cbuffer shaderState:register(b0){
 uniform float4 globalColor;
 uniform float2 texSizeRcp;
}
Texture2D <float4> texture1:register(t0);
艾莉兒有動態改變圖片顏色的功能,像Cyber Sprite打中敵人時會閃一下,globalColor是用在這裡。
texSizeRcp是貼圖寬高的倒數,C++裡的貼圖坐標單位是像素,vertex shader裡乘上這個值轉換成0~1。

C++端宣告一個對應的struct並建立ID3D11Buffer物件,用Map、Unmap填入資料
struct ShaderConstants{
 float color[4];
 float texSizeRcp[2];
};

D3D11_MAPPED_SUBRESOURCE ms;
context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
memcpy(ms.pData, data, byteNum);
context->Unmap(buffer, 0);

因為單位改用像素,測試的particle和矩形坐標也改一下
const ParticleVertex Vertices[]={
 {{0,30},{0,0},0xffffffff},
 {{30,0},{0,TEX_H},0xffffffff},
 {{0,-30},{TEX_W,TEX_H},0xffffffff},
 {{-30,0},{TEX_W,0},0xffffffff},
};
const float rectVertex[]={0,0, 50,0, 50,50, 0,50};
const int16_t rectTexCoord[]={0,0,TEX_W,0,TEX_W,TEX_H,0,TEX_H};
particle用坐標轉換把它放在(150,150)的位置

好,第三階段,compile and run!


艾莉兒:怪怪的,東西位置不對,而且每隔一秒左右會閃。

對吔,哪裡做錯了?

…………
…………

研究大概兩個小時才找到原因,modelViewMatrix也要包在一個cbuffer區塊
cbuffer register1:register(b1){
 uniform float4x4 modelViewMatrix;
}
cbuffer shaderState:register(b0){
 uniform float4 globalColor;
 uniform float2 texSizeRcp;
}
Texture2D <float4> texture1:register(t0);
找到的shader範例有些沒寫清楚是D3D10還是D3D9的,就寫成D3D9的寫法了。

再試一次,總算對了。




大概知道Direct3D 11的用法了,艾莉兒,覺得怎麼樣?
艾莉兒:初始化的時候就要一堆device->Create什麼的,看起來好麻煩。

很多狀態設定都要建一個物件再呼叫函式套用,要建一堆global物件,這有點費工。
做到這裡已經建立這麼多了。
ID3D11Device
IDXGISwapChain
ID3D11DeviceContext
ID3D11RenderTargetView

ID3D11Buffer* shaderStateUniform;  shader裡的constant buffer
ID3D11Buffer* modelViewMatrixUniform;
ID3D11Buffer* commonVertexBuffer;
ID3D11Buffer* commonTexCoordBuffer;
ID3D11Buffer* fanIndex;  模擬fan和quad的index array
ID3D11Buffer* quadIndex;

ID3D11VertexShader* particleVS;
ID3D11InputLayout* particleLayout;
ID3D11VertexShader* normalVS;
ID3D11InputLayout* normalLayout;  基本上一個vertex shader固定配一個layout
ID3D11PixelShader* flatPS;  純色
ID3D11PixelShader* multiplyPS;  套用貼圖

ID3D11RasterizerState  2個,2D和3D
ID3D11BlendState  5個,上面說的5種blend mode

ID3DXMatri xStack

這次剛好沒有鈷寶的工作,不過有一件事要由她做。
Direct3D有個fxc.exe可以事先將shader編譯成byte code,以後遊戲只要載入這個byte code。而OpenGL必須每次開遊戲時從原始碼編譯,Cyber Sprite其實有把shader程式碼放在程式裡某個地方。
以後準備shader會用這個東西,要研究一下用法。
鈷寶:好…,我研究看看。

另外關於shader的uniform變數,用過之後覺得constant buffer比單獨的uniform變數好用,查了一下發現OpenGL裡有個類似的東西uniform buffer object,之後試試看。



題外話,& copy如果中間沒有空白會變成©,所以上面某個地方只好加一個空白。
引用網址:https://home.gamer.com.tw/TrackBack.php?sn=3316009
All rights reserved. 版權所有,保留一切權利

相關創作

同標籤作品搜尋:程式|Direct3D|DirectX

留言共 0 篇留言

我要留言提醒:您尚未登入,請先登入再留言

1喜歡★shark0r 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:【程式】Direct3D... 後一篇:【程式】OpenGL u...

追蹤私訊切換新版閱覽

作品資料夾

d88931122所有巴友
歡迎諸君來參觀老僧的小屋,內含Steam與Google Play遊戲、3D角色模組、Line貼圖看更多我要大聲說1小時前


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】