您現在的位置是:首頁 > 單機遊戲首頁單機遊戲

C# 從零開始寫 SharpDx 應用 畫三角

簡介關於 Constant Buffer 請看Constant Buffer的高效使用,讓你碼出質量注意快取是需要去掉 其他被忽略的程式碼 public void Dispose(){_

頂點快取是什麼意思

在當前的畫面都是使用三角形,在開始就告訴大家如何畫三角,本文告訴大家如何用畫素著色器畫

目錄

頂點

頂點快取

畫素著色器

輸入層

設定 ViewPort

畫出頂點

本文是 SharpDX 系列部落格,更多部落格請點選SharpDX 系列

在 C# 從零開始寫 SharpDx 應用 初始化dx修改顏色 建立了資源,在這個部落格的程式碼繼續寫

頂點

為了建立三角形,需要使用頂點。頂點就是在 3D 空間的點。透過頂點可以新增資料,很多使用的頂點都使用三個值,就是 xyz 來表示點在三維空間。大家都知道三角形有三個頂點,所以下面來建立三個頂點。

這裡的頂點的範圍是 0-1,所以可以使用下面程式碼創建出頂點

private Vector3[] _vertices = new Vector3[] {new Vector3(-0。5f, 0。5f, 0。0f), new Vector3(0。5f, 0。5f, 0。0f), new Vector3(0。0f, -0。5f, 0。0f)};

這時會發現 Vector3 沒有定義,因為沒有安裝

SharpDX。Mathematics

,如果使用的是 VisualStudio 2017 格式,那麼複製下面程式碼放在專案

如果不是就開啟 Nuget 安裝 SharpDX。Mathematics ,安裝之後引用

using SharpDX

就可以使用這個類

頂點快取

現在的頂點資訊放在了記憶體,因為使用了上面程式碼建立。但是渲染的物件是在顯示卡,需要把記憶體的頂點資訊複製到顯示卡。為了做這個需要使用快取。在 DX ,可以使用快取,dx 會自動複製資訊到顯示卡。

下面使用快取來存放頂點資訊,這樣就會在使用資訊自動複製到顯示卡。先寫一個私有變數,透過這個變數把資訊放在快取,請看下面

private D3D11。Buffer _triangleVertexBuffer;

寫一個函式用來把

_vertices

轉換

_triangleVertexBuffer

,程式碼很簡單

private void InitializeTriangle() { _triangleVertexBuffer = D3D11。Buffer。Create(_d3DDevice, D3D11。BindFlags。VertexBuffer, _vertices); }

這個函式需要在構造使用

// 其他被忽略的程式碼 public KikuSimairme() { _renderForm = new RenderForm(); _renderForm。ClientSize = new Size(Width, Height); InitializeDeviceResources(); InitializeTriangle(); }

現在使用

D3D。Buffer。Create

建立新的快取,這裡的

Vector3

實際可以不需要傳。第一個引數 Direct3D 裝置就是建立資源的裝置,表示快取會在哪個裝置使用。第二個引數就是希望建立的型別,這裡寫的是頂點快取,這裡用的是 VertexBuffer ,除了這個還有 Constant buffer 和 IndexBuffer 。constant表明了constant buffer中的資料,在一次draw call的執行過程中都是不變的,用來從 CPU 傳資料到 GPU。而IndexBuffer是儲存索引編號的緩衝區。關於 Constant Buffer 請看Constant Buffer的高效使用,讓你碼出質量

注意快取是需要去掉

// 其他被忽略的程式碼 public void Dispose() { _renderTargetView。Dispose(); _swapChain。Dispose(); _d3DDevice。Dispose(); _d3DDeviceContext。Dispose(); _renderForm?。Dispose(); _triangleVertexBuffer。Dispose(); }

畫素著色器

為了畫出三角形,需要使用頂點著色器和畫素著色器。

使用這兩個著色器因為頂點著色器負責加工頂點集合,可以用來做變換,如移動旋轉頂點。而畫素著色器負責每個畫素,如何畫出每個畫素和紋理。

定義兩個私有變數,表示兩個著色器

private D3D11。VertexShader _vertexShader; private D3D11。PixelShader _pixelShader;

建立的著色器需要使用 D3DCompiler 編譯著色器檔案,編譯檔案的速度很快

using SharpDX。D3DCompiler; // 其他被忽略的程式碼 private void InitializeShaders() { using (var vertexShaderByteCode = ShaderBytecode。CompileFromFile(“VertexShader。hlsl”, “main”, “vs_4_0”, ShaderFlags。Debug)) { _vertexShader = new D3D11。VertexShader(_d3DDevice, vertexShaderByteCode); } using (var pixelShaderByteCode = ShaderBytecode。CompileFromFile(“PixelShader。hlsl”, “main”, “ps_4_0”, ShaderFlags。Debug)) { _pixelShader = new D3D11。PixelShader(_d3DDevice, pixelShaderByteCode); } }

可以從程式碼發現使用了兩個檔案,所以接下來就需要建立兩個檔案,這兩個檔案使用的是 hlsl 來寫,關於 hlsl 不屬於本文的內容,所以沒有詳細告訴大家,建議複製一下程式碼。這裡建立了著色器需要使用下面程式碼進行設定

// 其他被忽略的程式碼 _d3DDeviceContext。VertexShader。Set(_vertexShader); _d3DDeviceContext。PixelShader。Set(_pixelShader); _d3DDeviceContext。InputAssembler。PrimitiveTopology = PrimitiveTopology。TriangleList;

現在的 InitializeShaders 方法看起來就是如下

private void InitializeShaders() { using (var vertexShaderByteCode = ShaderBytecode。CompileFromFile(“VertexShader。hlsl”, “main”, “vs_4_0”, ShaderFlags。Debug)) { _vertexShader = new D3D11。VertexShader(_d3DDevice, vertexShaderByteCode); } using (var pixelShaderByteCode = ShaderBytecode。CompileFromFile(“PixelShader。hlsl”, “main”, “ps_4_0”, ShaderFlags。Debug)) { _pixelShader = new D3D11。PixelShader(_d3DDevice, pixelShaderByteCode); } _d3DDeviceContext。VertexShader。Set(_vertexShader); _d3DDeviceContext。PixelShader。Set(_pixelShader); _d3DDeviceContext。InputAssembler。PrimitiveTopology = PrimitiveTopology。TriangleList; }

這裡還使用

PrimitiveTopology

設定如何畫出來,更多請看Primitive Topologies

因為用到了兩個特殊的檔案,現在右擊專案新增兩個文字。

C# 從零開始寫 SharpDx 應用 畫三角

然後建立一個文字檔案,注意文字的名字,一個是 PixelShader。hlsl 另一個是 VertexShader。hlsl ,需要點選新建項才可以建立文字。為什麼需要使用文字,因為這樣編譯選項就不需要自己選

C# 從零開始寫 SharpDx 應用 畫三角

現在就建立了兩個檔案,請看自己的工程是否存在下面兩個檔案

C# 從零開始寫 SharpDx 應用 畫三角

現在需要右擊兩個檔案

PixelShader。hlsl

VertexShader。hlsl

屬性,選擇輸出

C# 從零開始寫 SharpDx 應用 畫三角

開啟

VertexShader。hlsl

並且寫入下面程式碼

float4 main(float4 position : POSITION) : SV_POSITION{ return position;}

上面程式碼就是建立一個 main 函式,寫法和 C 差不多,具體的意思在這裡不會告訴大家,因為關於這個的寫法是很複雜,這裡複製就好

開啟

PixelShader。hlsl

輸入下面程式碼

float4 main(float4 position : SV_POSITION) : SV_TARGET{ return float4(1。0, 0。0, 0。0, 1。0);}

這裡也不解釋程式碼的意思

開啟 KikuSimairme 類,在建構函式新增 InitializeShaders 初始化

// 其他被忽略的程式碼 public KikuSimairme() { _renderForm = new RenderForm(); _renderForm。ClientSize = new Size(Width, Height); InitializeDeviceResources(); InitializeTriangle(); InitializeShaders(); }

而且在清理的時候需要關閉

_vertexShader

,請看程式碼

public void Dispose() { // 其他被忽略的程式碼 _vertexShader。Dispose(); _pixelShader。Dispose(); }

如果在

var pixelShaderByteCode = ShaderBytecode。CompileFromFile(“PixelShader。hlsl”, “main”, “ps_4_0”, ShaderFlags。Debug)

出現

System。IO。FileNotFoundException

,那麼就是

PixelShader。hlsl

右擊屬性沒有輸出到和 exe 相同的資料夾

輸入層

現在已經有了頂點快取和頂點資料。但是 DirectX 同樣需要知道資料的結構和每個頂點型別,所以需要使用輸入層。建立輸入層需要兩步,首先需要描述每個頂點,然後從頂點建立輸入層。

因為這裡就使用一個頂點集合,所以只需要建立一個輸入元素集合

private D3D11。InputElement[] _inputElements = new D3D11。InputElement[] { new D3D11。InputElement(“POSITION”, 0, Format。R32G32B32_Float, 0)};

這裡的

POSITION

可以在 shader 的程式碼被識別,這個字串就是語義,用於匹配輸入的材質的簽名。第二個引數 0 就是語義槽的使用,表示使用哪個,在有多個

POSITION

語義的例子才使用。第三個引數就是資料的型別,使用的元素是包括三個浮點數,所以使用

Float

,還記得為什麼是三個浮點數?原因在三維的空間使用三個浮點數可以表示一個點。

在剛才的初始化函式獲取簽名,透過編譯的程式碼

// 其他被忽略的程式碼 private void InitializeShaders() { ShaderSignature inputSignature; using (var vertexShaderByteCode = ShaderBytecode。CompileFromFile(“VertexShader。hlsl”, “main”, “vs_4_0”, ShaderFlags。Debug)) { inputSignature = ShaderSignature。GetInputSignature(vertexShaderByteCode); // 其他被忽略的程式碼 } // 其他被忽略的程式碼 }

建立輸入層的私有變數,建立輸入層需要輸入簽名和輸入元素

private D3D11。InputLayout _inputLayout; private ShaderSignature _inputSignature; private void InitializeShaders() { using (var vertexShaderByteCode = ShaderBytecode。CompileFromFile(“VertexShader。hlsl”, “main”, “vs_4_0”, ShaderFlags。Debug)) { _inputSignature = ShaderSignature。GetInputSignature(vertexShaderByteCode); _vertexShader = new D3D11。VertexShader(_d3DDevice, vertexShaderByteCode); } _inputLayout = new D3D11。InputLayout(_d3DDevice, _inputSignature, _inputElements); _d3DDeviceContext。InputAssembler。InputLayout = _inputLayout; // 其他被忽略的程式碼 }

建立的程式碼第一個引數就是剛才使用的 D3D 裝置,第二個就是剛才的輸入簽名,最後一個就是輸入元素。

這裡建立了一個私有變數,最後還是需要去掉他

public void Dispose() { // 其他被忽略的程式碼 _inputLayout。Dispose(); _inputSignature。Dispose(); }

設定 ViewPort

在開始畫之前需要先設定 ViewPort ,在 DirectX 使用的座標是 Normalized Device Coordinates 左上角是 −1,−1−1,−1,右下角是 1,11,1 ,建立私有變數用來放 ViewPort 程式碼

private Viewport _viewport; private void InitializeDeviceResources() { // 其他被忽略的程式碼 _viewport = new Viewport(0, 0, Width, Height); _d3DDeviceContext。Rasterizer。SetViewport(_viewport); }

畫出頂點

在 Draw 畫出頂點

private void Draw() { _d3DDeviceContext。OutputMerger。SetRenderTargets(_renderTargetView); _d3DDeviceContext。ClearRenderTargetView(_renderTargetView, ColorToRaw4(Color。Coral)); _d3DDeviceContext。InputAssembler。SetVertexBuffers(0, new D3D11。VertexBufferBinding(_triangleVertexBuffer, Utilities。SizeOf(), 0)); _d3DDeviceContext。Draw(_vertices。Length, 0); _swapChain。Present(1, PresentFlags。None); RawColor4 ColorToRaw4(Color color) { const float n = 255f; return new RawColor4(color。R / n, color。G / n, color。B / n, color。A / n); } }

上面程式碼 SetVertexBuffers 是告訴

_d3DDeviceContext

使用頂點快取,第二個引數就是告訴每個頂點的長度

使用

_d3DDeviceContext。Draw

可以從頂點快取畫出,第二個引數就是指定畫出的偏移,從那個頂點開始畫,第一個引數是畫多少個。如輸入

3,2

就是從第2個開始畫三個

執行程式碼

參見:SharpDX Beginners Tutorial Part 4: Drawing a triangle - Johan Falk

作者 https://blog。lindexi。com

Top