本篇笔记要实现的是在屏幕上渲染出一个三角形,重点要学习的是渲染一个几何体的流程方式。
为了渲染几何图形,需要一个顶点缓存和一个描述顶点布局的输入层,还有着色器(主要是顶点着色器和像素着色器),下面来看看具体Demo的实现。
新建一个Win32项目 ,新建一个类我们叫做TriangleDemo,继承自前面教程我们实现的基类Dx11DemoBase。
TriangleDemo.h头文件
#pragma once #include "Dx11DemoBase.h" class TriangleDemo : public Dx11DemoBase
{
public:
TriangleDemo();
~TriangleDemo(); bool LoadContent() override;
void UnLoadContent() override; void Update(float dt) override;
void Render() override; private:
ID3D11Buffer *m_pVertexBuffer;
ID3D11InputLayout *m_pInputLayout;
ID3D11VertexShader *m_pSolidColorVS;
ID3D11PixelShader *m_pSolidColorPS;
};
在类中添加了四个成员变量,用来保存着色器、顶点缓存和顶点布局的指针。
定义顶点结构体
#include "TriangleDemo.h"
#include <xnamath.h> struct VertexPos
{
XMFLOAT3 pos;
}; TriangleDemo::TriangleDemo()
: m_pInputLayout(), m_pVertexBuffer(), m_pSolidColorPS(), m_pSolidColorVS()
{
} TriangleDemo::~TriangleDemo()
{
} void TriangleDemo::UnLoadContent()
{
if (m_pSolidColorPS)
m_pSolidColorPS->Release();
if (m_pSolidColorVS)
m_pSolidColorVS->Release();
if (m_pVertexBuffer)
m_pVertexBuffer->Release();
if (m_pInputLayout)
m_pInputLayout->Release();
m_pSolidColorVS = ;
m_pSolidColorPS = ;
m_pVertexBuffer = ;
m_pInputLayout = ;
}
着色器的加载
为了方便我们在基类中定义了一个CompileD3DShader函数实现加载着色器文本的功能,具体实现如下
bool Dx11DemoBase::CompileD3DShader(char* filePath, char* entry, char* shaderModel, ID3DBlob** buffer)
{
DWORD shaderFlags = D3DCOMPILE_ENABLE_STRICTNESS; #if defined _DEBUG || defined DEBUG
shaderFlags = D3DCOMPILE_DEBUG;
#endif ID3DBlob *errorBuffer = ;
HRESULT result; result = D3DX11CompileFromFile(filePath, , , entry, shaderModel, shaderFlags, , , buffer, &errorBuffer,); if (FAILED(result))
{
if (errorBuffer != )
{
OutputDebugString((char*)errorBuffer->GetBufferPointer());
errorBuffer->Release();
}
return false;
} if (errorBuffer != )
{
return false;
} return true;
}
具体加载着色器的代码我们写在LoadContent函数中,下面是该函数的一部分代码
//载入顶点着色器
ID3DBlob *vsBuffer = ;
bool compileResult = CompileD3DShader("SolidColor.fx", "VS_Main", "vs_4_0", &vsBuffer);
if (!compileResult)
{
MessageBox(, "载入顶点着色器错误", "编译错误", MB_OK);
return false;
} HRESULT result;
result = m_pd3dDevice->CreateVertexShader(vsBuffer->GetBufferPointer(), vsBuffer->GetBufferSize(),
, &m_pSolidColorVS); if (FAILED(result))
{
if (vsBuffer)
{
vsBuffer->Release();
}
return false;
} D3D11_INPUT_ELEMENT_DESC solidColorLayout[] =
{
{"POSITION",,DXGI_FORMAT_R32G32B32_FLOAT,,,D3D11_INPUT_PER_VERTEX_DATA,}
}; UINT numLayoutElements = ARRAYSIZE(solidColorLayout);
result = m_pd3dDevice->CreateInputLayout(solidColorLayout, numLayoutElements, vsBuffer->GetBufferPointer(),
vsBuffer->GetBufferSize(), &m_pInputLayout);
vsBuffer->Release(); if (FAILED(result))
{
return false;
} //载入像素着色器
ID3DBlob *psBuffer = ;
compileResult = CompileD3DShader("SolidColor.fx", "PS_Main", "ps_4_0", &psBuffer);
if (!compileResult)
{
MessageBox(, "像素着色器加载失败", "编译错误", MB_OK);
return false;
} result = m_pd3dDevice->CreatePixelShader(psBuffer->GetBufferPointer(), psBuffer->GetBufferSize(),
, &m_pSolidColorPS);
psBuffer->Release();
if (FAILED(result))
{
return false;
}
其中输入布局信息D3D11_INPUT_ELEMENT_DESC
(A description of a single element for the input-assembler stage.)
定义如下
typedef struct D3D11_INPUT_ELEMENT_DESC {
LPCSTR SemanticName;
UINT SemanticIndex;
DXGI_FORMAT Format;
UINT InputSlot;
UINT AlignedByteOffset;
D3D11_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate;
} D3D11_INPUT_ELEMENT_DESC;
顶点信息生成及处理
TriangleDemo::LoadContent() 的 上半部分完成了 inputlayout 和 shader, 剩下的就是 vertex 这些顶点的生成及处理了。
三角形的顶点列表 vertex list 存放处在 vertices数组里, 同时这个vertices 也作为 创建vertex buffer函数CreateBuffer()的参数之一:Subresource data。
下面是LoadContent()的另外一部分代码:
VertexPos vertices[] =
{
XMFLOAT3(0.5f, 0.5f, 0.5f),
XMFLOAT3(0.5f, -0.5f, 0.5f),
XMFLOAT3(-0.5f,-0.5f,0.5f)
}; D3D11_BUFFER_DESC vertexDesc;
ZeroMemory(&vertexDesc, sizeof(vertexDesc));
vertexDesc.Usage = D3D11_USAGE_DEFAULT;
vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexDesc.ByteWidth = sizeof(VertexPos)* ; D3D11_SUBRESOURCE_DATA resourceData;
ZeroMemory(&resourceData, sizeof(resourceData));
resourceData.pSysMem = vertices; result = m_pd3dDevice->CreateBuffer(&vertexDesc, &resourceData, &m_pVertexBuffer);
if (FAILED(result))
{
return false;
} return true;
其中D3D11_BUFFER_DESC定义如下:
typedef struct D3D11_BUFFER_DESC {
UINT ByteWidth;
D3D11_USAGE Usage;
UINT BindFlags;
UINT CPUAccessFlags;
UINT MiscFlags;
UINT StructureByteStride;
} D3D11_BUFFER_DESC;
D3D11_SUBRESOURCE_DATA定义如下:
typedef struct D3D11_SUBRESOURCE_DATA {
const void *pSysMem;
UINT SysMemPitch;
UINT SysMemSlicePitch;
} D3D11_SUBRESOURCE_DATA;
渲染几何体
剩下代码是渲染几何体和 shaders 。我们在TriangleDemo::Render() 函数进行渲染几何体的工作
void TriangleDemo::Render()
{
if (m_pImmediateContext == )
return;
//清除渲染目标视图
float clearColor[] = { 0.5f, 0.5f, 0.5f, 1.0f };//背景颜色
m_pImmediateContext->ClearRenderTargetView(m_pRenderTargetView, clearColor); UINT stride = sizeof(VertexPos);
UINT offset = ;
//设置数据信息格式控制信息
m_pImmediateContext->IASetInputLayout(m_pInputLayout);
//设置要绘制的几何体信息
m_pImmediateContext->IASetVertexBuffers(,,&m_pVertexBuffer,&stride,&offset);
//指明如何绘制三角形
m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_pImmediateContext->VSSetShader(m_pSolidColorVS, , );
m_pImmediateContext->PSSetShader(m_pSolidColorPS, , );
m_pImmediateContext->Draw(, );
//马上输出
m_pSwapChain->Present(, );
}
着色器.fx文件代码
float4 VS_Main( float4 pos : POSITION ) : SV_POSITION {
return pos; } float4 PS_Main( float4 pos : SV_POSITION ) : SV_TARGET { return float4( 1.0f, 0.0f, 0.0f, 1.0f ); }
我们使用的vertex shader很简单的, 仅仅是传递输入的顶点坐标到输出设备;
pixel shader的工作也很简单, 仅仅是 为每个 像素pixel 配置一种固定的颜色( 红色)。