cover_image

3D技术在数字藏品中的应用

李根(云墨) 大淘宝技术
2022年11月09日 08:20

图片




本文通过图文的方式详细介绍了在淘宝App中如何使用3D相关技术,优化淘宝App中的数字藏品的展示。从背景介绍、方案设计、模型预处理,模型处理、脚本操作等过过程出发来介绍,同时重点分析了其中的一些核心技术问题的解法。希望通过这篇文章,能够给初次接触 blender 和 unity 的前端开发同学有一定的启发和参考。


图片
背景&挑战

  业务背景


大淘宝技术为了优化淘宝App中的数字藏品的展示,为了凸显数字藏品的虚拟价值,带来营销增益buff,所以考虑建设对应的3D渲染能力,目前针对3D渲染侧有两部分诉求,一部分是如何渲染商家给到的 3D 模型,另一个部分是使用通用的相框模型将商家发行的虚拟藏品(一个的图片、视频)等进行动态的贴图展示,具体的相框模型如下:

图片


最终需要能力定制出这样的效果:

图片

▐  方案设计


针对目前上述的诉求,需要的核心的特性为:模型中各个GameObject中的材质和纹理的动态修改,整个链路设计的接入流程如下:

图片


当供应商提供模型落库完成,通过对应的 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>;}


▐  技术挑战


基于已有的模型渲染能力,结合本次的技术方案,这几部分挑战可能在这个后续的开发链路中需要重点关注:
  1. 针对通用相框模型需要预先处理,一个是mesh 的拆分,另一个是mesh 的合并,调整对应 mesh面的 UV 映射,这部分使用什么软件进行处理?
  2. 如何将web 中标准的 gltf 相框模型供给到淘内App,淘内App 模型是需要通过unity 进行转化,这中间的转化链路应该是怎么样?同时这个转化过程中如何能够保证两个平台中效果是一致的?
  3. 渲染脚本应该如何修改,整体的实现思路应该是怎么样?在这个过程中如何保证模型的渲染效果?提高模型的渲染性能,提高C端的用户体验?

图片
模型预处理


首先需要将给到的相框模型使用 Blender 进行处理,将模型拆分成三个物体,一个是对应的logo,一个是相框,另一个是相框需要贴图的面。


  导入模型


图片


  模型UV面拆分


首先将需要被贴图的面融合成一个完整的面


图片


然后将需要被贴图的面拆分成一个单独的面


图片


UV面投射


图片


针对mesh进行重命名,并检查模型是否拆分完成


图片


  创建 logo 图层


添加平面网格,并添加「缩裹」修改器,使平面网格贴近命名的 back 面


图片


贴图进行预览(不是必须的,可以在这里贴图看下渲染效果,过程中需要调整下 uv 映射)

图片

  导出处理完成的模型


图片


图片
模型处理


  导入FBX模型


按照供应商模型制作标准进行场景初始化操作,这里创建 NFT文件夹&场景并导入对应的asset。


图片

供应商模型制作标准地址:https://www.yuque.com/mmdkz9/kzu1iw/znxr3h#8P29y

  导入对应的FBX模型


首先将模型导入:


图片


导入之后记得导入对应的材质,然后将模型挂到相机下面进行预览。


图片


  材质的修改


因为unity中需要特定的材质,可以首先在unity中将模型的材质调整为大淘宝技术标准的材质。

图片


因为原图很高清,所以图片可以替换成低清晰度的占位图,或者直接去掉(这里为了标注先进行展示,后续通过渲染组件中的动态API进行替换)。


图片

针对logo 部分,可以直接使用固定的贴图,注意在unity中开启下下面渲染(透明通道)。

图片

  zip上传到平台,获取modelCode


这部分的操作可以直接参考:https://www.yuque.com/mmdkz9/kzu1iw/znxr3h#8P29y


图片

脚本操作


整体的思路比较清晰,找到对应 nam 的 GameObject,然后修改 GameObject 材质等基本数据,设计的 API 如下:


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; }}


图片
核心问题


实现之后,有两个问题比较突出,这里进行统一记录

  1. 模型转动畸变很大,感觉不是围绕中心点进行渲染。
  2. 贴图之后,受到光照的影响,部分角度图片颜色会有些许变化。
  3. 贴图之后,夹角处观察图片的质量会很差,可以参考下面这张图片示例。

图片

  模型转动畸变很大,感觉不是围绕中心点进行渲染 


这是因为受到模型设定的Fov的影响,FOV越大,视角越大,转动畸变越大,为了解决这个问题,需要在建模是修改对应的项目的FOV值,默认FOV为60,可以将这个值调整为30,具体效果可以参考下面:

图片

同一旋转角度下左边为FOV=60 的效果,右边为FOV=30 的效果:

图片

  unity中两种材质的对比,LitMaterial、UnlitMaterial区别


目前 acetiny-engine 引擎中,两种材质都支持,两个材质的区别是UnlitMaterial不会受到光照的影响,比较省资源,LitMaterial会受到光照的影响,针对业务的诉求,可以直接将以前使用的LitMaterial 变为 UnlitMaterial,即可满足业务的诉求。


  各向异性过滤,提高从掠射角观察时的纹理质量


各向异性过滤(英語:Anisotropic filtering,简称AF)是用来过滤、处理当视角变化导致3D物体表面倾斜时造成的纹理错误。如其名称所示,它是对周围各个方向上的像素进行取样计算后映射到目标像素上的技术。与双线性过滤和三线性过滤相比,它在大角度显示方面具有更高的精度,令画面更逼真,但计算量也更大,对显示卡的要求也更高。在actiny中默认是关闭的,可以开启并设置材质的采样率,用于提高从掠射角观察时的纹理质量。


tinyWeb.getApp().init({  renderOptions: {    anisotropy: true    ...  },  ...});


修改之后,对应的效果有了明显的提升,如图所示:

图片


图片
常见问题


  blender 导出 fbx丢失 纹理


如果纹理丢失,应该是对应的资源没有导出,在导出面板,需要将路径模式修改为「复制」并且将选中「内嵌纹理」,这样的话导出的模型就会有对应的图像纹理。

图片

  blender 导出 fbx 丢失材质


如果深度使用blender 的材质相关配置,比如应用变化,材质融合、颜色反转等等,如果直接导出会发现对应的设置都失效,针对这个问题,通常需要在 blender 中将材质进行烘焙,然后保存到具体的 material中,然后在 unity 重新关联进行配置,具体需要确定自己的业务使用场景确定。


  1. 首先安装blender插件

    图片

  2. 按「N」唤出对应面板,设置素材存放地址

    图片

  3. 选中对象,创建集合,基于集合进行烘焙

    图片

  4. 选择对应的属性贴图进行导出

    图片

  5. 查看已经导出的贴图

    图片

  6. unity中导入贴图关联材质进行使用


图片
总结


过程中首先通过 blender 处理 gltf 相框模型,针对模型进行预处理,之后通过 belender 导出fbx 格式的模型,然后将 fbx 格式的模型导入到unity中进行材质的设定,最终导出为淘宝App渲染引擎支持的模型文件。将模型交付给业务进行使用,支持业务根据诉求动态设定模型上每个 mesh 的素材。这个过程中发现了几个核心问题,比如模型的转动畸变、unity 两种模型材质的对比,两种材质针对C端渲染的影响,以及影响夹角渲染效果的各向异性过滤概念,同时也详细讲了下 belender 中如何导出模型到 unity 中,并且在这个过程中保证效果是一致的。希望通过这篇文章,可以给初次接触 blender 和 unity 的同学有一定的启发和参考。


图片
团队介绍

我们是大淘宝技术技术行业与商家技术前端团队,主要服务的业务包括电商运营工作台,商家千牛平台,服务市场以及淘系的垂直行业。团队致力于通过技术创新建设阿里运营、商家商业操作系统,打通新品的全周期运营,促进行业垂直化运营能力的升级。


¤ 拓展阅读 ¤

3DXR技术 | 终端技术 | 音视频技术

服务端技术 | 技术质量 | 数据算法


继续滑动看下一个
大淘宝技术
向上滑动看下一个