当前位置:   article > 正文

[Unity] GPU动画实现(三)——材质合并_unity合并材质与贴图

unity合并材质与贴图

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

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

  1. // 合并贴图(从收集的各Material中取)
  2. List<Texture2D> MainTexs = new List<Texture2D>();
  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<Vector2[]>();
  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);

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/98067
推荐阅读
相关标签
  

闽ICP备14008679号