如何使用Texturecube渲染一个带纹理的立方体?
Texturecube如何使用?
需要的纹理资源是什么样的,6副一样的图片传入同一个资源堆吗?
https://blog.csdn.net/u014038143/article/details/86656568
【以下回答由 GPT 生成】
首先,我们需要做几个准备工作来设置Direct3D 12并加载纹理资源。
创建交换链,并设置后台缓冲区。
加载纹理资源:
下面给出具体的代码实现。
#include <d3d12.h>
#include <dxgi1_6.h>
#include <DirectXMath.h>
#include <wincodec.h>
#include <wrl.h>
#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "windowscodecs.lib")
using namespace Microsoft::WRL;
// ...
// Step 1: 设置Direct3D 12
HWND hWnd; // 窗口句柄
ID3D12Device* pDevice = nullptr; // Direct3D 12设备
ID3D12CommandQueue* pCommandQueue = nullptr; // 命令队列
IDXGISwapChain3* pSwapChain = nullptr; // 交换链
// 创建Win32窗口并初始化
void CreateWin32Window()
{
// ...
}
// 创建Direct3D 12设备和命令队列
void CreateDeviceAndCommandQueue()
{
D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&pDevice));
D3D12_COMMAND_QUEUE_DESC queueDesc = {}; // 命令队列描述符
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; // 命令队列类型为直接
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; // 无特殊标志
pDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&pCommandQueue));
}
// 创建交换链和后台缓冲区
void CreateSwapChainAndBackBuffers()
{
ComPtr<IDXGIFactory4> pFactory;
CreateDXGIFactory1(IID_PPV_ARGS(&pFactory));
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; // 交换链描述符
swapChainDesc.BufferCount = 2; // 后台缓冲区数量
swapChainDesc.Width = 800; // 窗口宽度
swapChainDesc.Height = 600; // 窗口高度
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 后台缓冲区格式
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // 后台缓冲区用途为渲染目标输出
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; // 后台缓冲区交换方式为翻转丢弃
swapChainDesc.SampleDesc.Count = 1; // 采样数
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullScreenDesc = {}; // 全屏描述符
fullScreenDesc.Windowed = TRUE; // 非全屏
pFactory->CreateSwapChainForHwnd(pCommandQueue, hWnd, &swapChainDesc, &fullScreenDesc, nullptr, &pSwapChain);
}
// ...
// Step 2: 加载纹理资源
ID3D12Resource* pTexture = nullptr; // 纹理资源
ID3D12DescriptorHeap* pDescriptorHeap = nullptr; // 纹理资源堆
// 加载纹理图片文件并返回像素数据
void LoadTexture(const wchar_t* filePath, std::vector<BYTE>& pixels, UINT& width, UINT& height)
{
ComPtr<IWICImagingFactory> pFactory;
CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pFactory));
ComPtr<IWICBitmapDecoder> pDecoder;
pFactory->CreateDecoderFromFilename(filePath, nullptr, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder);
ComPtr<IWICBitmapFrameDecode> pFrame;
pDecoder->GetFrame(0, &pFrame);
UINT frameWidth, frameHeight;
pFrame->GetSize(&frameWidth, &frameHeight);
width = frameWidth;
height = frameHeight;
UINT stride = frameWidth * 4; // 4字节对齐
std::vector<BYTE> tempPixels(stride * frameHeight);
pFrame->CopyPixels(nullptr, stride, stride * frameHeight, tempPixels.data());
// 转换像素数据格式
UINT pixelSize = frameWidth * frameHeight;
pixels.resize(pixelSize * 4);
for (UINT i = 0; i < pixelSize; i++)
{
pixels[i * 4] = tempPixels[i * 4 + 2]; // B
pixels[i * 4 + 1] = tempPixels[i * 4 + 1]; // G
pixels[i * 4 + 2] = tempPixels[i * 4]; // R
pixels[i * 4 + 3] = tempPixels[i * 4 + 3]; // A
}
}
// 创建纹理资源堆
void CreateTextureHeap()
{
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; // 纹理资源堆描述符
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; // 堆类型为常量缓冲视图、着色器资源视图或无序访问视图
heapDesc.NumDescriptors = 1; // 堆中纹理资源个数
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; // 堆在着色器可见
pDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&pDescriptorHeap));
}
// 创建纹理资源视图并关联到纹理资源堆
void CreateTextureView()
{
D3D12_SHADER_RESOURCE_VIEW_DESC viewDesc = {}; // 纹理资源视图描述符
viewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 视图格式与后台缓冲区格式一致
viewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; // 纹理资源视图维度为TextureCube
viewDesc.TextureCube.MipLevels = 1; // 使用的mip等级数量
pDevice->CreateShaderResourceView(pTexture, &viewDesc, pDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
}
// 加载纹理资源并创建纹理资源视图
void LoadAndCreateTexture()
{
UINT textureWidth, textureHeight;
std::vector<BYTE> texturePixels;
// 加载纹理图片文件
LoadTexture(L"texture.png", texturePixels, textureWidth, textureHeight);
// 计算纹理资源大小
UINT textureSize = texturePixels.size();
// 创建纹理资源
D3D12_RESOURCE_DESC textureDesc = {}; // 纹理资源描述符
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; // 纹理资源维度为Texture2D
textureDesc.Alignment = 0; // 默认对齐
textureDesc.Width = textureWidth; // 纹理宽度
textureDesc.Height = textureHeight; // 纹理高度
textureDesc.DepthOrArraySize = 6; // 数组大小为6
textureDesc.MipLevels = 1; // 使用的mip等级数量
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 纹理格式
textureDesc.SampleDesc.Count = 1; // 采样数
textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // 纹理布局
textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE; // 无特殊标志
D3D12_HEAP_PROPERTIES heapProperties = {}; // 堆属性
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; // 默认堆类型
D3D12_CLEAR_VALUE clearValue = {}; // 清除值
clearValue.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 格式与纹理格式一致
pDevice->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &textureDesc, D3D12_RESOURCE_STATE_COPY_DEST, &clearValue, IID_PPV_ARGS(&pTexture));
// 创建纹理资源的上传堆
ComPtr<ID3D12Resource> pUploadHeap;
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; // 上传堆类型
pDevice->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &textureDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&pUploadHeap));
// 将纹理像素数据复制到上传堆
D3D12_SUBRESOURCE_DATA textureData = {}; // 子资源数据
textureData.pData = texturePixels.data(); // 纹理像素数据首地址
textureData.RowPitch = textureWidth * 4; // 每行像素所占字节数
textureData.SlicePitch = textureData.RowPitch * textureHeight; // 每个面的大小
UpdateSubresources(pCommandList, pTexture, pUploadHeap.Get(), 0, 0, 1, &textureData);
// 将纹理资源从COPY_DEST状态转换为PIXEL_SHADER_RESOURCE状态
pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pTexture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
// 创建纹理资源堆
CreateTextureHeap();
// 创建纹理资源视图
CreateTextureView();
}
// ...
// 渲染函数
void Render()
{
// ...
}
接下来,我们将在渲染函数中实现绘制带纹理的立方体的代码。
// 渲染函数
void Render()
{
// 设置渲染目标
auto rtvHandle = pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); // 解析纹理资源堆句柄
pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pRenderTarget)); // 获取后台缓冲区
pDevice->CreateRenderTargetView(pRenderTarget, nullptr, rtvHandle); // 创建渲染目标视图
// 清除渲染目标
const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
pCommandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
// 设置根签名和管道状态
pCommandList->SetGraphicsRootSignature(pRootSignature);
pCommandList->SetPipelineState(pPipelineState);
// 设置视口和裁剪矩形
D3D12_VIEWPORT viewport = { 0.0f, 0.0f, 800, 600, 0.0f, 1.0f };
pCommandList->RSSetViewports(1, &viewport);
D3D12_RECT scissorRect = { 0, 0, 800, 600 };
pCommandList->RSSetScissorRects(1, &scissorRect);
// 设置顶点缓冲区和索引缓冲区
pCommandList->IASetVertexBuffers(0, 1, &vertexBufferView);
pCommandList->IASetIndexBuffer(&indexBufferView);
// 设置纹理资源堆和纹理资源视图
pCommandList->SetDescriptorHeaps(1, &pDescriptorHeap);
pCommandList->SetGraphicsRootDescriptorTable(0, pDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
// 绘制立方体
pCommandList->DrawIndexedInstanced(36, 1, 0, 0, 0);
// 切换后台缓冲区的状态为PRESENT
pCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pRenderTarget, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
// 完成命令列表的执行
pCommandList->Close();
// 将命令列表添加到命令队列中执行
pCommandQueue->ExecuteCommandLists(1, ppCommandList);
// 交换后台缓冲区和前台缓冲区
pSwapChain->Present(1, 0);
}
至此,我们通过DirectX 12实现了在C++中渲染带纹理的立方体。在这个过程中,我们使用了TextureCube来存储6张纹理图片,并且只需要传入同一个纹理资源堆即可。