D3D12可编程渲染流水线(二)灯光和纹理

2023-12-25 20:44

本文主要是介绍D3D12可编程渲染流水线(二)灯光和纹理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、灯光和材质

顶点的颜色不再直接指定,而是由灯光、物体的材质和顶点的法向量,经过顶点着色器程序计算获得,像素的颜色通过像素着色器程序计算获得。

1.1 顶点格式

struct Vertex
{DirectX::XMFLOAT3 Pos; //位置DirectX::XMFLOAT3 Normal; //法向量
};//输入布局
mInputLayout =
{{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, //为纹理坐标预留
};

对应的着色器数据结构

struct VertexIn
{float3 PosL    : POSITION;float3 NormalL : NORMAL;
};

1.2 常量缓冲区

常量缓冲区的数据结构是256位(8个float)对齐的,不足时需要添加填充项。

//单个物体常量结构
struct ObjectConstants
{DirectX::XMFLOAT4X4 World = MathHelper::Identity4x4();//纹理转换矩阵,预留DirectX::XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
};//趟渲染常量结构,指定灯光
struct PassConstants
{DirectX::XMFLOAT4X4 View = MathHelper::Identity4x4();DirectX::XMFLOAT4X4 InvView = MathHelper::Identity4x4();DirectX::XMFLOAT4X4 Proj = MathHelper::Identity4x4();DirectX::XMFLOAT4X4 InvProj = MathHelper::Identity4x4();DirectX::XMFLOAT4X4 ViewProj = MathHelper::Identity4x4();DirectX::XMFLOAT4X4 InvViewProj = MathHelper::Identity4x4();DirectX::XMFLOAT3 EyePosW = { 0.0f, 0.0f, 0.0f };float cbPerObjectPad1 = 0.0f;  //填充项DirectX::XMFLOAT2 RenderTargetSize = { 0.0f, 0.0f };DirectX::XMFLOAT2 InvRenderTargetSize = { 0.0f, 0.0f };float NearZ = 0.0f;float FarZ = 0.0f;float TotalTime = 0.0f;float DeltaTime = 0.0f;DirectX::XMFLOAT4 AmbientLight = { 0.0f, 0.0f, 0.0f, 1.0f };// Indices [0, NUM_DIR_LIGHTS) are directional lights;// indices [NUM_DIR_LIGHTS, NUM_DIR_LIGHTS+NUM_POINT_LIGHTS) are point lights;// indices [NUM_DIR_LIGHTS+NUM_POINT_LIGHTS, NUM_DIR_LIGHTS+NUM_POINT_LIGHT+NUM_SPOT_LIGHTS)// are spot lights for a maximum of MaxLights per object.Light Lights[MaxLights];  //最多16个
};//灯光
struct Light
{DirectX::XMFLOAT3 Strength = { 0.5f, 0.5f, 0.5f };float FalloffStart = 1.0f;                          // point/spot light onlyDirectX::XMFLOAT3 Direction = { 0.0f, -1.0f, 0.0f };// directional/spot light onlyfloat FalloffEnd = 10.0f;                           // point/spot light onlyDirectX::XMFLOAT3 Position = { 0.0f, 0.0f, 0.0f };  // point/spot light onlyfloat SpotPower = 64.0f;                            // spot light only
};//材质
struct MaterialConstants
{DirectX::XMFLOAT4 DiffuseAlbedo = { 1.0f, 1.0f, 1.0f, 1.0f };DirectX::XMFLOAT3 FresnelR0 = { 0.01f, 0.01f, 0.01f };float Roughness = 0.25f;// Used in texture mapping.DirectX::XMFLOAT4X4 MatTransform = MathHelper::Identity4x4();
};

对应的着色器数据结构 ,寄存器中的变量都是全局变量,不同寄存器的变量不能重名。以下定义三种常量寄存器。

cbuffer cbPerObject : register(b0)
{float4x4 gWorld;
};// Constant data that varies per material.
cbuffer cbPass : register(b2)
{float4x4 gView;float4x4 gInvView;float4x4 gProj;float4x4 gInvProj;float4x4 gViewProj;float4x4 gInvViewProj;float3 gEyePosW;float cbPerObjectPad1;float2 gRenderTargetSize;float2 gInvRenderTargetSize;float gNearZ;float gFarZ;float gTotalTime;float gDeltaTime;float4 gAmbientLight;// Indices [0, NUM_DIR_LIGHTS) are directional lights;// indices [NUM_DIR_LIGHTS, NUM_DIR_LIGHTS+NUM_POINT_LIGHTS) are point lights;// indices [NUM_DIR_LIGHTS+NUM_POINT_LIGHTS, NUM_DIR_LIGHTS+NUM_POINT_LIGHT+NUM_SPOT_LIGHTS)// are spot lights for a maximum of MaxLights per object.Light gLights[MaxLights];
};struct Light
{float3 Strength;float FalloffStart; // point/spot light onlyfloat3 Direction;   // directional/spot light onlyfloat FalloffEnd;   // point/spot light onlyfloat3 Position;    // point light onlyfloat SpotPower;    // spot light only
};//材质寄存器
cbuffer cbMaterial : register(b1)
{float4 gDiffuseAlbedo;float3 gFresnelR0;float  gRoughness;float4x4 gMatTransform;
};struct Material
{float4 DiffuseAlbedo;float3 FresnelR0;float Shininess;
};

1.3 创建资源

分别创建物体、渲染趟、材质三种GPU资源,由于可能更新数据,在上传堆上创建。 

std::unique_ptr<UploadBuffer<PassConstants>> PassCB = nullptr;
std::unique_ptr<UploadBuffer<MaterialConstants>> MaterialCB = nullptr;
std::unique_ptr<UploadBuffer<ObjectConstants>> ObjectCB = nullptr;PassCB = std::make_unique<UploadBuffer<PassConstants>>(device, passCount, true);MaterialCB = std::make_unique<UploadBuffer<MaterialConstants>>(device, materialCount, true);ObjectCB = std::make_unique<UploadBuffer<ObjectConstants>>(device, objectCount, true);

1.4 根签名

根参数采用简单的根描述符方式。

// Root parameter can be a table, root descriptor or root constants.
CD3DX12_ROOT_PARAMETER slotRootParameter[3];// Create root CBV.
slotRootParameter[0].InitAsConstantBufferView(0);
slotRootParameter[1].InitAsConstantBufferView(1);
slotRootParameter[2].InitAsConstantBufferView(2);// A root signature is an array of root parameters.
CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(3, slotRootParameter, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

1.5 更新常量缓冲区数据

更新材质,与其他的上传堆常量缓冲区数据更新方式相同。通常材质更新不频繁,可以考虑放到默认堆里?

XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);MaterialConstants matConstants;
matConstants.DiffuseAlbedo = mat->DiffuseAlbedo;
matConstants.FresnelR0 = mat->FresnelR0;
matConstants.Roughness = mat->Roughness;
XMStoreFloat4x4(&matConstants.MatTransform, XMMatrixTranspose(matTransform));currMaterialCB->CopyData(mat->MatCBIndex, matConstants);

1.6 渲染

mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
//绑定趟渲染资源(公共资源)到b2
auto passCB = mCurrFrameResource->PassCB->Resource();
mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());//每个物体的渲染调用
auto ri = ritems[i];//绑定顶点和索引缓冲区资源
cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
cmdList->IASetPrimitiveTopology(ri->PrimitiveType);//绑定该物体使用的变换矩阵资源到b0
D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
cmdList->SetGraphicsRootConstantBufferView(0, objCBAddress);//绑定该物体对象的材质资源到b1
D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
cmdList->SetGraphicsRootConstantBufferView(1, matCBAddress);//绘制调用
cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);

二、纹理

2.1 顶点格式

顶点增加了纹理坐标

struct Vertex
{DirectX::XMFLOAT3 Pos;DirectX::XMFLOAT3 Normal;DirectX::XMFLOAT2 TexC;
};//输入布局
mInputLayout =
{{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, //为纹理坐标预留
};

 对应的着色器数据结构,顶点输入输出结构增加纹理坐标。

struct VertexIn
{float3 PosL    : POSITION;float3 NormalL : NORMAL;float2 TexC    : TEXCOORD;
};

如果纹理和材质绑定在一起,当物体选定某种材质时,也确定了他的纹理。Material结构体的DiffuseSrvHeapIndex表示所用纹理对应的描述符在描述符堆中的位置。

struct Material
{// Unique material name for lookup.std::string Name;// Index into constant buffer corresponding to this material.int MatCBIndex = -1;// Index into SRV heap for diffuse texture.int DiffuseSrvHeapIndex = -1;// Index into SRV heap for normal texture.int NormalSrvHeapIndex = -1;int NumFramesDirty = gNumFrameResources;// Material constant buffer data used for shading.DirectX::XMFLOAT4 DiffuseAlbedo = { 1.0f, 1.0f, 1.0f, 1.0f };DirectX::XMFLOAT3 FresnelR0 = { 0.01f, 0.01f, 0.01f };float Roughness = .25f;DirectX::XMFLOAT4X4 MatTransform = MathHelper::Identity4x4();
};

纹理通常放在默认堆中,不通过cpu修改。

2.2 纹理和静态采样器缓冲区

静态采样器放到静态采样器寄存器中,通过根签名描述里的静态采样器描述关联。

const CD3DX12_STATIC_SAMPLER_DESC pointWrap(0, // 采样器寄存器编号D3D12_FILTER_MIN_MAG_MIP_POINT, // filterD3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressUD3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressVD3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressWauto staticSamplers = GetStaticSamplers();// A root signature is an array of root parameters.
CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,(UINT)staticSamplers.size(), staticSamplers.data(),D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
);

在mCommandList->SetGraphicsRootSignature中执行绑定。

静态采样器描述包括对应的寄存器编号、过滤器和纹理寻址方式。根签名的采样器数据记录了对应的寄存器编号,后续绘制前按照这个编号进行资源绑定。之所以叫静态采样器,是因为设置完成后无法再修改采样器属性。也可以使用动态采样器,使用上传堆创建资源,在运行时动态修改值。

寄存器槽就是向着色器传递资源的手段,register(*#)中*表示寄存器传递的资源类型,可以是t(表示着色器资源视图)、s(采样器)、u(无序访问视图)、以及b(常量缓冲区视图),#则为所用的寄存器编号。

HLSL中增加静态采样寄存器s0s1s2等,增加2D纹理寄存器 t0,t1。

Texture2D    gDiffuseMap : register(t0);SamplerState gsamPointWrap        : register(s0);
SamplerState gsamPointClamp       : register(s1);
SamplerState gsamLinearWrap       : register(s2);
SamplerState gsamLinearClamp      : register(s3);
SamplerState gsamAnisotropicWrap  : register(s4);
SamplerState gsamAnisotropicClamp : register(s5);

物体常量寄存器增加纹理变换矩阵,可对纹理进行缩放等操作。

像素着色器程序,纹理参数参与颜色的计算。

常量寄存器三种: 物体,渲染趟常数,材质。

2.3 创建资源

加载本地文件到默认堆资源。

HRESULT DirectX::CreateDDSTextureFromFile12(_In_ ID3D12Device* device,_In_ ID3D12GraphicsCommandList* cmdList,_In_z_ const wchar_t* szFileName,_Out_ ComPtr<ID3D12Resource>& texture,_Out_ ComPtr<ID3D12Resource>& textureUploadHeap,_In_ size_t maxsize,_Out_opt_ DDS_ALPHA_MODE* alphaMode)

创建纹理资源的描述符堆和描述符

D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
srvHeapDesc.NumDescriptors = 3;
srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));//
// Fill out the heap with actual descriptors.
//
CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());auto bricksTex = mTextures["bricksTex"]->Resource;
auto stoneTex = mTextures["stoneTex"]->Resource;
auto tileTex = mTextures["tileTex"]->Resource;D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Format = bricksTex->GetDesc().Format;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = bricksTex->GetDesc().MipLevels;
srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
md3dDevice->CreateShaderResourceView(bricksTex.Get(), &srvDesc, hDescriptor);// next descriptor
hDescriptor.Offset(1, mCbvSrvDescriptorSize);

2.4 根签名

CD3DX12_DESCRIPTOR_RANGE texTable;
texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1,  // number of descriptors0); // register t0// Root parameter can be a table, root descriptor or root constants.
CD3DX12_ROOT_PARAMETER slotRootParameter[4];// Perfomance TIP: Order from most frequent to least frequent.
slotRootParameter[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);

2.5 更新缓冲区数据

顶点的纹理坐标也可以随时间变化,表现为水的流动。

ObjectConstants objConstants;
XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));currObjectCB->CopyData(e->ObjCBIndex, objConstants);

2.6 渲染

渲染中的mCommandList->SetDescriptorHeaps设置渲染中用到的描述符堆数组。一个描述符堆中的描述符对应了寄存器和需要访问的资源。

ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);mCommandList->SetGraphicsRootSignature(mRootSignature.Get());auto passCB = mCurrFrameResource->PassCB->Resource();
mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());

渲染单个物体,SetGraphicsRootDescriptorTable(根参数的索引号,第几个根参数),绑定资源到寄存器。

UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
UINT matCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(MaterialConstants));auto objectCB = mCurrFrameResource->ObjectCB->Resource();
auto matCB = mCurrFrameResource->MaterialCB->Resource();auto ri = ritems[i];cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
cmdList->IASetPrimitiveTopology(ri->PrimitiveType);CD3DX12_GPU_DESCRIPTOR_HANDLE tex(mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
tex.Offset(ri->Mat->DiffuseSrvHeapIndex, mCbvSrvDescriptorSize);
cmdList->SetGraphicsRootDescriptorTable(0, tex);D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
cmdList->SetGraphicsRootConstantBufferView(1, objCBAddress);D3D12_GPU_VIRTUAL_ADDRESS matCBAddress = matCB->GetGPUVirtualAddress() + ri->Mat->MatCBIndex*matCBByteSize;
cmdList->SetGraphicsRootConstantBufferView(3, matCBAddress);cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);

 

 

 

 

 

 

这篇关于D3D12可编程渲染流水线(二)灯光和纹理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/536875

相关文章

详解如何在React中执行条件渲染

《详解如何在React中执行条件渲染》在现代Web开发中,React作为一种流行的JavaScript库,为开发者提供了一种高效构建用户界面的方式,条件渲染是React中的一个关键概念,本文将深入探讨... 目录引言什么是条件渲染?基础示例使用逻辑与运算符(&&)使用条件语句列表中的条件渲染总结引言在现代

如何使用Ansible实现CI/CD流水线的自动化

如何使用Ansible实现CI/CD流水线的自动化 持续集成(CI)和持续交付(CD)是现代软件开发过程中的核心实践,它们帮助团队更快地交付高质量的软件。Ansible,作为一个强大的自动化工具,可以在CI/CD流水线中发挥关键作用。本文将详细介绍如何使用Ansible实现CI/CD流水线的自动化,包括设计流水线的结构、配置管理、自动化测试、部署、以及集成Ansible与CI/CD工具(如Jen

Go并发模型:流水线模型

Go作为一个实用主义的编程语言,非常注重性能,在语言特性上天然支持并发,Go并发模型有多种模式,通过流水线模型系列文章,你会更好的使用Go的并发特性,提高的程序性能。 这篇文章主要介绍流水线模型的流水线概念,后面文章介绍流水线模型的FAN-IN和FAN-OUT,最后介绍下如何合理的关闭流水线的协程。 Golang的并发核心思路 Golang并发核心思路是关注数据流动。数据流动的过程交给cha

opengl纹理操作

我们在前一课中,学习了简单的像素操作,这意味着我们可以使用各种各样的BMP文件来丰富程序的显示效果,于是我们的OpenGL图形程序也不再像以前总是只显示几个多边形那样单调了。——但是这还不够。虽然我们可以将像素数据按照矩形进行缩小和放大,但是还不足以满足我们的要求。例如要将一幅世界地图绘制到一个球体表面,只使用glPixelZoom这样的函数来进行缩放显然是不够的。OpenGL纹理映射功能支持将

OpenGL ES 2.0渲染管线

http://codingnow.cn/opengles/1504.html Opengl es 2.0实现了可编程的图形管线,比起1.x的固定管线要复杂和灵活很多,由两部分规范组成:Opengl es 2.0 API规范和Opengl es着色语言规范。下图是Opengl es 2.0渲染管线,阴影部分是opengl es 2.0的可编程阶段。   1. 顶点着色器(Vert

【鸿蒙HarmonyOS NEXT】调用后台接口及List组件渲染

【鸿蒙HarmonyOS NEXT】调用后台接口及List组件渲染 一、环境说明二、调用后台接口及List组件渲染三、总结 一、环境说明 DevEco Studio 版本: API版本:以12为主 二、调用后台接口及List组件渲染 后台接口及返回数据分析 JSON数据格式如下: {"code": 0,"data": {"total": 6,"pageSize"

【爬虫渲染神器】selenium 和pyppeteer 的动态渲染ajax反爬虫

许多网页是动态加载的网页,其中不乏使用了ajax异步技术,那么我们有没有一种渲染工具,直接省略分析过程,模拟浏览器渲染的操作呢,获取到我们想要的内容。当然有,下面我们介绍两种渲染工具的实战使用。 目标网站: http://www.porters.vip/verify/sign/ 点击参看详情页的里面内容。 前一篇文章,我们介绍了,js逆向分析两种方法JS逆向–签名验证反爬虫】sign签名验证

试用UE4的纹理数组(UTexture2DArray)

UTexture2DArray 我发现在我目前使用的版本(4.25)中,官方已经实现了纹理数组(可能在4.24或更早版本就已经实现了)。 纹理数组,其含义不言而喻。一个重要作用是可以使用更多的纹理而不受制于sampler数目限制。 这一篇里我想对官方的纹理数组进行一下简单的试用。 试用 0. 启用纹理数组 虽然我看到了代码中有UTexture2DArray这个类,不过一开始并没有在编辑器

研究纹理采样器在像素级别的采样位置

问题 【纹理采样器】是一个基础的概念。假设有一个正方形面片,顶点的UV范围是0.0~1.0,那么在这个正方形面片上采样一张纹理时,会呈现出完整的纹理。 但我现在关注的问题是,在像素级别上,采样的位置是怎样的。具体来讲:对于UV值是(0.0,0.0)的点,它对应的采样位置是纹理最左上角像素的中心?还是纹理最左上角像素的左上角?即,下面左右哪个是正确的情况? 在宏观上,尤其是像素较多的时候,二者

图形API学习工程(11):使用纹理

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics 目标 实现纹理采样。 参考教程/代码范例: OpenGL: 纹理 - LearnOpenGL CN Vulkan: Images - Vulkan Tutorial D3D11: DirectX11官方SDK范例【Tutorial 7: Texture Mapping and Constant