Unity小游戏 终极性能优化 海量粒子 飘字动画 子弹特效 性能翻倍 微信小游戏万人同屏

部署运行你感兴趣的模型镜像

万人同屏插件获取&体验Demo下载

万人同屏插件是一款通用的Unity性能优化插件,是实现千人同屏、万人同屏的必备插件,直击性能消耗痛点功能,将2D Spine和3D动画渲染性能十倍至百倍提升,Jobs多线程移动避让索敌算法,以及兼容全平台的高性能渲染器。新手友好简单易用无ECS技术门槛传统开发方式,同样适用于旧项目低成本性能优化。

万人同屏插件兼容Unity全平台,包括WebGL(2.0),微信/抖音小游戏等平台同样大幅性能翻倍

Unity万人同屏插件功能性能演示

Unity万人同屏集成方案Pro 支持微信小游戏https://efunstudio.cn/

性能/功能/红蓝对抗测试Demo Web在线体验https://assets.efunstudio.cn/

插件核心功能图

十万单位红蓝对抗 多兵种战斗 弹幕游戏项目模板

网页版在线测试性能

预览图

▷幸存者Demo

预览图

▷性能测试Demo

正文

Unity海量粒子 掉血飘字动画 子弹特效 性能优化 PC 手游 微信小游戏帧数翻倍 终极性能 FPS优化技巧 Shader实现教程


前言

        前面的博文中我们分享了如何实现一套通用的Unity项目性能优化插件,并在PC和移动平台使帧数提升数十倍。由于DOTS的Entities Graphics是通过BatchRendererGroup(简称BRG)接口封装实现,而WebGL暂不支持GraphicsBuffer、Compute Shader,因此BRG当前不兼容WebGL平台,也就导致了DOTS目前不支持Web平台,不能用于开发微信小游戏。本文将分享如何支持Web平台高性能合批渲染,以及如何对海量粒子特效、飘字动画、子弹弹幕等游戏特效性能优化。

WebGL高性能渲染

        如何解决DOTS不兼容Web平台的痛点呢?虽然Web平台不支持多线程和Burst,但Jobs代码仍然能以单个工作线程正常工作,Entities系统也能正常运作。也就意味着我们只需要解决Entities Graphics不支持Web平台的渲染问题即可。

        那我们就有两种解决方案,一是使用WebGL平台支持的图形接口替代,如Graphics.RenderMeshInstanced。二是参考团结引擎实现GPU Resident Drawer兼容Web平台的方法,针对小游戏不支持SSBO和Compute Shader的限制,使用Texture存储Renderer数据。这里我们免费分享方法一的实现,给大家介绍如何使用Graphics.RenderMeshInstanced接口自定义WebGLGraphicsSystem无感知接管Entities Graphics System,从而实现Web平台的GPU Instancing高性能合批渲染。

        在Unity万人同屏插件里我们已经使用Entities Graphics API高度封装了ECSGraphics渲染器,为了保持接口无感知兼容Web平台,只需定义一个WebGLGraphicsSystem的Job System代码,仅在WebGL时强制停用Entities Graphics System,启动我们自定义的WebGLGraphicsSystem。

#if UNITY_WEBGL// && !UNITY_EDITOR
        var graphicsSystem = ECSWorld.GetExistingSystemManaged<PresentationSystemGroup>();
        ECSWorld.GetExistingSystemManaged<SimulationSystemGroup>().RemoveSystemFromUpdateList(graphicsSystem);
        var entitiesGraphicsSystem = ECSWorld.GetExistingSystemManaged<EntitiesGraphicsSystem>();
        ECSWorld.GetExistingSystemManaged<SimulationSystemGroup>().RemoveSystemFromUpdateList(entitiesGraphicsSystem);
        var webglRenderSystem = ECSWorld.GetExistingSystemManaged<WebGLGraphicsSystem>();
        if (webglRenderSystem == null)
        {
            webglRenderSystem = ECSWorld.CreateSystemManaged<WebGLGraphicsSystem>();
            ECSWorld.GetExistingSystemManaged<SimulationSystemGroup>().AddSystemToUpdateList(webglRenderSystem);
        }
#endif

首先RenderMeshInstanced(RenderParams rparams, Mesh mesh, int submeshIndex, NativeArray<T> instanceData,  int instanceCount = -1, int startInstance = 0)我们可以了解到WebGL下合批渲染所需的数据,其中instanceData就是我们需要传递给GPU的渲染数据。

根据不同Mesh和Material拆分渲染批次,通过MaterialPropertyBlock为每个渲染物设置不同的材质参数值。

var matBlock = new MaterialPropertyBlock();
m_BatchesRenderParams.Add(batchKey, new RenderParams(ECSGraphicsComponent.Instance.GetMaterialFromInfo(batchKey.x))
{
    shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On,
    receiveShadows = false,
    lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off,
    matProps = matBlock
});

通过遍历Entities组织矩阵数据(RenderMeshInstanced接口所需渲染数据参数)

m_Query = this.GetEntityQuery(ComponentType.ReadOnly<LocalToWorld>(), ComponentType.ReadOnly<MaterialMeshInfo>());
m_BatchesMatrices = new NativeHashMap<int2, NativeList<Matrix4x4>>(16, Allocator.Persistent);

尽管WebGL平台不支持Jobs多线程,使用IJobsEntity遍历仍比直接Query遍历性能高。由于已知是单线程执行,因此这里也就不必考虑Native容器的并行风险。

    unsafe partial struct RenderDataJob : IJobEntity
    {
        [NativeDisableContainerSafetyRestriction][WriteOnly] public NativeHashMap<int2, NativeList<Matrix4x4>> BatchesMatrices;

#if ENABLE_COLOR
        [NativeDisableContainerSafetyRestriction][WriteOnly] public NativeHashMap<int2, NativeList<float4>> BatchesColors;
        [ReadOnly] public NativeHashMap<int2, float4> DefaultColors;
#endif

        void Execute([EntityIndexInChunk] int index, ECSNodeAspect node)
        {
            float4x4 matrix = node.Transform.ValueRO.Value;
            var meshInfo = node.MeshInfo.ValueRO;
            int2 batchKey = new int2(meshInfo.Material, meshInfo.Mesh);

            BatchesMatrices[batchKey].Add(matrix);
#if ENABLE_COLOR
            BatchesColors[batchKey].Add(node.Color.IsValid ? node.Color.ValueRO.Value : DefaultColors[batchKey]);
#endif
        }

当然,我们还必须支持视锥裁剪,以节省开销。

检测Entity包围盒是否在相机视口

Unity.Rendering.FrustumPlanes.IntersectResult Intersect(NativeArray<Plane> cullingPlanes, AABB a)
{
    float3 m = a.Center;
    float3 extent = a.Extents;

    var inCount = 0;
    int length = cullingPlanes.Length;
    for (int i = 0; i < length; i++)
    {
        float3 normal = cullingPlanes[i].normal;
        float dist = math.dot(normal, m) + cullingPlanes[i].distance;
        float radius = math.dot(extent, math.abs(normal));
        if (dist + radius <= 0)
            return Unity.Rendering.FrustumPlanes.IntersectResult.Out;

        if (dist > radius)
        {
            inCount++;
        }
    }

    return (inCount == length) ? Unity.Rendering.FrustumPlanes.IntersectResult.In : Unity.Rendering.FrustumPlanes.IntersectResult.Partial;
}

若在视口外侧跳过将此Entity的矩阵数据添加进渲染列表

Unity.Rendering.FrustumPlanes.IntersectResult intersectResult = Intersect(cullingPlanes, aabb);
if (intersectResult == Unity.Rendering.FrustumPlanes.IntersectResult.Out) return;

海量飘字动画特效优化

使用Shader实现,通过二阶贝塞尔曲线得到飘字的运动轨迹,对顶点偏移Vertex Offset来实现动画效果。

t * (1f - t) * pA + Mathf.Pow(t, 2) * pB;

Shader中绘制动态数字参考之前分享的教程。百万血条图文HUD优化:https://www.bilibili.com/video/BV1oqjPzhEs7/

海量子弹优化

通过对顶点偏移确定子弹移动距离,通过UV偏移对子弹贴图采样绘制得到子弹移动效果,为避免不同视角下子弹面片穿帮,还需要实现绕Z轴旋转的Billboard。

海量粒子特效优化

两种简单的方式,一是shader 帧动画+Billboard,足以应对2D粒子。二是使用Animation记录关键帧替代ParticleSystem,然后直接使用GPU动画插件转换为GPU动画。

以下是ASE中帧动画实现方法:

您可能感兴趣的与本文相关的镜像

Wan2.2-I2V-A14B

Wan2.2-I2V-A14B

图生视频
Wan2.2

Wan2.2是由通义万相开源高效文本到视频生成模型,是有​50亿参数的轻量级视频生成模型,专为快速内容创作优化。支持480P视频生成,具备优秀的时序连贯性和运动推理能力

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eFunTech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值