unity3d 合并相同材质_unity 材质球 合并为一个材质 - CSDN
  • Unity自带了一个合并网格的功能,Mesh.CombineMeshes 组合网格 function CombineMeshes (combine : CombineInstance[], mergeSubMeshes : bool = true, useMatrices : bool = true) : void 结合网格有利...

    Unity自带了一个合并网格的功能,Mesh.CombineMeshes 组合网格

    function CombineMeshes (combine : CombineInstance[], mergeSubMeshes : bool = true, useMatrices : bool = true) : void

    结合网格有利于性能最优化。如果mergeSubMeshes为true,所有的网格会被结合成一个单个子网格。否则每一个网格都将变成单个不同的子网格。如果所有的网格共享同一种材质,设定它为真。如果useMatrices为false,在CombineInstance结构中的变换矩阵将被忽略。

    用这函数我们可以把引用相同材质球的网格进行合并达到减少Draw Call,优化性能的效果。

    我的基本思路是:将所有的材质球用字典存(相同的只存一个),将引用相同材质球的网格存一个链表中用材质球的名称作为Key值;

    然后遍历字典用Mesh的成员方法CombineMeshes()合并相同;

    OK,上代码

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
     
    public class ComebinMesheDemo : MonoBehaviour {
     
    // Use this for initialization
    void Start () {
    //获取所有网格过滤器;
    MeshFilter[] meshFilters = gameObject.GetComponentsInChildren<MeshFilter>();
    //存放不同的材质球,相同的就存一个;
    Dictionary<string, Material> materials = new Dictionary<string, Material>();
     
    //存放要合并的网格对象;
    Dictionary<string, List<CombineInstance>> combines = new Dictionary<string, List<CombineInstance>>();
    for (int i = 0; i < meshFilters.Length; i++)
    {
    //构造一个网格合并结构体;
    CombineInstance combine = new CombineInstance();
     
    //给结构体的mesh赋值;
    combine.mesh = meshFilters[i].mesh;
    combine.transform = meshFilters[i].transform.localToWorldMatrix;
     
    MeshRenderer renderer = meshFilters[i].GetComponent<MeshRenderer>();
    Material mat = renderer.sharedMaterial;
     
    if (!materials.ContainsKey(mat.name))
    {
    materials.Add(mat.name, mat);
    }
    if (combines.ContainsKey(mat.name))
    {
    combines[mat.name].Add(combine);
    }
    else
    {
    List<CombineInstance> coms = new List<CombineInstance>();
    coms.Add(combine);
    combines[mat.name] = coms;
    }
     
    Destroy(meshFilters[i].gameObject);
    }
    GameObject combineObj = new GameObject("Combine");
    combineObj.transform.parent = transform;
    foreach (KeyValuePair<string, Material> mater in materials)
    {
    GameObject obj = new GameObject(mater.Key);
    obj.transform.parent = combineObj.transform;
    MeshFilter combineMeshFilter = obj.AddComponent<MeshFilter>();
    combineMeshFilter.mesh = new Mesh();
     
    //将引用相同材质球的网格合并;
    combineMeshFilter.mesh.CombineMeshes(combines[mater.Key].ToArray(), true,true);
    MeshRenderer rend = obj.AddComponent<MeshRenderer>();
     
    //指定材质球;
    rend.sharedMaterial = mater.Value;
    rend.castShadows = false;
    rend.receiveShadows = true;
    }
    }
    }
    好了,本篇unity3d教程关于合并相同材质的mesh网格的教程到此结束,下篇我们再会!


    展开全文
  • Unity中提供了模型动画合并的功能,也就是说我们可以把人物模型的4个部位合并到一个GameObject中。

    在上一篇教程

    Unity3d换装之 模型动画分离

    中介绍了如何把人物身体部分动画组合起来让人物模型动起来,但是在UnityEditor中可以看到,模型的4个部分是以4个GameObject的形式独立存在的,这样造成的影响我们可以猜到,在播放人物动画的时候,比如想让人物模型走动,那我们就需要调用

    head.animation.Play("run");  
    jack.animation.Play("run");  
    pant.animation.Play("run");  
    weapon.animation.Play("run");  

    需要对4个部分分别执行相同动作才能是人物整体动起来。这样无疑增加了很多操作,让人费解。

    如何解决这个问题呢?


    在Unity中提供了模型动画合并的功能,也就是说我们可以把人物模型的4个部位合并到一个GameObject中,这样我们之后对人物的操作就只需要一句代码了。

    下面用一个简单的Demo来作为示例。


    构造下面的场景:


    在Character 下面的三个Cube分别贴上了不同颜色的贴图 便于 识别与实验。



    然后合并Mesh、合并材质 到 Character 这个GameObject上。

    using UnityEngine;
    using System.Collections;
    
    public class NewBehaviourScript : MonoBehaviour {
    
    	// Use this for initialization
    	void Start () {
    
            //获取MeshRender;
            MeshRenderer[] meshRenders = GetComponentsInChildren<MeshRenderer>();
    
            //材质;
            Material[] mats=new Material[meshRenders.Length];
            for (int i = 0; i < meshRenders.Length;i++ )
            {
                mats[i] = meshRenders[i].sharedMaterial;
            }
            
    
            //合并Mesh;
            MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter>();
    
            CombineInstance[] combine = new CombineInstance[meshFilters.Length];
    
            for (int i = 0; i < meshFilters.Length;i++ )
            {
                combine[i].mesh = meshFilters[i].sharedMesh;
                combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
                meshFilters[i].gameObject.SetActive(false);
            }
    
            transform.gameObject.AddComponent<MeshRenderer>();
            transform.gameObject.AddComponent<MeshFilter>();
            transform.GetComponent<MeshFilter>().mesh = new Mesh();
            transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine, false);
            transform.gameObject.SetActive(true);
    
            transform.GetComponent<MeshRenderer>().sharedMaterials = mats;
    	}
    	
    	// Update is called once per frame
    	void Update () {
    	
    	}
    }
    

    将上面的脚本挂载到 Character 上面。

    运行之后的效果:


    工程示例下载;

    http://pan.baidu.com/s/1o6socoM




    展开全文
  • Unity网格合并_材质合并

    万次阅读 2014-12-08 17:37:48
    从换装的角度(这里指的是换形状、换组成部件的换装,而不是挂点型的换装),都需要网格合并材质合并。 从优化角度,Mesh也需要合并。 以下就是使用unity进行mesh合并的例子。

    写在前面:

    从优化角度,Mesh需要合并。

    从换装的角度(这里指的是换形状、换组成部件的换装,而不是挂点型的换装),都需要网格合并、材质合并。如果是人物的换装,那么需要合并SkinnedMeshRenderer,并重刷对应的骨骼列表。


    示例:

    1,新建两个Cube,和一个Cylinder。分别作为坦克的底盘(Cube_chassis)、炮塔(Cube_turret)、炮管(Cylinder_gun)。如下图所示。



    2,为了测试换装,我们加入三个材质球,调整一下颜色,然后分别赋给底盘(Cube_chassis)、炮塔(Cube_turret)、炮管(Cylinder_gun)。


    3,把炮塔(Cube_turret)和炮管(Cylinder_gun),变成底盘(Cube_chassis)的子物体。也就是说,新的模型,是以底盘为基础的。



    4,用CombineMeshes方法,合并mesh。并且用代码把【材质】也一起“合并”了。把下面的Combine_Test.cs文件,拖拽到底盘(Cube_chassis)上,之后运行。

    using UnityEngine;
    using System.Collections;
    
    public class Combine_Test : MonoBehaviour {
    
    	// Use this for initialization
    	void Start ()
    	{
    		//---------------- 先获取材质 -------------------------
    		//获取自身和所有子物体中所有MeshRenderer组件
    		MeshRenderer[] meshRenderers = GetComponentsInChildren<MeshRenderer>();  
    		//新建材质球数组
    		Material[] mats = new Material[meshRenderers.Length];  
    		for (int i = 0; i < meshRenderers.Length; i++) {
    			//生成材质球数组 
    			mats[i] = meshRenderers[i].sharedMaterial;   
    		}
    		//---------------- 合并 Mesh -------------------------
    		//获取自身和所有子物体中所有MeshFilter组件
    		MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter>();  
    		CombineInstance[] combine = new CombineInstance[meshFilters.Length];   
    		for (int i = 0; i < meshFilters.Length; i++) {
    			combine[i].mesh = meshFilters[i].sharedMesh;
    			//矩阵(Matrix)自身空间坐标的点转换成世界空间坐标的点 
    			combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
    			meshFilters[i].gameObject.SetActive(false);
    		} 
    		//为新的整体新建一个mesh
    		transform.GetComponent<MeshFilter>().mesh = new Mesh(); 
    		//合并Mesh. 第二个false参数, 表示并不合并为一个网格, 而是一个子网格列表
    		transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine, false);
    		transform.gameObject.SetActive(true);
    
    		//为合并后的新Mesh指定材质 ------------------------------
    		transform.GetComponent<MeshRenderer>().sharedMaterials = mats; 
    	}
    	
    	// Update is called once per frame
    	void Update () {
    		
    	}
    }
    

    5,运行效果如下。可以看到,Mesh和材质,都很好的得到了合并。坦克已经由零件,变成一个整体了!

    但是,大家会发现这个模型,产生了一些变形!难道是这样不对,或者是bug么?不,其实不用担心。这是因为前面用的Cube、Cylinder 等模拟底盘炮塔,手动调节了他们的缩放比例放造成的。如果以某个组件为根物体,那么它的缩放比例,直接影响合并后生成的新物体。各个部件的缩放比都会按它走!

    也就是说,如果你想合并后不变形,就不要更改根物体的缩放比例。





    参考:

    关键函数,就是下面这个合并网格的函数了:

    CombineMeshes(CombineInstance[]combine, boolmergeSubMeshes = true, booluseMatrices = true);


    Unity官网,关于网格合并的例子:

    http://docs.unity3d.com/ScriptReference/Mesh.CombineMeshes.html 


    程序员俱乐部-Unity3d网格合并:

    http://www.cxyclub.cn/n/54078/


    展开全文
  • Unity中的网格与材质合并

    万次阅读 2016-05-27 22:48:07
    很多时候我们需要把具有相同shader的材质合并,从而减少drawcall的产生。 比如多部位的人物换装,手、脚、身体分别来自不同的FBX文件,它们各自有自己的材质球,拼装成一个人物的时候,就会带上多个drawcall,...

    很多时候我们需要把具有相同shader的材质球合并,从而减少drawcall的产生。  

    比如九龙战里面,一个人物带有10个部位,10个部位各自来自不同的fbx文件,加上身体,就有11个材质球,占上11个drawcall。如果主城里面跑着10个角色,光人物就占了110个drawcall!所以这种时候材质球合并是必须的。

    (下图为九龙战里面的多部位换装效果)


    材质球合并,分以下几步走,首先我们讨论普通的MeshRenderer的材质球合并,然后再讨论SkinnedMeshRenderer的材质球合并。

    普通的MeshRenderer的材质球合并:

    1.合并所有材质球所携带的贴图,新建一个材质球,并把合并好的贴图赋予新的材质球。

    2.记录下每个被合并的贴图所处于新贴图的Rect,用一个Rect[]数组存下来。

    3.合并网格,并把需要合并的各个网格的uv,根据第2步得到的Rect[]刷一遍。

    4.把新的材质球赋予合并好的网格,此时就只占有1个drawcall了。

    下面是关键代码:

    void CombineMesh()
        {
            
            MeshFilter[] mfChildren = GetComponentsInChildren<MeshFilter>();
            CombineInstance[] combine = new CombineInstance[mfChildren.Length];
    
    
            MeshRenderer[] mrChildren = GetComponentsInChildren<MeshRenderer>();
            Material[] materials = new Material[mrChildren.Length];
    
    
            MeshRenderer mrSelf = gameObject.AddComponent<MeshRenderer>();
            MeshFilter mfSelf = gameObject.AddComponent<MeshFilter>();
    
    
            Texture2D[] textures = new Texture2D[mrChildren.Length];
            for (int i = 0; i < mrChildren.Length; i++)
            {
                if (mrChildren[i].transform == transform)
                {
                    continue;
                }
                materials[i] = mrChildren[i].sharedMaterial;
                Texture2D tx = materials[i].GetTexture("_MainTex") as Texture2D;
    
    
                Texture2D tx2D = new Texture2D(tx.width, tx.height, TextureFormat.ARGB32, false);
                tx2D.SetPixels(tx.GetPixels(0, 0, tx.width, tx.height));
                tx2D.Apply();
                textures[i] = tx2D;
            }
    
    
            Material materialNew = new Material(materials[0].shader);
            materialNew.CopyPropertiesFromMaterial(materials[0]);
            mrSelf.sharedMaterial = materialNew;
    
    
            Texture2D texture = new Texture2D(1024, 1024);
            materialNew.SetTexture("_MainTex", texture);
            Rect[] rects = texture.PackTextures(textures, 10, 1024);
    
    
            for (int i = 0; i < mfChildren.Length; i++)
            {
                if (mfChildren[i].transform == transform)
                {
                    continue;
                }
                Rect rect = rects[i];
    
    
                Mesh meshCombine = mfChildren[i].mesh;
                Vector2[] uvs = new Vector2[meshCombine.uv.Length];
                //把网格的uv根据贴图的rect刷一遍
                for (int j = 0; j < uvs.Length; j++)
                {
                    uvs[j].x = rect.x + meshCombine.uv[j].x * rect.width;
                    uvs[j].y = rect.y + meshCombine.uv[j].y * rect.height;
                }
                meshCombine.uv = uvs;
                combine[i].mesh = meshCombine;
                combine[i].transform = mfChildren[i].transform.localToWorldMatrix;
                mfChildren[i].gameObject.SetActive(false);
            }
    
    
            Mesh newMesh = new Mesh();
            newMesh.CombineMeshes(combine, true,true);//合并网格
            mfSelf.mesh = newMesh;
        }


    合并前的drawcall:

    合并后的drawcall:


    合并好的网格:


    合并好的贴图:


    下面我们将讨论SkinnedMeshRenderer的合并。

    SkinnedMeshRenderer比MeshRenderer稍微麻烦一点,因为SkinnedMeshRenderer要处理bones。

    以下是步骤:

    1.合并所有材质球所携带的贴图,新建一个材质球,并把合并好的贴图赋予新的材质球。

    2.记录下每个被合并的贴图所处于新贴图的Rect,用一个Rect[]数组存下来。

    3.记录下需要合并的SkinnedMeshRenderer的bones。

    4.合并网格,并把需要合并的各个网格的uv,根据第2步得到的Rect[]刷一遍。

    5.把合并好的网格赋予新的SkinnedMeshRenderer,并把第3步记录下的bones赋予新的SkinnedMeshRenderer。

    6.把新的材质球赋予合并好的网格,此时就只占有1个drawcall了。


    上面红色部分的步骤就是与MeshRenderer不同之处。

    下面是关键代码:

    void CombineMesh()
        {
            SkinnedMeshRenderer[] smrs = GetComponentsInChildren<SkinnedMeshRenderer>();
            CombineInstance[] combine = new CombineInstance[smrs.Length];
            Material[] materials = new Material[smrs.Length];
            Texture2D[] textures = new Texture2D[smrs.Length];
    
            SkinnedMeshRenderer smrCombine = combineMesh.gameObject.AddComponent<SkinnedMeshRenderer>();
            smrCombine.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
            smrCombine.receiveShadows = false;
    
            for (int i = 0; i < smrs.Length; i++)
            {
                materials[i] = smrs[i].sharedMaterial;
                Texture2D tx = materials[i].GetTexture("_MainTex") as Texture2D;
    
                Texture2D tx2D = new Texture2D(tx.width, tx.height, TextureFormat.ARGB32, false);
                tx2D.SetPixels(tx.GetPixels(0, 0, tx.width, tx.height));
                tx2D.Apply();
                textures[i] = tx2D;
            }
    
            Material materialNew = new Material(materials[0].shader);
            materialNew.CopyPropertiesFromMaterial(materials[0]);
            
            Texture2D texture = new Texture2D(1024, 1024);
            Rect[] rects = texture.PackTextures(textures, 10, 1024);
            materialNew.SetTexture("_MainTex", texture);
    
            List<Transform> boneTmp = new List<Transform>();
    
            for (int i = 0; i < smrs.Length; i++)
            {
                if (smrs[i].transform == transform)
                {
                    continue;
                }
                Rect rect = rects[i];
    
                Mesh meshCombine = CreatMeshWithMesh(smrs[i].sharedMesh);
                Vector2[] uvs = new Vector2[meshCombine.uv.Length];
    
                for (int j = 0; j < uvs.Length; j++)
                {
                    uvs[j].x = rect.x + meshCombine.uv[j].x * rect.width;
                    uvs[j].y = rect.y + meshCombine.uv[j].y * rect.height;
                }
    
                boneTmp.AddRange(smrs[i].bones);
    
                meshCombine.uv = uvs;
                combine[i].mesh = meshCombine;
                combine[i].transform = smrs[i].transform.localToWorldMatrix;
                GameObject.Destroy(smrs[i].gameObject);
            }
    
            Mesh newMesh = new Mesh();
            newMesh.CombineMeshes(combine, true, true);
    
            smrCombine.bones = boneTmp.ToArray();
            smrCombine.rootBone = rootBone;
            smrCombine.sharedMesh = newMesh;
            smrCombine.sharedMaterial = materialNew;
        }
        Mesh CreatMeshWithMesh(Mesh mesh)
        {
            Mesh mTmp = new Mesh();
            mTmp.vertices = mesh.vertices;
            mTmp.name = mesh.name;
            mTmp.uv = mesh.uv;
            mTmp.uv2 = mesh.uv2;
            mTmp.uv2 = mesh.uv2;
            mTmp.bindposes = mesh.bindposes;
            mTmp.boneWeights = mesh.boneWeights;
            mTmp.bounds = mesh.bounds;
            mTmp.colors = mesh.colors;
            mTmp.colors32 = mesh.colors32;
            mTmp.normals = mesh.normals;
            mTmp.subMeshCount = mesh.subMeshCount;
            mTmp.tangents = mesh.tangents;
            mTmp.triangles = mesh.triangles;
    
            return mTmp;
        }
    未合并前,有两个网格,占用2drawcall,分别为人物和刀的网格和材质球。



    合并后,只占用 1 drawcall了,而且AnimationController以及其动画能够正常工作:



    合并好的网格:


    合并好的贴图:



    以上便是合并Mesh和Material的内容,目前只关注实现,还可以进一步优化,有以下几点要注意的:

    1.合并的材质球需要使用同一个shader,如果多个材质球使用了不同shader,就要做进一步的出分类处理了。

    2.材质球所用的Texture文件的Read/Write Enable选项要打上勾。

    项目的github地址:  https://github.com/arBao/MeshMaterialCombine

    原创文章,转载请注明出处:   http://blog.csdn.net/dardgen2015/article/details/51517860


    展开全文
  • Unity 模型合并

    千次阅读 2018-12-26 17:44:18
    当场景中模型非常多,不妨试一下模型合并技术,可以在3dMax或其他建模软件上进行操作,也可在Unity中进行操作,这里我仅介绍Unity中的模型合并方法。  前提:合并的物体必须是相同材质,否则合并之后赋值多个...
  • Unity3d 人物换装 之 Mesh 合并 材质合并
  • Unity在运行时可以将一些物体进行合并,从而用一个绘制调用来渲染他们。这一操作,我们称之为“批处理”。一般来说,Unity批处理的物体越多,你就会得到越好的渲染性能。 Unity中内建的批处理机制
  • Unity3d 引擎原理详细介绍

    万次阅读 2014-03-25 13:22:52
     为了更好地理解游戏的软件架构和对象模型,它获得更好的外观仅有一名Unity3D的游戏引擎和编辑器是非常有用的,它的主要原则。 Unity3D 引擎  Unity3D的是一个屡获殊荣的工具,用于创建交互式3D应用程序在多个...
  • Unity3D性能优化总结

    2015-05-19 13:50:10
    原文 http://blog.csdn.net/dj0379/article/details/27314163 ... ...Unity3D合并材质球 unity 3d中每倒入一次模型就多一个材质球,可我的这些模型都是共用一张贴图的就想共用一个材质球,所以每次都要
  • Unity合并网格和贴图

    千次阅读 2017-03-05 15:32:50
    最近项目中由于场景中的小物件比较多导致在进入场景的时候DrawCall数量明显升高,所以就需要针对场景中的小物件进行网格的合并与贴图的合并,下面是贴图与网格合并的代码,更详细的逻辑需要根据需要去补充,如:搜索...
  • 解析OBJ模型并将其加载到Unity3D场景中

    万次阅读 热门讨论 2015-11-23 10:23:41
    今天想和大家交流的是解析obj模型并将其加载到Unity3D场景中,虽然我们知道Unity3D是可以直接导入OBJ模型的,可是有时候我们并不能保证我们目标客户知道如何使用Unity3D的这套制作流程,可能对方最终提供给我们的...
  •  Unity3D的是一个屡获殊荣的工具,用于创建交互式3D应用程序在多个platforms.Unity3D由游戏引擎和编辑器。该引擎包含的软件组件,在游戏的研究与开发中最常见的和经常性的任务。发动机所涵盖的主题包括声音,图形,
  • Unity3d场景快速烘焙【2019】

    万次阅读 多人点赞 2019-12-26 19:09:28
    很多刚刚接触Unity3d的童鞋花了大量的时间自学,可总是把握不好Unity3d的烘焙,刚从一个坑里爬出来,又陷入另一个新的坑,每次烘焙一个场景少则几个小时,多则几十个小时,机器总是处于假死机状态,半天看不到结果,...
  • unity3d 各大插件评测

    万次阅读 2018-01-30 15:00:43
    原创文章如需转载请注明:转载自风宇冲Unity3D教程学院 引言:想用Unity3D制作优秀的游戏,插件是必不可少的。工欲善其事必先利其器。本文主旨是告诉使用Unity3D引擎的同学们如何根据需求选择适当的工具...
  • Unity3D游戏场景优化之批处理

    万次阅读 2015-09-07 10:53:56
    最近开始研究Unity3D游戏场景优化,每次提及游戏优化这个话题的时候,我的脑海中都会浮现出《仙剑奇侠传六》这个让四路泰坦都光荣陨落的神奇游戏,作为一个使用Unity3D引擎进行游戏开发的仙剑玩家,我曾经天真的以为...
1 2 3 4 5 ... 20
收藏数 1,429
精华内容 571
关键字:

unity3d 合并相同材质