着色器和相关资源的创建
着色器和相关资源的创建
QG-Homework/小组作业/第一周 at main · wsdanshenmiao/QG-Homework (github.com)
编写着色器代码
首先是编写处理各种效果的HLSL代码
//顶点着色器
VertexOut VS(VertexIn vIn)
{
VertexOut vOut;
vOut.posH = float4(vIn.posH, 1.0f); //转换为齐次坐标
vOut.color = vIn.color;
return vOut;
}
//像素着色器
float4 PS(VertexOut pIn) : SV_TARGET
{
return pIn.color;
}
注意这里要在文件的属性中调整入口:
变量后的是修饰变量的语义:
语义名 | 具体含义 |
---|---|
POSITION | 描述该变量是一个坐标点 |
SV_POSITION | 说明该顶点的位置在从顶点着色器输出后,后续的着色器都不能改变它的值,作为光栅化时最终确定的像素位置 |
COLOR | 描述该变量是一个颜色 |
SV_Target | 说明输出的颜色值将会直接保存到渲染目标视图的后备缓冲区对应位置 |
设置输入布局
接下来在C++项目中编写对应的结构体,并创建ID3D11InputLayout
输入布局来建立C++层和HLSL层对应的关系:
struct VertexPosColor
{
DirectX::XMFLOAT3 pos;
DirectX::XMFLOAT4 color;
static const D3D11_INPUT_ELEMENT_DESC inputLayout[2];
};
随后初始化输入布局:
const D3D11_INPUT_ELEMENT_DESC VertexPosColor::inputLayout[2] = {
{ "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}
};
输入布局对应的成员信息:
typedef struct D3D11_INPUT_ELEMENT_DESC
{
LPCSTR SemanticName; // 语义名
UINT SemanticIndex; // 语义索引
DXGI_FORMAT Format; // 数据格式
UINT InputSlot; // 输入槽索引(0-15)
UINT AlignedByteOffset; // 初始位置(字节偏移量)
D3D11_INPUT_CLASSIFICATION InputSlotClass; // 输入类型
UINT InstanceDataStepRate; //在缓冲区中前进一个元素之前,使用相同每个实例数据绘制的实例数。
} D3D11_INPUT_ELEMENT_DESC;
创建着色器和输入布局
在GameApp::InitEffect方法中着色器或特效相关的初始化。
-
方法的声明:
private: bool InitEffect(); //用于创建着色器或特效相关的方法
-
建立相应的成员:
private: ComPtr<ID3D11VertexShader> m_pVertexShader; //顶点着色器 ComPtr<ID3D11InputLayout> m_pInputLayout; //顶点输入布局 ComPtr<ID3D11PixelShader> m_pPixelShader; //像素着色器
-
创建二进制流:
ComPtr<ID3DBlob> blob;
-
从HLSL文件中读取顶点着色器信息:
HR(D3DReadFileToBlob(L"HLSL Files\\Octagon_VS.cso", blob.GetAddressOf()));
-
创建顶点着色器:
HR(m_pd3dDevice->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), 0, m_pVertexShader.GetAddressOf()));
创建顶点着色器函数的参数信息:
HRESULT ID3D11Device::CreateVertexShader( const void *pShaderBytecode, // [In]着色器字节码 SIZE_T BytecodeLength, // [In]字节码长度 ID3D11ClassLinkage *pClassLinkage, // [In_Opt]忽略 ID3D11VertexShader **ppVertexShader); // [Out]获取顶点着色器
其他着色器与之相同。
-
创建顶点输入布局:
HR(m_pd3dDevice->CreateInputLayout(VertexPosColor::inputLayout, ARRAYSIZE(VertexPosColor::inputLayout), blob->GetBufferPointer(), blob->GetBufferSize(), m_pInputLayout.GetAddressOf()));
创建输入布局函数的参数信息:
HRESULT ID3D11Device::CreateInputLayout( const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs, // [In]输入布局描述 UINT NumElements, // [In]上述数组元素个数 const void *pShaderBytecodeWithInputSignature, // [In]顶点着色器字节码 SIZE_T BytecodeLength, // [In]顶点着色器字节码长度 ID3D11InputLayout **ppInputLayout); // [Out]获取的输入布局
-
从HLSL文件中读取像素着色器信息:
HR(D3DReadFileToBlob(L"HLSL Files\\Octagon_PS.cso", blob.GetAddressOf()));
-
创建像素着色器:
HR(m_pd3dDevice->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), 0, m_pPixelShader.GetAddressOf()));
创建并设置缓冲区和设置图元
在GameApp::InitResource
方法中初始化资源。
-
函数声明:
bool InitResource(); //用于初始化相关资源
-
创建缓冲区成员:
ComPtr<ID3D11Buffer> m_pVertexBuffer; //顶点缓冲区
-
设置图形顶点:
GameApp::VertexPosColor vertices[] = { {XMFLOAT3(-0.5f,1.0f,0.0f),XMFLOAT4(0.0f,0.0f,0.0f,0.0f)}, {XMFLOAT3(0.5f,1.0f,0.0f),XMFLOAT4(0.0f,0.0f,0.0f,0.0f)}, {XMFLOAT3(1.0f,0.5f,0.0f),XMFLOAT4(0.0f,0.0f,0.0f,0.0f)}, {XMFLOAT3(1.0f,-0.5f,0.0f),XMFLOAT4(0.0f,0.0f,0.0f,0.0f)}, {XMFLOAT3(0.5f,-1.0f,0.0f),XMFLOAT4(0.0f,0.0f,0.0f,0.0f)}, {XMFLOAT3(-0.5f,-1.0f,0.0f),XMFLOAT4(0.0f,0.0f,0.0f,0.0f)}, {XMFLOAT3(-1.0f,-0.5f,0.0f),XMFLOAT4(0.0f,0.0f,0.0f,0.0f)}, {XMFLOAT3(-1.0f,0.5f,0.0f),XMFLOAT4(0.0f,0.0f,0.0f,0.0f)}, };
-
设置顶点缓冲区描述:
D3D11_BUFFER_DESC vbd; ZeroMemory(&vbd, sizeof(vbd)); vbd.ByteWidth = sizeof(vertices); //字节数 vbd.Usage = D3D11_USAGE_IMMUTABLE; //CPU,GPU读写权限 vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; //缓冲区类型 vbd.CPUAccessFlags = 0; //CPU读写权限
缓冲区描述的对应的成员信息:
typedef struct D3D11_BUFFER_DESC { UINT ByteWidth; // 数据字节数 D3D11_USAGE Usage; // CPU和GPU的读写权限相关 UINT BindFlags; // 缓冲区类型的标志 UINT CPUAccessFlags; // CPU读写权限的指定 UINT MiscFlags; // 忽略 UINT StructureByteStride; // 忽略 } D3D11_BUFFER_DESC;
D3D11_USAGE
枚举类型对应的读写关系:CPU读 CPU写 GPU读 GPU写 D3D11_USAGE_DEFAULT √ √ D3D11_USAGE_IMMUTABLE √ D3D11_USAGE_DYNAMIC √ √ D3D11_USAGE_STAGING √ √ √ √ -
创建并填充子资源:
D3D11_SUBRESOURCE_DATA initData; ZeroMemory(&initData, sizeof(initData)); initData.pSysMem = vertices;
-
创建顶点缓冲区:
m_pVertexBuffer = nullptr; HR(m_pd3dDevice->CreateBuffer(&vbd, &initData, m_pVertexBuffer.GetAddressOf()));
创建顶点缓冲区函数的参数信息:
HRESULT ID3D11Device::CreateBuffer( const D3D11_BUFFER_DESC *pDesc, // [In]顶点缓冲区描述 const D3D11_SUBRESOURCE_DATA *pInitialData, // [In]子资源数据 ID3D11Buffer **ppBuffer); // [Out] 获取缓冲区
-
设置顶点索引:
DWORD indices[] = { //DWORD == unsigned long 0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,7, };
-
设置索引缓冲区描述:
D3D11_BUFFER_DESC ibd; ZeroMemory(&ibd, sizeof(ibd)); ibd.ByteWidth = sizeof(indices); ibd.Usage = D3D11_USAGE_IMMUTABLE; ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0;
-
填充子资源:
initData.pSysMem = indices;
-
创建索引缓冲区:
m_pIndexBuffer = nullptr; HR(m_pd3dDevice->CreateBuffer(&ibd, &initData, m_pIndexBuffer.GetAddressOf()));
-
输入装配阶段的顶点缓冲区设置:
UINT stride = sizeof(VertexPosColor); // 跨越字节数 UINT offset = 0; // 起始偏移量 m_pd3dImmediateContext->IASetVertexBuffers(0, 1, m_pVertexBuffer.GetAddressOf(), &stride, &offset);
绑定顶点缓冲区函数的参数信息:
void ID3D11DeviceContext::IASetVertexBuffers( UINT StartSlot, // [In]输入槽索引 UINT NumBuffers, // [In]缓冲区数目 ID3D11Buffer *const *ppVertexBuffers, // [In]指向缓冲区数组的指针 const UINT *pStrides, // [In]一个数组,规定了对所有缓冲区每次读取的字节数分别是多少 const UINT *pOffsets); // [In]一个数组,规定了对所有缓冲区的初始字节偏移量
-
设置顶点输入布局:
m_pd3dImmediateContext->IASetInputLayout(m_pInputLayout.Get());
设置顶点输入布局函数的参数信息:
void ID3D11DeviceContext::IASetInputLayout( ID3D11InputLayout *pInputLayout); // [In]输入布局
-
输入装配阶段的索引缓冲区设置:
m_pd3dImmediateContext->IASetIndexBuffer(m_pIndexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
-
将着色器绑定到渲染管线:
m_pd3dImmediateContext->VSSetShader(m_pVertexShader.Get(), nullptr, 0); m_pd3dImmediateContext->PSSetShader(m_pPixelShader.Get(), nullptr, 0);
-
设置图元类型:
m_pd3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);