大型 3D 互动开发和优化实践 | 京东云技术团队

news2024/12/28 18:50:36

开发背景

得益于“元宇宙”概念在前段时间的爆火,各家公司都推出了使用 3D 场景的活动或频道。

3D 场景相比传统的 2D 页面优点是多一个维度,同屏展示的内容可以更多,能完整的展示物体、商品的信息。

相应带来的缺点是用户使用方式改变,用户需要额外的学习成本。另外初期需要的开发量、美术资源和生成3D模型的设备也是增加的成本。

在这样的背景下,我们团队接到了食品频道的一个互动项目的开发需求,希望通过 3D 场景的展示和互动方式,作为对未来购物的一种尝试与探索,满足用户对未来美好新奇的一个需求。将购物场景化、娱乐化,给用户带来美好的购物感受。

前端框架选择

3D项目相比之前的2D项目改变的主要是客户端的表现。在希望不依赖app客户端支持和在尽量多的环境下能运行,我们首先采用的方案是在 Web 端实现 3D 项目实现。

开发套件

首先我们考虑的是成熟的开发套件,如unity/egret等,但这些开发套件都有一些我们不能绕过的问题,例如:

  • 商业化使用需要收费

  • 需要使用其他语言开发(如 C# ),对团队学习成本较大

  • 打包输出的文件大小过大

  • 官方文档不够详细,学习曲线较抖

引擎名称/对比维度使用价格(权重50%脚本上手(权重30%场景搭建(权重20%支持模型格式(权重10%社区资料丰富程度(权重30%支持web端发布(一票否决
Unity 3d3710810Y
Laya49777Y
Egret108776Y
Cocos2d-jsN
Godot107787Y

由于以上的原因,开发套件里没有令团队很满意的选择,我们从其他方向寻找开发工具。

开源渲染库

另外也比较了 Web 前端使用量较多的两个 3D 渲染库:

◦three.js 提供的组件粒度较小,较基础,能做很高程度的定制化二次开发,但如果需要开发一个互动项目,需要开发的组件比较多

◦babylon.js 既提供了粒度小的基础组件,也封装了接近开箱即用的组件。并自带了性能测量工具,提供了方便的debug方法和优化策略

经过团队内对各个开发套件/渲染库的试用,最后选择了 babylon.js 作为项目的渲染层库,在其提供的组件上二次开发业务逻辑。

项目场景搭建

渲染分层结构

项目渲染层级总体分为两层:3D 场景层和 HUD 层

1.3D 场景层顾名思义渲染 3D 场景,由 人物模型、建筑模型和宝箱这些互动模型组成

2.HUD 层渲染互动按钮、弹窗、业务需要的商品列表等2D UI 内容

本来 babylonjs 是支持 3D 和 2D 内容混合渲染的,但是如果都使用 babylonjs 渲染,在设置两种内容需要使用统一的分辨率,而在现在的移动端设备上,能支持像素分辨率(如iPhone 14的像素分辨率为1170x2532)渲染不卡顿的只占一小部分。在大部分的设备上,最多只能支持在逻辑分辨率(如iPhone 14逻辑分辨率为390x844)下流畅运行,但设置这样的分辨率会使 2D 层渲染模糊,所以使用分层的方法渲染。

由 babylonjs 渲染 3D 场景层,而 HUD 层则通过 react 框架使用传统 DOM 方式渲染。

第二个 3D 渲染层

渲染层分为 3D 场景层和 HUD 层带来了一个问题,,需要在 HUD 层上再渲染 3D 内容时,例如展示 3D 模型,则不得不再增加一层 3D渲染层,而 3D 渲染层不停地在调用渲染方法,以响应用户操作和播放动画,这耗费了大量CPU和GPU的计算资源,还占用了存储模型顶点信息和贴图纹理的内存空间。因此在多个 3D 渲染层共存的情况下,需进行一定的管理以优化性能。我们采用以下策略管理多个 3D 渲染层:

◦在展示另外的 3D 渲染层时再实例化,并暂停原来 3D 渲染层的渲染

◦在不需要展示的时候销毁,恢复原 3D 渲染层的渲染方法调用

以尽量减少资源的占用,提高项目的渲染性能。

交互组件开发

碰撞检测

babylonjs 自带检测模型间是否碰撞的方法,但使用设计师提供的高精度模型直接去调用碰撞检测方法的话,计算量会很大,虽然未在测试设备上出现较严重的卡顿现象,但是已经使设备发热。

因此需要使用一个包围模型的不可见的、精简面的“空气墙”模型来做碰撞检测。在项目初期,这个“空气墙”模型需要设计师提供,在建模软件里根据原模型制作低精度包围模型。在后续迭代开发中,我们团队开发了“一键生成空气墙”的工具,自动生成低精度模型,减少设计师交付的资源数量,也减少更新模型时出错的机会。

镜头避障

因为项目用的是第三人称的镜头,镜头离开人物模型有一定的距离,在人物走动或用户控制角度的时候,镜头有可能和建筑模型或场景模型碰撞,造成“镜头穿模”的现象。

babylonjs 自带的镜头没有避开模型的功能,在产品也没有处理经验的时候,我们做了如下两个方案:

  1. 镜头外围用一个不可见模型包围,跟人物一样与建筑、场景模型做碰撞检测,使镜头不会进入到模型中去。

这种方法的优点是可以使用内置的碰撞检测方法,不需要额外的开发量。但是缺点也很明显,用户对镜头和模型的碰撞导致停止没有预期,总会觉得镜头不自然的不受控制。

  1. 镜头和人物之间用棒状的模型连接,同样在棒状模型上调用与建筑、场景模型的碰撞检测,当棒状模型的某个位置发生碰撞时,镜头将移动到人物与碰撞点之间的位置,避免镜头进入模型的同时,也避免模型穿插在人物与镜头中间,造成导致用户找不到人物的问题。

这种方法实现的效果符合一些同样是第三人称视角的 3D 游戏的镜头运动逻辑,用户感受更自然,不会出现失控的现象。而引入的额外开发量也在可控的范围内。

与设计团队的资源交接

模型格式

在众多的 3D 模型格式中,我们选择了 .gltf 格式。相对于其他模型格式,.gltf 可以减少 3D 格式中与渲染无关的的冗余数据,从而确保文件体积更小。

目前 3D 素材相对来说都比较大,这对于移动端加载体验来说,无疑是致命的。因此拥有更小体积的格式,也拥有了更高的优先选择权重。

除此之外,.gltf 是对近二十年来各种 3D 格式的总结,使用最优的数据结构,从而保证最大的兼容性以及可伸缩性,在拥有大容量的同时,支持更多的拓展,比如支持多贴图、多动画等。

所以 .gltf 成为了我们与视觉约定好的唯一素材格式。

模型输出流程

本来设计师工作流使用的建模软件是 C4D ,但是在资源交接的过程中,我们发现了几个问题:

1.缺少导出 gltf 文件功能。 在某些版本的 C4D 不能导出 gltf 格式的模型;某些版本能导出,但是导出有问题。而又因为设计师使用的一些渲染器支持问题,不能轻易更新 C4D 版本。

2.导出模型大小不统一。 可能因为某些版本的 C4D 导出的问题,或是 C4D 里的一些设置没能导出到 gltf 文件,设计师几次导出的模型大小并不统一,例如人物模型比建筑模型还要大上好几倍。

3.导出材质信息丢失。 设计师在建模时,因为模型可能会在多个渠道使用,例如渲染宣传图片,大部分情况会使用第三方的渲染器做渲染,这时候可能模型里会使用这些渲染器独有的材质。而这些材质导出到 gltf 文件时,会丢失这些独有材质的信息。再导入到页面的场景中时,设计师会发现展示的效果跟他们在建模软件里看到的相差甚远。

在和设计师多次沟通后,我们之间定立了一个导出模型的工作流:

在 C4D 建模完成后,导出 FBX 格式的文件,再导入到对 gltf 支持较好的 blender 软件中,设计师可以预览他们的材质在中转过程中有没有丢失效果,blender 导出的 gltf 文件中的模型也能保持一致的大小。

预设光影

在默认的渲染设置中,我们把设计侧输出的模型放进场景中,加上光源,也只有明暗的变化,没有影子,缺少了一些立体感。

在我们尝试加入影子的过程中,发现性能受到严重影响。在查阅了渲染原理后,发现当每在一个平面上增加影子,相当于多渲染一次场景,渲染的压力成倍增加。

跟设计侧交流后,决定在地板的贴图纹理上预先加上建筑的投影。这种方法对大部分是固定模型的场景能有较好的效果,而人物的阴影可以用静态图片跟随模型移动模拟。

渲染优化

压缩纹理

在开发期间发现在型号旧一点的iPhone设备上很容易出现闪退的现象,应该是页面使用的内存超过了上限。

在项目中使用的资源体积最大的是模型 gltf 文件,检查文件的内容,占体积很大一部分的是纹理贴图,解析资源发现很多贴图的大小是3K(3072x3072的图片),根据 WebGL 渲染原理,无论贴图的资源原来是什么格式,最后在渲染前需要解压,相当于一张贴图需要在内存中占 3072 x 3072 x 3Byte = 27MB,解压后还需要传到 GPU,在多张贴图同时渲染时很可能占用大量的内存。

经过和设计侧的沟通,同意在一些展示距离不可能很近的模型上替换较低分辨率的贴图。

另外通常 2D 项目中使用的 png/jpg 格式图片,并不适合 3D 渲染,他们需要经过上述的解压过程,才能被 GPU 读取。

在 3D 渲染领域,有其他适合 GPU 读取的格式,如安卓支持的 ETC ,iOS 支持的 PVRTC,新一代的标准压缩纹理格式 ASTC ,他们都不需要解压就可以被 GPU 读取,可以大大减少中间解压占用的内存容量。

在项目中,我们使用 gltf-transform 工具做缩小贴图分辨率,和转换格式的工作。

模型减面

模型在 WebGL 中渲染的流程是先用模型的顶点信息确定三角面,再在每个三角面上计算需要展示的颜色。所以如果能减少模型面的数量,能减少每次渲染的计算量,减少每帧需要的渲染时间。

而如上面所说的,设计师建模的时候,可能面对的需求是输出渲染图,而不会对实时渲染做优化,所以在某些地方可能使用了过多的面。

参考了团队内其他同学的优化经验1,使用 gltf-transform 工具对模型进行自动化减面。在和设计测反复沟通后,我们确定了减面的参数 ratio = 0, error = 0.0001

合批渲染

在 3D 渲染中有一个 draw call 的概念,一次 draw call 就是 CPU 向 GPU 下的一次画图指令。在一次指令中,CPU 会向 GPU 传递需要画的三角形信息,和三角形上颜色怎么计算的方法,这个方法用人类明白的语言称作材质。所以一次 draw call 只能画相同材质的面。

因为每次 draw call 有这些准备的动作,所以通常两次 draw call 会比一次花的时间多。

在模型文件中,相同材质的面,可能不是定义在同一个模型中,这样 CPU 会把这些面拆分成不同的画图指令,令 draw call 数量增加。

有一种对这种情况的优化方法叫合批,可以对这些相同材质的面合并,使他们可以在一次 draw call 中完成绘制。

这工作没有工具帮助我们处理模型文件,但是在前端加载模型文件时,可以遍历模型中的网格 mesh ,把使用相同材质的做合并。

需要注意的是带动画的网格不能这样处理,因为合并后的物体中心会变化,例如两个自转的球合并之后会围绕两个球的中点公转。

后续迭代

模型懒加载和分级加载

虽然暂时的项目展示的场景还不是很大,同时加载和渲染对设备的压力不算很大,但在场景增长到一定程度的时候,需要引入模型的懒加载和分级加载。

◦懒加载策略:在镜头移动到足够靠近时再加载并插入模型到场景,销毁离镜头足够远的模型。

◦分级加载策略:在镜头较远时,加载较低精度的模型,较近时再切换成精度高的模型。

以上两个策略都是现在较大型的 3D 游戏会使用的加载策略,能减少同一屏幕中绘制的面数量,减轻渲染压力。

分级渲染

现时访问 3D 项目的设备性能差距非常大,有加上特效也能流畅运行的,也有只能在设备分辨率下基本运行的。

babylonjs 自带一个分级渲染的功能,能实时检测运行帧率决定是否降级,在之后的迭代中,可以增加从像素分辨率加上特效到设备分辨率基本渲染的分级渲染策略。

实时光影

在使用以上的分级渲染策略后,可以在性能较好的设备上加上实时光影的特效,动态替换预烘焙贴图

场景搭建工具

在之前的项目开发过程中,设计师和产品、运营都需要通过前端输出demo才能大概体验到 3D 场景的效果,决定下一步如何调整。为解决这个痛点,我们团队开发了一个 3D 场景的搭建工具,用户可通过上传 gltf 文件搭建 3D 场景,实时预览渲染效果。

并加入了在项目中沉淀的互动组件,快速生成 3D 场景项目。

参考来源:

  1. 说一说 glTF 文件压缩 https://jelly.jd.com/article/61057292df18aa019e8a2967

作者:京东零售 胡俊文

来源:京东云开发者社区

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/611448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

yolov8模型训练结果分析以及如何评估yolov8模型训练的效果

1.运行结果目录 一、 confusion_matrix_normalized.png和confusion_matrix.png 混淆矩阵 混淆矩阵以矩阵形式将数据集中的记录按照真实的类别与分类模型预测的类别判断两个标准进行汇总。其中矩阵的行表示真实值,矩阵的列表示预测值。 TP(True Positiv…

python 创建Django项目基础

一. 安装Django pip install django 默认安装最新版本二. 创建一个Django项目 三、运行项目 创建好Django项目后,我们就可以运行了 使用命令 python manage.py runserver四、目录结构 五、创建一个文件views用来存放方法 在创建的文件中写入以下方法 def sa…

使用GCN根据颗粒图像预测对应性能

之前做一个小实验写的代码,本想创建个git repo,想了想好像没必要,直接用篇博文记录一下吧。 对应资源 : https://download.csdn.net/download/rayso9898/87865298 0. 大纲 0.1 代码说明 dataGeneration.py -> RSA生成n张图像&…

【Springboot】| 阿里云发送短信验证码,你会了吗?

目录 🦁 题外话🦁 需要准备的东西🦁 进入主题1. 添加依赖2. 配置yaml文件3. 创建阿里云客户端4. 编写发送短信方法5. 完整代码展示6. 测试 🦁 场景实操1. 编写生成验证码工具类2. 保存到redis操作3. 编写发送验证码短信4. 发送登录…

大数据:spark共享广播变量,累加器

大数据:共享变量 2022找工作是学历、能力和运气的超强结合体,遇到寒冬,大厂不招人,可能很多算法学生都得去找开发,测开 测开的话,你就得学数据库,sql,oracle,尤其sql要学…

三面阿里被挂,竟获内推名额,历经 5 面拿下口碑 offer...

每一个互联网人心中都有一个大厂梦,百度、阿里巴巴、腾讯是很多互联网人梦寐以求的地方,而我也不例外。但是,BAT 等一线互联网大厂并不是想进就能够进的,它对人才的技术能力和学历都是有一定要求的,所以除了学历以外&a…

STM32单片机WIFI物联网厨房燃气安全系统超声波人员检测MQ4燃气报警

实践制作DIY- GC0140-WIFI物联网厨房燃气安全系统 基于STM32单片机设计---WIFI物联网厨房燃气安全系统 二、功能介绍: 硬件组成:STM32F103C系列最小系统继电器模拟阀门MQ-4然气传感器HSR04超声波测距LCD1602显示器ESP8266-WIFI模块蜂鸣器多个按键 1.有…

MySQL命令行速查手册(持续更新ing...)

诸神缄默不语-个人CSDN博文目录 最近更新时间:2023.6.5 最早更新时间:2023.6.5 每个命令都以;作为结尾(以下localhost都可以替换成实际IP地址)(和’的区别应该不大)用户管理 修改密码:ALTER U…

如何使用Facebook Business Suite来管理你的FB和Ins商业账户

Facebook Business Suite是Facebook推出的一种强大的数字营销工具,可帮助企业轻松管理其在Facebook和Instagram上的商业账户。该工具集成了多种功能,提供了一种简单、直观的方式来管理你的社交媒体营销活动。 在本文中,我们将详细介绍如何优化…

深眸科技基于技术与人才优势,创新研发机器视觉系统赋能工业生产

随着人工智能技术加速进入生产生活,机器视觉系统作为工业发展的刚需,凭借着能够为机器提供视觉,并在众多场景实现柔性化生产应用的能力,逐步被接受和普及,并在工业生产领域发挥巨大作用。 深眸科技作为国家高新技术企…

物流货运车货匹配平台源码

网络货运平台具有较强的信息数据交互和处理能力,能够对托运人,平台运营人,实际承运人,驾驶员的相关方的交易,运输,结算等全过程进行透明,动态的管理,该平台由托运人、实际承运人、司…

ControlNet: Adding Conditional Control to Text-to-Image Diffusion Models

Adding Conditional Control to Text-to-Image Diffusion Models (Paper reading) Lvmin Zhang and Maneesh Agrawala, Stanford University, arXiv, Cited:113, Code, Paper 1. 前言 我们提出了一种名为ControlNet的神经网络结构,用于控制预训练的大规模扩散模型…

element中table的列标题自定义

一、需求 工作中要求表格table中的某一列标题为红色如图 二、方案一 使用el-table-column自带的:render-header"renderHeader"函数 render-header列标题 Label 区域渲染使用的 FunctionFunction(h, { column, $index })—— 使用有点像v-html插入代码片段&#xf…

PubChem介绍及API及PubChempy

PubChem 【官网 https://pubchem.ncbi.nlm.nih.gov/】 简介 PubChem is the world’s largest collection of freely accessible chemical information. Search chemicals by name, molecular formula, structure, and other identifiers. Find chemical and physical proper…

casbin基于RBAC的权限管理案例

在RBAC模型中新定义了角色和继承关系,用户可以通过角色区分不同的权限,继承不同的角色时用户有多个权限。 [role_definition] g _, _ g2 _, _g 是一个 RBAC系统, g2 是另一个 RBAC 系统。 _, _表示角色继承关系的前项和后项,即前项继承后项…

局部探索测试的要素

局部探索测试的要素 局部探索测试是软件测试过程中的一种方法,旨在发现一个系统、软件或应用程序的局部缺陷和问题。局部探索测试不是全面测试,而是通过对特定功能、模块或环节进行测试来检查其中潜在的缺陷,从而提高软件的质量和可靠性。 局…

【白话机器学习系列】白话Broadcasting

白话 Broadcasting 文章目录 什么是 BroadcastingBroadcasting 的规则逐元素操作向量与标量运算矩阵与向量运算行向量列向量 张量与向量运算张量与矩阵运算 矩阵与张量的点积总结 什么是 Broadcasting 在 《白话张量》 中我们讲过,张量之间进行运算需要满足一定的…

Hadoop之MapReduce概述

MapReduce概述 MapReduce定义MapReduce优缺点MapReduce核心思想MapReduce进程MapReduce编程规范MapTask并行度决定机制ReduceTask并行度决定机制mapreduce中job的提交流程MapReduce工作流程shuffle机制分区partition数据清洗(ETL)进一步分析MapTask和Red…

Jenkins+RF持续集成测试(二) 定时更新SVN完成构建

在上一篇中讲了Jenkins的安装,这篇将介绍 定时从SVN库中(git库与之类似,这里就不具体介绍了,有需要自己折腾)拉取最新的测试脚本,完成jenkins的定时构建。这是我们做自动化测试最基本的环节,每天…

【Linux】还在用top命令?可以试试atop工具,信息一目了然,运维工程师的新选择

atop使用 Linux以其稳定性,越来越多地被用作服务器的操作系统(当然,有人会较真地说一句:Linux只是操作系统内核:)。但使用了Linux作为底层的操作系统,是否我们就能保证我们的服务做到7*24地稳定呢?非也,要…