DirectX12(D3D12)基础教程 二“纹理”

2 篇文章 2 订阅
2 篇文章 0 订阅

什么是纹理,简单理解叫贴图,比如现在一张1920X1080图片要显示在1920X1080的窗口上,那么图片像素与窗口一一对应简单的复制粘贴。如果图片大小与目标大小不一样时通过某种算法实现显示目标窗口上,这就叫纹理过滤。

纹理坐标 范围0到1,原点在左下角

使用d3d12窗口显示一张图片,如果用gdi+现实简单多了,调用一个函数就可以解决。

1. 读取图片信息 大小,像素深度BPP,d3d12所要的格式, 数据 。这里使用了 WIC接口,全称就是Windows Image Component(Windows图像组件)详情见官网wic接口。为了简化程序我们写类去处理读取图片信息代码:

class CWICIamge
{
public:
	DXGI_FORMAT GetImageInfo(const wchar_t *pathImage, UINT& w, UINT& h, UINT& bpp, UINT& nPicRowPitch, BYTE**pbPicData);

private:
	void WicLoadImage(const wchar_t * pathImage,ComPtr<IWICImagingFactory>& pIWICFactory, ComPtr<IWICBitmapDecoder>& pIWICDecoder);
	void GetImagePixelFormat(ComPtr<IWICBitmapDecoder> pIWICDecoder,ComPtr<IWICBitmapFrameDecode>&pIWICFrame, WICPixelFormatGUID& wpf);
	void GetBitmapSource(WICPixelFormatGUID wpf, GUID tgFormat, ComPtr<IWICImagingFactory>pIWICFactory, ComPtr<IWICBitmapFrameDecode>pIWICFrame, ComPtr<IWICBitmapSource>& pIBMP);
	void GetBitmapInfo(GUID tgFormat,ComPtr<IWICImagingFactory> pIWICFactory, ComPtr<IWICBitmapSource> pIBMP, UINT& w, UINT& h, UINT& bpp);
	
	bool GetTargetPixelFormat(const GUID* pSourceFormat, GUID* pTargetFormat, DXGI_FORMAT& dxForma);
};

简单调用GetImageInfo()就得到d3d12所需图片所有信息。

2. 编写Shader程序:Texture.hlsl

cbuffer SceneConstantBuffer : register(b0)
{
	float4 offset;
	float4 padding[60];
};

struct PSInput
{
	float4 position : SV_POSITION;
	float2 uv : TEXCOORD;
};

Texture2D g_texture : register(t0);
SamplerState g_sampler : register(s0);

PSInput VSMain(float4 position : POSITION, float4 uv : TEXCOORD)
{
	PSInput result;

	result.position = position + offset;
	result.uv = uv;

	return result;
}

float4 PSMain(PSInput input) : SV_TARGET
{
	return g_texture.Sample(g_sampler, input.uv);
}

说明一下:

register(b0)表示: CBV描述符-常量缓冲区视图
register(t0)表示: CBV描述符-着色器资源视图
register(s0)表示: Sample采样器(sampler / 取样器)
struct PSInput
{
    float4 position : SV_POSITION; 
    float2 uv : TEXCOORD;
};
顶点输入数据排布是:顶点坐标+纹理坐标

3.先了解一下 d3d12相关资源,视图描述符的具体类型:

渲染目标视图描述符(RTV)用于描述渲染目标视图的属性,例如关联的资源类型、资源格式等
深度模板视图描述符(DSV)用于描述深度模板视图的属性,包括关联的资源类型、资源格式、使用的深度模板格式等。
着色器资源视图描述符(SRV)用于描述着色器资源视图的属性,例如关联的资源类型、资源格式、资源在着色器中的访问方式等。
常量缓冲区视图描述(CBV)用于描述常量缓冲区视图的属性,包括关联的常量缓冲区的大小。
无序访问视图描述符(UAV)用于描述无序访问视图的属性,例如关联的资源类型、资源格式、在着色器中的访问方式等。
采样器描述符(Sampler)用于描述采样器的属性,例如过滤方式、边界模式、向导等。

4. D3D12中创建资源的三种方式(这里使用“提交方式”,简单点)

提交方式(CreateCommittedResource)为了兼容旧的,D3D12不推荐使用
定位方式(CreatePlacedResource)创建放置在特定堆中的资源。放置的资源是可用的最轻量资源对象,是创建和销毁速度最快的资源对象,推荐使用。
保留方式(CreateReservedResource)保留方式创建作为更高级的方法,目前不解

5. D3D12中堆的类型

D3D12_HEAP_TYPE_DEFAULT  默认堆GPU 可读写,CPU无法访问,通常上传堆对其进行填充资源。
D3D12_HEAP_TYPE_UPLOAD   上传堆此堆类型最适合 CPU-write-once、GPU-read-once 数据

D3D12_HEAP_TYPE_READBACK  回读堆

此堆类型最适合 GPU-write-once、CPU 可读数据。
D3D12_HEAP_TYPE_CUSTOM 自定义堆 支持自定义堆

6. 要用d3d12显示一张图片需要相关资源和流程如图:


        

第一章显示“三角形”流程差不多,在其代码修改出来成了显示纹理因为其他流程都一样,只是多“加载图片”、“填充纹理”、“相连SRV-视图描述符”这三部份。“加载图片”前面上面讲过,“填充纹理”是这部份难重点(上面流程图编号:4)

4.1 使用 wic读取图片信息 应该没有问题

4.2 创建默认堆,  参数是图片格式、宽度、高度。它的最终目标是放图片数据资源,因它GPU 可读写,CPU无法访问,所以需要上传堆。

4.3 上传堆,图片数据先复制到上传堆,再由上传堆复制到默认堆上(这个操作由gpu来完成,CPU无法访问),这里借助DirectX-Headers的函数UpdateSubresources()来完成复杂的操作,参数:(默认堆,上传堆,图片数据)代码:

	D3D12_SUBRESOURCE_DATA textureData = {};
	textureData.pData = pImageData;
	textureData.RowPitch = w * bpp / 8;
	textureData.SlicePitch = textureData.RowPitch * h;

	UpdateSubresources(m_commandList.Get(), m_texture.Get(), m_textureUploadHeap.Get(), 0, 0, 1, &textureData);

资源屏障(Resource Barrier)只有当图片数据完全复制到默认堆后默认堆数据才完整,让访问其数据数据才有意义,所以要设置资源屏障,借助DirectX-Headers让代码变得简单

	m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));

通资源前后状态变化,默认堆资源由D3D12_RESOURCE_STATE_COPY_DEST变成D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE说明复制完成。这里有问题上传堆数据复制到默认堆什么时候执行?以上这些操作在命令列表上,加到命令列队列上去执行:

	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

填充纹理数据的代码:

void CD3D12Texture::CopyImageDataCommitted(int w,int h,int bpp, BYTE* pImageData)
{

    /// bpp为图片格式
	D3D12_SUBRESOURCE_DATA textureData = {};
	textureData.pData = pImageData;
	textureData.RowPitch = w * bpp / 8;
	textureData.SlicePitch = textureData.RowPitch * h;

	UpdateSubresources(m_commandList.Get(), m_texture.Get(), m_textureUploadHeap.Get(), 0, 0, 1, &textureData);

	m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
	
	ThrowIfFailed(m_commandList->Close());

	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
}

5. SRV-视图描述符 ,先创建描述符堆,再创建SRV-视图描述符,关连图片数据资源默认堆,代码:


void CD3D12Texture::CreateShaderResource(DXGI_FORMAT dxFormat)
{
	D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
	srvHeapDesc.NumDescriptors = 2; // srv +cbv
	srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
	srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
	ThrowIfFailed(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap)));

	D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
	srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
	srvDesc.Format = dxFormat;
	srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
	srvDesc.Texture2D.MipLevels = 1;

     m_texture 图片数据资源默认堆
	m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_srvHeap->GetCPUDescriptorHandleForHeapStart());
	m_nSRVDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}

题外话: 看到这里,相信学习d3d12已有一段时间,严格来说还没有入门。只所以这样说是因为1.这两章显示的东西是2D平面,静态,2.还需要线性代数,学习线性代数以下教程比较精简推荐给大家变换 - LearnOpenGL CN (learnopengl-cn.github.io)

工程HelloCube代码已实现一个自动旋转的立方体 后面有时间会再写一篇

本章完整代码 

【免费】HelloDirectX12_directx12资源-CSDN文库 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq00769539

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值