Direct3D 11 总结 —— 4 绘制三角形

19 篇文章 0 订阅
13 篇文章 3 订阅

介绍

本文主要介绍如何使用 direct3D 11 绘制三角形。

pipeline 介绍

从 msdn 的文章,可以获得 direct3D 的 pipeline 如下图所示,对于本文只需要设置红框内的部分。
在这里插入图片描述

输入装配阶段

在这里需要将顶点坐标、顶点数据是使用什么格式保存的(float 还是 int;是几位的等)、想要顶点组成什么图像(比如传入3个点,你可能就是想画3个点或者一条线和1一个点或者一个三角形等)

顶点着色器阶段

着色器就是 gpu 执行的代码,gpu 的特点是计算单元的算力有线,但是每个 gpu 上有多个执行单元,就可以并行处理数据了。
所以着色器的代码一般不会很复杂,我理解着色器语法是 c/c++ 的简化版。
对于着色器代码,会对每个传入的点都运行一遍,且相互之间独立,这个就可以充分发挥 gpu 的高并发的特点。
顶点着色器阶段主要就是对点的位置进行一些几何的变化,如平移、旋转和缩放等

像素着色器阶段

像素着色器阶段就是通过传入的顶点位置,计算该位置应该显示什么颜色。

输出阶段

该阶段是整个 pipeline 的输出,你需要设置 pipeline 最后将处理的数据保存在哪个位置。

代码

重要函数解释与理解

上一篇文章也讲到

device 主要用于显示是否支持某些特性和分配资源
context 主要用于设置渲染状态、将资源绑定到 pipeline 和 发出渲染命令

本文通过 CreateBuffer 向 device 申请的资源,用于存储顶点数据。(即 cpu 中申请一块内存 new malloc)
通过 context 绑定的资源如下所述:

IASetVertexBuffers

向 input-Assembler 阶段设置 顶点缓存数据,即通过该接口将顶点数据保存到 gpu 显存中。此时,gpu只是有了一堆数据,但是不知道这堆数据是什么意思,应该怎么来使用。

IASetInputLayout

告诉 input-Assembler 阶段,每种缓存的数据应该如何来读取,如 DXGI_FORMAT_R32G32B32_FLOAT,表示每组数据有 3 个数,每个数为 4 字节,用 float 格式来解析该数据。
也会写入该数据供哪个变量来读取。
如 int add(int a, int b) ,需要告诉 gpu 你这个数据是传给 a 还是 b的。
shader 中函数写成这样 VSOut MyVs(float3 pos : POSITION),这里的 POSITION 就是 cpu 和 gpu 之间数据传输的标识。 pos 标识是 gpu 内部使用的

IASetPrimitiveTopology

告诉 input-Assembler ,这些点之间的拓扑结构是怎么样,如点、直线和三角形。

VSSetShader

设置 顶点着色器
着色器的编译方式,和 cpu 的代码也不一样,具体的编译方式可以参考这篇文章

PSSetShader

设置 像素着色器

OMSetRenderTargets

设置输出的渲染目标,即把处理后的数据保存在哪里。

RSSetViewports

这个函数是用来设置输出数据,显示在目标纹理的哪个位置,起点和宽度。

Draw

设置上述的配置后,通过该函数控制 pipeline 开始执行。

具体代码

void Graphics::DrawTriangle()
{
	/************************************* 输入装配阶段 **************************************/	
	 //创建顶点缓存
	struct SimpleVertex
	{
		DirectX::XMFLOAT3 pos;
	};
	SimpleVertex vertices[] =
	{
		DirectX::XMFLOAT3(0.0f, 0.5f, 0.5f),
		DirectX::XMFLOAT3(0.5f,-0.5f, 0.5f),
		DirectX::XMFLOAT3(-0.5f,-0.5, 0.5f)
	};

	D3D11_BUFFER_DESC verticsDesc = {};
	verticsDesc.ByteWidth = sizeof(vertices) * 3; // 字节数
	// 将 usage 设为 D3D11_USAGE_IMMUTABLE  D3D11_USAGE_DEFAULT 可行
	verticsDesc.Usage = D3D11_USAGE_DEFAULT; // 资源的使用,gpu和cpu 的读写权限 
	verticsDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; // 标识如何将资源绑定到 pipeline 
	verticsDesc.CPUAccessFlags = 0; // CPU 的读写权限
	verticsDesc.MiscFlags = 0;
	verticsDesc.StructureByteStride = 0;

	D3D11_SUBRESOURCE_DATA resourceData = {};
	resourceData.pSysMem = vertices;
	resourceData.SysMemPitch = 0;
	resourceData.SysMemSlicePitch = 0;
	ID3D11Buffer* verticesBuffer;
	m_pDevice->CreateBuffer(&verticsDesc, &resourceData, &verticesBuffer);
	
	UINT strider = sizeof(SimpleVertex);
	UINT offset = 0;
	m_pContext->IASetVertexBuffers(
		0,				// start slot
		1,				// buffer 数量  (start slot ~ start slot + buffer number
		&verticesBuffer,// 顶点缓存
		&strider,		// 每组数据的字节数
		&offset);		// 偏移量
	
	// 输入数据解释
	D3D11_INPUT_ELEMENT_DESC layout[] = {{
		"POSITION",									// shader 中的变量名
		0,
		DXGI_FORMAT_R32G32B32_FLOAT,				// 顶点数据格式
		0,											// 代表顶点缓存数据通过哪个 slot 传给 GPU, input slot 数字,范围从0到15
		0,											// 偏移量,告诉 GPU 从哪个位置开始拿数据
		D3D11_INPUT_PER_VERTEX_DATA ,				// 输入槽的数据类型
		0
	}};

	// 图元拓扑结构
	m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	/************************************* 顶点着色器阶段 **************************************/
	ID3DBlob* pBlob = NULL;
	D3DReadFileToBlob(L"HLSL/vs.cso", &pBlob);
	ID3D11VertexShader* pVertexShader = NULL;
	m_pDevice->CreateVertexShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &pVertexShader);
	m_pContext->VSSetShader(pVertexShader, nullptr, 0);

	ID3D11InputLayout* inputLayout = NULL;
	m_pDevice->CreateInputLayout(layout, 
		1, 
		pBlob->GetBufferPointer(), // 该 shader 有 layout 中定义的 SemanticName
		pBlob->GetBufferSize(), 
		&inputLayout);
	m_pContext->IASetInputLayout(inputLayout);

	/************************************* 像素着色器阶段 **************************************/
	D3DReadFileToBlob(L"HLSL/ps.cso", &pBlob);
	ID3D11PixelShader* pPixelShader = NULL;
	m_pDevice->CreatePixelShader(pBlob->GetBufferPointer(), pBlob->GetBufferSize(), nullptr, &pPixelShader);
	m_pContext->PSSetShader(pPixelShader, nullptr, 0);

	
	/************************************* 输出阶段 **************************************/
	// 设置渲染目标
	m_pContext->OMSetRenderTargets(1, &m_pRenderTargetView, NULL);
	
	// 设置视口
	D3D11_VIEWPORT viewPort = {};
	viewPort.TopLeftX = 0;
	viewPort.TopLeftY = 0;
	viewPort.Width = 300;
	viewPort.Height = 200;
	viewPort.MinDepth = 0.0f;
	viewPort.MaxDepth = 1.0f;
	m_pContext->RSSetViewports(1, &viewPort);
						
	// 开始绘制
	m_pContext->Draw(3, 0);
}

vs.hlsl

struct VSOut
{
	float4 pos : SV_Position;
};

VSOut MyVs(float3 pos : POSITION)
{
	VSOut vsOut;
	vsOut.pos = float4(pos.x, pos.y, pos.z, 1.0);
	return vsOut;
}

ps.hlsl

float4 MyPs() : SV_Target
{
	return float4(0.0f, 1.0f, 0.0f, 1.0f);
}

最终效果

在这里插入图片描述

本人也是刚开始学习,理解的可能不是很正确,表达不正确的地方,感谢各位大佬指点。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值