1. 项目概述:为什么是DirectX11-With-Windows-SDK?
如果你是一名C++游戏开发者,尤其是从OpenGL或者更早期的DirectX版本转过来,第一次接触现代DirectX 11开发时,大概率会被各种“SDK”搞晕。是去下载那个传说中的“DirectX SDK (June 2010)”吗?还是用Visual Studio自带的?网上搜到的教程,有的让你配置DXSDK_DIR环境变量,有的又说不用。这个“DirectX11-With-Windows-SDK”项目,就是帮你拨开这团迷雾,让你用上微软官方推荐的、最现代、最“干净”的DirectX 11开发方式。
简单来说,“DirectX11-With-Windows-SDK”不是一个具体的游戏引擎或框架,而是一种使用官方最新工具链进行DirectX 11开发的实践范式。它的核心在于摒弃了已经过时、停止维护的独立“DirectX SDK”,转而使用集成在“Windows SDK”中的DirectX组件。从Windows 8开始,DirectX的核心API(如Direct3D 11, Direct2D, XAudio2, XInput等)就已经成为Windows SDK的一部分。这意味着,只要你安装了Visual Studio(通常会自动包含对应版本的Windows SDK),你就拥有了开发DirectX应用所需的一切头文件和库,无需再单独安装那个陈旧的、可能引起冲突的DirectX SDK。
这个转变带来的好处是巨大的:
- 环境纯净:避免了旧SDK中过时的工具链(如老版本的HLSL编译器fxc)与新系统或新Visual Studio版本冲突的问题。
- 维护性佳:Windows SDK会随Windows和Visual Studio更新,能获得最新的安全补丁和性能优化。
- 现代工具链:可以直接使用Visual Studio内建的强大图形调试器(Graphics Debugger),替代老旧的PIX工具。
- 清晰的依赖:项目配置更简单,通常只需要在Visual Studio中正确设置目标平台版本对应的Windows SDK即可。
所以,理解这个“项目”,本质上是理解一套新的、官方的开发工作流。接下来,我们就深入拆解这套工作流下的项目结构应该如何组织,以及各个核心组件如何协同工作。
2. 核心组件与依赖关系解析
在DirectX11-With-Windows-SDK的范式下,你的项目依赖关系变得清晰而现代。我们不再需要那个庞大的DXSDK_DIR,而是依赖于Windows SDK和Visual Studio。
2.1 Windows SDK:一切的基础
Windows SDK是你的基石。它包含了:
- 头文件(Headers):如
d3d11.h,d3dcompiler.h,dxgi.h,xaudio2.h,xinput.h等。它们位于类似C:\Program Files (x86)\Windows Kits\10\Include\10.0.xxxxx.0\um的目录下。 - 库文件(Libs):对应的
.lib文件,如d3d11.lib,d3dcompiler.lib,xaudio2.lib等,位于...\Lib\10.0.xxxxx.0\um\x64或x86目录。 - 工具(Tools):如HLSL编译器
fxc.exe,现在也集成在Windows SDK的bin目录下。
注意:在Visual Studio中创建项目时,务必在“项目属性 -> 常规 -> Windows SDK版本”中选择一个已安装的版本。这是项目能正确找到上述头文件和库的关键。
2.2 Visual Studio与平台工具集
Visual Studio不仅是代码编辑器,更是构建生态的核心。你需要关注:
- 平台工具集(Platform Toolset):这决定了使用哪个版本的MSVC编译器。对于新项目,应选择最新的稳定版本(如Visual Studio 2022的
v143)。这确保了C++语言特性和标准库的支持。 - C++语言标准:建议至少使用
C++17。现代C++特性(如智能指针、lambda表达式、标准文件系统库等)能极大提升DirectX封装代码的健壮性和可读性。
2.3 第三方辅助库:填补D3DX的空白
这是从旧范式过渡到新范式最关键的一步。旧的DirectX SDK提供了一个庞大的D3DX库,包含了数学库、纹理加载、网格处理、精灵渲染等大量实用功能。在Windows SDK中,D3DX已被彻底移除。
因此,你需要寻找替代品。微软官方在GitHub上维护了一系列优秀的开源库来填补这些空白,这也是现代DirectX开发的标准做法:
- DirectXMath:替代
D3DXMath。这是一个高度优化的SIMD数学库,用于向量、矩阵、四元数运算。它是Windows SDK的一部分,直接包含#include <DirectXMath.h>即可使用。 - DirectXTex:替代
D3DX中的纹理加载、处理、转换功能。支持大量图片格式(DDS, PNG, JPEG, TGA, HDR等),并能进行复杂的纹理操作(如生成Mipmap、压缩纹理格式转换)。 - DirectXTK(The DirectX Tool Kit):这是一个“瑞士军刀”式的库,提供了精灵批处理(SpriteBatch)、基本图元绘制(PrimitiveBatch)、字体渲染(SpriteFont)、简单音频播放、鼠标/键盘/游戏手柄输入封装等。它是开始一个DirectX 11项目最快捷的起点。
- DirectXMesh:替代
D3DX中的网格处理功能,用于计算法线、切线、网格优化(如顶点缓存优化、网格简化)等。 - UVAtlas:用于为网格生成均匀的UV图表(用于光照贴图等)。
实操心得:对于新手或中小型项目,我强烈建议从DirectXTK和DirectXTex开始。它们能解决你80%的常见需求(如显示图片、文字、播放音效),让你能快速搭建起游戏原型,而不是陷在底层API的细节里。可以通过Visual Studio的NuGet包管理器轻松安装这些库。
2.4 运行时依赖:DLL分发
你的应用程序最终需要一些系统组件才能运行:
- Direct3D 11运行时:这是Windows系统的一部分,从Windows 7 SP1开始就内置了,通常无需担心。
- D3DCompiler DLL:这是编译和运行时加载HLSL着色器所必需的。重要!这个DLL不再是系统组件。你需要将对应版本的
D3DCompiler_47.dll(或更新版本)随你的游戏一起分发。它可以在Windows SDK的Redist目录(如C:\Program Files (x86)\Windows Kits\10\Redist\D3D\<arch>)中找到。 - XAudio2 Redist:如果你使用了XAudio2,并且需要支持Windows 7,你需要单独分发
XAudio2_9.dll或XAudio2_8.dll。对于Windows 8及以上,XAudio2已是系统组件。
3. 现代DirectX 11项目结构详解
一个清晰、可维护的项目结构是成功的一半。下面是一个典型的、采用DirectX11-With-Windows-SDK范式的游戏项目结构示例:
MyDirectX11Game/ ├── .vs/ # Visual Studio临时文件(通常忽略) ├── bin/ # 输出目录(可执行文件、资源) │ ├── x64/ │ │ ├── Debug/ # 调试版输出 │ │ │ ├── MyDirectX11Game.exe │ │ │ ├── D3DCompiler_47.dll # 必须随游戏分发的DLL │ │ │ └── assets/ # 游戏资源(纹理、模型、音效等) │ │ └── Release/ # 发布版输出 ├── libs/ # 第三方库(如果不用NuGet,可手动管理) │ ├── DirectXTK/ │ ├── DirectXTex/ │ └── ... ├── src/ # 项目源代码 │ ├── core/ # 核心系统 │ │ ├── Application.cpp/.h # 应用主循环、窗口管理 │ │ ├── Graphics.cpp/.h # Direct3D设备、交换链、渲染状态管理 │ │ ├── Input.cpp/.h # 输入系统封装(基于DirectXTK或原生) │ │ └── Timer.cpp/.h # 高精度计时器 │ ├── renderer/ # 渲染相关 │ │ ├── D3DClass.cpp/.h # Direct3D 11设备与上下文封装类 │ │ ├── ShaderManager.cpp/.h # 着色器管理(加载、编译、绑定) │ │ ├── TextureManager.cpp/.h # 纹理资源管理(使用DirectXTex) │ │ ├── Model.cpp/.h # 网格模型类 │ │ └── Camera.cpp/.h # 摄像机类 │ ├── game/ # 游戏逻辑 │ │ ├── Game.cpp/.h # 游戏主逻辑更新 │ │ ├── Player.cpp/.h │ │ └── World.cpp/.h │ ├── utils/ # 工具类 │ │ ├── FileSystem.cpp/.h # 文件读写辅助 │ │ ├── Logger.cpp/.h # 日志系统 │ │ └── MathHelper.cpp/.h # 自定义数学辅助函数 │ ├── shaders/ # HLSL着色器文件(.hlsl) │ │ ├── BasicVS.hlsl │ │ ├── BasicPS.hlsl │ │ └── ... │ └── main.cpp # 程序入口点 ├── assets/ # 原始资源文件(开发用) │ ├── textures/ │ ├── models/ │ ├── sounds/ │ └── fonts/ ├── external/ # 项目外部依赖(如assimp模型加载库) ├── MyDirectX11Game.sln # Visual Studio解决方案文件 └── README.md # 项目说明3.1 关键目录与文件说明
src/core/Application:这是项目的“大脑”。它负责创建和管理主窗口(通常使用CreateWindowEx或更现代的CreateWindowAPI),建立消息循环,并调用游戏主循环的Update和Render函数。它也是初始化Direct3D设备的地方。src/renderer/D3DClass:这是渲染系统的“心脏”。一个设计良好的D3DClass应该封装以下内容:ID3D11Device*和ID3D11DeviceContext*:这是与GPU通信的核心接口。IDXGISwapChain*:交换链,管理前后缓冲区,实现双缓冲渲染,防止画面撕裂。ID3D11RenderTargetView*和ID3D11DepthStencilView*:渲染目标视图和深度模板视图,定义了渲染输出的目的地。- 设备能力检查、多重采样设置、全屏/窗口切换逻辑。
src/shaders/:存放HLSL源代码。最佳实践是将HLSL文件作为“内容”添加到Visual Studio项目中,并设置其“项类型”为“不参与生成”,然后通过自定义生成步骤或使用DirectXTK的BasicEffect等内置着色器来管理。更现代的方式是使用Visual Studio的“着色器设计器”或编写脚本在编译时自动编译着色器。bin/与assets/分离:这是非常重要的工程实践。assets/目录存放原始的、未处理的资源(如.png,.fbx)。在构建过程中(或首次运行时),通过工具(如使用DirectXTex命令行工具)将这些资源处理成游戏运行时的高效格式(如.dds纹理),并复制到bin/目录下的对应平台(如x64/Debug/assets/)中。这样能保证发布版本只包含优化后的资源。
3.2 Visual Studio项目属性配置
这是将理论转化为实践的关键一步。你需要正确配置项目属性,让编译器链接器找到所有依赖。
常规设置:
- Windows SDK版本:选择你安装的版本(如10.0.22621.0)。
- 平台工具集:选择
v143(VS2022)或对应版本。 - C++语言标准:选择
ISO C++17 Standard (/std:c++17)。
VC++目录:
- 包含目录:添加你的第三方库头文件路径,例如
$(SolutionDir)libs\DirectXTK\Inc;$(SolutionDir)libs\DirectXTex\Inc。注意:Windows SDK和标准库的路径通常由系统变量自动设置,无需手动添加。 - 库目录:添加第三方库的
.lib文件路径,例如$(SolutionDir)libs\DirectXTK\Lib\$(PlatformTarget);$(SolutionDir)libs\DirectXTex\Lib\$(PlatformTarget)。
- 包含目录:添加你的第三方库头文件路径,例如
链接器 -> 输入 -> 附加依赖项: 这里添加你需要链接的
.lib文件。一个典型的Debug配置依赖项如下:d3d11.lib d3dcompiler.lib dxgi.lib dxguid.lib winmm.lib xaudio2.lib xinput.lib DirectXTK.lib DirectXTex.lib注意顺序:一般将系统库(如
d3d11.lib)放在前面,第三方库放在后面。dxguid.lib在某些情况下(如查询设备接口)是必需的。winmm.lib是Windows多媒体库,用于高精度计时。生成事件: 这是实现资源自动处理的关键。你可以在“生成事件 -> 预生成事件”中添加命令行脚本,将
assets/下的资源处理并复制到输出目录。示例命令(批处理):xcopy /Y /E "$(ProjectDir)assets\*" "$(OutDir)assets\" "$(SolutionDir)tools\TextureConverter.exe" "$(ProjectDir)assets\textures\*.png" "$(OutDir)assets\textures\" /format:BC3_UNORM
4. 核心渲染循环与组件交互实战
理解了结构,我们来看看代码如何在这些组件间流动。一个最简化的、但结构清晰的渲染循环如下:
// main.cpp #include "core/Application.h" #include "game/Game.h" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 1. 初始化应用层(创建窗口、消息循环) Application app; if (!app.Initialize(hInstance, L"My DirectX11 Game", 1280, 720)) return -1; // 2. 初始化游戏逻辑层和渲染层 Game game; if (!game.Initialize(app.GetWindowHandle(), app.GetWidth(), app.GetHeight())) return -1; // 3. 主消息循环 MSG msg = {}; while (msg.message != WM_QUIT) { // 处理窗口消息 if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { // 4. 游戏逻辑更新(输入、状态、物理等) app.ProcessInput(); // 例如,使用DirectXTK的Keyboard/Mouse类 game.Update(app.GetDeltaTime()); // 5. 渲染帧 game.Render(); } } // 6. 清理资源 game.Shutdown(); app.Shutdown(); return 0; }4.1 设备与交换链创建详解
在D3DClass::Initialize中,创建ID3D11Device和IDXGISwapChain是最关键的步骤。这里有几个容易踩坑的细节:
bool D3DClass::Initialize(HWND hwnd, int screenWidth, int screenHeight, bool vsync, bool fullscreen) { HRESULT result; UINT createDeviceFlags = 0; #ifdef _DEBUG // 调试模式下启用D3D11调试层,可以捕获API错误和内存泄漏, invaluable! createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif // 1. 填充交换链描述结构 DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferCount = 2; // 双缓冲 swapChainDesc.BufferDesc.Width = screenWidth; swapChainDesc.BufferDesc.Height = screenHeight; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // 最常用的后备缓冲区格式 swapChainDesc.BufferDesc.RefreshRate.Numerator = vsync ? 60 : 0; // 垂直同步刷新率分子 swapChainDesc.BufferDesc.RefreshRate.Denominator = vsync ? 1 : 0; // 分母 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.OutputWindow = hwnd; swapChainDesc.SampleDesc.Count = 1; // 多重采样数,1表示禁用 swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.Windowed = !fullscreen; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // 交换后丢弃旧内容,性能好 swapChainDesc.Flags = 0; // 2. 创建设备、设备上下文和交换链 D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 }; // 我们只需要11.0 D3D_FEATURE_LEVEL selectedFeatureLevel; result = D3D11CreateDeviceAndSwapChain( nullptr, // 使用默认适配器(主显卡) D3D_DRIVER_TYPE_HARDWARE, // 使用硬件驱动 nullptr, // 没有软件驱动 createDeviceFlags, // 调试标志 featureLevels, // 特性等级数组 1, // 特性等级数量 D3D11_SDK_VERSION, // SDK版本,总是用这个宏 &swapChainDesc, // 交换链描述 &m_swapChain, // 输出的交换链指针 &m_device, // 输出的设备指针 &selectedFeatureLevel, // 输出的特性等级 &m_deviceContext // 输出的设备上下文指针 ); if (FAILED(result)) { /* 错误处理 */ } // 3. 创建渲染目标视图(指向交换链的后备缓冲区) ID3D11Texture2D* backBuffer = nullptr; result = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer); if (FAILED(result)) { /* 错误处理 */ } result = m_device->CreateRenderTargetView(backBuffer, nullptr, &m_renderTargetView); backBuffer->Release(); // 记得释放临时获取的接口 if (FAILED(result)) { /* 错误处理 */ } // 4. 创建深度模板缓冲区和视图 D3D11_TEXTURE2D_DESC depthBufferDesc = {}; depthBufferDesc.Width = screenWidth; depthBufferDesc.Height = screenHeight; depthBufferDesc.MipLevels = 1; depthBufferDesc.ArraySize = 1; depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; // 24位深度+8位模板 depthBufferDesc.SampleDesc.Count = 1; depthBufferDesc.SampleDesc.Quality = 0; depthBufferDesc.Usage = D3D11_USAGE_DEFAULT; depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; depthBufferDesc.CPUAccessFlags = 0; depthBufferDesc.MiscFlags = 0; result = m_device->CreateTexture2D(&depthBufferDesc, nullptr, &m_depthStencilBuffer); if (FAILED(result)) { /* 错误处理 */ } result = m_device->CreateDepthStencilView(m_depthStencilBuffer, nullptr, &m_depthStencilView); if (FAILED(result)) { /* 错误处理 */ } // 5. 将渲染目标视图和深度模板视图绑定到输出合并阶段 m_deviceContext->OMSetRenderTargets(1, &m_renderTargetView, m_depthStencilView); // 6. 设置视口(告诉GPU渲染到后备缓冲区的哪个区域) D3D11_VIEWPORT viewport = {}; viewport.Width = static_cast<float>(screenWidth); viewport.Height = static_cast<float>(screenHeight); viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; viewport.TopLeftX = 0.0f; viewport.TopLeftY = 0.0f; m_deviceContext->RSSetViewports(1, &viewport); return true; }4.2 着色器管理与资源绑定
现代DirectX 11渲染管线是高度可编程的,着色器是灵魂。管理好着色器至关重要。
// ShaderManager.h 示例 class ShaderManager { public: struct BasicShader { Microsoft::WRL::ComPtr<ID3D11VertexShader> vertexShader; Microsoft::WRL::ComPtr<ID3D11PixelShader> pixelShader; Microsoft::WRL::ComPtr<ID3D11InputLayout> inputLayout; Microsoft::WRL::ComPtr<ID3D11Buffer> constantBuffer; // 用于传递MVP矩阵等 }; bool LoadShader(const std::wstring& vsPath, const std::wstring& psPath, const std::string& shaderName); void BindShader(const std::string& shaderName); // ... 其他方法,如更新常量缓冲区 private: std::unordered_map<std::string, BasicShader> m_shaders; }; // 在Game::Render()中 void Game::Render() { // 清屏 const float clearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f }; // 蓝色背景 m_d3dClass->GetDeviceContext()->ClearRenderTargetView(m_renderTargetView.Get(), clearColor); m_d3dClass->GetDeviceContext()->ClearDepthStencilView(m_depthStencilView.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0); // 绑定着色器 m_shaderManager->BindShader("Basic"); // 更新常量缓冲区(例如传递世界-视图-投影矩阵) // ... 设置顶点/索引缓冲区 // ... 绘制调用 // 呈现(交换前后缓冲区) m_d3dClass->Present(m_vsyncEnabled); }重要提示:使用
Microsoft::WRL::ComPtr(Windows Runtime C++ Template Library)来管理COM接口指针是最佳实践。它实现了自动引用计数(AddRef/Release),能极大避免资源泄漏。这是现代DirectX C++代码的标配。
5. 常见问题、调试技巧与性能考量
即使按照最佳实践搭建了项目,在实际开发中你依然会遇到各种问题。这里记录一些高频问题和解决思路。
5.1 编译与链接问题排查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
fatal error C1083: 无法打开包括文件: “d3dx11.h” | 项目仍配置为使用旧的DirectX SDK路径。 | 1. 检查项目属性 -> VC++目录 -> 包含目录,移除所有对$(DXSDK_DIR)的引用。2. 确保Windows SDK版本已正确设置。 |
error LNK2019: 无法解析的外部符号 _D3DX11CreateShaderResourceViewFromFile | 链接器找不到D3DX11库,因为它已被移除。 | 1.不要链接d3dx11.lib。2. 改用DirectXTex库中的函数,如 DirectX::CreateDDSTextureFromFile或DirectX::CreateWICTextureFromFile来加载纹理。 |
程序运行时崩溃,提示找不到D3DCompiler_47.dll | 该DLL未随程序分发。 | 1. 从Windows SDK的Redist目录(如C:\Program Files (x86)\Windows Kits\10\Redist\D3D\x64)复制D3DCompiler_47.dll到你的可执行文件(.exe)同级目录。2. 对于发布版本,应在安装包制作流程中包含此DLL。 |
调试时看到大量D3D11 WARNING输出 | 启用了D3D11调试层,这是好事!它帮你发现API使用错误。 | 仔细阅读输出窗口的警告信息。常见警告包括:资源绑定后未解除绑定、映射的资源未正确解锁、设置了无效的渲染状态等。根据警告信息修正代码。 |
| 画面全黑或渲染异常 | 着色器编译失败或输入布局不匹配。 | 1. 检查Visual Studio输出窗口,看是否有HLSL编译错误。 2. 使用 ID3DBlob获取着色器编译错误信息。3. 确保顶点着色器的输入结构体( struct VS_INPUT)与你在C++端创建的D3D11_INPUT_ELEMENT_DESC数组完全匹配(语义名、索引、格式、偏移量)。 |
5.2 图形调试器:你的最强力工具
Visual Studio自带的图形调试器(Graphics Debugger)是DirectX开发者的神器。它远强于古老的PIX。
- 如何启动:在调试时,点击菜单栏的“调试” -> “图形” -> “启动图形调试”。
- 核心功能:
- 帧分析:捕获一帧的所有DirectX API调用,你可以一步步回放,查看每次调用前后的渲染状态和资源内容。
- 管道状态:实时查看当前绑定的顶点/像素着色器、纹理、采样器、混合状态等。
- 事件列表:清晰列出每一帧的所有绘制调用(Draw Call),点击即可跳转到对应代码位置。
- 资源查看器:可以以多种格式(RGB、Alpha、深度)查看任何纹理、缓冲区的内容。
实操心得:遇到渲染问题时,第一反应不应该是盲目修改代码,而是捕获一帧用图形调试器分析。90%的渲染问题(如纹理没绑定、深度测试设置错误、常量缓冲区数据不对)都能在这里直观地找到原因。
5.3 性能优化初步考量
对于刚入门的项目,在正确性之后,就要开始关注性能。
- 减少Draw Call:这是最重要的优化之一。将使用相同着色器、纹理和渲染状态的物体合并批次(Batch)进行绘制。DirectXTK的
SpriteBatch和PrimitiveBatch内部就做了批次处理。 - 常量缓冲区管理:将每帧变化的(如世界矩阵)和变化频率低的(如投影矩阵)数据分到不同的常量缓冲区(
cbuffer)中,避免更新整个大缓冲区。使用D3D11_USAGE_DEFAULT和D3D11_CPU_ACCESS_WRITE配合Map/Unmap来更新动态缓冲区。 - 资源状态管理:理解资源屏障(Resource Barrier,在DX12中更显式,但DX11也有隐式状态)。例如,一个纹理被用作渲染目标后,如果想作为着色器资源读取,需要调用
ID3D11DeviceContext::ResolveSubresource(对于多重采样)或确保渲染操作完成。 - 对象生命周期管理:使用
ComPtr确保资源及时释放。在设备丢失(如用户切换分辨率、显卡驱动更新)时,需要重建所有DEFAULT类型的资源(纹理、缓冲区)。设计你的资源管理器时就要考虑这一点。
5.4 从DX11到更现代图形API的思考
虽然DirectX 11仍然是目前PC游戏开发最稳定、支持最广的API,但了解其局限性有助于你规划未来。DirectX 12和Vulkan提供了更底层的硬件控制,能榨取更多性能,但代价是复杂度飙升,需要手动管理内存、同步和管线状态。对于大多数中小型项目或入门学习,DirectX 11 with Windows SDK + DirectXTK的组合提供了绝佳的生产力与性能平衡。当你需要极致性能,并且团队有能力驾驭其复杂度时,再考虑迁移到DX12也不迟。
我个人在多个项目中坚持使用这套现代DX11工作流。它让我摆脱了旧SDK的依赖地狱,能更专注于游戏逻辑和渲染效果本身。尤其是配合DirectXTK,实现一个带2D精灵、文字、3D模型和基础光照的演示程序,速度比以前快了好几倍。记住,清晰的架构和正确的工具选择,往往比盲目追求最新的API更能带来项目成功。