▐ 业务背景
大淘宝技术为了优化淘宝App中的数字藏品的展示,为了凸显数字藏品的虚拟价值,带来营销增益buff,所以考虑建设对应的3D渲染能力,目前针对3D渲染侧有两部分诉求,一部分是如何渲染商家给到的 3D 模型,另一个部分是使用通用的相框模型将商家发行的虚拟藏品(一个的图片、视频)等进行动态的贴图展示,具体的相框模型如下:
最终需要能力定制出这样的效果:
当供应商提供模型落库完成,通过对应的 mid(模型的oss地址索引),业务可以接入 对应的渲染组件进行渲染,过程中可以调用 setGameObjectInfo 这个函数进行动态纹理的修改,具体渲染组件中的 API 接口设计如下
interface GameObjectInfo { /** * 图片纹理url,淘宝 CDN 资源地址 */ img?: string; /** * 视频纹理url,淘宝CDN资源地址 * * @remarks * 如果img 和 videoSrc同时存在优先videoSrc */ videoSrc?: string; /** * 设定 gameObject 颜色 */ color?: string; /** * 材质是否需要反光 */ isShine?: boolean; } interface setGameObjectInfo { /** * 针对模型或者模型中sku的某一个面进行贴图设置 */ (midOrSkuName: string, data: Record<string, GameObjectInfo>,): Promise<void>; }
▐ 技术挑战
基于已有的模型渲染能力,结合本次的技术方案,这几部分挑战可能在这个后续的开发链路中需要重点关注:
- 针对通用相框模型需要预先处理,一个是mesh 的拆分,另一个是mesh 的合并,调整对应 mesh面的 UV 映射,这部分使用什么软件进行处理?
- 如何将web 中标准的 gltf 相框模型供给到淘内App,淘内App 模型是需要通过unity 进行转化,这中间的转化链路应该是怎么样?同时这个转化过程中如何能够保证两个平台中效果是一致的?
- 渲染脚本应该如何修改,整体的实现思路应该是怎么样?在这个过程中如何保证模型的渲染效果?提高模型的渲染性能,提高C端的用户体验?
UV面投射
interface GameObjectInfo { /** * 贴图url,淘内地址 */ img?: string; /** * gameObject 颜色 */ color?: string; /** * 材质是否需要反光 */ isShine?: boolean; } interface setGameObjectInfo { /** * 针对模型或者模型中sku的某一个面进行贴图设置 */ (midOrSkuName: string, data: Record<string, GameObjectInfo>,): Promise<void>; }
▐ 通过mid找到对应的GameObject
const findResult: FindPrefabResult = this.findNode(mid); if (!findResult) return undefined; const skuGos: Node[] = []; forEachSkuGo(findResult.prefabObject, (node) => { skuGos.push(node); }); const nftNames = Object.keys(data); const texList: Promise<void>[] = []; skuGos.forEach(sku => { sku.forEachChild(mesh => { if (nftNames.includes(mesh.name)) { texList.push(this.udpateNodeMaterial(mesh, data[mesh.name])); } }); }); return await Promise.all(texList);
▐ 根据参数修改GameObject对应的参数
private async udpateNodeMaterial(imgGo: Node, option: {img?: string; color?: string; isShine?: boolean}) { const { img, color, isShine = true } = option; const imgRender = imgGo.getComponent(MeshRenderer); const material = isShine ? new LitMaterial() : new UnlitMaterial(); imgRender.materials.clear(); imgRender.materials.add(material); if (color) { material.color.set(color); } if (img) { material.offset.set(0, 1); material.scale.set(1, -1); const tex = await this._assetManager.loadAsync(Texture2D, '', img); tex.samplerFlags |= SamplerFlags.MinAnisotropic | SamplerFlags.MagAnisotropic; material.texAlbedo = tex; }}
▐ 模型转动畸变很大,感觉不是围绕中心点进行渲染
这是因为受到模型设定的Fov的影响,FOV越大,视角越大,转动畸变越大,为了解决这个问题,需要在建模是修改对应的项目的FOV值,默认FOV为60,可以将这个值调整为30,具体效果可以参考下面:
▐ unity中两种材质的对比,LitMaterial、UnlitMaterial区别
目前 acetiny-engine 引擎中,两种材质都支持,两个材质的区别是UnlitMaterial不会受到光照的影响,比较省资源,LitMaterial会受到光照的影响,针对业务的诉求,可以直接将以前使用的LitMaterial 变为 UnlitMaterial,即可满足业务的诉求。
▐ 各向异性过滤,提高从掠射角观察时的纹理质量
各向异性过滤(英語:Anisotropic filtering,简称AF)是用来过滤、处理当视角变化导致3D物体表面倾斜时造成的纹理错误。如其名称所示,它是对周围各个方向上的像素进行取样计算后映射到目标像素上的技术。与双线性过滤和三线性过滤相比,它在大角度显示方面具有更高的精度,令画面更逼真,但计算量也更大,对显示卡的要求也更高。在actiny中默认是关闭的,可以开启并设置材质的采样率,用于提高从掠射角观察时的纹理质量。
tinyWeb.getApp().init({ renderOptions: { anisotropy: true ... }, ...});
修改之后,对应的效果有了明显的提升,如图所示: