一,看本节教程前应该掌握:
(1)D3D11基础教程二之D3D11初始化
(2)了解3D渲染流水线的知识,如世界变换,相机变换,透视投影变换,视口变换,光栅化,线性插值,gouraud着色等,最好具备一定的图形学基础,我推荐一本书<3D游戏编程大师技巧>,这本书完整的讲解了3D渲染流水线的方方面面。
二,本节教程的程序结构:
三,VertexShader(顶点着色器)和PixelShader(像素着色器)的作用:
在讲解VertexShader(顶点着色器)和PixelShader(像素着色器)的作用之前,我先放出一张D3D11简略版的3D渲染流水线图:
(1)VertexShader(顶点着色器):顶点着色器顾名思义,也就是对顶点进行操作,对顶点进行变换的着色器,看上面图红色圈住的部分就是顶点变换的过程了,而我们的VertexShader(顶点着色器),一般是对顶点进行上面红色圈的 世界变换(WorldTransform), 相机变换(也称视角变换,ViewTransform), 透视投影变换(PerspectiveProjection),(得注意的是"视口变换"不属于VertexShader,而是与"背面剔除'和"顶点属性线性插值"共属于光栅化阶段")剩下的几种变换经常是显卡帮我们自动进行的。
(2) PixelShader(像素着色器):像素着色器顾名思义,也就是对像素进行的操作的着色器,也就是上面图里的蓝色圈住的部分。像素着色器主要是对像素(像素的位置,颜色,向量等)操作,最终输出像素的颜色。
(3)VertexShader(顶点着色器)和PixelShader(像素着色器)之间的关系:这里用一个三角形作为例子,一个三角形由三个顶点ABC组成,三角形ABC位于局部空间,三个顶点ABC分别在VertexShader进行世界变换,相机变换等等各种变换,最终变换到屏幕空间,然后对屏幕空间的三角形ABC进行光栅化,得到三角形里面的像素,然后用PixelShader对像素进行操作,最终输出颜色到屏幕上。如下面图所示:
看图中的三角形ABC以及三角形ABC里面的像素,图中我用红色点表示像素,一个红色点就是一个像素。
(其实上面也不对,这里为了初学者教学的简便,我们就不引入其它种类的Shader了,以及深度缓存一大堆乱七八糟的)
三,程序的代码:
首先能GraphicsClass包含四个类,分别为D3DClass,ModelClass,CameraClass,ColorShaderClass
(1) GrapgicsClass
GraphicsClass.h
- #pragma once
- #ifndef _GRAPHICS_CLASS_H
- #define _GRAPHICS_CLASS_H
-
- #include"D3DClass.h"
- #include"CameraClass.h"
- #include"ColorShaderClass.h"
- #include"ModelClass.h"
-
-
-
- const bool FULL_SCREEN = false;
- const bool VSYNC_ENABLE = true;
- const float SCREEN_FAR = 1000.0f;
- const float SCREEN_NEAR = 0.1f;
-
-
-
- class GraphicsClass
- {
-
- private:
-
- D3DClass* mD3D;
-
-
- CameraClass* mCamera;
-
-
- ColorShaderClass* mColorShader;
-
-
- ModelClass* mModel;
-
- private:
- bool Render();
-
- public:
- GraphicsClass();
- GraphicsClass(const GraphicsClass&);
- ~GraphicsClass();
-
- public:
- bool Initialize(int ScreenWidth, int ScreenHeight, HWND hwnd);
- void Shutdown();
- bool Frame();
- };
- #endif // !_GRAPHICS_CLASS_H
(2) ColorShaderClass
ColorShaderClass.h (用于加载VertexShader和PixelShader)
- #pragma once
- #ifndef _COLOR_SHADER_CLASS_H
- #define _COLOR_SHADER_CLASS_H
- #define HR2(X) {if(FAILED(X)) { MessageBox(0,L"Create Failed",0,0); return false;}}
-
- #include<d3d11.h>
- #include<xnamath.h>
- #include<D3DX11.h> //含编译Shader程序的函数
- #include<d3dcompiler.h>
- #include<fstream>
- using namespace std;
-
- class ColorShaderClass
- {
-
- private:
-
- struct CBMatrix
- {
- XMMATRIX mWorldMatrix;
- XMMATRIX mViewMatrix;
- XMMATRIX mProjMatrix;
- };
-
- private:
- ID3D11VertexShader* md3dVertexShader;
- ID3D11PixelShader* md3dPixelShader;
- ID3D11InputLayout* md3dInputLayout;
- ID3D11Buffer* mCBMatrixBuffer;
-
- private:
- bool InitializeShader(ID3D11Device*, HWND, WCHAR*, WCHAR*);
- bool ShutdownShader();
- void OutputShaderErrorMessage(ID3D10Blob*, HWND, WCHAR*);
-
- bool SetShaderParameter(ID3D11DeviceContext*, CXMMATRIX, CXMMATRIX, CXMMATRIX);
- void RenderShader(ID3D11DeviceContext*, int);
-
- public:
- ColorShaderClass();
- ColorShaderClass(const ColorShaderClass&);
- ~ColorShaderClass();
-
- public:
- bool Initialize(ID3D11Device*, HWND);
- void Shutdown();
- bool Render(ID3D11DeviceContext*, int, CXMMATRIX, CXMMATRIX, CXMMATRIX);
-
- };
- #endif
ColorShaderClass.CPP- #include"ColorShaderClass.h"
-
- ColorShaderClass::ColorShaderClass()
- {
- md3dVertexShader=NULL;
- md3dPixelShader=NULL;
- md3dInputLayout=NULL;
- mCBMatrixBuffer=NULL;
- }
-
-
- ColorShaderClass::ColorShaderClass(const ColorShaderClass&)
- {
-
- }
-
- ColorShaderClass::~ColorShaderClass()
- {
-
- }
-
-
- bool ColorShaderClass::Initialize(ID3D11Device* d3dDevice, HWND hwnd)
- {
- bool result;
- result = InitializeShader(d3dDevice, hwnd, L"MyShader.fx", L"MyShader.fx");
- if (!result)
- return false;
-
- return true;
- }
-
- void ColorShaderClass::Shutdown()
- {
- ShutdownShader();
- }
-
- bool ColorShaderClass::Render(ID3D11DeviceContext* d3dDeviceContext, int indexCount, CXMMATRIX worldMatrix, CXMMATRIX viewMatrix, CXMMATRIX ProjMatrix)
- {
- bool result;
-
-
- result = SetShaderParameter(d3dDeviceContext, worldMatrix, viewMatrix, ProjMatrix);
- if (!result)
- return false;
-
-
- RenderShader(d3dDeviceContext, indexCount);
-
- return true;
- }
-
- bool ColorShaderClass::InitializeShader(ID3D11Device* d3dDevice, HWND hwnd, WCHAR* VSFileName, WCHAR* PSFileName)
- {
- HRESULT result;
- ID3D10Blob* errorMessage;
- ID3D10Blob* VertexShaderBuffer;
- ID3D10Blob* PixelShaderBuffer;
-
-
- errorMessage = NULL;
- VertexShaderBuffer=NULL;
- PixelShaderBuffer=NULL;
-
-
- result = D3DX11CompileFromFile(VSFileName, NULL, NULL, "VS", "vs_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, NULL, &VertexShaderBuffer, &errorMessage, NULL);
- if (FAILED(result))
- {
-
- if (errorMessage)
- {
- OutputShaderErrorMessage(errorMessage, hwnd, VSFileName);
- }
-
- else
- {
- MessageBox(hwnd, L"can not find VS file", L"error", MB_OK);
- }
- }
-
- HR2(d3dDevice->CreateVertexShader(VertexShaderBuffer->GetBufferPointer(),VertexShaderBuffer->GetBufferSize(),NULL,&md3dVertexShader));
-
-
-
- result = D3DX11CompileFromFile(PSFileName, NULL, NULL, "PS", "ps_5_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, NULL, &PixelShaderBuffer, &errorMessage, NULL);
- if (FAILED(result))
- {
-
- if (errorMessage)
- {
- OutputShaderErrorMessage(errorMessage, hwnd, PSFileName);
- }
-
- else
- {
- MessageBox(hwnd, L"can not find PS file", L"error", MB_OK);
- }
- }
-
- HR2(d3dDevice->CreatePixelShader(PixelShaderBuffer->GetBufferPointer(), PixelShaderBuffer->GetBufferSize(), NULL, &md3dPixelShader));
-
-
- D3D11_INPUT_ELEMENT_DESC VertexInputLayout[] =
- {
- { "POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0 },
- { "COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0 },
- };
-
- unsigned int numElements = sizeof(VertexInputLayout) / sizeof(VertexInputLayout[0]);
-
- HR2(d3dDevice->CreateInputLayout(VertexInputLayout, numElements, VertexShaderBuffer->GetBufferPointer(), VertexShaderBuffer->GetBufferSize(), &md3dInputLayout));
-
-
- VertexShaderBuffer->Release();
- VertexShaderBuffer = NULL;
- PixelShaderBuffer->Release();
- PixelShaderBuffer = NULL;
-
-
- D3D11_BUFFER_DESC matrixBufferDesc;
- ZeroMemory(&matrixBufferDesc, sizeof(matrixBufferDesc));
- matrixBufferDesc.Usage = D3D11_USAGE_DEFAULT;
- matrixBufferDesc.ByteWidth = sizeof(CBMatrix);
- matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
- matrixBufferDesc.CPUAccessFlags = 0;
-
- HR2(d3dDevice->CreateBuffer(&matrixBufferDesc, NULL, &mCBMatrixBuffer));
-
- return true;
- }
-
- bool ColorShaderClass::ShutdownShader()
- {
- HR2(mCBMatrixBuffer);
- HR2(md3dInputLayout);
- HR2(md3dPixelShader);
- HR2(md3dVertexShader);
- return true;
- }
-
- void ColorShaderClass::OutputShaderErrorMessage(ID3D10Blob* errorMessage, HWND hwnd, WCHAR* shaderFilename)
- {
- char* compileErrors;
- unsigned long bufferSize, i;
- ofstream fout;
-
-
-
- compileErrors = (char*)(errorMessage->GetBufferPointer());
-
-
- bufferSize = errorMessage->GetBufferSize();
-
-
- fout.open("shader-error.txt");
-
-
- for (i = 0; i<bufferSize; i++)
- {
- fout << compileErrors[i];
- }
-
-
- fout.close();
-
-
- errorMessage->Release();
- errorMessage = 0;
-
-
- MessageBox(hwnd, L"Error compiling shader. Check shader-error.txt for message.", shaderFilename, MB_OK);
-
- }
-
-
- bool ColorShaderClass::SetShaderParameter(ID3D11DeviceContext* d3dDeviceContext, CXMMATRIX worldMatrix, CXMMATRIX viewMatrix, CXMMATRIX ProjMatrix)
- {
-
-
-
-
- unsigned int bufferNum;
-
-
- CBMatrix cb;
- XMMATRIX worldMa = XMMatrixTranspose(worldMatrix);
- XMMATRIX viewMa = XMMatrixTranspose(viewMatrix);
- XMMATRIX ProjMa = XMMatrixTranspose(ProjMatrix);
- cb.mWorldMatrix = worldMa;
- cb.mViewMatrix = viewMa;
- cb.mProjMatrix = ProjMa;
- d3dDeviceContext->UpdateSubresource(mCBMatrixBuffer, 0, NULL, &cb, 0, 0);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bufferNum = 0;
-
-
- d3dDeviceContext->VSSetConstantBuffers(bufferNum, 1, &mCBMatrixBuffer);
-
- return true;
- }
-
- void ColorShaderClass::RenderShader(ID3D11DeviceContext* deviceContext, int indexCount)
- {
-
- deviceContext->IASetInputLayout(md3dInputLayout);
-
-
- deviceContext->VSSetShader(md3dVertexShader, NULL, 0);
- deviceContext->PSSetShader(md3dPixelShader, NULL, 0);
-
-
- deviceContext->DrawIndexed(indexCount, 0, 0);
- }
(3) ModelClass
ModelClass.h(用于加载顶点缓存和索引缓存)
- #pragma once
- #ifndef _MODEL_CLASS_H
- #define _MODEL_CLASS_H
-
- #include<d3d11.h>
- #include<xnamath.h>
- #define HR1(X) {if(FAILED(X)) { MessageBox(0,L"Create Failed",0,0); return false;}}
- #define ReleaseCOM1(x) { if (x) { x->Release(); x = 0; } }
-
- class ModelClass
- {
- private:
- struct Vertex
- {
- XMFLOAT3 pos;
- XMFLOAT4 color;
- };
- private:
- ID3D11Buffer* md3dVertexBuffer;
- ID3D11Buffer* md3dIndexBuffer;
- int mVertexCount;
- int mIndexCount;
-
- private:
- bool InitializeBuffer(ID3D11Device* d3dDevice);
- void ShutdownBuffer();
- void RenderBuffers(ID3D11DeviceContext* d3dDeviceContext);
-
- public:
- ModelClass();
- ModelClass(const ModelClass&);
- ~ModelClass();
-
- public:
-
- bool Initialize(ID3D11Device* d3dDevice);
- void Shutdown();
- void Render(ID3D11DeviceContext* d3dDeviceContext);
-
- int GetIndexCount() { return mIndexCount; }
-
- };
- #endif
ModelClass.CPP- #include"ModelClass.h"
-
- ModelClass::ModelClass()
- {
- md3dVertexBuffer=NULL;
- md3dIndexBuffer=NULL;
- mVertexCount = 0;
- mIndexCount = 0;
-
- }
-
-
- ModelClass::ModelClass(const ModelClass& other)
- {
-
- }
-
- ModelClass::~ModelClass()
- {
-
- }
-
- bool ModelClass::Initialize(ID3D11Device* d3dDevice)
- {
- bool result;
- result = InitializeBuffer(d3dDevice);
-
- if (!result)
- return false;
-
- return true;
- }
-
- void ModelClass::Shutdown()
- {
- ShutdownBuffer();
- }
-
-
- void ModelClass::Render(ID3D11DeviceContext* d3dDeviceContext)
- {
-
- RenderBuffers(d3dDeviceContext);
- }
-
- bool ModelClass::InitializeBuffer(ID3D11Device* d3dDevice)
- {
- Vertex* vertexs=NULL;
- WORD*indices=NULL;
-
- mVertexCount = 4;
- mIndexCount = 6;
-
-
- vertexs = new Vertex[mVertexCount];
- if (!vertexs)
- return false;
-
-
- indices = new WORD[mIndexCount];
- if (!indices)
- return false;
-
-
- vertexs[0].pos = XMFLOAT3(-1.0f, -1.0f, 0.0f);
- vertexs[0].color = XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f);
- vertexs[1].pos = XMFLOAT3(1.0f, 1.0f, 0.0f);
- vertexs[1].color = XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f);
- vertexs[2].pos = XMFLOAT3(1.0f, -1.0f, 0.0f);
- vertexs[2].color = XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f);
- vertexs[3].pos = XMFLOAT3(-1.0f, 1.0f, 0.0f);
- vertexs[3].color = XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f);
-
-
-
- indices[0] = 0;
- indices[1] = 3;
- indices[2] = 2;
- indices[3] = 1;
- indices[4] = 2;
- indices[5] = 3;
-
-
-
- D3D11_BUFFER_DESC vertexBufferDesc;
- vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
- vertexBufferDesc.ByteWidth = sizeof(Vertex) * mVertexCount;
- vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
- vertexBufferDesc.CPUAccessFlags = 0;
- vertexBufferDesc.MiscFlags = 0;
- vertexBufferDesc.StructureByteStride = 0;
-
- D3D11_SUBRESOURCE_DATA vertexData;
- vertexData.pSysMem = vertexs;
- vertexData.SysMemPitch = 0;
- vertexData.SysMemSlicePitch = 0;
- HR1(d3dDevice->CreateBuffer(&vertexBufferDesc, &vertexData, &md3dVertexBuffer));
-
-
- D3D11_BUFFER_DESC indexBufferDesc;
- indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
- indexBufferDesc.ByteWidth = sizeof(WORD) * mIndexCount;
- indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
- indexBufferDesc.CPUAccessFlags = 0;
- indexBufferDesc.MiscFlags = 0;
- indexBufferDesc.StructureByteStride = 0;
-
- D3D11_SUBRESOURCE_DATA indexData;
- indexData.pSysMem = indices;
- indexData.SysMemPitch = 0;
- indexData.SysMemSlicePitch = 0;
- HR1(d3dDevice->CreateBuffer(&indexBufferDesc, &indexData, &md3dIndexBuffer));
-
-
- delete[]vertexs;
- vertexs = NULL;
- delete[]indices;
- indices = NULL;
-
- return true;
- }
-
- void ModelClass::ShutdownBuffer()
- {
-
- ReleaseCOM1(md3dIndexBuffer);
- ReleaseCOM1(md3dVertexBuffer);
- }
-
- void ModelClass::RenderBuffers(ID3D11DeviceContext* d3dDeviceContext)
- {
-
- UINT stride = sizeof(Vertex);
- UINT offset = 0;
- d3dDeviceContext->IASetVertexBuffers(0, 1, &md3dVertexBuffer, &stride, &offset);
-
-
- d3dDeviceContext->IASetIndexBuffer(md3dIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
-
-
- d3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
- }
四,本节教程的程序得注意的地方:
(1)在一个.h文件里包含XNAMATH.h一定得先包含一个windows.h。
(2)XMMATRIX作为函数参数时应该用CXMMATRIX。
(3)指定顶点的索引值时得注意绕线方向,用左手定则,得到三角形法线方向跟相机LookAt方向为钝角的被正面,反之为背面.
(4)我的VertexShader和PixelShader都在从MyShader.fx文件中编译的,其实.HLSL文件.VS文件.PS文件.FX文件都能编译成Shader
(5)在.FX文件中常量缓存CBMatrix注意用register()注册,注册为b0,则在ColorShaderClass::SetShaderParameter()的d3dDeviceContext->VSSetConstantBuffers(bufferNum, 1, &mCBMatrixBuffer)的bufferNum为0,若注册为b1,则bufferNum为1,以此类推.
(6)在VertexShader阶段和PixelShade阶段,常量缓存的值一直未曾改变,不会进行光栅化,因此世界空间的平行光,聚光灯,点光源都是采用常量缓存。
(7)在对应与常量缓存的结构体一定是16个字节的倍数,XMMATRIX为64个字节,float为4个字节,实在要是怕忘记16字节对齐规则,可在结构体前加个前缀,__declspec(align(16)) ,比如
- __declspec(align(16))
- struct CbNeverChange //常量缓存结构严格16字节的倍数
- {
- DirectionLight DireLight;
- PointLight PoLight;
- SpotLight SpLight;
- Material SkullMaterial;
- XMFLOAT3 EyePostion;
- };
五,本节教程的程序运行的结果:
六,程序源代码链接如下
点击打开链接