网格及材质合并

本贴最后更新于 2290 天前,其中的信息可能已经时移世易

最近弄 unity 地图导出 pmd,发现好多网格合并代码用不了,我无法理解那些合并代码里的网格合并到底是什么意思.我说说我理解的网格合并
一般一个地图场景,有很多个 gameobject,每个有网格的 gameobject 上都有一个 meshfilter 组件和一个 meshrenderer 组件
而对 meshrenderer 组件来说,他可能具有一系列材质来对应渲染 meshfilter 里的每个 submesh,而每个材质都有自己的 shader 参数等.但是使用同一材质的,这些 shader 参数都一样
而对于每个 meshfilter 组件来说,他拥有顶点缓冲区,索引缓冲区,uv,color,normal,以及每个 submesh 对应了哪些顶点,以及这个 meshfilter 所在的 gameobject 的坐标(世界变换矩阵)
所以要合并,应该是先要统计这些信息,然后把所有信息存储到一个在原点,无旋转,无缩放的 gameobject 上,把所有网格信息,为其添加 meshfilter 组件放到 mesh 里,把所有材质放到 meshrenderer 里的 materials 里
而这个主要麻烦,就是网格和材质的对应关系,以及网格顶点信息的重新计算(要把原来 meshfilter 里的顶点算出世界坐标然后放到这里).这整个流程只要心里有数了,就可以写代码来实现了.

最后放一个组件代码,用于合并一系列的 gameobject 到一个 gameobject 里,主要是合并网格信息,材质等
这个组件没有合并同材质的 submesh,事实上,使用了同一材质的不同网格,可以合并到一个 submesh 里,这个点可以继续优化,但是现在是没处理的,我只是想把地图场景保存为 pmd 的,所以这部分忽略了
如果有不对的请指教

在一个 Editor 类里添加一个类
[CustomEditor(typeof(PMDSave))]
public class PMDSaveInspector : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (GUILayout.Button("Combine"))
{
var obj = (PMDSave)target;
obj.CombineMapMesh();
}
}
}

然后在 Asset 目录下新增此组件
然后在地图的根节点处,挂入此脚本组件,点组件 Inspector 栏下的 CombineMesh 按钮,这个单网格就可以替代全部地图下的所有 gameobejct 了。

public class PMDSave : MonoBehaviour {
void CombineMapMesh()
{
Transform GenMapRoot = new GameObject("GenMapRoot").transform;
GenMapRoot.position = Vector3.zero;
GenMapRoot.localScale = Vector3.one;
GenMapRoot.rotation = Quaternion.identity;
MeshFilter mf = GenMapRoot.gameObject.AddComponent();
MeshRenderer mr = GenMapRoot.gameObject.AddComponent();
MeshFilter[] mfs = GetComponentsInChildren();
MeshRenderer[] mrs = GetComponentsInChildren();
//统计材质
List mat = new List();
for (int i = 0; i < mrs.Length; i++)
{
if (!mrs[i].enabled)
continue;
mat.AddRange(mrs[i].sharedMaterials);
}
mr.sharedMaterials = mat.ToArray();
int subMeshIndex = 0;
List vertex = new List();
List uv = new List();
List normal = new List();
List co = new List();
Dictionary<int, int[]> subMeshIndices = new Dictionary<int, int[]>();
//统计顶点.
for (int i = 0; i < mfs.Length; i++)
{
//隐藏了的不要
if (!mrs[i].enabled)
continue;
//推入顶点
int vertexIndex = vertex.Count;//记录推入之前的索引起始
for (int j = 0; j < mfs[i].sharedMesh.vertexCount; j++)
vertex.Add(mfs[i].transform.localToWorldMatrix * mfs[i].sharedMesh.vertices[j]);

	  //推入颜色,UV,法线
	  int uv_len = mfs[i].sharedMesh.uv.Length;
	  for (int j = 0; j < uv_len; j++)
		  uv.Add(mfs[i].sharedMesh.uv[j]);
	  int normal_len = mfs[i].sharedMesh.normals.Length;
	  for (int j = 0; j < normal_len; j++)
		  normal.Add(mfs[i].sharedMesh.normals[j]);
	  int color_len = mfs[i].sharedMesh.colors.Length;
	  for (int j = 0; j < color_len; j++)
		  co.Add(mfs[i].sharedMesh.colors[j]);
	  for (int j = 0; j < mfs[i].sharedMesh.subMeshCount; j++)
	  {
		  int[] indices = mfs[i].sharedMesh.GetIndices(j);
		  //把这些索引,都加上全局索引下标
		  for (int k = 0; k < indices.Length; k++)
			  indices[k] += vertexIndex;
		  subMeshIndices.Add(subMeshIndex, indices);
		  subMeshIndex++;
	  }
  }
  mf.sharedMesh = new Mesh();
  mf.sharedMesh.SetVertices(vertex);
  mf.sharedMesh.SetColors(co);
  mf.sharedMesh.uv = uv.ToArray();
  mf.sharedMesh.SetNormals(normal);
  mf.sharedMesh.subMeshCount = subMeshIndices.Count;
  vertexCnt = vertex.Count;
  foreach (var each in subMeshIndices)
	  mf.sharedMesh.SetIndices(each.Value, MeshTopology.Triangles, each.Key);

}
}

之前做这个 PMDSave 主要是来保存和官方 PMD 骨骼结构调整一致的流星.net 人物角色的,因为想让.net 流星角色也跳极乐净土,后来朋友想把场景也弄进去,就让我导出下场景
其实导出角色的时候,要导出骨骼结构,以及部分的腿部 IK 设置,以及蒙皮数据,所以导出角色,是比导出地图更麻烦的。
而一个 pmd 貌似只能保存一个 meshfilter 里的顶点和材质,所以后来就找代码合并网格和材质到一个物件上,找了半天都是些不能用的,我就想不通到底哪里理解不一样
于是自己折腾了一个,过几天朋友就会发出一个流星蝴蝶剑.net 角色跳舞蹈的视频。其实转换骨骼结构为官方 mmd 的标准骨架后,舞蹈动作都可以通用了,想想一群.net 的角色一起跳舞
就觉得好滑稽。

最后合并网格是用来减少 drawcall 的,相同材质的网格合并能减少 drawcall,所以在这个组件基础上,只要把材质相同的 submesh 合并到一个 submesh 里,drawcall 也就会被优化掉
不过合并后,成为一个整体,是无法控制地图上的任何元素的,因为都在一起了,要显示就一起显示,要隐藏就一起隐藏

  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 247 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    16 引用 • 53 回帖 • 120 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    215 引用 • 462 回帖 • 1 关注
  • 电影

    这是一个不能说的秘密。

    120 引用 • 597 回帖 • 1 关注
  • 笔记

    好记性不如烂笔头。

    303 引用 • 777 回帖 • 1 关注
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    15 引用 • 7 回帖 • 9 关注
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    53 引用 • 85 回帖
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    368 引用 • 1212 回帖 • 580 关注
  • Oracle

    Oracle(甲骨文)公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩。1989 年正式进入中国市场。2013 年,甲骨文已超越 IBM,成为继 Microsoft 后全球第二大软件公司。

    103 引用 • 126 回帖 • 448 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    76 引用 • 37 回帖 • 1 关注
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    21 引用 • 37 回帖 • 513 关注
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖 • 1 关注
  • AngularJS

    AngularJS 诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。AngularJS 有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等。2.0 版本后已经改名为 Angular。

    12 引用 • 50 回帖 • 422 关注
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 683 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 45 关注
  • 大疆创新

    深圳市大疆创新科技有限公司(DJI-Innovations,简称 DJI),成立于 2006 年,是全球领先的无人飞行器控制系统及无人机解决方案的研发和生产商,客户遍布全球 100 多个国家。通过持续的创新,大疆致力于为无人机工业、行业用户以及专业航拍应用提供性能最强、体验最佳的革命性智能飞控产品和解决方案。

    2 引用 • 14 回帖 • 1 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3168 引用 • 8207 回帖 • 1 关注
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 247 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    84 引用 • 139 回帖
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    284 引用 • 4481 回帖 • 656 关注
  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 548 关注
  • 星云链

    星云链是一个开源公链,业内简单的将其称为区块链上的谷歌。其实它不仅仅是区块链搜索引擎,一个公链的所有功能,它基本都有,比如你可以用它来开发部署你的去中心化的 APP,你可以在上面编写智能合约,发送交易等等。3 分钟快速接入星云链 (NAS) 测试网

    3 引用 • 16 回帖
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 594 关注
  • 创造

    你创造的作品可能会帮助到很多人,如果是开源项目的话就更赞了!

    172 引用 • 990 回帖
  • gRpc
    10 引用 • 8 回帖 • 54 关注
  • DevOps

    DevOps(Development 和 Operations 的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

    39 引用 • 24 回帖