可以参考 catlikecoding.com/unity/tutor…
制作一个创建 Texture Array 的工具
但是更简单的可以参考 medium.com/@calebfaith…
在代码中创建一个 Texture2DArray 变量,然后逐像素赋值
public Texture2D[] ordinaryTextures;
public GameObject objectToAddTextureTo;
private void CreateTextureArray()
{
// Create Texture2DArray
Texture2DArray texture2DArray = new
Texture2DArray(ordinaryTextures[0].width,
ordinaryTextures[0].height, ordinaryTextures.Length,
TextureFormat.RGBA32, true, false); // Apply settings
texture2DArray.filterMode = FilterMode.Bilinear;
texture2DArray.wrapMode = TextureWrapMode.Repeat; // Loop through ordinary textures and copy pixels to the
// Texture2DArray
for (int i = 0; i < ordinaryTextures.Length; i++)
{
texture2DArray.SetPixels(ordinaryTextures[i].GetPixels(0),
i, 0);
} // Apply our changes
texture2DArray.Apply(); // Set the texture to a material
objectToAddTextureTo.GetComponent<Renderer>()
.sharedMaterial.SetTexture("_MainTex", texture2DArray);
}
我觉得这个可以放到 Helper 里面
using UnityEngine;
namespace Universal
{
public class MaterialHelper
{
/// <summary>
/// All textures must have an identical width and height.
/// </summary>
/// <param name="ordinaryTextures"></param>
/// <param name="objectToAddTextureTo"></param>
public static void CreateTextureArray(Texture2D[] ordinaryTextures, GameObject objectToAddTextureTo)
{
// Create Texture2DArray
Texture2DArray texture2DArray = new
Texture2DArray(ordinaryTextures[0].width,
ordinaryTextures[0].height, ordinaryTextures.Length,
TextureFormat.RGBA32, true, false); // Apply settings
texture2DArray.filterMode = FilterMode.Bilinear;
texture2DArray.wrapMode = TextureWrapMode.Repeat; // Loop through ordinary textures and copy pixels to the
// Texture2DArray
for (int i = 0; i < ordinaryTextures.Length; i++)
{
texture2DArray.SetPixels(ordinaryTextures[i].GetPixels(0),
i, 0);
} // Apply our changes
texture2DArray.Apply(); // Set the texture to a material
objectToAddTextureTo.GetComponent<Renderer>()
.sharedMaterial.SetTexture("_MainTex", texture2DArray);
}
}
}
对于任意一个 mono,使用方法:
[Header("Material")]
public Texture2D[] mapGridTextures;
private void Awake()
{
MaterialHelper.CreateTextureArray(mapGridTextures, gameObject);
}
然后 shader 就使用默认的模板就好了
shader 的设置参考 catlikecoding.com/unity/tutor…
用例:在一个网格上,每一个格子的贴图是随机的
Shader "Unlit/UnlitGrid"
{
Properties
{
_MainTex ("Main Texture Array", 2DArray) = "white" {}
_GridTextureCount("Main Texture Array Length", int) = 1
_RandSeed("Rand Seed", float) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
#pragma target 3.5
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
float4 worldSpacePos : TEXCOORD1;
};
UNITY_DECLARE_TEX2DARRAY(_MainTex);
int _GridTextureCount;
float _RandSeed;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
o.worldSpacePos = mul(unity_ObjectToWorld, v.vertex);
return o;
}
float PHI = 1.61803398874989484820459; // Φ = Golden Ratio
float gold_noise(float2 xy){
return frac(tan(distance(xy*PHI, xy)*_RandSeed)*xy.x);
}
int random_range(float2 xy, int range)
{
float rand = gold_noise(xy);
return clamp(floor(rand * range), 0, range - 1);
}
fixed4 frag (v2f i) : SV_Target
{
float2 st = i.worldSpacePos.xy / _GridSize;
float2 ipos = floor(st); // integer
int rand = random_range(ipos, _GridTextureCount);
fixed4 col = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(i.uv, rand));
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
那么对于任意一个 mono,使用方法:
[Header("Material")]
public Texture2D[] mapGridTextures;
private void Awake()
{
MaterialHelper.CreateTextureArray(mapGridTextures, gameObject);
render.material.SetInt("_GridTextureCount", mapGridTextures.Length);
render.material.SetFloat("_RandSeed", Random.Range(1f, 100f));
}