在上一篇
中,我通过一个例子,将三个带有不同颜色 RGB的立方体,合并Mesh和材质到Character这一个GameObject中。这样原本对3个GameObject的操作只需要对Character这一个GameObject进行操作就好了。但是我们的任务还没有完成。
合并之前的游戏:
合并之后的游戏:
大家注意看合并之前和合并之后,虽然GameObject数量减少了,但是DrawCall一个都没有减少哦!之前是4个,合并之后仍然是4个。
简单的来说呢,就是一个材质球,一个DrawCall。也就是说呢,一个Shader,一个DrawCall。
既然知道了一个Shader一个DrawCall,那我们就开始着手去处理,把红、绿、蓝这三张图片,在一个Shader中进行处理,只使用一个材质球,这样就只有1个DrawCall了。
我们来创建一个Shader,就叫CombineShader吧,在默认的Shader代码基础上,删掉MainTex这个纹理,添加我们自己的三个纹理:_Red 、_Green 、_Blue .
Shader "Custom/CombineShader" { Properties { _Red ("Base (RGB)", 2D) = "white" {} _Green ("Base (RGB)", 2D) = "white" {} _Blue ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _Red; sampler2D _Green; sampler2D _Blue; struct Input { float2 uv_RedTex; float2 uv_GreenTex; float2 uv_BlueTex; }; void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_Red, IN.uv_RedTex); o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
using UnityEngine; using System.Collections; public class NewBehaviourScript : MonoBehaviour { // Use this for initialization void Start () { //获取纹理; Texture redTex=transform.Find("CubeRed").GetComponent<MeshRenderer>().sharedMaterial.mainTexture; Texture greenTex=transform.Find("CubeGreen").GetComponent<MeshRenderer>().sharedMaterial.mainTexture; Texture blueTex=transform.Find("CubeBlue").GetComponent<MeshRenderer>().sharedMaterial.mainTexture; //合并材质; Shader combineShader = Shader.Find("Custom/CombineShader"); Material combineMaterial = new Material(combineShader); combineMaterial.SetTexture("_Red", redTex); combineMaterial.SetTexture("_Green", greenTex); combineMaterial.SetTexture("_Blue", blueTex); //合并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>().sharedMaterial = combineMaterial; } // Update is called once per frame void Update () { } }
现在再看,DrawCall数量已经降到2了,也就是说,合并之后 由原来的3个DrawCall 降到了 1个DrawCall。
但是还是有问题呢,为什么只显示一个立方体,哈哈,是我们代码写错了。
transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine, false);
transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine, true);
为什么没有贴图?因为我们只是在Unity中设置了贴图,但是在Shader中还没有去使用它们。
将Shader修改如下:
Shader "Custom/CombineShader" { Properties { _Red ("Base (RGB)", 2D) = "white" {} _Green ("Base (RGB)", 2D) = "white" {} _Blue ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _Red; sampler2D _Green; sampler2D _Blue; struct Input { float2 uv_RedTex; float2 uv_GreenTex; float2 uv_BlueTex; float4 color:COLOR; }; void surf (Input IN, inout SurfaceOutput o) { half4 colorIn; if(IN.color.a<0.33) { colorIn=tex2D(_Red,IN.uv_RedTex); } else if(IN.color.a<0.6) { colorIn=tex2D(_Green,IN.uv_GreenTex); } else { colorIn=tex2D(_Blue,IN.uv_BlueTex); } o.Albedo=colorIn.rgb; o.Alpha=colorIn.a; } ENDCG } FallBack "Diffuse" }
using UnityEngine; using System.Collections; using System.Collections.Generic; public class NewBehaviourScript : MonoBehaviour { // Use this for initialization void Start () { //获取纹理; Texture redTex=transform.Find("CubeRed").GetComponent<MeshRenderer>().sharedMaterial.mainTexture; Texture greenTex=transform.Find("CubeGreen").GetComponent<MeshRenderer>().sharedMaterial.mainTexture; Texture blueTex=transform.Find("CubeBlue").GetComponent<MeshRenderer>().sharedMaterial.mainTexture; //合并材质; Shader combineShader = Shader.Find("Custom/CombineShader"); Material combineMaterial = new Material(combineShader); combineMaterial.SetTexture("_Red", redTex); combineMaterial.SetTexture("_Green", greenTex); combineMaterial.SetTexture("_Blue", blueTex); //合并Mesh; MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter>(); CombineInstance[] combine = new CombineInstance[meshFilters.Length]; List<Color> combineMeshColor=new List<Color>(); //Combine之后Mesh的Color; for (int i = 0; i < meshFilters.Length;i++ ) { combine[i].mesh = meshFilters[i].sharedMesh; //处理顶点位置; combine[i].transform = meshFilters[i].transform.localToWorldMatrix; //处理顶点颜色; Vector2[] UVArray = meshFilters[i].sharedMesh.uv; float bodyPart = i / (float)meshFilters.Length; for (int uvindex = 0; uvindex < UVArray.Length; uvindex++) { combineMeshColor.Add(new Color(bodyPart, bodyPart, bodyPart, bodyPart)); } meshFilters[i].gameObject.SetActive(false); } Mesh combineMesh = new Mesh(); combineMesh.CombineMeshes(combine, true); combineMesh.colors = combineMeshColor.ToArray(); combineMesh.name = gameObject.name; transform.gameObject.AddComponent<MeshRenderer>(); transform.gameObject.AddComponent<MeshFilter>(); transform.gameObject.GetComponent<MeshFilter>().sharedMesh = combineMesh; //设置材质; transform.GetComponent<MeshRenderer>().material = combineMaterial; transform.gameObject.SetActive(true); } // Update is called once per frame void Update () { } }
工程示例下载:
http://pan.baidu.com/s/1o6ytCoU
Unity3d 人物换装之 一个Shader处理3张图片 减少DrawCall
原文:http://blog.csdn.net/huutu/article/details/44570981