云计算百科
云计算领域专业知识百科平台

第13章 Direct3D核心编程精要——从初始化到渲染流水线

第13章 Direct3D核心编程精要——从初始化到渲染流水线

13.1 Direct3D初始化深度解析与商业实践

13.1.1 Direct3D设备创建的艺术

在商业游戏开发中,Direct3D设备的创建不仅仅是一个技术步骤,更是性能和兼容性的平衡艺术。以《巫师3:狂猎》为例,这款游戏需要支持从DirectX 9到DirectX 11的各种硬件配置,因此其设备创建逻辑必须足够健壮和灵活。

Windows游戏编程理论中,设备创建的核心是理解特性级别(Feature Level)的概念。特性级别定义了GPU支持的功能集,从9.1到11.0,每个级别都对应着不同的硬件能力。商业游戏通常会从最高级别开始尝试,然后逐步降级直到找到合适的级别。

下面是一个商业级的设备创建函数,它考虑了多种硬件配置和错误处理:

#include <windows.h>
#include <d3d11.h>
#include <dxgi.h>
#include <vector>
#include <string>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

class Direct3DDeviceManager
{
private:
struct GPUInfo
{
std::wstring description;
UINT dedicatedVideoMemory;
UINT dedicatedSystemMemory;
UINT sharedSystemMemory;
bool isPrimaryAdapter;
};

std::vector<GPUInfo> gpuList;
IDXGIFactory* dxgiFactory;
IDXGIAdapter* selectedAdapter;
ID3D11Device* direct3DDevice;
ID3D11DeviceContext* deviceContext;
D3D_FEATURE_LEVEL selectedFeatureLevel;

public:
Direct3DDeviceManager()
: dxgiFactory(nullptr)
, selectedAdapter(nullptr)
, direct3DDevice(nullptr)
, deviceContext(nullptr)
, selectedFeatureLevel(D3D_FEATURE_LEVEL_9_1)
{
}

bool Initialize(bool enableDebugLayer = false)
{
HRESULT result = S_OK;

// 1. 创建DXGI工厂
result = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&dxgiFactory);
if (FAILED(result))
{
LogError(L"创建DXGI工厂失败");
return false;
}

// 2. 枚举所有GPU并选择最佳适配器
if (!EnumerateAndSelectGPU())
{
return false;
}

// 3. 定义特性级别数组(从高到低尝试)
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1, // Windows 8及更高版本
D3D_FEATURE_LEVEL_11_0, // Windows 7及更高版本
D3D_FEATURE_LEVEL_10_1, // Windows Vista SP2及更高版本
D3D_FEATURE_LEVEL_10_0, // Windows Vista及更高版本
D3D_FEATURE_LEVEL_9_3, // Windows 7及更高版本
D3D_FEATURE_LEVEL_9_2, // Windows 7及更高版本
D3D_FEATURE_LEVEL_9_1 // Windows 7及更高版本
};

// 4. 创建标志
UINT creationFlags = 0;
if (enableDebugLayer)
{
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
}

// 5. 创建设备和上下文
result = D3D11CreateDevice(
selectedAdapter,
selectedAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE,
NULL,
creationFlags,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&direct3DDevice,
&selectedFeatureLevel,
&deviceContext
);

// 6. 如果使用硬件适配器失败,尝试使用WARP软件适配器
if (FAILED(result))
{
LogWarning(L"硬件设备创建失败,尝试WARP软件设备");

result = D3D11CreateDevice(
NULL,
D3D_DRIVER_TYPE_WARP, // WARP软件渲染器
NULL,
creationFlags,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&direct3DDevice,
&selectedFeatureLevel,
&deviceContext
);

if (FAILED(result))
{
LogError(L"WARP设备创建也失败");
return false;
}
}

// 7. 输出设备信息
LogDeviceInfo();

return true;
}

bool EnumerateAndSelectGPU()
{
IDXGIAdapter* adapter = nullptr;
UINT adapterIndex = 0;
GPUInfo bestAdapter;
bool foundBest = false;

// 枚举所有适配器
while (dxgiFactory->EnumAdapters(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND)
{
GPUInfo gpuInfo;
DXGI_ADAPTER_DESC adapterDesc;

if (SUCCEEDED(adapter->GetDesc(&adapterDesc)))
{
gpuInfo.description = adapterDesc.Description;
gpuInfo.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory;
gpuInfo.dedicatedSystemMemory = adapterDesc.DedicatedSystemMemory;
gpuInfo.sharedSystemMemory = adapterDesc.SharedSystemMemory;
gpuInfo.isPrimaryAdapter = (adapterIndex == 0);

gpuList.push_back(gpuInfo);

// 选择策略:优先选择专用显存最大的GPU
if (!foundBest || gpuInfo.dedicatedVideoMemory > bestAdapter.dedicatedVideoMemory)
{
bestAdapter = gpuInfo;
foundBest = true;

// 更新选中的适配器
if (selectedAdapter)
{
selectedAdapter->Release();
}
adapter->AddRef();
selectedAdapter = adapter;
}
}

adapter->Release();
adapterIndex++;
}

if (!foundBest)
{
LogWarning(L"未找到合适的GPU适配器,将使用默认适配器");
// 使用默认适配器(NULL表示使用默认)
selectedAdapter = nullptr;
}

return true;
}

void LogDeviceInfo()
{
std::wstring featureLevelStr;

switch (selectedFeatureLevel)
{
case D3D_FEATURE_LEVEL_11_1:
featureLevelStr = L"Direct3D 11.1";
break;
case D3D_FEATURE_LEVEL_11_0:
featureLevelStr = L"Direct3D 11.0";
break;
case D3D_FEATURE_LEVEL_10_1:
featureLevelStr = L"Direct3D 10.1";
break;
case D3D_FEATURE_LEVEL_10_0:
featureLevelStr = L"Direct3D 10.0";
break;
case D3D_FEATURE_LEVEL_9_3:
featureLevelStr = L"Direct3D 9.3";
break;
case D3D_FEATURE_LEVEL_9_2:
featureLevelStr = L"Direct3D 9.2";
break;
case D3D_FEATURE_LEVEL_9_1:
featureLevelStr = L"Direct3D 9.1";
break;
default:
featureLevelStr = L"Unknown";
}

std::wstring logMessage = L"Direct3D设备创建成功\\n";
logMessage += L"特性级别: " + featureLevelStr + L"\\n";

if (!gpuList.empty())
{
logMessage += L"GPU数量: " + std::to_wstring(gpuList.size()) + L"\\n";

for (size_t i = 0; i < gpuList.size(); ++i)
{
logMessage += L"GPU " + std::to_wstring(i) + L": " + gpuList[i].description + L"\\n";
logMessage += L" 专用显存: " + std::to_wstring(gpuList[i].dedicatedVideoMemory / (1024 * 1024)) + L" MB\\n";
logMessage += L" 专用系统内存: " + std::to_wstring(gpuList[i].dedicatedSystemMemory / (1024 * 1024)) + L" MB\\n";
logMessage += L" 共享系统内存: " + std::to_wstring(gpuList[i].sharedSystemMemory / (1024 * 1024)) + L" MB\\n";
}
}

OutputDebugString(logMessage.c_str());
}

void LogError(const std::wstring& message)
{
std::wstring errorMessage = L"[ERROR] " + message + L"\\n";
OutputDebugString(errorMessage.c_str());
}

void LogWarning(const std::wstring& message)
{
std::wstring warningMessage = L"[WARNING] " + message + L"\\n";
OutputDebugString(warningMessage.c_str());
}

void Cleanup()
{
if (deviceContext)
{
deviceContext->Release();
deviceContext = nullptr;
}

if (direct3DDevice)
{
direct3DDevice->Release();
direct3DDevice = nullptr;
}

if (selectedAdapter)
{
selectedAdapter->Release();
selectedAdapter = nullptr;
}

if (dxgiFactory)
{
dxgiFactory->Release();
dxgiFactory = nullptr;
}
}

ID3D11Device* GetDevice() const { return direct3DDevice; }
ID3D11DeviceContext* GetDeviceContext() const { return deviceContext; }
D3D_FEATURE_LEVEL GetFeatureLevel() const { return selectedFeatureLevel; }

~Direct3DDeviceManager()
{
Cleanup();
}
};

这个设备管理器展示了商业游戏开发中的最佳实践:

  • 健壮的错误处理:从最高特性级别开始尝试,逐步降级
  • 多GPU支持:自动选择性能最好的GPU
  • 备用方案:硬件加速失败时使用WARP软件渲染器
  • 详细的日志:帮助调试和用户技术支持
  • 13.1.2 交换链配置的商业考量

    交换链配置直接影响游戏的视觉体验和性能。在《赛博朋克2077》等现代游戏中,玩家可以在多种显示模式间切换:全屏独占模式、无边框窗口模式和窗口模式。每种模式都有其优缺点。

    让我们深入探讨交换链配置的各个方面:

    #include <windows.h>
    #include <d3d11.h>
    #include <dxgi.h>
    #include <string>

    #pragma comment(lib, "d3d11.lib")
    #pragma comment(lib, "dxgi.lib")

    enum class DisplayMode
    {
    FullscreenExclusive, // 全屏独占模式(最佳性能)
    BorderlessWindow, // 无边框窗口模式(Alt+Tab切换流畅)
    Windowed // 窗口模式(兼容性最好)
    };

    enum class RefreshRateMode
    {
    VSyncEnabled, // 垂直同步开启(防止撕裂,可能限制帧率)
    VSyncDisabled, // 垂直同步关闭(最大帧率,可能撕裂)
    AdaptiveSync // 自适应同步(G-Sync/FreeSync)
    };

    class SwapChainManager
    {
    private:
    IDXGISwapChain* swapChain;
    DisplayMode currentDisplayMode;
    RefreshRateMode currentRefreshRateMode;

    // 配置参数
    UINT width;
    UINT height;
    DXGI_FORMAT format;
    UINT bufferCount;
    UINT sampleCount;
    UINT sampleQuality;
    HWND windowHandle;

    // 全屏相关
    bool isFullscreen;
    DXGI_MODE_DESC fullscreenMode;

    public:
    SwapChainManager()
    : swapChain(nullptr)
    , currentDisplayMode(DisplayMode::Windowed)
    , currentRefreshRateMode(RefreshRateMode::VSyncEnabled)
    , width(0)
    , height(0)
    , format(DXGI_FORMAT_R8G8B8A8_UNORM)
    , bufferCount(2) // 双缓冲
    , sampleCount(1)
    , sampleQuality(0)
    , windowHandle(nullptr)
    , isFullscreen(false)
    {
    ZeroMemory(&fullscreenMode, sizeof(fullscreenMode));
    }

    bool Initialize(
    ID3D11Device* device,
    HWND hwnd,
    UINT initialWidth,
    UINT initialHeight,
    DisplayMode displayMode = DisplayMode::Windowed,
    RefreshRateMode refreshRateMode = RefreshRateMode::VSyncEnabled)
    {
    windowHandle = hwnd;
    width = initialWidth;
    height = initialHeight;
    currentDisplayMode = displayMode;
    currentRefreshRateMode = refreshRateMode;

    // 获取DXGI工厂(通过设备查询)
    IDXGIDevice* dxgiDevice = nullptr;
    HRESULT result = device->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);

    if (FAILED(result))
    {
    return false;
    }

    IDXGIAdapter* adapter = nullptr;
    result = dxgiDevice->GetAdapter(&adapter);
    dxgiDevice->Release();

    if (FAILED(result))
    {
    return false;
    }

    IDXGIFactory* factory = nullptr;
    result = adapter->GetParent(__uuidof(IDXGIFactory), (void**)&factory);
    adapter->Release();

    if (FAILED(result))
    {
    return false;
    }

    // 根据显示模式创建交换链
    DXGI_SWAP_CHAIN_DESC swapChainDesc;
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

    // 基本配置
    swapChainDesc.BufferDesc.Width = width;
    swapChainDesc.BufferDesc.Height = height;
    swapChainDesc.BufferDesc.Format = format;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = bufferCount;
    swapChainDesc.OutputWindow = windowHandle;
    swapChainDesc.Windowed = (displayMode != DisplayMode::FullscreenExclusive);
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

    // 采样配置
    swapChainDesc.SampleDesc.Count = sampleCount;
    swapChainDesc.SampleDesc.Quality = sampleQuality;

    // 刷新率配置
    ConfigureRefreshRate(swapChainDesc.BufferDesc);

    // 根据显示模式进行特殊配置
    if (displayMode == DisplayMode::BorderlessWindow)
    {
    // 无边框窗口模式需要特殊处理
    ConfigureBorderlessWindow(factory, swapChainDesc);
    }

    // 创建交换链
    result = factory->CreateSwapChain(device, &swapChainDesc, &swapChain);

    if (displayMode == DisplayMode::FullscreenExclusive && SUCCEEDED(result))
    {
    // 设置为全屏模式
    swapChain->SetFullscreenState(TRUE, NULL);

    // 获取当前显示模式
    IDXGIOutput* output = nullptr;
    result = swapChain->GetContainingOutput(&output);

    if (SUCCEEDED(result) && output)
    {
    DXGI_MODE_DESC currentMode;
    result = swapChain->GetDesc(&swapChainDesc);

    if (SUCCEEDED(result))
    {
    fullscreenMode = swapChainDesc.BufferDesc;
    isFullscreen = true;
    }

    output->Release();
    }
    }

    factory->Release();

    return SUCCEEDED(result);
    }

    void ConfigureRefreshRate(DXGI_MODE_DESC& bufferDesc)
    {
    switch (currentRefreshRateMode)
    {
    case RefreshRateMode::VSyncEnabled:
    // 开启垂直同步,使用显示器的原生刷新率
    bufferDesc.RefreshRate.Numerator = 60; // 默认60Hz
    bufferDesc.RefreshRate.Denominator = 1;
    break;

    case RefreshRateMode::VSyncDisabled:
    // 关闭垂直同步,最大帧率
    bufferDesc.RefreshRate.Numerator = 0;
    bufferDesc.RefreshRate.Denominator = 1;
    break;

    case RefreshRateMode::AdaptiveSync:
    // 自适应同步,需要检测显示器支持
    if (IsAdaptiveSyncSupported())
    {
    // 设置自适应同步参数
    bufferDesc.RefreshRate.Numerator = 0;
    bufferDesc.RefreshRate.Denominator = 1;

    // 这里需要设置特殊的交换链标志
    // DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING (Windows 10及更高版本)
    }
    else
    {
    // 不支持自适应同步,回退到垂直同步
    bufferDesc.RefreshRate.Numerator = 60;
    bufferDesc.RefreshRate.Denominator = 1;
    }
    break;
    }
    }

    void ConfigureBorderlessWindow(IDXGIFactory* factory, DXGI_SWAP_CHAIN_DESC& swapChainDesc)
    {
    // 获取主显示器的尺寸
    IDXGIOutput* primaryOutput = nullptr;
    if (SUCCEEDED(factory->EnumOutputs(0, &primaryOutput)) && primaryOutput)
    {
    DXGI_OUTPUT_DESC outputDesc;
    if (SUCCEEDED(primaryOutput->GetDesc(&outputDesc)))
    {
    // 将窗口设置为覆盖整个显示器
    width = outputDesc.DesktopCoordinates.right outputDesc.DesktopCoordinates.left;
    height = outputDesc.DesktopCoordinates.bottom outputDesc.DesktopCoordinates.top;

    // 调整交换链尺寸
    swapChainDesc.BufferDesc.Width = width;
    swapChainDesc.BufferDesc.Height = height;

    // 设置窗口样式为无边框
    SetWindowLong(windowHandle, GWL_STYLE, WS_POPUP | WS_VISIBLE);
    SetWindowPos(windowHandle, HWND_TOP,
    outputDesc.DesktopCoordinates.left,
    outputDesc.DesktopCoordinates.top,
    width, height,
    SWP_FRAMECHANGED);
    }

    primaryOutput->Release();
    }
    }

    bool IsAdaptiveSyncSupported()
    {
    // 在实际应用中,这里需要检测G-Sync或FreeSync支持
    // 简化版本:总是返回false
    return false;
    }

    bool Resize(UINT newWidth, UINT newHeight)
    {
    if (!swapChain)
    {
    return false;
    }

    // 释放现有的渲染目标视图等资源
    // (这里假设调用者已经释放了相关资源)

    width = newWidth;
    height = newHeight;

    HRESULT result = swapChain->ResizeBuffers(
    bufferCount,
    width,
    height,
    format,
    DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
    );

    return SUCCEEDED(result);
    }

    bool ToggleFullscreen()
    {
    if (!swapChain)
    {
    return false;
    }

    BOOL isCurrentlyFullscreen = FALSE;
    IDXGIOutput* currentOutput = nullptr;

    // 获取当前全屏状态
    swapChain->GetFullscreenState(&isCurrentlyFullscreen, &currentOutput);

    // 切换全屏状态
    HRESULT result = swapChain->SetFullscreenState(!isCurrentlyFullscreen, currentOutput);

    if (currentOutput)
    {
    currentOutput->Release();
    }

    if (SUCCEEDED(result))
    {
    isFullscreen = !isCurrentlyFullscreen;

    if (isFullscreen)
    {
    currentDisplayMode = DisplayMode::FullscreenExclusive;
    }
    else
    {
    currentDisplayMode = DisplayMode::Windowed;
    }
    }

    return SUCCEEDED(result);
    }

    void SetRefreshRateMode(RefreshRateMode mode)
    {
    if (currentRefreshRateMode == mode)
    {
    return;
    }

    currentRefreshRateMode = mode;

    // 需要重新创建交换链来应用新的刷新率设置
    // 在实际应用中,这里应该保存当前状态并重新初始化
    }

    void Present(UINT syncInterval = 1, UINT flags = 0)
    {
    if (!swapChain)
    {
    return;
    }

    // 根据刷新率模式调整呈现参数
    UINT presentFlags = flags;

    switch (currentRefreshRateMode)
    {
    case RefreshRateMode::VSyncEnabled:
    syncInterval = 1; // 等待垂直同步
    break;

    case RefreshRateMode::VSyncDisabled:
    syncInterval = 0; // 立即呈现
    break;

    case RefreshRateMode::AdaptiveSync:
    if (IsAdaptiveSyncSupported())
    {
    syncInterval = 0;
    presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
    }
    else
    {
    syncInterval = 1;
    }
    break;
    }

    swapChain->Present(syncInterval, presentFlags);
    }

    void Cleanup()
    {
    if (swapChain)
    {
    // 切换到窗口模式再释放,避免全屏状态的问题
    swapChain->SetFullscreenState(FALSE, NULL);
    swapChain->Release();
    swapChain = nullptr;
    }
    }

    IDXGISwapChain* GetSwapChain() const { return swapChain; }
    UINT GetWidth() const { return width; }
    UINT GetHeight() const { return height; }
    DisplayMode GetDisplayMode() const { return currentDisplayMode; }
    RefreshRateMode GetRefreshRateMode() const { return currentRefreshRateMode; }

    ~SwapChainManager()
    {
    Cleanup();
    }
    };

    这个交换链管理器处理了现代游戏中的多种显示配置需求:

  • 多种显示模式支持:全屏独占、无边框窗口、窗口模式
  • 刷新率控制:垂直同步、无限制帧率、自适应同步
  • 动态调整:窗口大小改变时自动调整交换链
  • 性能优化:根据显示模式优化呈现参数
  • 13.1.3 深度模板缓冲区的商业级实现

    深度模板缓冲区对于3D游戏的正确渲染至关重要。在《荒野大镖客2》等开放世界游戏中,复杂的场景需要高效的深度管理来确保正确的物体遮挡关系。

    #include <windows.h>
    #include <d3d11.h>
    #include <dxgi.h>
    #include <vector>

    #pragma comment(lib, "d3d11.lib")

    class DepthStencilManager
    {
    private:
    struct DepthStencilConfig
    {
    DXGI_FORMAT format;
    UINT width;
    UINT height;
    UINT sampleCount;
    UINT sampleQuality;
    bool enableDepthTest;
    bool enableStencilTest;
    D3D11_COMPARISON_FUNC depthComparisonFunc;
    D3D11_DEPTH_WRITE_MASK depthWriteMask;
    UINT stencilReadMask;
    UINT stencilWriteMask;
    };

    ID3D11Device* device;
    ID3D11DeviceContext* deviceContext;

    // 深度模板资源
    ID3D11Texture2D* depthStencilTexture;
    ID3D11DepthStencilView* depthStencilView;
    ID3D11DepthStencilState* depthStencilState;

    // 配置
    DepthStencilConfig currentConfig;

    // 多重深度缓冲区(用于特殊效果,如深度剥离)
    std::vector<ID3D11Texture2D*> multiDepthTextures;
    std::vector<ID3D11DepthStencilView*> multiDepthViews;

    public:
    DepthStencilManager(ID3D11Device* dev, ID3D11DeviceContext* context)
    : device(dev)
    , deviceContext(context)
    , depthStencilTexture(nullptr)
    , depthStencilView(nullptr)
    , depthStencilState(nullptr)
    {
    // 默认配置
    currentConfig.format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    currentConfig.width = 0;
    currentConfig.height = 0;
    currentConfig.sampleCount = 1;
    currentConfig.sampleQuality = 0;
    currentConfig.enableDepthTest = true;
    currentConfig.enableStencilTest = false;
    currentConfig.depthComparisonFunc = D3D11_COMPARISON_LESS;
    currentConfig.depthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
    currentConfig.stencilReadMask = 0xFF;
    currentConfig.stencilWriteMask = 0xFF;
    }

    bool Initialize(UINT width, UINT height, UINT sampleCount = 1, UINT sampleQuality = 0)
    {
    currentConfig.width = width;
    currentConfig.height = height;
    currentConfig.sampleCount = sampleCount;
    currentConfig.sampleQuality = sampleQuality;

    return CreateDepthStencilResources();
    }

    bool CreateDepthStencilResources()
    {
    // 清理现有资源
    ReleaseResources();

    // 创建深度模板纹理
    D3D11_TEXTURE2D_DESC depthStencilDesc;
    ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));

    depthStencilDesc.Width = currentConfig.width;
    depthStencilDesc.Height = currentConfig.height;
    depthStencilDesc.MipLevels = 1;
    depthStencilDesc.ArraySize = 1;
    depthStencilDesc.Format = currentConfig.format;
    depthStencilDesc.SampleDesc.Count = currentConfig.sampleCount;
    depthStencilDesc.SampleDesc.Quality = currentConfig.sampleQuality;
    depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
    depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    depthStencilDesc.CPUAccessFlags = 0;
    depthStencilDesc.MiscFlags = 0;

    HRESULT result = device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilTexture);

    if (FAILED(result))
    {
    return false;
    }

    // 创建深度模板视图
    D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
    ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));

    depthStencilViewDesc.Format = currentConfig.format;

    if (currentConfig.sampleCount > 1)
    {
    depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
    }
    else
    {
    depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    depthStencilViewDesc.Texture2D.MipSlice = 0;
    }

    result = device->CreateDepthStencilView(depthStencilTexture, &depthStencilViewDesc, &depthStencilView);

    if (FAILED(result))
    {
    return false;
    }

    // 创建深度模板状态
    D3D11_DEPTH_STENCIL_DESC depthStencilStateDesc;
    ZeroMemory(&depthStencilStateDesc, sizeof(depthStencilStateDesc));

    // 深度测试配置
    depthStencilStateDesc.DepthEnable = currentConfig.enableDepthTest;
    depthStencilStateDesc.DepthWriteMask = currentConfig.depthWriteMask;
    depthStencilStateDesc.DepthFunc = currentConfig.depthComparisonFunc;

    // 模板测试配置
    depthStencilStateDesc.StencilEnable = currentConfig.enableStencilTest;
    depthStencilStateDesc.StencilReadMask = currentConfig.stencilReadMask;
    depthStencilStateDesc.StencilWriteMask = currentConfig.stencilWriteMask;

    // 正面多边形模板操作
    depthStencilStateDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    depthStencilStateDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
    depthStencilStateDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    depthStencilStateDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

    // 背面多边形模板操作
    depthStencilStateDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    depthStencilStateDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
    depthStencilStateDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    depthStencilStateDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

    result = device->CreateDepthStencilState(&depthStencilStateDesc, &depthStencilState);

    if (FAILED(result))
    {
    return false;
    }

    // 设置深度模板状态
    deviceContext->OMSetDepthStencilState(depthStencilState, 1);

    return true;
    }

    bool CreateMultiDepthBuffers(UINT count, DXGI_FORMAT format = DXGI_FORMAT_R32_FLOAT)
    {
    // 清理现有的多重深度缓冲区
    for (auto& texture : multiDepthTextures)
    {
    if (texture) texture->Release();
    }
    multiDepthTextures.clear();

    for (auto& view : multiDepthViews)
    {
    if (view) view->Release();
    }
    multiDepthViews.clear();

    // 创建多个深度缓冲区(用于深度剥离等高级技术)
    for (UINT i = 0; i < count; ++i)
    {
    ID3D11Texture2D* depthTexture = nullptr;
    ID3D11DepthStencilView* depthView = nullptr;

    // 创建纹理
    D3D11_TEXTURE2D_DESC texDesc;
    ZeroMemory(&texDesc, sizeof(texDesc));

    texDesc.Width = currentConfig.width;
    texDesc.Height = currentConfig.height;
    texDesc.MipLevels = 1;
    texDesc.ArraySize = 1;
    texDesc.Format = format;
    texDesc.SampleDesc.Count = 1;
    texDesc.SampleDesc.Quality = 0;
    texDesc.Usage = D3D11_USAGE_DEFAULT;
    texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
    texDesc.CPUAccessFlags = 0;
    texDesc.MiscFlags = 0;

    HRESULT result = device->CreateTexture2D(&texDesc, NULL, &depthTexture);

    if (FAILED(result))
    {
    // 清理已创建的资源
    for (auto& texture : multiDepthTextures)
    {
    if (texture) texture->Release();
    }
    for (auto& view : multiDepthViews)
    {
    if (view) view->Release();
    }
    return false;
    }

    // 创建视图
    D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
    ZeroMemory(&dsvDesc, sizeof(dsvDesc));

    dsvDesc.Format = DXGI_FORMAT_D32_FLOAT; // 深度格式
    dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    dsvDesc.Texture2D.MipSlice = 0;

    result = device->CreateDepthStencilView(depthTexture, &dsvDesc, &depthView);

    if (FAILED(result))
    {
    depthTexture->Release();

    // 清理已创建的资源
    for (auto& texture : multiDepthTextures)
    {
    if (texture) texture->Release();
    }
    for (auto& view : multiDepthViews)
    {
    if (view) view->Release();
    }
    return false;
    }

    multiDepthTextures.push_back(depthTexture);
    multiDepthViews.push_back(depthView);
    }

    return true;
    }

    void Clear(float depthValue = 1.0f, UINT8 stencilValue = 0)
    {
    if (depthStencilView)
    {
    UINT clearFlags = 0;

    if (currentConfig.enableDepthTest)
    {
    clearFlags |= D3D11_CLEAR_DEPTH;
    }

    if (currentConfig.enableStencilTest)
    {
    clearFlags |= D3D11_CLEAR_STENCIL;
    }

    if (clearFlags != 0)
    {
    deviceContext->ClearDepthStencilView(depthStencilView, clearFlags, depthValue, stencilValue);
    }
    }

    // 清除多重深度缓冲区
    for (auto& view : multiDepthViews)
    {
    deviceContext->ClearDepthStencilView(view, D3D11_CLEAR_DEPTH, depthValue, stencilValue);
    }
    }

    void SetDepthTestEnabled(bool enabled)
    {
    if (currentConfig.enableDepthTest == enabled)
    {
    return;
    }

    currentConfig.enableDepthTest = enabled;

    // 重新创建深度模板状态
    if (depthStencilState)
    {
    depthStencilState->Release();
    depthStencilState = nullptr;
    }

    D3D11_DEPTH_STENCIL_DESC depthStencilStateDesc;
    ZeroMemory(&depthStencilStateDesc, sizeof(depthStencilStateDesc));

    depthStencilStateDesc.DepthEnable = enabled;
    depthStencilStateDesc.DepthWriteMask = currentConfig.depthWriteMask;
    depthStencilStateDesc.DepthFunc = currentConfig.depthComparisonFunc;

    // … 其他配置

    device->CreateDepthStencilState(&depthStencilStateDesc, &depthStencilState);
    deviceContext->OMSetDepthStencilState(depthStencilState, 1);
    }

    void SetDepthComparisonFunc(D3D11_COMPARISON_FUNC func)
    {
    if (currentConfig.depthComparisonFunc == func)
    {
    return;
    }

    currentConfig.depthComparisonFunc = func;

    // 重新创建深度模板状态
    if (depthStencilState)
    {
    depthStencilState->Release();
    depthStencilState = nullptr;
    }

    D3D11_DEPTH_STENCIL_DESC depthStencilStateDesc;
    ZeroMemory(&depthStencilStateDesc, sizeof(depthStencilStateDesc));

    depthStencilStateDesc.DepthEnable = currentConfig.enableDepthTest;
    depthStencilStateDesc.DepthWriteMask = currentConfig.depthWriteMask;
    depthStencilStateDesc.DepthFunc = func;

    // … 其他配置

    device->CreateDepthStencilState(&depthStencilStateDesc, &depthStencilState);
    deviceContext->OMSetDepthStencilState(depthStencilState, 1);
    }

    void Resize(UINT newWidth, UINT newHeight)
    {
    if (newWidth == currentConfig.width && newHeight == currentConfig.height)
    {
    return;
    }

    currentConfig.width = newWidth;
    currentConfig.height = newHeight;

    // 重新创建资源
    CreateDepthStencilResources();

    // 重新创建多重深度缓冲区(如果存在)
    if (!multiDepthTextures.empty())
    {
    CreateMultiDepthBuffers(static_cast<UINT>(multiDepthTextures.size()));
    }
    }

    void ReleaseResources()
    {
    if (depthStencilState)
    {
    depthStencilState->Release();
    depthStencilState = nullptr;
    }

    if (depthStencilView)
    {
    depthStencilView->Release();
    depthStencilView = nullptr;
    }

    if (depthStencilTexture)
    {
    depthStencilTexture->Release();
    depthStencilTexture = nullptr;
    }

    // 释放多重深度缓冲区
    for (auto& texture : multiDepthTextures)
    {
    if (texture) texture->Release();
    }
    multiDepthTextures.clear();

    for (auto& view : multiDepthViews)
    {
    if (view) view->Release();
    }
    multiDepthViews.clear();
    }

    ID3D11DepthStencilView* GetDepthStencilView() const { return depthStencilView; }
    ID3D11DepthStencilState* GetDepthStencilState() const { return depthStencilState; }

    UINT GetWidth() const { return currentConfig.width; }
    UINT GetHeight() const { return currentConfig.height; }

    ~DepthStencilManager()
    {
    ReleaseResources();
    }
    };

    这个深度模板管理器提供了以下高级功能:

  • 动态配置:可以运行时修改深度测试和模板测试参数
  • 多重深度缓冲区:支持深度剥离等高级渲染技术
  • 自动资源管理:窗口大小改变时自动重新创建资源
  • 性能优化:只在需要时更新状态
  • 13.2 Direct3D渲染流水线完整实现

    13.2.1 现代渲染流水线架构

    现代游戏如《最终幻想7重制版》使用复杂的渲染流水线,包括前向渲染、延迟渲染、前向+等多种技术。理解这些流水线架构对于商业游戏开发至关重要。

    下面实现一个灵活的渲染流水线管理器:

    #include <windows.h>
    #include <d3d11.h>
    #include <d3dcompiler.h>
    #include <DirectXMath.h>
    #include <vector>
    #include <map>
    #include <string>

    #pragma comment(lib, "d3d11.lib")
    #pragma comment(lib, "d3dcompiler.lib")

    using namespace DirectX;

    enum class RenderPipelineType
    {
    Forward, // 前向渲染(传统方式)
    Deferred, // 延迟渲染(现代AAA游戏常用)
    ForwardPlus, // 前向+渲染(平衡方案)
    TileBased // 基于分块的延迟渲染(移动平台)
    };

    enum class LightingModel
    {
    Phong, // Phong光照模型
    BlinnPhong, // Blinn-Phong光照模型(更高效)
    PBR, // 基于物理的渲染(现代标准)
    CelShading // 卡通渲染
    };

    struct PipelineConfig
    {
    RenderPipelineType pipelineType;
    LightingModel lightingModel;
    bool enableShadows;
    bool enableSSAO; // 屏幕空间环境光遮蔽
    bool enableBloom; // 泛光效果
    bool enableMotionBlur; // 运动模糊
    bool enableDepthOfField; // 景深效果
    UINT shadowMapSize;
    UINT msaaLevel;
    };

    class RenderPipelineManager
    {
    private:
    ID3D11Device* device;
    ID3D11DeviceContext* deviceContext;

    // 当前配置
    PipelineConfig currentConfig;

    // 渲染目标
    ID3D11RenderTargetView* mainRenderTargetView;
    ID3D11Texture2D* mainRenderTargetTexture;

    // G-Buffer用于延迟渲染
    struct GBuffer
    {
    ID3D11Texture2D* texture;
    ID3D11RenderTargetView* rtv;
    ID3D11ShaderResourceView* srv;
    DXGI_FORMAT format;
    };

    std::vector<GBuffer> gBuffer;

    // 深度缓冲区
    ID3D11Texture2D* depthStencilTexture;
    ID3D11DepthStencilView* depthStencilView;
    ID3D11ShaderResourceView* depthSRV;

    // 着色器
    ID3D11VertexShader* forwardVS;
    ID3D11PixelShader* forwardPS;
    ID3D11VertexShader* deferredVS;
    ID3D11PixelShader* deferredPS;
    ID3D11PixelShader* lightingPS;

    // 输入布局
    ID3D11InputLayout* inputLayout;

    // 常量和采样器
    ID3D11Buffer* perFrameConstantBuffer;
    ID3D11Buffer* perObjectConstantBuffer;
    ID3D11SamplerState* linearSampler;
    ID3D11SamplerState* pointSampler;

    // 视口
    D3D11_VIEWPORT mainViewport;

    public:
    RenderPipelineManager(ID3D11Device* dev, ID3D11DeviceContext* context)
    : device(dev)
    , deviceContext(context)
    , mainRenderTargetView(nullptr)
    , mainRenderTargetTexture(nullptr)
    , depthStencilTexture(nullptr)
    , depthStencilView(nullptr)
    , depthSRV(nullptr)
    , forwardVS(nullptr)
    , forwardPS(nullptr)
    , deferredVS(nullptr)
    , deferredPS(nullptr)
    , lightingPS(nullptr)
    , inputLayout(nullptr)
    , perFrameConstantBuffer(nullptr)
    , perObjectConstantBuffer(nullptr)
    , linearSampler(nullptr)
    , pointSampler(nullptr)
    {
    // 默认配置
    currentConfig.pipelineType = RenderPipelineType::Forward;
    currentConfig.lightingModel = LightingModel::BlinnPhong;
    currentConfig.enableShadows = true;
    currentConfig.enableSSAO = true;
    currentConfig.enableBloom = false;
    currentConfig.enableMotionBlur = false;
    currentConfig.enableDepthOfField = false;
    currentConfig.shadowMapSize = 2048;
    currentConfig.msaaLevel = 1;
    }

    bool Initialize(UINT width, UINT height, PipelineConfig config)
    {
    currentConfig = config;

    // 创建视口
    mainViewport.TopLeftX = 0.0f;
    mainViewport.TopLeftY = 0.0f;
    mainViewport.Width = static_cast<float>(width);
    mainViewport.Height = static_cast<float>(height);
    mainViewport.MinDepth = 0.0f;
    mainViewport.MaxDepth = 1.0f;

    // 创建主渲染目标
    if (!CreateMainRenderTarget(width, height))
    {
    return false;
    }

    // 创建深度缓冲区
    if (!CreateDepthStencil(width, height))
    {
    return false;
    }

    // 创建G-Buffer(如果是延迟渲染)
    if (config.pipelineType == RenderPipelineType::Deferred ||
    config.pipelineType == RenderPipelineType::ForwardPlus)
    {
    if (!CreateGBuffer(width, height))
    {
    return false;
    }
    }

    // 编译着色器
    if (!CompileShaders())
    {
    return false;
    }

    // 创建常量缓冲区
    if (!CreateConstantBuffers())
    {
    return false;
    }

    // 创建采样器状态
    if (!CreateSamplerStates())
    {
    return false;
    }

    return true;
    }

    bool CreateMainRenderTarget(UINT width, UINT height)
    {
    // 创建主渲染目标纹理
    D3D11_TEXTURE2D_DESC textureDesc;
    ZeroMemory(&textureDesc, sizeof(textureDesc));

    textureDesc.Width = width;
    textureDesc.Height = height;
    textureDesc.MipLevels = 1;
    textureDesc.ArraySize = 1;
    textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    textureDesc.SampleDesc.Count = currentConfig.msaaLevel;
    textureDesc.SampleDesc.Quality = 0;
    textureDesc.Usage = D3D11_USAGE_DEFAULT;
    textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
    textureDesc.CPUAccessFlags = 0;
    textureDesc.MiscFlags = 0;

    HRESULT result = device->CreateTexture2D(&textureDesc, NULL, &mainRenderTargetTexture);

    if (FAILED(result))
    {
    return false;
    }

    // 创建渲染目标视图
    result = device->CreateRenderTargetView(mainRenderTargetTexture, NULL, &mainRenderTargetView);

    return SUCCEEDED(result);
    }

    bool CreateDepthStencil(UINT width, UINT height)
    {
    // 创建深度模板纹理
    D3D11_TEXTURE2D_DESC depthStencilDesc;
    ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));

    depthStencilDesc.Width = width;
    depthStencilDesc.Height = height;
    depthStencilDesc.MipLevels = 1;
    depthStencilDesc.ArraySize = 1;
    depthStencilDesc.Format = DXGI_FORMAT_R24G8_TYPELESS; // 用于创建SRV
    depthStencilDesc.SampleDesc.Count = currentConfig.msaaLevel;
    depthStencilDesc.SampleDesc.Quality = 0;
    depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
    depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
    depthStencilDesc.CPUAccessFlags = 0;
    depthStencilDesc.MiscFlags = 0;

    HRESULT result = device->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilTexture);

    if (FAILED(result))
    {
    return false;
    }

    // 创建深度模板视图
    D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
    ZeroMemory(&dsvDesc, sizeof(dsvDesc));

    dsvDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;

    if (currentConfig.msaaLevel > 1)
    {
    dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
    }
    else
    {
    dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    dsvDesc.Texture2D.MipSlice = 0;
    }

    result = device->CreateDepthStencilView(depthStencilTexture, &dsvDesc, &depthStencilView);

    if (FAILED(result))
    {
    return false;
    }

    // 创建深度纹理的着色器资源视图(用于后处理)
    D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
    ZeroMemory(&srvDesc, sizeof(srvDesc));

    srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;

    if (currentConfig.msaaLevel > 1)
    {
    srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
    }
    else
    {
    srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Texture2D.MostDetailedMip = 0;
    srvDesc.Texture2D.MipLevels = 1;
    }

    result = device->CreateShaderResourceView(depthStencilTexture, &srvDesc, &depthSRV);

    return SUCCEEDED(result);
    }

    bool CreateGBuffer(UINT width, UINT height)
    {
    // G-Buffer通常包含:
    // 1. 漫反射颜色 + 材质类型
    // 2. 法线 + 粗糙度
    // 3. 位置 + 金属度
    // 4. 自发光 + 其他数据

    DXGI_FORMAT gBufferFormats[] =
    {
    DXGI_FORMAT_R8G8B8A8_UNORM, // 漫反射 + 材质
    DXGI_FORMAT_R16G16B16A16_FLOAT, // 法线 + 粗糙度
    DXGI_FORMAT_R32G32B32A32_FLOAT, // 位置 + 金属度
    DXGI_FORMAT_R8G8B8A8_UNORM // 自发光 + 其他
    };

    const char* gBufferNames[] =
    {
    "DiffuseMaterial",
    "NormalRoughness",
    "PositionMetalness",
    "EmissiveOther"
    };

    for (int i = 0; i < 4; ++i)
    {
    GBuffer buffer;

    // 创建纹理
    D3D11_TEXTURE2D_DESC texDesc;
    ZeroMemory(&texDesc, sizeof(texDesc));

    texDesc.Width = width;
    texDesc.Height = height;
    texDesc.MipLevels = 1;
    texDesc.ArraySize = 1;
    texDesc.Format = gBufferFormats[i];
    texDesc.SampleDesc.Count = 1; // G-Buffer通常不使用多重采样
    texDesc.SampleDesc.Quality = 0;
    texDesc.Usage = D3D11_USAGE_DEFAULT;
    texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
    texDesc.CPUAccessFlags = 0;
    texDesc.MiscFlags = 0;

    HRESULT result = device->CreateTexture2D(&texDesc, NULL, &buffer.texture);

    if (FAILED(result))
    {
    // 清理已创建的缓冲区
    for (auto& gb : gBuffer)
    {
    if (gb.srv) gb.srv->Release();
    if (gb.rtv) gb.rtv->Release();
    if (gb.texture) gb.texture->Release();
    }
    gBuffer.clear();
    return false;
    }

    // 创建渲染目标视图
    result = device->CreateRenderTargetView(buffer.texture, NULL, &buffer.rtv);

    if (FAILED(result))
    {
    buffer.texture->Release();

    // 清理已创建的缓冲区
    for (auto& gb : gBuffer)
    {
    if (gb.srv) gb.srv->Release();
    if (gb.rtv) gb.rtv->Release();
    if (gb.texture) gb.texture->Release();
    }
    gBuffer.clear();
    return false;
    }

    // 创建着色器资源视图
    result = device->CreateShaderResourceView(buffer.texture, NULL, &buffer.srv);

    if (FAILED(result))
    {
    buffer.rtv->Release();
    buffer.texture->Release();

    // 清理已创建的缓冲区
    for (auto& gb : gBuffer)
    {
    if (gb.srv) gb.srv->Release();
    if (gb.rtv) gb.rtv->Release();
    if (gb.texture) gb.texture->Release();
    }
    gBuffer.clear();
    return false;
    }

    buffer.format = gBufferFormats[i];
    gBuffer.push_back(buffer);
    }

    return true;
    }

    bool CompileShaders()
    {
    HRESULT result = S_OK;

    // 编译前向着色器
    const char* forwardVSCode =
    "cbuffer PerFrameConstants : register(b0)\\n"
    "{\\n"
    " float4x4 viewMatrix;\\n"
    " float4x4 projectionMatrix;\\n"
    " float3 cameraPosition;\\n"
    " float padding;\\n"
    "};\\n"
    "\\n"
    "cbuffer PerObjectConstants : register(b1)\\n"
    "{\\n"
    " float4x4 worldMatrix;\\n"
    " float4 materialColor;\\n"
    " float roughness;\\n"
    " float metalness;\\n"
    " float2 paddingObj;\\n"
    "};\\n"
    "\\n"
    "struct VertexInput\\n"
    "{\\n"
    " float3 position : POSITION;\\n"
    " float3 normal : NORMAL;\\n"
    " float2 texcoord : TEXCOORD;\\n"
    "};\\n"
    "\\n"
    "struct PixelInput\\n"
    "{\\n"
    " float4 position : SV_POSITION;\\n"
    " float3 worldPosition : POSITION;\\n"
    " float3 normal : NORMAL;\\n"
    " float2 texcoord : TEXCOORD;\\n"
    "};\\n"
    "\\n"
    "PixelInput main(VertexInput input)\\n"
    "{\\n"
    " PixelInput output;\\n"
    " \\n"
    " // 世界变换\\n"
    " float4 worldPos = mul(float4(input.position, 1.0f), worldMatrix);\\n"
    " \\n"
    " // 视图和投影变换\\n"
    " output.position = mul(mul(worldPos, viewMatrix), projectionMatrix);\\n"
    " \\n"
    " // 传递其他数据\\n"
    " output.worldPosition = worldPos.xyz;\\n"
    " output.normal = normalize(mul(input.normal, (float3x3)worldMatrix));\\n"
    " output.texcoord = input.texcoord;\\n"
    " \\n"
    " return output;\\n"
    "}";

    const char* forwardPSCode =
    "cbuffer PerFrameConstants : register(b0)\\n"
    "{\\n"
    " float4x4 viewMatrix;\\n"
    " float4x4 projectionMatrix;\\n"
    " float3 cameraPosition;\\n"
    " float padding;\\n"
    "};\\n"
    "\\n"
    "cbuffer PerObjectConstants : register(b1)\\n"
    "{\\n"
    " float4x4 worldMatrix;\\n"
    " float4 materialColor;\\n"
    " float roughness;\\n"
    " float metalness;\\n"
    " float2 paddingObj;\\n"
    "};\\n"
    "\\n"
    "struct PixelInput\\n"
    "{\\n"
    " float4 position : SV_POSITION;\\n"
    " float3 worldPosition : POSITION;\\n"
    " float3 normal : NORMAL;\\n"
    " float2 texcoord : TEXCOORD;\\n"
    "};\\n"
    "\\n"
    "// 简单光照计算(Blinn-Phong)\\n"
    "float3 CalculateLighting(float3 position, float3 normal, float3 viewDir)\\n"
    "{\\n"
    " float3 lightColor = float3(1.0f, 1.0f, 1.0f);\\n"
    " float3 lightDirection = normalize(float3(1.0f, 1.0f, -1.0f));\\n"
    " \\n"
    " // 漫反射\\n"
    " float diffuse = max(dot(normal, lightDirection), 0.0f);\\n"
    " float3 diffuseColor = lightColor * diffuse;\\n"
    " \\n"
    " // 镜面反射(Blinn-Phong)\\n"
    " float3 halfVector = normalize(lightDirection + viewDir);\\n"
    " float specular = pow(max(dot(normal, halfVector), 0.0f), 32.0f);\\n"
    " float3 specularColor = lightColor * specular;\\n"
    " \\n"
    " // 环境光\\n"
    " float3 ambientColor = float3(0.1f, 0.1f, 0.1f);\\n"
    " \\n"
    " return ambientColor + diffuseColor + specularColor;\\n"
    "}\\n"
    "\\n"
    "float4 main(PixelInput input) : SV_TARGET\\n"
    "{\\n"
    " // 标准化法线\\n"
    " float3 normal = normalize(input.normal);\\n"
    " \\n"
    " // 计算视线方向\\n"
    " float3 viewDir = normalize(cameraPosition – input.worldPosition);\\n"
    " \\n"
    " // 计算光照\\n"
    " float3 lighting = CalculateLighting(input.worldPosition, normal, viewDir);\\n"
    " \\n"
    " // 应用材质颜色\\n"
    " float3 finalColor = materialColor.rgb * lighting;\\n"
    " \\n"
    " return float4(finalColor, materialColor.a);\\n"
    "}";

    ID3DBlob* vsBlob = nullptr;
    ID3DBlob* psBlob = nullptr;
    ID3DBlob* errorBlob = nullptr;

    // 编译顶点着色器
    result = D3DCompile(
    forwardVSCode,
    strlen(forwardVSCode),
    "ForwardVS",
    nullptr,
    nullptr,
    "main",
    "vs_5_0",
    0,
    0,
    &vsBlob,
    &errorBlob
    );

    if (FAILED(result))
    {
    if (errorBlob)
    {
    OutputDebugStringA((char*)errorBlob->GetBufferPointer());
    errorBlob->Release();
    }
    return false;
    }

    // 创建顶点着色器
    result = device->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nullptr, &forwardVS);

    if (FAILED(result))
    {
    vsBlob->Release();
    return false;
    }

    // 编译像素着色器
    result = D3DCompile(
    forwardPSCode,
    strlen(forwardPSCode),
    "ForwardPS",
    nullptr,
    nullptr,
    "main",
    "ps_5_0",
    0,
    0,
    &psBlob,
    &errorBlob
    );

    if (FAILED(result))
    {
    vsBlob->Release();
    if (errorBlob)
    {
    errorBlob->Release();
    }
    return false;
    }

    // 创建像素着色器
    result = device->CreatePixelShader(psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nullptr, &forwardPS);

    // 创建输入布局
    D3D11_INPUT_ELEMENT_DESC layout[] =
    {
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }
    };

    result = device->CreateInputLayout(
    layout,
    3,
    vsBlob->GetBufferPointer(),
    vsBlob->GetBufferSize(),
    &inputLayout
    );

    // 清理临时对象
    vsBlob->Release();
    psBlob->Release();
    if (errorBlob)
    {
    errorBlob->Release();
    }

    return SUCCEEDED(result);
    }

    bool CreateConstantBuffers()
    {
    // 创建每帧常量缓冲区
    D3D11_BUFFER_DESC perFrameDesc;
    ZeroMemory(&perFrameDesc, sizeof(perFrameDesc));

    perFrameDesc.Usage = D3D11_USAGE_DYNAMIC;
    perFrameDesc.ByteWidth = sizeof(PerFrameConstants);
    perFrameDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    perFrameDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

    HRESULT result = device->CreateBuffer(&perFrameDesc, NULL, &perFrameConstantBuffer);

    if (FAILED(result))
    {
    return false;
    }

    // 创建每个对象常量缓冲区
    D3D11_BUFFER_DESC perObjectDesc;
    ZeroMemory(&perObjectDesc, sizeof(perObjectDesc));

    perObjectDesc.Usage = D3D11_USAGE_DYNAMIC;
    perObjectDesc.ByteWidth = sizeof(PerObjectConstants);
    perObjectDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    perObjectDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

    result = device->CreateBuffer(&perObjectDesc, NULL, &perObjectConstantBuffer);

    return SUCCEEDED(result);
    }

    bool CreateSamplerStates()
    {
    // 创建线性采样器
    D3D11_SAMPLER_DESC linearDesc;
    ZeroMemory(&linearDesc, sizeof(linearDesc));

    linearDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    linearDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    linearDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    linearDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    linearDesc.MipLODBias = 0.0f;
    linearDesc.MaxAnisotropy = 1;
    linearDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
    linearDesc.BorderColor[0] = 0;
    linearDesc.BorderColor[1] = 0;
    linearDesc.BorderColor[2] = 0;
    linearDesc.BorderColor[3] = 0;
    linearDesc.MinLOD = 0;
    linearDesc.MaxLOD = D3D11_FLOAT32_MAX;

    HRESULT result = device->CreateSamplerState(&linearDesc, &linearSampler);

    if (FAILED(result))
    {
    return false;
    }

    // 创建点采样器
    D3D11_SAMPLER_DESC pointDesc;
    ZeroMemory(&pointDesc, sizeof(pointDesc));

    pointDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
    pointDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    pointDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    pointDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    pointDesc.MipLODBias = 0.0f;
    pointDesc.MaxAnisotropy = 1;
    pointDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
    pointDesc.BorderColor[0] = 0;
    pointDesc.BorderColor[1] = 0;
    pointDesc.BorderColor[2] = 0;
    pointDesc.BorderColor[3] = 0;
    pointDesc.MinLOD = 0;
    pointDesc.MaxLOD = D3D11_FLOAT32_MAX;

    result = device->CreateSamplerState(&pointDesc, &pointSampler);

    return SUCCEEDED(result);
    }

    void BeginFrame(const float clearColor[4])
    {
    // 设置视口
    deviceContext->RSSetViewports(1, &mainViewport);

    // 清除主渲染目标
    deviceContext->ClearRenderTargetView(mainRenderTargetView, clearColor);
    deviceContext->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);

    // 根据流水线类型设置渲染目标
    switch (currentConfig.pipelineType)
    {
    case RenderPipelineType::Forward:
    // 前向渲染:直接渲染到主渲染目标
    deviceContext->OMSetRenderTargets(1, &mainRenderTargetView, depthStencilView);
    break;

    case RenderPipelineType::Deferred:
    case RenderPipelineType::ForwardPlus:
    // 延迟渲染:渲染到G-Buffer
    {
    ID3D11RenderTargetView* rtvs[4];
    for (int i = 0; i < 4; ++i)
    {
    rtvs[i] = gBuffer[i].rtv;
    // 清除G-Buffer
    const float clearGBuffer[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    deviceContext->ClearRenderTargetView(rtvs[i], clearGBuffer);
    }
    deviceContext->OMSetRenderTargets(4, rtvs, depthStencilView);
    }
    break;
    }

    // 设置采样器
    deviceContext->PSSetSamplers(0, 1, &linearSampler);
    deviceContext->PSSetSamplers(1, 1, &pointSampler);
    }

    void RenderObject(
    ID3D11Buffer* vertexBuffer,
    ID3D11Buffer* indexBuffer,
    UINT vertexCount,
    UINT indexCount,
    const XMMATRIX& worldMatrix,
    const XMFLOAT4& materialColor,
    float roughness = 0.5f,
    float metalness = 0.0f)
    {
    // 更新每对象常量缓冲区
    D3D11_MAPPED_SUBRESOURCE mapped;
    deviceContext->Map(perObjectConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);

    PerObjectConstants* constants = static_cast<PerObjectConstants*>(mapped.pData);
    XMStoreFloat4x4(&constants->worldMatrix, XMMatrixTranspose(worldMatrix));
    constants->materialColor = materialColor;
    constants->roughness = roughness;
    constants->metalness = metalness;

    deviceContext->Unmap(perObjectConstantBuffer, 0);

    // 设置常量缓冲区
    deviceContext->VSSetConstantBuffers(1, 1, &perObjectConstantBuffer);
    deviceContext->PSSetConstantBuffers(1, 1, &perObjectConstantBuffer);

    // 设置输入布局和顶点缓冲区
    UINT stride = sizeof(Vertex);
    UINT offset = 0;
    deviceContext->IASetInputLayout(inputLayout);
    deviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);

    // 设置索引缓冲区(如果有)
    if (indexBuffer && indexCount > 0)
    {
    deviceContext->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R32_UINT, 0);
    }

    // 设置图元拓扑
    deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    // 根据流水线类型设置着色器
    if (currentConfig.pipelineType == RenderPipelineType::Forward)
    {
    deviceContext->VSSetShader(forwardVS, nullptr, 0);
    deviceContext->PSSetShader(forwardPS, nullptr, 0);
    }
    else
    {
    // 延迟渲染使用不同的着色器
    deviceContext->VSSetShader(deferredVS, nullptr, 0);
    deviceContext->PSSetShader(deferredPS, nullptr, 0);
    }

    // 绘制
    if (indexBuffer && indexCount > 0)
    {
    deviceContext->DrawIndexed(indexCount, 0, 0);
    }
    else
    {
    deviceContext->Draw(vertexCount, 0);
    }
    }

    void ApplyLightingPass()
    {
    if (currentConfig.pipelineType == RenderPipelineType::Deferred ||
    currentConfig.pipelineType == RenderPipelineType::ForwardPlus)
    {
    // 延迟渲染的照明阶段
    // 1. 将渲染目标切换回主渲染目标
    deviceContext->OMSetRenderTargets(1, &mainRenderTargetView, nullptr);

    // 2. 设置G-Buffer作为纹理输入
    ID3D11ShaderResourceView* srvs[5];
    srvs[0] = gBuffer[0].srv; // 漫反射+材质
    srvs[1] = gBuffer[1].srv; // 法线+粗糙度
    srvs[2] = gBuffer[2].srv; // 位置+金属度
    srvs[3] = gBuffer[3].srv; // 自发光+其他
    srvs[4] = depthSRV; // 深度

    deviceContext->PSSetShaderResources(0, 5, srvs);

    // 3. 设置照明着色器
    deviceContext->VSSetShader(nullptr, nullptr, 0); // 全屏四边形不需要顶点着色器
    deviceContext->PSSetShader(lightingPS, nullptr, 0);

    // 4. 绘制全屏四边形
    deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    deviceContext->Draw(6, 0); // 6个顶点形成2个三角形

    // 5. 解除纹理绑定
    ID3D11ShaderResourceView* nullSRVs[5] = { nullptr, nullptr, nullptr, nullptr, nullptr };
    deviceContext->PSSetShaderResources(0, 5, nullSRVs);
    }
    }

    void ApplyPostProcessing()
    {
    // 这里可以实现各种后处理效果
    if (currentConfig.enableSSAO)
    {
    ApplySSAO();
    }

    if (currentConfig.enableBloom)
    {
    ApplyBloom();
    }

    if (currentConfig.enableMotionBlur)
    {
    ApplyMotionBlur();
    }

    if (currentConfig.enableDepthOfField)
    {
    ApplyDepthOfField();
    }
    }

    void ApplySSAO()
    {
    // 屏幕空间环境光遮蔽实现
    // 在实际应用中,这通常需要单独的渲染目标和复杂的着色器
    }

    void ApplyBloom()
    {
    // 泛光效果实现
    // 通常包括:亮度提取、高斯模糊、合成等步骤
    }

    void ApplyMotionBlur()
    {
    // 运动模糊实现
    // 需要速度缓冲区记录像素运动
    }

    void ApplyDepthOfField()
    {
    // 景深效果实现
    // 基于深度信息模糊背景和前景
    }

    void EndFrame()
    {
    // 后处理完成后,可以在这里执行最终的呈现
    // 注意:实际的呈现应该在交换链中进行
    }

    void Resize(UINT newWidth, UINT newHeight)
    {
    // 更新视口
    mainViewport.Width = static_cast<float>(newWidth);
    mainViewport.Height = static_cast<float>(newHeight);

    // 重新创建渲染目标
    if (mainRenderTargetView) mainRenderTargetView->Release();
    if (mainRenderTargetTexture) mainRenderTargetTexture->Release();
    CreateMainRenderTarget(newWidth, newHeight);

    // 重新创建深度缓冲区
    if (depthStencilView) depthStencilView->Release();
    if (depthStencilTexture) depthStencilTexture->Release();
    if (depthSRV) depthSRV->Release();
    CreateDepthStencil(newWidth, newHeight);

    // 重新创建G-Buffer(如果存在)
    if (!gBuffer.empty())
    {
    for (auto& buffer : gBuffer)
    {
    if (buffer.srv) buffer.srv->Release();
    if (buffer.rtv) buffer.rtv->Release();
    if (buffer.texture) buffer.texture->Release();
    }
    gBuffer.clear();
    CreateGBuffer(newWidth, newHeight);
    }
    }

    void Cleanup()
    {
    // 清理所有资源
    if (inputLayout) inputLayout->Release();

    if (forwardVS) forwardVS->Release();
    if (forwardPS) forwardPS->Release();
    if (deferredVS) deferredVS->Release();
    if (deferredPS) deferredPS->Release();
    if (lightingPS) lightingPS->Release();

    if (perFrameConstantBuffer) perFrameConstantBuffer->Release();
    if (perObjectConstantBuffer) perObjectConstantBuffer->Release();

    if (linearSampler) linearSampler->Release();
    if (pointSampler) pointSampler->Release();

    if (depthSRV) depthSRV->Release();
    if (depthStencilView) depthStencilView->Release();
    if (depthStencilTexture) depthStencilTexture->Release();

    if (mainRenderTargetView) mainRenderTargetView->Release();
    if (mainRenderTargetTexture) mainRenderTargetTexture->Release();

    for (auto& buffer : gBuffer)
    {
    if (buffer.srv) buffer.srv->Release();
    if (buffer.rtv) buffer.rtv->Release();
    if (buffer.texture) buffer.texture->Release();
    }
    gBuffer.clear();
    }

    // 常量缓冲区结构
    struct PerFrameConstants
    {
    XMFLOAT4X4 viewMatrix;
    XMFLOAT4X4 projectionMatrix;
    XMFLOAT3 cameraPosition;
    float padding;
    };

    struct PerObjectConstants
    {
    XMFLOAT4X4 worldMatrix;
    XMFLOAT4 materialColor;
    float roughness;
    float metalness;
    XMFLOAT2 paddingObj;
    };

    struct Vertex
    {
    XMFLOAT3 position;
    XMFLOAT3 normal;
    XMFLOAT2 texcoord;
    };

    ~RenderPipelineManager()
    {
    Cleanup();
    }
    };

    这个渲染流水线管理器实现了现代游戏引擎的核心功能:

  • 多流水线支持:前向渲染、延迟渲染等
  • G-Buffer管理:为延迟渲染提供支持
  • 后处理效果:SSAO、泛光、运动模糊、景深等
  • 动态调整:窗口大小改变时自动调整资源
  • 模块化设计:易于扩展和维护
  • 13.3 高级渲染技术与优化

    13.3.1 实例化渲染

    实例化渲染是现代游戏中的重要优化技术,特别是在渲染大量相似对象时(如草地、树木、人群)。《刺客信条:英灵殿》中广阔的场景就大量使用了实例化渲染。

    class InstancedRenderer
    {
    private:
    struct InstanceData
    {
    XMFLOAT4X4 worldMatrix;
    XMFLOAT4 color;
    XMFLOAT2 uvOffset;
    float scale;
    float rotation;
    };

    ID3D11Device* device;
    ID3D11DeviceContext* deviceContext;

    // 实例缓冲区
    ID3D11Buffer* instanceBuffer;
    ID3D11Buffer* dynamicInstanceBuffer;

    // 顶点和索引缓冲区
    ID3D11Buffer* vertexBuffer;
    ID3D11Buffer* indexBuffer;

    // 着色器
    ID3D11VertexShader* instancedVS;
    ID3D11PixelShader* instancedPS;
    ID3D11InputLayout* instancedInputLayout;

    // 常量缓冲区
    ID3D11Buffer* perFrameBuffer;
    ID3D11Buffer* perInstanceBuffer;

    // 实例数据
    std::vector<InstanceData> instances;
    UINT maxInstances;
    UINT instanceStride;

    public:
    InstancedRenderer(ID3D11Device* dev, ID3D11DeviceContext* context)
    : device(dev)
    , deviceContext(context)
    , instanceBuffer(nullptr)
    , dynamicInstanceBuffer(nullptr)
    , vertexBuffer(nullptr)
    , indexBuffer(nullptr)
    , instancedVS(nullptr)
    , instancedPS(nullptr)
    , instancedInputLayout(nullptr)
    , perFrameBuffer(nullptr)
    , perInstanceBuffer(nullptr)
    , maxInstances(1000)
    , instanceStride(sizeof(InstanceData))
    {
    }

    bool Initialize(UINT maxInstanceCount = 1000)
    {
    maxInstances = maxInstanceCount;

    // 创建实例缓冲区
    D3D11_BUFFER_DESC instanceBufferDesc;
    ZeroMemory(&instanceBufferDesc, sizeof(instanceBufferDesc));

    instanceBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    instanceBufferDesc.ByteWidth = maxInstances * instanceStride;
    instanceBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    instanceBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    instanceBufferDesc.MiscFlags = 0;
    instanceBufferDesc.StructureByteStride = 0;

    HRESULT result = device->CreateBuffer(&instanceBufferDesc, NULL, &instanceBuffer);

    if (FAILED(result))
    {
    return false;
    }

    // 编译实例化着色器
    if (!CompileInstancedShaders())
    {
    return false;
    }

    // 创建常量缓冲区
    if (!CreateConstantBuffers())
    {
    return false;
    }

    return true;
    }

    bool CompileInstancedShaders()
    {
    // 实例化专用顶点着色器
    const char* instancedVSCode =
    "cbuffer PerFrameConstants : register(b0)\\n"
    "{\\n"
    " float4x4 viewProjMatrix;\\n"
    " float3 cameraPosition;\\n"
    " float time;\\n"
    "};\\n"
    "\\n"
    "struct VertexInput\\n"
    "{\\n"
    " float3 position : POSITION;\\n"
    " float3 normal : NORMAL;\\n"
    " float2 texcoord : TEXCOORD0;\\n"
    " float4 instanceColor : COLOR;\\n"
    " float4x4 instanceWorld : WORLD;\\n"
    " float2 instanceUVOffset : TEXCOORD1;\\n"
    "};\\n"
    "\\n"
    "struct PixelInput\\n"
    "{\\n"
    " float4 position : SV_POSITION;\\n"
    " float3 worldPosition : POSITION;\\n"
    " float3 normal : NORMAL;\\n"
    " float2 texcoord : TEXCOORD0;\\n"
    " float4 color : COLOR;\\n"
    "};\\n"
    "\\n"
    "PixelInput main(VertexInput input)\\n"
    "{\\n"
    " PixelInput output;\\n"
    " \\n"
    " // 应用实例的世界变换\\n"
    " float4 worldPos = mul(float4(input.position, 1.0f), input.instanceWorld);\\n"
    " \\n"
    " // 应用视图投影变换\\n"
    " output.position = mul(worldPos, viewProjMatrix);\\n"
    " \\n"
    " // 传递其他数据\\n"
    " output.worldPosition = worldPos.xyz;\\n"
    " output.normal = normalize(mul(input.normal, (float3x3)input.instanceWorld));\\n"
    " output.texcoord = input.texcoord + input.instanceUVOffset;\\n"
    " output.color = input.instanceColor;\\n"
    " \\n"
    " return output;\\n"
    "}";

    // 编译着色器…
    // (为了简洁,省略了编译代码,与前面类似)

    return true;
    }

    void UpdateInstances(const std::vector<InstanceData>& newInstances)
    {
    instances = newInstances;

    // 确保不超过最大实例数
    if (instances.size() > maxInstances)
    {
    instances.resize(maxInstances);
    }

    // 更新实例缓冲区
    if (instances.empty())
    {
    return;
    }

    D3D11_MAPPED_SUBRESOURCE mapped;
    deviceContext->Map(instanceBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);

    memcpy(mapped.pData, instances.data(), instances.size() * instanceStride);

    deviceContext->Unmap(instanceBuffer, 0);
    }

    void Render()
    {
    if (instances.empty())
    {
    return;
    }

    // 设置顶点缓冲区(两个缓冲区:几何体数据和实例数据)
    ID3D11Buffer* buffers[2] = { vertexBuffer, instanceBuffer };
    UINT strides[2] = { sizeof(Vertex), instanceStride };
    UINT offsets[2] = { 0, 0 };

    deviceContext->IASetVertexBuffers(0, 2, buffers, strides, offsets);
    deviceContext->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R32_UINT, 0);

    // 设置输入布局
    deviceContext->IASetInputLayout(instancedInputLayout);

    // 设置图元拓扑
    deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    // 设置着色器
    deviceContext->VSSetShader(instancedVS, nullptr, 0);
    deviceContext->PSSetShader(instancedPS, nullptr, 0);

    // 绘制实例化几何体
    // 假设每个实例的三角形数量为triangleCount
    UINT triangleCount = 100; // 示例值
    deviceContext->DrawIndexedInstanced(triangleCount * 3, instances.size(), 0, 0, 0);
    }

    void Cleanup()
    {
    if (instanceBuffer) instanceBuffer->Release();
    if (dynamicInstanceBuffer) dynamicInstanceBuffer->Release();
    if (vertexBuffer) vertexBuffer->Release();
    if (indexBuffer) indexBuffer->Release();
    if (instancedVS) instancedVS->Release();
    if (instancedPS) instancedPS->Release();
    if (instancedInputLayout) instancedInputLayout->Release();
    if (perFrameBuffer) perFrameBuffer->Release();
    if (perInstanceBuffer) perInstanceBuffer->Release();
    }

    ~InstancedRenderer()
    {
    Cleanup();
    }
    };

    13.3.2 级联阴影映射

    级联阴影映射是大型开放世界游戏中的关键技术,《上古卷轴5:天际》和《巫师3》都使用了这项技术来处理大范围的动态阴影。

    class CascadedShadowMap
    {
    private:
    struct CascadeData
    {
    XMFLOAT4X4 viewProjMatrix;
    XMFLOAT4 splitDepth;
    XMFLOAT3 lightDirection;
    float padding;
    };

    ID3D11Device* device;
    ID3D11DeviceContext* deviceContext;

    // 阴影图纹理和视图
    ID3D11Texture2D* shadowMapArray;
    ID3D11DepthStencilView* shadowDSV;
    ID3D11ShaderResourceView* shadowSRV;

    // 阴影图尺寸和级联数量
    UINT shadowMapSize;
    UINT cascadeCount;

    // 视锥分割距离
    std::vector<float> cascadeSplits;

    // 常量缓冲区
    ID3D11Buffer* cascadeBuffer;

    // 视口数组
    std::vector<D3D11_VIEWPORT> cascadeViewports;

    public:
    CascadedShadowMap(ID3D11Device* dev, ID3D11DeviceContext* context)
    : device(dev)
    , deviceContext(context)
    , shadowMapArray(nullptr)
    , shadowDSV(nullptr)
    , shadowSRV(nullptr)
    , shadowMapSize(2048)
    , cascadeCount(4)
    , cascadeBuffer(nullptr)
    {
    // 默认级联分割(基于到摄像机的距离)
    cascadeSplits = { 0.05f, 0.15f, 0.50f, 1.0f };
    }

    bool Initialize(UINT size = 2048, UINT cascades = 4)
    {
    shadowMapSize = size;
    cascadeCount = cascades;

    // 创建阴影图数组纹理
    D3D11_TEXTURE2D_DESC shadowMapDesc;
    ZeroMemory(&shadowMapDesc, sizeof(shadowMapDesc));

    shadowMapDesc.Width = shadowMapSize;
    shadowMapDesc.Height = shadowMapSize;
    shadowMapDesc.MipLevels = 1;
    shadowMapDesc.ArraySize = cascadeCount; // 每个级联一层
    shadowMapDesc.Format = DXGI_FORMAT_R32_TYPELESS; // 用于深度和着色器采样
    shadowMapDesc.SampleDesc.Count = 1;
    shadowMapDesc.SampleDesc.Quality = 0;
    shadowMapDesc.Usage = D3D11_USAGE_DEFAULT;
    shadowMapDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
    shadowMapDesc.CPUAccessFlags = 0;
    shadowMapDesc.MiscFlags = 0;

    HRESULT result = device->CreateTexture2D(&shadowMapDesc, NULL, &shadowMapArray);

    if (FAILED(result))
    {
    return false;
    }

    // 创建深度模板视图
    D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc;
    ZeroMemory(&dsvDesc, sizeof(dsvDesc));

    dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
    dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
    dsvDesc.Texture2DArray.MipSlice = 0;
    dsvDesc.Texture2DArray.FirstArraySlice = 0;
    dsvDesc.Texture2DArray.ArraySize = cascadeCount;

    result = device->CreateDepthStencilView(shadowMapArray, &dsvDesc, &shadowDSV);

    if (FAILED(result))
    {
    return false;
    }

    // 创建着色器资源视图
    D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
    ZeroMemory(&srvDesc, sizeof(srvDesc));

    srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
    srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
    srvDesc.Texture2DArray.MostDetailedMip = 0;
    srvDesc.Texture2DArray.MipLevels = 1;
    srvDesc.Texture2DArray.FirstArraySlice = 0;
    srvDesc.Texture2DArray.ArraySize = cascadeCount;

    result = device->CreateShaderResourceView(shadowMapArray, &srvDesc, &shadowSRV);

    if (FAILED(result))
    {
    return false;
    }

    // 为每个级联创建视口
    for (UINT i = 0; i < cascadeCount; ++i)
    {
    D3D11_VIEWPORT viewport;
    viewport.TopLeftX = 0.0f;
    viewport.TopLeftY = 0.0f;
    viewport.Width = static_cast<float>(shadowMapSize);
    viewport.Height = static_cast<float>(shadowMapSize);
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;

    cascadeViewports.push_back(viewport);
    }

    // 创建常量缓冲区
    D3D11_BUFFER_DESC bufferDesc;
    ZeroMemory(&bufferDesc, sizeof(bufferDesc));

    bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    bufferDesc.ByteWidth = sizeof(CascadeData) * cascadeCount;
    bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

    result = device->CreateBuffer(&bufferDesc, NULL, &cascadeBuffer);

    return SUCCEEDED(result);
    }

    void BeginShadowPass(UINT cascadeIndex)
    {
    if (cascadeIndex >= cascadeCount)
    {
    return;
    }

    // 设置当前级联的渲染目标
    deviceContext->RSSetViewports(1, &cascadeViewports[cascadeIndex]);

    // 清除深度缓冲区
    deviceContext->ClearDepthStencilView(shadowDSV, D3D11_CLEAR_DEPTH, 1.0f, 0);

    // 绑定阴影图为深度缓冲区
    deviceContext->OMSetRenderTargets(0, nullptr, shadowDSV);
    }

    void CalculateCascadeMatrices(
    const XMFLOAT3& cameraPosition,
    const XMFLOAT3& cameraDirection,
    const XMFLOAT3& lightDirection,
    float cameraNear, float cameraFar,
    float cameraFOV, float aspectRatio)
    {
    // 计算每个级联的视图投影矩阵
    std::vector<CascadeData> cascadeData(cascadeCount);

    for (UINT i = 0; i < cascadeCount; ++i)
    {
    float splitNear = (i == 0) ? cameraNear : cascadeSplits[i1] * cameraFar;
    float splitFar = cascadeSplits[i] * cameraFar;

    // 计算级联的视锥
    XMFLOAT4X4 cascadeViewProj = CalculateCascadeViewProj(
    cameraPosition, cameraDirection, lightDirection,
    splitNear, splitFar, cameraFOV, aspectRatio);

    cascadeData[i].viewProjMatrix = cascadeViewProj;
    cascadeData[i].splitDepth = XMFLOAT4(splitNear, splitFar, 0.0f, 0.0f);
    cascadeData[i].lightDirection = lightDirection;
    }

    // 更新常量缓冲区
    D3D11_MAPPED_SUBRESOURCE mapped;
    deviceContext->Map(cascadeBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);

    memcpy(mapped.pData, cascadeData.data(), sizeof(CascadeData) * cascadeCount);

    deviceContext->Unmap(cascadeBuffer, 0);
    }

    XMFLOAT4X4 CalculateCascadeViewProj(
    const XMFLOAT3& cameraPos,
    const XMFLOAT3& cameraDir,
    const XMFLOAT3& lightDir,
    float nearPlane, float farPlane,
    float fov, float aspect)
    {
    // 计算摄像机视锥的角点
    std::vector<XMFLOAT3> frustumCorners = CalculateFrustumCorners(
    cameraPos, cameraDir, nearPlane, farPlane, fov, aspect);

    // 计算包围这些点的AABB
    XMFLOAT3 minBounds = frustumCorners[0];
    XMFLOAT3 maxBounds = frustumCorners[0];

    for (const auto& corner : frustumCorners)
    {
    minBounds.x = min(minBounds.x, corner.x);
    minBounds.y = min(minBounds.y, corner.y);
    minBounds.z = min(minBounds.z, corner.z);

    maxBounds.x = max(maxBounds.x, corner.x);
    maxBounds.y = max(maxBounds.y, corner.y);
    maxBounds.z = max(maxBounds.z, corner.z);
    }

    // 从光源方向创建视图矩阵
    XMVECTOR lightPos = XMVectorSet(
    (minBounds.x + maxBounds.x) * 0.5f,
    (minBounds.y + maxBounds.y) * 0.5f,
    (minBounds.z + maxBounds.z) * 0.5f,
    1.0f);

    XMVECTOR lightTarget = XMVectorAdd(lightPos, XMLoadFloat3(&lightDir));
    XMVECTOR lightUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);

    XMMATRIX lightView = XMMatrixLookAtLH(lightPos, lightTarget, lightUp);

    // 计算正交投影矩阵
    XMFLOAT3 aabbMin, aabbMax;
    TransformAABB(minBounds, maxBounds, lightView, aabbMin, aabbMax);

    XMMATRIX lightProj = XMMatrixOrthographicOffCenterLH(
    aabbMin.x, aabbMax.x,
    aabbMin.y, aabbMax.y,
    aabbMin.z, aabbMax.z);

    // 组合视图投影矩阵
    XMFLOAT4X4 result;
    XMStoreFloat4x4(&result, XMMatrixMultiply(lightView, lightProj));

    return result;
    }

    std::vector<XMFLOAT3> CalculateFrustumCorners(
    const XMFLOAT3& cameraPos,
    const XMFLOAT3& cameraDir,
    float nearPlane, float farPlane,
    float fov, float aspect)
    {
    std::vector<XMFLOAT3> corners(8);

    // 计算近平面和远平面的半高和半宽
    float nearHalfHeight = nearPlane * tan(fov * 0.5f);
    float nearHalfWidth = nearHalfHeight * aspect;

    float farHalfHeight = farPlane * tan(fov * 0.5f);
    float farHalfWidth = farHalfHeight * aspect;

    // 计算摄像机的右向量和上向量
    XMVECTOR cameraRight = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f); // 简化:假设X轴为右
    XMVECTOR cameraUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); // Y轴为上

    XMVECTOR cameraForward = XMLoadFloat3(&cameraDir);

    // 计算角点
    // 近平面
    corners[0] = cameraPos + cameraForward * nearPlane cameraRight * nearHalfWidth cameraUp * nearHalfHeight;
    corners[1] = cameraPos + cameraForward * nearPlane + cameraRight * nearHalfWidth cameraUp * nearHalfHeight;
    corners[2] = cameraPos + cameraForward * nearPlane + cameraRight * nearHalfWidth + cameraUp * nearHalfHeight;
    corners[3] = cameraPos + cameraForward * nearPlane cameraRight * nearHalfWidth + cameraUp * nearHalfHeight;

    // 远平面
    corners[4] = cameraPos + cameraForward * farPlane cameraRight * farHalfWidth cameraUp * farHalfHeight;
    corners[5] = cameraPos + cameraForward * farPlane + cameraRight * farHalfWidth cameraUp * farHalfHeight;
    corners[6] = cameraPos + cameraForward * farPlane + cameraRight * farHalfWidth + cameraUp * farHalfHeight;
    corners[7] = cameraPos + cameraForward * farPlane cameraRight * farHalfWidth + cameraUp * farHalfHeight;

    return corners;
    }

    void TransformAABB(
    const XMFLOAT3& minPt,
    const XMFLOAT3& maxPt,
    const XMMATRIX& transform,
    XMFLOAT3& outMin,
    XMFLOAT3& outMax)
    {
    // 变换AABB的所有角点
    XMFLOAT3 corners[8] =
    {
    minPt,
    XMFLOAT3(maxPt.x, minPt.y, minPt.z),
    XMFLOAT3(minPt.x, maxPt.y, minPt.z),
    XMFLOAT3(maxPt.x, maxPt.y, minPt.z),
    XMFLOAT3(minPt.x, minPt.y, maxPt.z),
    XMFLOAT3(maxPt.x, minPt.y, maxPt.z),
    XMFLOAT3(minPt.x, maxPt.y, maxPt.z),
    maxPt
    };

    // 初始化输出边界
    XMVECTOR vMin = XMVectorSet(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);
    XMVECTOR vMax = XMVectorSet(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);

    // 变换所有点并更新边界
    for (int i = 0; i < 8; ++i)
    {
    XMVECTOR corner = XMLoadFloat3(&corners[i]);
    corner = XMVector3Transform(corner, transform);

    vMin = XMVectorMin(vMin, corner);
    vMax = XMVectorMax(vMax, corner);
    }

    XMStoreFloat3(&outMin, vMin);
    XMStoreFloat3(&outMax, vMax);
    }

    void Cleanup()
    {
    if (shadowSRV) shadowSRV->Release();
    if (shadowDSV) shadowDSV->Release();
    if (shadowMapArray) shadowMapArray->Release();
    if (cascadeBuffer) cascadeBuffer->Release();
    }

    ID3D11ShaderResourceView* GetShadowSRV() const { return shadowSRV; }
    ID3D11Buffer* GetCascadeBuffer() const { return cascadeBuffer; }
    UINT GetCascadeCount() const { return cascadeCount; }

    ~CascadedShadowMap()
    {
    Cleanup();
    }
    };

    13.4 性能优化与调试

    13.4.1 Direct3D调试技巧

    在商业游戏开发中,调试图形问题是一项重要技能。以下是一些实用的调试技巧:

    class Direct3DDebugHelper
    {
    private:
    ID3D11Device* device;
    ID3D11DeviceContext* deviceContext;

    // 调试接口
    ID3D11Debug* d3dDebug;
    ID3D11InfoQueue* infoQueue;

    public:
    Direct3DDebugHelper(ID3D11Device* dev, ID3D11DeviceContext* context)
    : device(dev)
    , deviceContext(context)
    , d3dDebug(nullptr)
    , infoQueue(nullptr)
    {
    }

    bool InitializeDebugLayer()
    {
    HRESULT result = device->QueryInterface(__uuidof(ID3D11Debug), (void**)&d3dDebug);

    if (SUCCEEDED(result))
    {
    result = device->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&infoQueue);

    if (SUCCEEDED(result))
    {
    // 设置信息队列过滤器
    D3D11_INFO_QUEUE_FILTER filter;
    ZeroMemory(&filter, sizeof(filter));

    // 允许所有消息类型
    D3D11_MESSAGE_SEVERITY severities[] =
    {
    D3D11_MESSAGE_SEVERITY_CORRUPTION,
    D3D11_MESSAGE_SEVERITY_ERROR,
    D3D11_MESSAGE_SEVERITY_WARNING,
    D3D11_MESSAGE_SEVERITY_INFO,
    D3D11_MESSAGE_SEVERITY_MESSAGE
    };

    filter.AllowList.NumSeverities = ARRAYSIZE(severities);
    filter.AllowList.pSeverityList = severities;

    // 设置存储限制
    infoQueue->SetStorageFilterStackIndex(0);
    infoQueue->AddStorageFilterEntries(&filter);

    // 设置回调函数
    infoQueue->SetMessageCountLimit(1000);

    return true;
    }
    }

    return false;
    }

    void CheckForLiveObjects()
    {
    if (d3dDebug)
    {
    OutputDebugString(L"=== 检查Direct3D存活对象 ===\\n");
    d3dDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL | D3D11_RLDO_IGNORE_INTERNAL);
    OutputDebugString(L"=== 检查完成 ===\\n");
    }
    }

    void PrintMessages()
    {
    if (!infoQueue)
    {
    return;
    }

    UINT64 messageCount = infoQueue->GetNumStoredMessages();

    for (UINT64 i = 0; i < messageCount; ++i)
    {
    SIZE_T messageSize = 0;
    infoQueue->GetMessage(i, nullptr, &messageSize);

    D3D11_MESSAGE* message = (D3D11_MESSAGE*)malloc(messageSize);
    infoQueue->GetMessage(i, message, &messageSize);

    // 根据严重级别输出消息
    switch (message->Severity)
    {
    case D3D11_MESSAGE_SEVERITY_CORRUPTION:
    OutputDebugString(L"[CORRUPTION] ");
    break;
    case D3D11_MESSAGE_SEVERITY_ERROR:
    OutputDebugString(L"[ERROR] ");
    break;
    case D3D11_MESSAGE_SEVERITY_WARNING:
    OutputDebugString(L"[WARNING] ");
    break;
    case D3D11_MESSAGE_SEVERITY_INFO:
    OutputDebugString(L"[INFO] ");
    break;
    case D3D11_MESSAGE_SEVERITY_MESSAGE:
    OutputDebugString(L"[MESSAGE] ");
    break;
    }

    OutputDebugStringA(message->pDescription);
    OutputDebugString(L"\\n");

    free(message);
    }

    // 清空消息队列
    infoQueue->ClearStoredMessages();
    }

    void BeginEvent(const std::wstring& eventName)
    {
    // 在GPU调试器中标记事件开始
    // 注意:这需要Windows 8或更高版本
    // 在实际代码中应使用条件编译
    #ifdef _DEBUG
    // deviceContext->BeginEvent(eventName.c_str());
    #endif
    }

    void EndEvent()
    {
    #ifdef _DEBUG
    // deviceContext->EndEvent();
    #endif
    }

    void SetMarker(const std::wstring& markerName)
    {
    #ifdef _DEBUG
    // deviceContext->SetMarker(markerName.c_str());
    #endif
    }

    void Cleanup()
    {
    if (infoQueue) infoQueue->Release();
    if (d3dDebug) d3dDebug->Release();
    }

    ~Direct3DDebugHelper()
    {
    Cleanup();
    }
    };

    13.4.2 性能分析

    性能分析对于优化游戏至关重要。以下是一个简单的性能分析器:

    class PerformanceProfiler
    {
    private:
    struct ProfileSample
    {
    std::string name;
    LARGE_INTEGER startTime;
    LARGE_INTEGER endTime;
    double duration;
    UINT callCount;
    double totalTime;
    double minTime;
    double maxTime;
    };

    LARGE_INTEGER frequency;
    std::map<std::string, ProfileSample> samples;

    public:
    PerformanceProfiler()
    {
    QueryPerformanceFrequency(&frequency);
    }

    void BeginSample(const std::string& sampleName)
    {
    ProfileSample& sample = samples[sampleName];
    sample.name = sampleName;
    QueryPerformanceCounter(&sample.startTime);
    }

    void EndSample(const std::string& sampleName)
    {
    auto it = samples.find(sampleName);
    if (it == samples.end())
    {
    return;
    }

    ProfileSample& sample = it->second;
    QueryPerformanceCounter(&sample.endTime);

    // 计算持续时间(毫秒)
    sample.duration = static_cast<double>(sample.endTime.QuadPart sample.startTime.QuadPart) * 1000.0 / frequency.QuadPart;

    // 更新统计信息
    sample.callCount++;
    sample.totalTime += sample.duration;

    if (sample.callCount == 1)
    {
    sample.minTime = sample.duration;
    sample.maxTime = sample.duration;
    }
    else
    {
    sample.minTime = min(sample.minTime, sample.duration);
    sample.maxTime = max(sample.maxTime, sample.duration);
    }
    }

    void PrintResults()
    {
    OutputDebugString(L"=== 性能分析结果 ===\\n");

    for (const auto& pair : samples)
    {
    const ProfileSample& sample = pair.second;

    double avgTime = sample.totalTime / sample.callCount;

    wchar_t buffer[512];
    swprintf_s(buffer, L"%S: 调用次数=%u, 平均时间=%.3fms, 最小时间=%.3fms, 最大时间=%.3fms, 总时间=%.3fms\\n",
    sample.name.c_str(),
    sample.callCount,
    avgTime,
    sample.minTime,
    sample.maxTime,
    sample.totalTime);

    OutputDebugString(buffer);
    }

    OutputDebugString(L"=== 分析结束 ===\\n");

    // 重置统计信息
    samples.clear();
    }

    double GetSampleDuration(const std::string& sampleName)
    {
    auto it = samples.find(sampleName);
    if (it != samples.end())
    {
    return it->second.duration;
    }
    return 0.0;
    }
    };

    13.5 总结

    本章深入探讨了Direct3D核心编程的各个方面,从设备创建到高级渲染技术。我们学习了:

  • 设备管理:如何创建健壮的Direct3D设备,处理多种硬件配置
  • 交换链配置:全屏、窗口、无边框窗口等显示模式
  • 深度模板管理:高级深度测试和模板测试技术
  • 渲染流水线:前向渲染、延迟渲染等现代渲染架构
  • 高级技术:实例化渲染、级联阴影映射
  • 性能优化:调试技巧和性能分析
  • 这些技术是商业游戏开发的基础。《赛博朋克2077》、《荒野大镖客2》等AAA游戏都建立在类似的架构之上。通过掌握这些核心概念,你已经为开发自己的Windows游戏奠定了坚实的基础。

    记住,图形编程是一个不断发展的领域。DirectX 12已经引入了更底层的API控制,Vulkan也在跨平台领域占据重要地位。但无论API如何变化,本章讨论的核心概念——渲染流水线、资源管理、性能优化——都将是游戏开发中的重要基石。

    在下一章中,我们将探讨更高级的主题,包括高级着色器技术、几何着色器、曲面细分和计算着色器。继续学习,你将成为一名真正的Windows游戏编程专家。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 第13章 Direct3D核心编程精要——从初始化到渲染流水线
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!