Unity3D学习笔记10——纹理数组
目录
1. 概述
个人认为,纹理数组是一个非常有用的图形特性。纹理本质上是一个二维的图形数据;通过纹理数组,给图形数据再加上了一个维度。这无疑会带来一个巨大的性能提升:一次性传输大量的数据总是比分批次传输数据要快。
2. 详论
2.1. 实现
创建一个GameObject对象,并且加入Mesh Filter组件和Mesh Renderer组件。Mesh Filter我们可以设置Mesh为Quad,同时在Mesh Filter上挂一个我们新建的材质:
在这个GameObject对象上挂接一个我们创建的C#脚本:
using Unity.Collections; using UnityEngine; [ExecuteInEditMode] public class Note10Main : MonoBehaviour { public Texture2D texture1; public Texture2D texture2; [Range(0.0f, 1.0f)] public float weight; Material material; // Start is called before the first frame update void Start() { MeshRenderer mr = GetComponent<MeshRenderer>(); material = mr.sharedMaterial; Texture2DArray texture2DArray = CreateTexture2DArray(); material.mainTexture = texture2DArray; material.SetFloat("_Weight", weight); } Texture2DArray CreateTexture2DArray() { Texture2DArray texture2DArray = new Texture2DArray(texture1.width, texture1.height, 2, texture1.format, false); NativeArray<byte> pixelData1 = texture1.GetPixelData<byte>(0); NativeArray<byte> pixelData2 = texture2.GetPixelData<byte>(0); texture2DArray.SetPixelData(pixelData1, 0, 0, 0); texture2DArray.SetPixelData(pixelData2, 0, 1, 0); texture2DArray.Apply(false, false); return texture2DArray; } // Update is called once per frame void Update() { material.SetFloat("_Weight", weight); } }
这段C#脚本的意思是,通过传入两个Texture2d,生成一个texture2DArray;并且,将这个texture2DArray传入到材质中。需要注意的是纹理数组中的每个纹理的参数如宽、高等参数都需要一致,否则不能组成纹理数组。
材质使用我们自定义的Shader:
Shader "Custom/TextureArrayShader" { Properties { _MainTex ("Texture", 2DArray) = "" {} _Weight ("Weight", float) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; UNITY_DECLARE_TEX2DARRAY(_MainTex); float _Weight; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col0 = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(i.uv, 0)); fixed4 col1 = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(i.uv, 1)); return lerp(col0, col1, _Weight); } ENDCG } } }
这里实现的效果是,将纹理数组中的两个纹理根据权重进行混合。权重值也是在C#脚本中传入到Shader中的。在编辑器中将权重调整到中间一点的位置(例如0.5):
Shader代码也很好理解,关键在于纹理数组相关的宏,其实是对hlsl或者glsl的封装:
#define UNITY_DECLARE_TEX2DARRAY(tex) Texture2DArray tex; SamplerState sampler##tex #define UNITY_SAMPLE_TEX2DARRAY(tex,coord) tex.Sample (sampler##tex,coord) #define UNITY_DECLARE_TEX2DARRAY(tex) sampler2DArray tex #define UNITY_SAMPLE_TEX2DARRAY(tex,coord) tex2DArray (tex,coord)
2.2. 注意
- 关于纹理数组的创建,也可以使用Graphics.CopyTexture()这个接口。这个接口是纯走GPU端的,效率应该回更高。
- 纹理数组这个特性在低端显卡上可能不支持,但是不一定就会非常耗费性能。可以考虑通过纹理数组的方式来合并渲染的批次。
- 纹理数组个数的限制并不是纹理单元个数。实际上一个纹理数组只会绑定到一个纹理单元上,而在本人GTX 1660 Ti的显卡上,纹理数组个数的限制是4096个。
3. 参考
分类: Unity3D