Unity3d 人物换装之 一个Shader处理3张图片 减少DrawCall

在上一篇

Unity3d人物换装之Mesh合并(材质合并)

中,我通过一个例子,将三个带有不同颜色 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 200CGPROGRAM#pragma surface surf Lambertsampler2D _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"}在上面的未完成的Shader中,我取了_Red 的纹理来做取样。我们接着修改脚本代码,,使合并之后的GameObject Character使用CombineShader创建的材质。

using UnityEngine;using System.Collections;public class NewBehaviourScript : MonoBehaviour {// Use this for initializationvoid 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 framevoid Update () {}}运行之后能看到,在Character这个GameObject使用的材质球中,需要输入三张纹理图片。

现在再看,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 200CGPROGRAM#pragma surface surf Lambertsampler2D _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"}我们看到在surf 中对顶点颜色的Alpha值进行了判断处理,这是利用顶点色Color的属性,在代码中进行赋值,来区分当前顶点原来是属于哪一个立方体的。比如说color.a是0,那么原来就属于红色立方体,就给它从红色纹理来取样。

木已成舟便要顺其自然

Unity3d 人物换装之 一个Shader处理3张图片 减少DrawCall

相关文章:

你感兴趣的文章:

标签云: