当供应商提供模型落库完成,通过对应的 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>;
}
首先需要将给到的相框模型使用 Blender 进行处理,将模型拆分成三个物体,一个是对应的logo,一个是相框,另一个是相框需要贴图的面。
首先将需要被贴图的面融合成一个完整的面
然后将需要被贴图的面拆分成一个单独的面
UV面投射
针对mesh进行重命名,并检查模型是否拆分完成
添加平面网格,并添加「缩裹」修改器,使平面网格贴近命名的 back 面
按照供应商模型制作标准进行场景初始化操作,这里创建 NFT文件夹&场景并导入对应的asset。
供应商模型制作标准地址:https://www.yuque.com/mmdkz9/kzu1iw/znxr3h#8P29y
首先将模型导入:
导入之后记得导入对应的材质,然后将模型挂到相机下面进行预览。
因为原图很高清,所以图片可以替换成低清晰度的占位图,或者直接去掉(这里为了标注先进行展示,后续通过渲染组件中的动态API进行替换)。
这部分的操作可以直接参考: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>;
}
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);
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;
}
}
实现之后,有两个问题比较突出,这里进行统一记录
目前 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 重新关联进行配置,具体需要确定自己的业务使用场景确定。
首先安装blender插件
按「N」唤出对应面板,设置素材存放地址
选中对象,创建集合,基于集合进行烘焙
选择对应的属性贴图进行导出
查看已经导出的贴图
unity中导入贴图关联材质进行使用
过程中首先通过 blender 处理 gltf 相框模型,针对模型进行预处理,之后通过 belender 导出fbx 格式的模型,然后将 fbx 格式的模型导入到unity中进行材质的设定,最终导出为淘宝App渲染引擎支持的模型文件。将模型交付给业务进行使用,支持业务根据诉求动态设定模型上每个 mesh 的素材。这个过程中发现了几个核心问题,比如模型的转动畸变、unity 两种模型材质的对比,两种材质针对C端渲染的影响,以及影响夹角渲染效果的各向异性过滤概念,同时也详细讲了下 belender 中如何导出模型到 unity 中,并且在这个过程中保证效果是一致的。希望通过这篇文章,可以给初次接触 blender 和 unity 的同学有一定的启发和参考。