本文主要是介绍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可编程渲染流水线(二)灯光和纹理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!