我注意到你真的很想用着色器来做这件事。你不能单独使用着色器来做到这一点。问题是无法在着色器中生成随机数。问题是能够做到一次。我还没有找到这样做的方法,也不认为你可以。
这是一个应该通过 C# 端的代码来解决的问题。
(1) 生成几个不同版本的材质,每个版本都有不同的平铺,并为每个立方体随机选择一个,这完全是微不足道的。这不是要走的路
(2) 请注意,如果您改变一种材料,它当然会产生不止一个副本。你不可能有成千上万种材料。
根本不是问题。这就是MaterialPropertyBlock
用途。它允许您修改着色器属性,而无需创建该材质的新实例。
“在您想用相同的材料绘制多个对象但属性略有不同的情况下使用它。” MaterialPropertyBlock
下面的代码会导致创建许多材质实例:
void Start()
{
MeshRenderer meshRenderer = gameObject.GetComponent<MeshRenderer>();
int tileX = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
int tileY = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
Vector2 tile = new Vector2(tileX, tileY);
meshRenderer.material.SetTextureScale("_MainTex", tile);
}
有了MaterialPropertyBlock
,这个问题就解决了。不制作材料副本。由于您关心性能,因此您还应该使用Shader.PropertyToID
:
void Start()
{
int propertyID = Shader.PropertyToID("_MainTex_ST");
meshRenderer = gameObject.GetComponent<MeshRenderer>();
int tileX = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
int tileY = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
Vector2 tile = new Vector2(tileX, tileY);
MaterialPropertyBlock matPropBlock = new MaterialPropertyBlock();
//Get the current MaterialPropertyBlock settings
meshRenderer.GetPropertyBlock(matPropBlock);
//Assign the new tile value
matPropBlock.SetVector(propertyID, tile);
//matPropBlock.SetVector(Shader.PropertyToID("_MainTex_ST"), tile);
//Apply the modified MaterialPropertyBlock back to the renderer
meshRenderer.SetPropertyBlock(matPropBlock);
}
如果在游戏中这样做了一次,那么将脚本附加到每个 GameObject 上并没有什么意义。只需将它附加到一个空的 GameObject 上,按标签查找所有对象,然后在每个对象上运行代码。
void Start()
{
GameObject[] objs = GameObject.FindGameObjectsWithTag("YourObjTag");
int propertyID = Shader.PropertyToID("_MainTex_ST");
for (int i = 0; i < objs.Length; i++)
{
MeshRenderer meshRenderer = objs[i].GetComponent<MeshRenderer>();
int tileX = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
int tileY = (UnityEngine.Random.Range(1, 3) == 1) ? 1 : -1;
Vector2 tile = new Vector2(tileX, tileY);
MaterialPropertyBlock matPropBlock = new MaterialPropertyBlock();
//Get the current MaterialPropertyBlock settings
meshRenderer.GetPropertyBlock(matPropBlock);
//Assign the new tile value
matPropBlock.SetVector(propertyID, tile);
//Apply the modified MaterialPropertyBlock back to the renderer
meshRenderer.SetPropertyBlock(matPropBlock);
}
}