VulkanSceneGraph学习教程(十)

发布时间:2026/8/13 10:01:09

VulkanSceneGraph学习教程(十)
第 10 章 描述符与资源绑定摘要本章系统讲解了 Vulkan 场景图VSG中描述符Descriptor与资源绑定的核心机制。内容涵盖从概念Descriptor → DescriptorSet → BindDescriptorSet到实践DescriptorSetLayout 定义、DescriptorBuffer 传递 uniform 数据、DescriptorImage 传递纹理的完整流程并提供了带 MVP uniform 和纹理的完整 StateGroup 示例。最后总结了常见问题排查要点为后续相机、模型加载等章节奠定数据传入基础。本章定位着色器需要从外部读取数据——MVP 矩阵、纹理、灯光参数……这些通过描述符Descriptor传入。本章讲清DescriptorSetLayout/DescriptorSet/ 各类Descriptor/BindDescriptorSet的协作。10.1 本章目标理解描述符集布局DescriptorSetLayout与描述符集DescriptorSet的关系会用DescriptorBuffer传 uniform 数据、DescriptorImage传纹理用BindDescriptorSet把描述符挂到StateGroup掌握「每帧更新 uniform」的标准写法。10.2 前置准备第 8 章状态命令与第 9 章管线 /PipelineLayout已读第 4 章了解过 SPIR-V 与 GLSL。10.3 概念Descriptor→DescriptorSet→BindDescriptorSetVulkan 的数据传入分三层Descriptor基类单个资源条目携带dstBinding/dstArrayElement/descriptorType。子类有DescriptorBufferuniform/storage 缓冲、DescriptorImage纹理采样器等。DescriptorSet一组Descriptor绑定到某个DescriptorSetLayout。BindDescriptorSet状态命令在录制时执行vkCmdBindDescriptorSets把DescriptorSet绑到管线的某个firstSet槽。10.4 布局DescriptorSetLayout描述「这个集合有哪些绑定、各自类型/阶段」auto dsl vsg::DescriptorSetLayout::create(); dsl-addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT); // binding 0: MVP 矩阵 dsl-addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); // binding 1: 纹理addBinding(binding, descriptorType, descriptorCount, stageFlags, flags0)对应一个VkDescriptorSetLayoutBinding。10.5 Uniform 数据DescriptorBuffer把 CPU 端数据MVP 矩阵等作为 uniform 缓冲传入// 用 vsg 的 Value 类型承载矩阵自动管理缓冲 auto mvp vsg::mat4Value::create(); mvp-value vsg::mat4(1.0); auto ubo vsg::DescriptorBuffer::create(mvp, 0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); // 参数(data, dstBinding0, dstArrayElement0, descriptorType)每帧更新CPU → GPU// 在帧循环里 mvp-value cameraViewProj * modelMatrix; // 更新矩阵 ubo-copyDataListToBuffers(); // 把 CPU 数据拷进 GPU 缓冲DescriptorBuffer还支持DataList/BufferInfoList构造可一次传多个缓冲或共享BufferInfo。10.6 纹理DescriptorImage传入「采样器 图像」// 加载图像vsgXchange见第 13 章此处假设已得到 ref_ptrData image auto image vsg::readvsg::Data(textures/brick.png); // 返回 Data实为 vsg::Image auto sampler vsg::Sampler::create(); // 默认采样器 auto tex vsg::DescriptorImage::create(sampler, image, 1, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); // 参数(sampler, image, dstBinding1, dstArrayElement0, descriptorType)也可用createCombinedImageSamplerDescriptor(sampler, image, dstBinding)便捷函数第 4 章DescriptorImage.h中声明。10.7 描述符集与绑定DescriptorSet/BindDescriptorSet把若干Descriptor装进DescriptorSet再用BindDescriptorSet挂到场景图// 方式一先建 DescriptorSet再绑定 auto descriptorSet vsg::DescriptorSet::create(dsl, vsg::Descriptors{ubo, tex}); auto bindDS vsg::BindDescriptorSet::create( VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, descriptorSet); // 方式二便捷直接给 descriptors自动用 pipelineLayout-setLayouts[firstSet] 建 DescriptorSet auto bindDS2 vsg::BindDescriptorSet::create( VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, vsg::Descriptors{ubo, tex}); stateGroup-add(bindDS);BindDescriptorSet的firstSet必须和着色器里layout(bindingx) sety的set以及PipelineLayout::setLayouts的下标对应。10.8 完整示例带 MVP uniform 纹理的 StateGroup下面是一个完整的、可直接运行的示例展示如何创建包含 MVP uniform 缓冲和纹理的StateGroup。这个示例整合了前面章节的所有概念。1. 着色器代码GLSL首先创建顶点和片段着色器// vertex.vert #version 450 #extension GL_ARB_separate_shader_objects : enable layout(binding 0, set 0) uniform UniformBufferObject { mat4 mvp; } ubo; layout(location 0) in vec3 inPosition; layout(location 1) in vec2 inTexCoord; layout(location 0) out vec2 fragTexCoord; void main() { gl_Position ubo.mvp * vec4(inPosition, 1.0); fragTexCoord inTexCoord; }// fragment.frag #version 450 #extension GL_ARB_separate_shader_objects : enable layout(binding 1, set 0) uniform sampler2D texSampler; layout(location 0) in vec2 fragTexCoord; layout(location 0) out vec4 outColor; void main() { outColor texture(texSampler, fragTexCoord); }2. C 完整代码#include vsg/all.h #include iostream int main(int argc, char** argv) { // 1. 创建窗口和视图器 auto windowTraits vsg::WindowTraits::create(); windowTraits-width 800; windowTraits-height 600; windowTraits-windowTitle VSG Descriptor Example; auto window vsg::Window::create(windowTraits); if (!window) { std::cerr lt;lt; Failed to create window. lt;lt; std::endl; return 1; } auto viewer vsg::Viewer::create(); viewer-gt;addWindow(window); // 2. 创建描述符集布局 auto dsl vsg::DescriptorSetLayout::create(); dsl-gt;addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT); dsl-gt;addBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); // 3. 创建 uniform 缓冲 auto mvp vsg::mat4Value::create(); mvp-gt;value vsg::mat4(1.0); // 初始化为单位矩阵 auto ubo vsg::DescriptorBuffer::create(mvp, 0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); // 4. 加载纹理 auto image vsg::read(textures/brick.png); if (!image) { std::cerr lt;lt; Failed to load texture. lt;lt; std::endl; return 1; } auto sampler vsg::Sampler::create(); auto tex vsg::DescriptorImage::create(sampler, image, 1, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); // 5. 创建着色器模块 auto vertexShader vsg::read_castlt;vsg::ShaderStagegt;(shaders/vertex.vert); auto fragmentShader vsg::read_castlt;vsg::ShaderStagegt;(shaders/fragment.frag); if (!vertexShader || !fragmentShader) { std::cerr lt;lt; Failed to load shaders. lt;lt; std::endl; return 1; } // 6. 创建管线布局和图形管线 auto pipelineLayout vsg::PipelineLayout::create( vsg::DescriptorSetLayouts{dsl}, vsg::PushConstantRanges{} ); auto graphicsPipeline vsg::GraphicsPipeline::create( pipelineLayout, vsg::ShaderStages{vertexShader, fragmentShader}, vsg::InputAssemblyState::create(), vsg::RasterizationState::create(), vsg::MultisampleState::create(), vsg::ColorBlendState::create(), vsg::DepthStencilState::create() ); // 7. 创建几何体一个简单的四边形 auto vertices vsg::vec3Array::create({ {-0.5f, -0.5f, 0.0f}, { 0.5f, -0.5f, 0.0f}, { 0.5f, 0.5f, 0.0f}, {-0.5f, 0.5f, 0.0f} }); auto texcoords vsg::vec2Array::create({ {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} }); auto indices vsg::ushortArray::create({ 0, 1, 2, 2, 3, 0 }); auto geometry vsg::Geometry::create(); geometry-gt;arrays vsg::DataList{vertices, texcoords}; geometry-gt;indices indices; geometry-gt;commands.push_back(vsg::DrawIndexed::create(6, 1, 0, 0, 0)); // 8. 创建 StateGroup 并添加状态命令 auto stateGroup vsg::StateGroup::create(); // 绑定图形管线 stateGroup-gt;add(vsg::BindGraphicsPipeline::create(graphicsPipeline)); // 绑定描述符集使用便捷方式 auto bindDS vsg::BindDescriptorSet::create( VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, // firstSet vsg::Descriptors{ubo, tex} ); stateGroup-gt;add(bindDS); // 添加几何体 stateGroup-gt;addChild(geometry); // 9. 创建场景图 auto scene vsg::Group::create(); scene-gt;addChild(stateGroup); // 10. 设置相机 auto lookAt vsg::lookAt(vsg::dvec3(2.0, 2.0, 2.0), vsg::dvec3(0.0, 0.0, 0.0), vsg::dvec3(0.0, 0.0, 1.0)); auto perspective vsg::perspective(vsg::radians(45.0), static_castlt;doublegt;(windowTraits-gt;width) / windowTraits-gt;height, 0.1, 10.0); auto camera vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(window-gt;extent2D())); auto commandGraph vsg::createCommandGraphForView(window, camera, scene); viewer-gt;assignRecordAndSubmitTaskAndPresentation({commandGraph}); // 11. 编译资源 viewer-gt;compile(); // 12. 主循环 while (viewer-gt;advanceToNextFrame()) { // 更新 MVP 矩阵 auto time std::chrono::durationlt;floatgt;(viewer-gt;getFrameStamp()-gt;time - viewer-gt;start_point()).count(); float angle time * 0.5f; auto modelMatrix vsg::rotate(angle, vsg::vec3(0.0f, 0.0f, 1.0f)); auto viewMatrix vsg::lookAt(vsg::vec3(2.0f, 2.0f, 2.0f), vsg::vec3(0.0f, 0.0f, 0.0f), vsg::vec3(0.0f, 0.0f, 1.0f)); auto projMatrix vsg::perspective(vsg::radians(45.0f), 800.0f / 600.0f, 0.1f, 10.0f); mvp-amp;gt;value projMatrix * viewMatrix * modelMatrix; // 将数据复制到 GPU 缓冲 ubo-amp;gt;copyDataListToBuffers(); viewer-amp;gt;handleEvents(); viewer-amp;gt;update(); viewer-amp;gt;recordAndSubmit(); viewer-amp;gt;present(); } return 0; }3. 关键点说明着色器绑定对齐GLSL 中的layout(binding 0, set 0)对应 C 中的addBinding(0, ...)和DescriptorBuffer::create(mvp, 0)。描述符集创建示例使用了便捷方式通过BindDescriptorSet::create()直接传入Descriptors{ubo, tex}VSG 会自动创建DescriptorSet。每帧更新在帧循环中更新mvp-value后必须调用ubo-copyDataListToBuffers()将数据复制到 GPU。资源管理VSG 的ref_ptr自动管理内存不需要手动释放。错误处理实际项目中应添加更完善的错误检查特别是文件加载和资源创建。4. 项目结构建议project/ ├── CMakeLists.txt ├── main.cpp ├── shaders/ │ ├── vertex.vert │ └── fragment.frag └── textures/ └── brick.png这个完整示例展示了从着色器编写、资源加载、管线创建到场景渲染的完整流程可以直接编译运行。10.9 常见问题现象原因解决着色器读到全 0 / 错值dstBinding与 GLSLlayout(bindingx)不符逐一对齐 binding 编号uniform 更新无效没调用copyDataListToBuffers()每帧改完value后调用它纹理为黑/紫图像未正确加载或采样器为 null检查vsg::read返回值、Sampler::create()非空描述符集不匹配firstSet与PipelineLayout::setLayouts下标不一致让BindDescriptorSet的firstSet对应 set 下标Vulkan 验证层报错VUID-VkDescriptorSetLayoutBinding-descriptorType-00339Uniform Buffer 类型C 端声明为VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER但 GLSL 中对应 binding 的变量类型不是uniform buffer1. 检查DescriptorSetLayout::addBinding()的descriptorType参数2. 确保 GLSL 中对应 binding 的声明为layout(binding0) uniform MyUBO { ... };形式3. 示例VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER必须对应 GLSL 的layout(binding0) uniform MyUBO { mat4 mvp; };Vulkan 验证层报错VUID-VkDescriptorSetLayoutBinding-descriptorType-00339Combined Image Sampler 类型C 端声明为VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER但 GLSL 中对应 binding 的变量类型不是sampler2D/samplerCube等采样器类型1. 检查DescriptorSetLayout::addBinding()的descriptorType参数2. 确保 GLSL 中对应 binding 的声明为layout(binding1) uniform sampler2D tex;形式3. 示例VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER必须对应 GLSL 的layout(binding1) uniform sampler2D tex;实战调试技巧除了上表的排查思路还可以借助以下工具和方法快速定位描述符绑定问题利用 Vulkan 验证层信息定位描述符绑定错误开启 Vulkan 验证层VK_LAYER_KHRONOS_validation运行程序时观察控制台输出。验证层会精确报告描述符绑定不匹配、类型错误、绑定缺失等问题。例如若看到VUID-VkDescriptorSetLayoutBinding-descriptorType-00339错误直接对照 C 的addBinding()与 GLSL 的layout(binding...)声明确保类型Uniform Buffer、Combined Image Sampler 等完全一致。使用 RenderDoc 等 GPU 调试工具验证 uniform 数据是否正确传入着色器在 RenderDoc 中捕获一帧查看「Pipeline State」→「Descriptor Sets」选项卡可以直观检查每个 binding 槽的资源是否正确绑定、缓冲地址和大小是否合理。点击「Mesh Viewer」或「Texture Viewer」还能验证 uniform 缓冲内的矩阵、向量值以及纹理的像素内容确保 CPU 端数据已正确复制到 GPU。编写简单的验证着色器快速排查问题临时将片段着色器改为直接输出 uniform 值或纹理坐标可以快速判断数据是否传入。例如// 验证 uniform 矩阵是否传入 layout(binding 0, set 0) uniform UniformBufferObject { mat4 mvp; } ubo; layout(location 0) out vec4 outColor; void main() { // 将矩阵的某个分量映射到颜色 outColor vec4(ubo.mvp[0][0], ubo.mvp[1][1], ubo.mvp[2][2], 1.0); }如果屏幕出现非黑色说明 uniform 数据已传入若为纯黑则需检查 binding 编号、描述符类型或copyDataListToBuffers()调用。10.10 小结数据传入三层单个Descriptor→DescriptorSet按DescriptorSetLayout→BindDescriptorSet状态命令DescriptorBuffer传 uniform/storageDescriptorImage传纹理每帧更新 uniform 用value ...; descriptor-copyDataListToBuffers()BindDescriptorSet的firstSet须与PipelineLayout::setLayouts下标、GLSLset一致。10.11 延伸阅读与下一章预告第 11 章《相机与视图》MVP 里的「VP」来自Camera第 13 章《加载 3D 模型》vsgXchange读 glTF纹理由加载器自动生成DescriptorImage第 20 章《后处理》多描述符集 多渲染通道的组合。

相关新闻

3分钟极速配置:让MusicBee拥有网易云音乐海量歌词库的终极指南

3分钟极速配置:让MusicBee拥有网易云音乐海量歌词库的终极指南

2026/8/13 9:51:09

3分钟极速配置:让MusicBee拥有网易云音乐海量歌词库的终极指南 【免费下载链接】MusicBee-NeteaseLyrics A plugin to retrieve lyrics from Netease Cloud Music for MusicBee. 项目地址: https://gitcode.com/gh_mirrors/mu/MusicBee-NeteaseLyrics 还在为…

C# Vp机器视觉

C# Vp机器视觉

2026/8/13 9:51:09

vp显示屏幕 new CogRecordDisplay() 的常用属性以下是创建一个 CogRecordDisplay 实例后,你可以直接使用的核心属性(假设你已添加了 Cognex.VisionPro.Display 的引用):属性类型说明ImageICogImage / CogImage要显示的图像。可赋值…

Ubuntu安装全攻略:从版本选择到系统优化,新手避坑指南

Ubuntu安装全攻略:从版本选择到系统优化,新手避坑指南

2026/8/13 9:51:09

1. 从零到一:为什么选择Ubuntu,以及安装前的关键决策 如果你正准备踏入Linux世界,或者厌倦了Windows/macOS的某些限制,Ubuntu大概率是你的第一站。它就像一个开箱即用的“精装房”,社区庞大、文档齐全、软件生态成熟&a…

大模型推理显存优化:KV Cache原理、计算与vLLM部署实践

大模型推理显存优化:KV Cache原理、计算与vLLM部署实践

2026/8/13 11:11:12

1. 从一次显存“爆仓”说起:KV Cache的显存账单那天下午,我正在本地调试一个基于Qwen-7B的长文档摘要任务。文档大约有8000个token,我信心满满地启动了推理服务,心想7B模型对一张24G显存的消费级显卡来说应该绰绰有余。然而&#…

一招重置Windows更新组件:Reset Windows Update Tool让我摆脱0x80070002报错的纠缠

一招重置Windows更新组件:Reset Windows Update Tool让我摆脱0x80070002报错的纠缠

2026/8/13 11:11:12

一招重置Windows更新组件:Reset Windows Update Tool让我摆脱0x80070002报错的纠缠 【免费下载链接】Reset-Windows-Update-Tool Troubleshooting Tool with Windows Updates (Developed in Dev-C). 项目地址: https://gitcode.com/gh_mirrors/re/Reset-Windows-U…

阿里云Elasticsearch日志采集与加工服务:一体化托管方案解析与实践

阿里云Elasticsearch日志采集与加工服务:一体化托管方案解析与实践

2026/8/13 11:11:12

1. 项目概述:从“组件堆叠”到“服务内聚”的日志管理新范式在云原生和微服务架构成为主流的今天,日志管理是每个技术团队都无法绕开的“必修课”。回想一下我们构建一个标准日志链路的典型过程:首先,我们需要在每台服务器或容器里…

Vue3低代码平台物料模式配置:从Schema设计到AI智能生成

Vue3低代码平台物料模式配置:从Schema设计到AI智能生成

2026/8/13 11:11:12

1. 从“搭积木”到“造积木”:物料模式配置的本质 在低代码或者AI驱动的开发平台里,我们总说“像搭积木一样构建应用”。这话听起来很美,但如果你真去用过一些平台,可能会发现一个尴尬的现实:平台提供的“积木”要么太…

碧蓝幻想Relink伤害统计利器GBFR Logs快速上手:免费开源DPS工具5步通关

碧蓝幻想Relink伤害统计利器GBFR Logs快速上手:免费开源DPS工具5步通关

2026/8/13 11:11:12

碧蓝幻想Relink伤害统计利器GBFR Logs快速上手:免费开源DPS工具5步通关 【免费下载链接】gbfr-logs GBFR Logs lets you track damage statistics with a nice overlay DPS meter for Granblue Fantasy: Relink. 项目地址: https://gitcode.com/gh_mirrors/gb/gbf…

Python爬虫实战:基于Playwright的企业数据采集与反爬策略

Python爬虫实战:基于Playwright的企业数据采集与反爬策略

2026/8/13 11:01:12

1. 项目概述与核心价值 最近在做一个市场分析的项目,需要批量获取一批目标公司的工商信息、股东背景和经营状况。手动去天眼查、企查查这类网站一个个搜,效率低不说,还容易出错。于是,用Python写一个爬虫来自动化这个数据采集过程…

比较好的亚太EMBA,问了6位校友师资差别真的挺大

比较好的亚太EMBA,问了6位校友师资差别真的挺大

2026/8/13 11:01:28

比较好的亚太EMBA核心差异先看什么?对于希望兼顾工作与系统管理能力提升的亚太区高管而言,筛选匹配度高的EMBA项目时,师资配置是决定学习体验与实际收获的核心要素之一。我们结合3-4个公开信息透明、办学历史较长的亚太区主流EMBA项目特点&am…

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

2026/8/11 8:44:43

备考海外游学的亚洲EMBA面试,核心要围绕项目国际化设计逻辑、个人跨文化管理经验匹配度两个维度准备,避免把游学模块等同于普通旅游参访的认知偏差。不少备考者花3个月对比6份资料,却容易忽略面试官对“国际视野落地能力”的考察——比如香港…

比较好的国内EMBA,问了二十位校友聊透人脉价值

比较好的国内EMBA,问了二十位校友聊透人脉价值

2026/8/11 15:57:54

比较好的国内EMBA核心差异体现在哪些方面?比较好的国内EMBA的核心长期价值,很大程度上依托于校友网络的连接质量与资源生态的活跃度,这也是不少高管在择校时优先考量的因素。我们结合3-4个市场关注度较高的项目公开信息,从课程、师…

电商毛利率别再手动算了!2026年3种自动分析工具实测对比

电商毛利率别再手动算了!2026年3种自动分析工具实测对比

2026/8/13 0:00:21

一、开篇:毛利率——电商运营最该盯但最难盯的指标 电商运营中有一个指标,几乎所有老板都会问,但几乎所有运营都回答得不够确定——毛利率。不是"店铺毛利率",而是"每条链接的毛利率""每个品类的毛利率…

15-SaaS系统灰度发布:滚动更新、金丝雀发布、不停机迭代

15-SaaS系统灰度发布:滚动更新、金丝雀发布、不停机迭代

2026/8/13 0:00:21

15-SaaS系统灰度发布:滚动更新、金丝雀发布、不停机迭代 一、为什么需要不停机发布? 传统发布方式:停服务 → 替换包 → 启服务。在内部系统里勉强能用,但在SaaS系统中是灾难。 我们的无人售货柜SaaS平台服务全国几千台设备&#…

17-线上Bug热修复流程:紧急分支、补丁合并、版本快速回退方案

17-线上Bug热修复流程:紧急分支、补丁合并、版本快速回退方案

2026/8/13 0:00:21

17-线上Bug热修复流程:紧急分支、补丁合并、版本快速回退方案 前言 大家好,我是黒漂技术佬。 线上出 Bug 这种事,就像你正吃着火锅唱着歌,突然接到电话说"柜子门打不开了"。炸不炸?慌不慌?别急&a…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/8 5:07:31

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/9 13:42:46

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/8 2:30:15

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…