news 2026/10/8 8:32:14

Unity DOTS实战:Entities Graphics实现万人同屏渲染优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Unity DOTS实战:Entities Graphics实现万人同屏渲染优化

1. 万人同屏到底难在哪:先搞清楚瓶颈再谈方案

很多人第一次听到“万人同屏”这四个字,第一反应是“显卡扛不住”。我刚开始做这类需求的时候也这么想,结果实测下来发现,真正先崩的往往不是 GPU,而是 CPU 的主线程。Unity 传统的 GameObject + MonoBehaviour 架构,每个对象身上挂一个脚本,Unity 每帧要遍历这些对象、调用 Update、做 Transform 层级同步、再一个个提交渲染。几百个还行,几千个就开始掉帧,上万基本就是幻灯片。

这里面的开销拆开看,主要分三块。第一块是CPU 端的逻辑更新,也就是你写的游戏逻辑,寻路、状态机、碰撞检测这些。第二块是Transform 与渲染数据的同步,Unity 要把每个物体的位置、旋转、缩放从托管层传到引擎层,再组织成 DrawCall。第三块才是GPU 端的实际绘制。传统架构下,前两块的开销随对象数量线性甚至超线性增长,第三块反而因为合批做得好的话增长没那么夸张。

所以万人同屏的核心矛盾,不是“怎么画一万个东西”,而是“怎么让 CPU 别被一万个对象的逻辑和同步拖死”。这就是 DOTS 这套东西存在的意义。DOTS 是 Data-Oriented Technology Stack 的缩写,中文一般叫面向数据的技术栈,它包含几个关键部分:ECS(实体组件系统)、Burst 编译器、Job System,以及我们这篇文章的主角 Entities Graphics。

Entities Graphics 是专门为 ECS 世界设计的渲染方案,它替代了传统的 Renderer 组件,直接和 ECS 的 chunk 内存布局配合,把渲染数据的准备过程也 Job 化、Burst 化了。简单说,传统方案是“一个物体一个物体地处理”,Entities Graphics 是“一批一批地处理”,这个差别在万级数量下就是天壤之别。

这篇文章我打算按实际项目的推进顺序来讲:先讲整体架构怎么设计,再拆核心细节,然后是完整的实操落地流程,最后把我踩过的坑和排查经验整理出来。适合已经会 Unity 基础操作、想往高性能方向进阶的开发者,也适合正在做数字孪生、大场景仿真、SLG 团战这类需求的朋友。哪怕你之前没碰过 ECS,跟着走一遍也能跑起来。

2. 整体方案设计与技术选型思路

2.1 为什么是 ECS 而不是优化传统 GameObject

有人会问,我不用 ECS,就用传统方式,靠 GPU Instancing 加对象池能不能做到万人?能,但很勉强,而且天花板很低。GPU Instancing 解决的是 DrawCall 问题,它让一万个相同 Mesh 的物体用一次 DrawCall 画出来,这个确实有效。但它没解决 CPU 端的逻辑更新和 Transform 同步问题。你还是要维护一万个 GameObject,还是要每帧更新它们的位置。

我做过对比测试,同样是一万个移动单位,传统 GameObject + GPU Instancing 的方案,在主流台式机上大概能跑到 30 到 40 帧,CPU 主线程占用率接近满载。换成 ECS + Entities Graphics 之后,同样的机器能稳定 60 帧以上,主线程占用降到 30% 左右,多出来的算力还能跑更复杂的逻辑。这个差距的来源就是数据布局。

传统面向对象的内存布局是散的,一个单位的数据分散在堆内存各处,CPU 缓存命中率低。ECS 把同类实体的数据按组件连续存放在 chunk 里,比如一万个单位的 Position 组件就是一段连续内存,遍历的时候缓存友好,加上 Burst 编译成 SIMD 指令,一次能处理一批数据。这就是为什么 ECS 在数量级上碾压传统方案。

2.2 Entities Graphics 在渲染管线中的位置

Entities Graphics 不是独立渲染管线,它是挂在 SRP(可编程渲染管线,也就是 URP 或 HDRP)之上的。它做的事情是:从 ECS 世界里读取带有渲染相关组件的实体,把这些数据整理成 GPU 能直接用的格式,然后通过 BatchRendererGroup 提交绘制。BatchRendererGroup 是 Unity 底层的一个 API,允许你绕过传统的 Renderer 体系,自己管理大批量的绘制。

这里有个关键点要理解:Entities Graphics 的渲染数据准备也是跑在 Job 里的。也就是说,当你的逻辑 Job 在算位置的时候,渲染数据的组织也在并行进行,两者通过 ECS 的依赖系统自动排序,不需要你手动同步。这个自动化是 DOTS 很舒服的地方,你只要声明好读写依赖,剩下的调度交给系统。

选型上,如果你做的是 URP 项目,Entities Graphics 支持得比较成熟,配置也简单。HDRP 功能更全但配置复杂,对硬件要求也高。我建议先用 URP 跑通,确认方案可行再考虑要不要上 HDRP。至于内置管线,Entities Graphics 基本不支持,别在这上面浪费时间。

2.3 数量级目标与硬件预算的匹配

“万人同屏”这个目标本身要拆细。是一万个静态物体,还是一万个各自跑逻辑的动态单位?是每个单位都是独立 Mesh,还是共用几个 Mesh?这些差别巨大。

我的经验是,先明确三个指标:同屏实体总数、每帧需要更新逻辑的实体比例、每个实体的渲染复杂度。如果一万个里只有一千个在动,那压力小很多。如果一万个全在跑寻路和状态机,那逻辑侧要下大功夫。渲染侧,如果每个单位都是几千面的高模,那 GPU 也会成为瓶颈,这时候要考虑 LOD 和 Impostor。

一般建议的硬件基线:中端独显(比如 GTX 1660 级别以上)、四核以上 CPU、16G 内存。这个配置下,一万个中等复杂度单位、共用少量 Mesh、逻辑相对简单的情况下,稳定 60 帧是现实的。如果要上两万甚至更多,就得在 LOD、剔除、逻辑降频上做文章了。

3. 核心细节拆解与实操要点

3.1 ECS 世界的搭建与实体创建

第一步是把 ECS 世界跑起来。Unity 现在推荐用 Entities 包配合 SubScene 来管理,但万人同屏这种动态生成的场景,我一般不用 SubScene,而是用代码在运行时批量创建实体。原因是 SubScene 更适合静态摆放的场景物件,动态单位用代码创建更灵活,也方便做对象池。

创建实体的核心是 EntityManager 或者 EntityCommandBuffer。这里有个性能陷阱:如果你在循环里一个个调 EntityManager.CreateEntity,一万次调用本身就有开销。更好的做法是用 EntityCommandBuffer 或者 Archetype 批量创建。Archetype 是 ECS 里描述“一个实体有哪些组件”的模板,相同 Archetype 的实体会被放在同一个 chunk 里,创建时可以一次性分配。

// 定义单位的基础组件 public struct UnitTag : IComponentData { } public struct MoveSpeed : IComponentData { public float Value; } public struct TargetPosition : IComponentData { public float3 Value; } // 批量创建 var archetype = entityManager.CreateArchetype( typeof(UnitTag), typeof(LocalTransform), typeof(MoveSpeed), typeof(TargetPosition), typeof(URPMaterialMeshRenderer) // Entities Graphics 的渲染组件 ); var entities = new NativeArray<Entity>(10000, Allocator.Temp); entityManager.CreateEntity(archetype, entities);

注意LocalTransform是 Entities 包里的新 Transform 类型,替代了老的 Translation/Rotation/Scale 三个独立组件。用新版本的话直接用 LocalTransform 就行,性能更好,API 也更统一。

3.2 渲染组件的配置与材质绑定

Entities Graphics 的渲染组件有好几种,最常用的是URPMaterialMeshRenderer(URP 下)或MaterialMeshInfo配合RenderMesh。新版本推荐用URPMaterialMeshRenderer,它把材质和 Mesh 的引用打包在一起,配置起来更直观。

材质这块有个坑:Entities Graphics 不支持所有 Shader。它需要 Shader 兼容 DOTS 的渲染路径,官方提供了一批转换好的 Shader,比如Universal Render Pipeline/Lit的 DOTS 版本。如果你用自定义 Shader,需要手动处理,否则会出现材质变紫或者不显示的问题。我建议初期直接用官方支持的 Shader,跑通之后再考虑自定义。

Mesh 的复用也很关键。一万个单位如果每个都用不同的 Mesh,那合批就废了。实际项目里通常是几种单位类型,每种共用一个 Mesh 和材质,这样 Entities Graphics 能把这些实体合批到少数几个 DrawCall 里。我实测过,一万个单位用三种 Mesh,DrawCall 能压到个位数。

3.3 Burst 与 Job System 的配合方式

Burst 是这套方案性能的核心来源之一。它把 C# 的 Job 代码编译成高度优化的机器码,自动做 SIMD 向量化。但 Burst 有严格限制:不能用托管对象、不能用引用类型、不能抛异常、不能调用大部分 Unity API。写 Burst 兼容的代码需要转变思维,一切用值类型和 NativeContainer。

Job System 负责把这些 Burst 编译的 Job 调度到多核上并行执行。ECS 的 SystemBase 或 ISystem 本质上就是帮你组织 Job 的框架。用 ISystem 配合 Burst 是性能最好的组合,因为 ISystem 是结构体,没有托管开销。

[BurstCompile] public partial struct MoveSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { float dt = SystemAPI.Time.DeltaTime; foreach (var (transform, speed, target) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<MoveSpeed>, RefRO<TargetPosition>>()) { float3 dir = target.ValueRO.Value - transform.ValueRO.Position; float dist = math.length(dir); if (dist > 0.01f) { float3 move = math.normalize(dir) * speed.ValueRO.Value * dt; transform.ValueRW.Position += move; } } } }

这段代码看起来像普通 C#,但经过 Burst 编译后,math库的运算会变成 SIMD 指令,一次处理多个单位。这就是为什么 ECS 能在一帧内处理上万个单位的移动逻辑。

3.4 数据布局对缓存命中率的影响

这一点很多人忽略,但它直接决定性能上限。ECS 的 chunk 是按 Archetype 组织的,同一个 chunk 里所有实体的组件数据连续存放。当你遍历查询时,CPU 是按顺序读内存的,缓存命中率高。但如果你在组件里塞了大的结构体,或者组件种类太多导致 chunk 利用率低,性能就会下降。

我的建议是:组件尽量小,只放必要的数据。比如移动逻辑只需要 Position、Speed、Target,就不要把血量、攻击力这些塞进同一个组件。把数据按使用频率和访问模式拆分,让热数据集中,冷数据分离。这样遍历热数据时不会把冷数据也拉进缓存。

另外,IComponentData的大小最好控制在 16 到 64 字节之间。太小浪费 chunk 空间,太大降低缓存效率。如果确实需要存大量数据,考虑用DynamicBuffer或者共享组件ISharedComponentData。

4. 完整实操流程与关键环节实现

4.1 环境准备与包安装

先把项目环境搭好。Unity 版本建议用 2022 LTS 或更新的版本,Entities 包在 1.0 之后 API 稳定了很多。通过 Package Manager 安装这几个包:Entities、Entities Graphics、Burst、Collections、Mathematics。这几个是核心依赖,缺一不可。

安装完之后,在 Project Settings 里确认一下 Scripting Backend 是 IL2CPP,因为 Burst 在 IL2CPP 下效果最好。另外把 Api Compatibility Level 设成 .NET Standard 2.1 或更高,避免一些 API 找不到。

URP 的话,记得在 URP Asset 里确认渲染路径配置正确。Entities Graphics 需要 URP 的某些特性支持,如果用的是很老的 URP 版本可能会报错。我一般直接用当前 Unity 版本推荐的 URP 版本,不折腾。

4.2 定义组件与创建实体原型

组件定义要遵循“小而专”的原则。下面是我在一个万人同屏 Demo 里用的组件集合:

// 标记组件,用于筛选 public struct UnitTag : IComponentData { } // 移动相关 public struct MoveSpeed : IComponentData { public float Value; } public struct TargetPosition : IComponentData { public float3 Value; } // 渲染相关,用 Entities Graphics 的组件 // 实际使用时通过 Authoring 或代码配置

创建实体的时候,我习惯先建一个 Archetype,然后批量创建。一万个实体用CreateEntity(archetype, nativeArray)一次性搞定,比循环单建快很多。创建完之后,用 Job 或者直接在主线程给每个实体赋初始值。如果初始值计算复杂,用 Job 并行赋值。

这里有个细节:LocalTransform的初始值要设对,否则实体可能都在原点重叠。我一般用随机分布或者网格分布初始化位置,方便观察。

4.3 移动逻辑的 Job 化实现

移动逻辑是最基础也最能体现性能差异的部分。上面给的 MoveSystem 例子是简化版,实际项目里还要考虑边界、避让、到达判定等。但核心思路一样:用SystemAPI.Query遍历,用math库做运算,全部 Burst 化。

如果要加避让,简单的做法是每个单位检测周围一定半径内的其他单位,做排斥力计算。这个用空间划分(比如网格哈希)加速,否则一万个单位两两检测就是 O(n²),直接爆炸。空间划分可以用 NativeHashMap 实现,把空间分成格子,每个格子记录里面的实体。

// 简化的网格哈希思路 var grid = new NativeParallelMultiHashMap<int, Entity>(capacity, Allocator.TempJob); // 把每个实体按位置算出的格子 key 插入 // 查询时只查邻近格子

这个部分比较复杂,建议先跑通基础移动,确认帧率达标后再加避让。不要一上来就堆功能,容易出问题还不好定位。

4.4 渲染数据的组织与提交

渲染这块,Entities Graphics 会自动处理。你只要保证实体上有正确的渲染组件,它就会在渲染阶段把这些实体画出来。但有几个配置点要注意。

第一是材质的 Shader 必须是 DOTS 兼容的。URP 下用Universal Render Pipeline/Lit的 DOTS 版本,在材质面板上能看到一个标记。如果不是 DOTS 版本,材质会显示异常。

第二是 Mesh 的 LOD 配置。Entities Graphics 支持 LOD,但需要你手动配置 LOD Group 的 ECS 版本。对于万人同屏,LOD 很重要,远处的小单位用低模甚至 Impostor,能省大量 GPU 开销。

第三是剔除。Entities Graphics 支持视锥剔除和遮挡剔除,但默认配置可能不够激进。可以在渲染设置里调整剔除参数,把屏幕外的实体尽早剔除掉。

4.5 性能验证与帧率测试

跑起来之后,第一件事是看 Profiler。重点看几个指标:主线程耗时、渲染线程耗时、Job 耗时、DrawCall 数量、Batches 数量。如果主线程耗时高,说明逻辑或同步有问题;如果渲染线程高,说明 GPU 侧压力大;如果 DrawCall 多,说明合批没做好。

我一般会做一个压力测试:逐步增加实体数量,从一千到一万到两万,记录每个数量级下的帧率和各线程耗时。这样能清楚看到瓶颈在哪里,也能预估目标硬件的上限。

实测数据参考:一万个移动单位,URP,中端独显,主线程约 4 到 6 毫秒,渲染线程约 8 到 12 毫秒,DrawCall 在 10 以内,稳定 60 帧。这个数据会因硬件和场景复杂度浮动,但量级上可以作为参考。

5. 常见问题与排查技巧实录

5.1 实体不显示或材质变紫

这是新手最常遇到的问题。原因通常有三个:Shader 不兼容、渲染组件没配好、或者实体没有进入渲染查询。

排查顺序:先确认材质用的 Shader 是不是 DOTS 版本,在材质面板上看有没有 DOTS 标记。然后确认实体上有没有URPMaterialMeshRenderer或等价的渲染组件。最后确认实体的LocalTransform是否有效,位置是不是在相机视野外。

材质变紫是典型的 Shader 不兼容表现,和传统 Unity 里 Shader 编译失败一个道理。换成官方 DOTS Shader 基本能解决。

5.2 帧率上不去但 GPU 占用不高

这种情况说明瓶颈在 CPU 侧。用 Profiler 看主线程,如果主线程耗时远高于渲染线程,那就是逻辑或同步的问题。

常见原因:查询写得太宽泛,遍历了不需要的实体;组件太大导致缓存效率低;有同步点阻塞了 Job 并行;或者不小心在 Job 里用了托管对象导致 Burst 失效。Burst 失效是个隐蔽的坑,代码能跑但性能差很多,一定要在 Burst Inspector 里确认 Job 真的被编译了。

5.3 Burst 编译报错的典型原因

Burst 报错信息有时候不太直观。常见的几类:用了class而不是struct;用了string或数组等托管类型;调用了不支持的 API;在 Job 里访问了静态可变字段。

解决办法是逐个排除。先把可疑代码注释掉,确认能编译后再逐步加回来。Burst 的错误一般会指出具体行号,顺着看基本能找到。实在找不到就用[BurstDiscard]标记可疑方法,让它走托管路径,先跑通再优化。

5.4 实体数量增加后性能断崖式下跌

如果从五千加到一万时性能突然崩了,通常是某个资源到上限了。可能是 chunk 数量超过了某个阈值,可能是 DrawCall 突然增多,也可能是内存分配触发了 GC。

排查方法是看 Profiler 里的内存和 GC 曲线。如果看到 GC Alloc 飙升,说明有地方在每帧分配托管内存。ECS 代码里要特别注意不要在 Job 里分配 NativeContainer 而不释放,也不要在 System 的 OnUpdate 里 new 托管对象。

5.5 常见问题速查表

现象可能原因排查方向
实体不显示Shader 不兼容 / 渲染组件缺失检查材质 DOTS 标记和渲染组件
材质变紫Shader 编译失败换官方 DOTS Shader
帧率低但 GPU 闲CPU 逻辑或同步瓶颈Profiler 看主线程和 Job
Burst 报错用了托管类型或非法 API检查 struct 和 API 兼容性
数量增加后崩溃资源上限或 GC看内存和 GC 曲线
DrawCall 多合批失败检查 Mesh 和材质复用

5.6 我踩过的几个坑

第一个坑是在 Job 里用了Debug.Log。这玩意是托管调用,Burst 直接报错,而且报错信息不明确,找了半天才发现。调试 ECS 代码尽量用UnityEngine.Debug.DrawLine或者把数据写进 NativeArray 再在主线程打印。

第二个坑是忘了 Dispose NativeContainer。Job 里创建的 NativeArray、NativeHashMap 这些,用完必须 Dispose,否则会内存泄漏,而且 Unity 会报一堆警告。我一般用Allocator.TempJob配合[DeallocateOnJobCompletion]自动释放,省心。

第三个坑是LocalTransform 和老的 Translation 混用。新版本 Entities 用 LocalTransform,老教程里还是 Translation,混着用会编译不过或者行为异常。看教程的时候注意版本,1.0 之后的 API 变化挺大的。

第四个坑是SubScene 和运行时创建的实体混用。SubScene 里的实体是烘焙出来的,运行时创建的实体是代码生成的,两者的 Archetype 可能不一致,导致查询漏掉一部分。我一般统一用代码创建,避免这种混乱。

6. 进阶优化与扩展方向

6.1 LOD 与 Impostor 的实战配置

一万个单位如果都用高模,GPU 迟早扛不住。LOD 是必须的。Entities Graphics 支持 LOD,配置方式和传统 LOD Group 类似,但要在 ECS 层面设置。我一般分三级:近距离用高模,中距离用中模,远距离用 Impostor(也就是用一张贴图代替模型)。

Impostor 的实现可以用 Unity 的 Impostor 工具,或者自己烘焙。烘焙的思路是从多个角度拍模型的照片,运行时根据相机角度选对应的贴图。这个技术在大场景里很常见,能省大量三角形。

6.2 空间划分加速邻近查询

避让、碰撞、视野检测这些都需要查邻近单位。一万个单位两两查是 O(n²),必须用空间划分降到接近 O(n)。常用的是均匀网格哈希,把空间切成固定大小的格子,每个格子记录里面的实体。查询时只查目标格子及周围格子。

实现上用NativeParallelMultiHashMap<int, Entity>,key 是格子坐标算出的哈希值。插入和查询都在 Job 里做,Burst 化。格子大小要根据单位密度调,太大会导致单个格子实体太多,太小会导致查询格子数太多。一般让平均每个格子有 4 到 8 个实体比较合适。

6.3 逻辑降频与分帧更新

不是所有逻辑都需要每帧跑。比如寻路可以每 5 帧算一次,状态机可以每 3 帧更新一次。把逻辑按重要性分级,高频的每帧跑,低频的分帧跑,能省大量 CPU。

ECS 里实现分帧可以用SystemAPI.Time.ElapsedTime配合取模,或者用帧计数器。注意分帧要均匀,别让某一帧突然跑太多逻辑,否则会出现帧率抖动。

6.4 多线程渲染与 GPU Driven 的展望

Entities Graphics 已经在往 GPU Driven 方向走了。GPU Driven 的意思是让 GPU 自己决定画什么、怎么画,CPU 只负责提交数据。这样能进一步降低 CPU 开销,支持更大规模。

目前 Unity 的 GPU Driven 还在演进中,但 BatchRendererGroup 已经提供了基础。如果你的项目对规模要求极高,可以关注这块的进展。不过现阶段,把 ECS + Entities Graphics 用好,已经能满足绝大多数万人同屏的需求了。

7. 一些个人体会

这套方案我从早期版本一路用到现在,最大的感受是:DOTS 的学习曲线陡,但一旦跨过去,性能提升是数量级的。刚开始写 ECS 代码会觉得别扭,什么都不能用,什么都要自己管。但写习惯了之后,反而觉得这种显式的数据管理更清晰,性能也可控。

另一个体会是,不要过早优化。先把功能跑通,用 Profiler 找到真正的瓶颈,再针对性优化。我见过太多人一上来就堆各种高级技巧,结果代码复杂到没法维护,性能还没提升多少。ECS 本身已经很快了,大部分情况下你只要按规范写,性能就够用。

最后说个实际的:万人同屏这个需求,很多时候客户或策划说的“一万”是个虚数,实际同屏可能就几千。先确认清楚真实需求,别为了一个虚数把方案做得过度复杂。如果确实要一万,那这套方案是靠谱的;如果只是几千,传统方案优化一下也能凑合,不一定非要上 DOTS。技术选型要看投入产出比,适合自己的才是最好的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 8:32:00

Win7 缺失 api-ms-win-core-sysinfo-l1-2-0.dll 的根因与修复指南

简介&#xff1a;这份资源面向在Windows 7 32位或64位系统上遭遇api-ms-win-core-sysinfo-l1-2-0.dll丢失或损坏报错的用户&#xff0c;提供与系统架构匹配的dll文件替换方案&#xff0c;帮助解决程序无法启动、系统信息查询API调用失败等常见故障。压缩包共4个文件&#xff0c…

作者头像 李华
网站建设 2026/10/8 8:31:59

GitHub Desktop for Mac 从安装配置到工作流实战与避坑指南

简介&#xff1a;GitHub Desktop for Mac的安装资源包&#xff0c;面向需要在Mac平台完成Git版本管理与GitHub协作开发的开发者&#xff0c;尤其适合希望用图形界面替代命令行操作的用户。资源包共1556个文件&#xff0c;以891个PNG界面图标、58个TIFF图像、55个nib界面布局文件…

作者头像 李华
网站建设 2026/10/8 8:29:34

WinForm TextBox 关键字智能提示:从卡顿到流畅的落地实践

简介&#xff1a;这份资源面向 WinForm 桌面开发初学者与需要快速实现输入联想功能的开发者&#xff0c;针对原生 TextBox 只能从头匹配、ComboBox 自动补全不够灵活的问题&#xff0c;给出一种比重写 ListBox 更轻量的关键字智能提示实现思路&#xff0c;支持任意位置匹配与多…

作者头像 李华
网站建设 2026/10/8 8:29:34

WPF贝塞尔曲线绘制折线图:从Polyline到高性能平滑曲线实战

简介&#xff1a;这份资源面向具备一定C#基础的WPF开发者与图形学初学者&#xff0c;聚焦于用贝塞尔曲线实现动态折线图这一具体问题。内容围绕Path与PathGeometry的绘制机制展开&#xff0c;涵盖BezierSegment控制点计算、数据绑定驱动量程变化、Path.Data实时更新与Invalidat…

作者头像 李华
网站建设 2026/10/8 8:29:05

WPF D3D demo:NV12 YUV帧硬件加速送入D3DImage

简介&#xff1a;面向WPF桌面开发者的一手D3D视频渲染示例&#xff0c;演示在WPF框架中借助Direct3D硬件加速呈现YUV视频流&#xff0c;弥补WPF原生控件对YUV格式支持不足、软件渲染开销高的短板&#xff0c;适合做高性能播放器或实时视频展示的.NET开发者参考。压缩包共43个文…

作者头像 李华
网站建设 2026/10/8 8:27:57

ECS与函数计算用角色替换长期密钥

跑在 ECS 或函数计算上的程序不要再带长期 AccessKey。角色按信任方拆开,策略可以共用;先绑上并读到临时凭证,再删环境变量里的旧密钥。 目录 前言 一、角色和策略各管什么 二、ECS:一台实例一个角色 三、函数计算:先记下旧 role 四、代码走默认凭证链

作者头像 李华