• [Unity] GPU动画实现(三)——材质合并


    实现合批的必要条件是只有一个material,因此将多texture对象合并成一张texture是必要的。无论是SkinnedMeshRenderer或是MeshRenderer,其合并材质的原理都是一样的。

    其调用到的核心API是Texture2D.PackTextures 

    1. // 合并贴图(从收集的各Material中取)
    2. List MainTexs = new List();
    3. for (int i = 0; i < materials.Count; i++)
    4. {
    5. MainTexs.Add(materials[i].GetTexture("_MainTex") as Texture2D);
    6. }
    7. //所有贴图合并到newDiffuseTex这张大贴图上
    8. newMainTex = new Texture2D(COMBINE_TEXTURE_MAX, COMBINE_TEXTURE_MAX, TextureFormat.RGBA32, true);
    9. Rect[] uvs = newMainTex.PackTextures(MainTexs.ToArray(), 0);
    10. newMaterial.SetTexture("_MainTex", newMainTex);
    11. AssetDatabase.CreateAsset(newMainTex, $"Assets/Resources/CombineTexture.asset");

    这里先获取到每个material里用到的材质(手动合并可以自己声明一个texture2d数组,之后在editor模式下拖拽),之后直接声明一张1024*1024的texture,我用到的子tex为512*512,因此1024*1024对我已经足够,可视实际情况进行调整。

    调用Texture2D.PackTextures接口生成合并贴图,返回合并后的uv,这里的uv对应的是子texture在合并后的大texture的uv,而不是传统意义上片元的uv。

    之后将新的材质直接赋值到新的material,也可以调用AssetDatabase.CreateAsset接口,将合并后的材质保存下来。

    PS:这里有个问题是执行:newMaterial.SetTexture("_MainTex", newMainTex)后,理论上新的材质应该是合并后的材质,但实际上材质仍然是合并前的子材质,而调用AssetDatabase.CreateAsset创建出来的材质是正常的,在editor模式下拖拽赋值后,才表现正常。目前作者暂不清楚原因,如果有人知道原因务必在评论区告知我,非常感谢。

    1. // reset uv
    2. // 计算好uvb赋值到到combineInstances[j].mesh.uv
    3. oldUV = new List();
    4. Vector2[] uva, uvb;
    5. for (int j = 0; j < combineInstances.Count; j++)
    6. {
    7. //uva = (Vector2[])(combineInstances[j].mesh.uv);
    8. uva = combineInstances[j].mesh.uv;
    9. uvb = new Vector2[uva.Length];
    10. for (int k = 0; k < uva.Length; k++)
    11. {
    12. uvb[k] = new Vector2((uva[k].x * uvs[j].width) + uvs[j].x, (uva[k].y * uvs[j].height) + uvs[j].y);
    13. }
    14. //oldUV.Add(combineInstances[j].mesh.uv);
    15. oldUV.Add(uva);
    16. combineInstances[j].mesh.uv = uvb;
    17. }

    在合并完材质之后,还需要对uv进行处理,根据合并的偏移对每个uv加上对应的偏移值即可,这里不赘述,只得一提的是,这里还需要保存旧的uv,在合并网格之后,将旧的uv重新赋值回去,以免影响到其他使用到同一个Mesh的对象。

    1. //重新赋值,以免影响其他对象的Mesh
    2. for (int i = 0; i < combineInstances.Count; i++)
    3. {
    4. combineInstances[i].mesh.uv = oldUV[i];
    5. }

    合并网格依旧是调用Mesh.CombineMeshes ,不同的是,第二个参数我们设置为true,因为我们已经将其合并成一个材质,因此不再需要多material。

    render.sharedMesh.CombineMeshes(combineInstances.ToArray(), true, false);

  • 相关阅读:
    C++标准模板(STL)- 类型支持 (数值极限,min_exponent10,max_exponent,max_exponent10)
    IDEA中点击New没有Java Class
    Kotlin编程实战——与Java互操作(10)
    嵌入式开发--Altium技巧:原理图设置
    Qwt开发笔记(一):Qwt简介、下载以及基础demo工程模板
    怎么通过ip地址连接共享打印机
    反射、枚举以及lambda表达式
    Guava类库——BiMap和Multimap详解
    统计学-双变量相关分析-相关系数、相关比、克莱姆相关系数
    学生问的一道CSS3媒体查询,实现响应式设计的题
  • 原文地址:https://blog.csdn.net/Zhidai_/article/details/126122896