Я заметил, что вы действительно хотите сделать это только с помощью шейдера. Вы не можете сделать это с одним шейдером. Проблема не в том, чтобы генерировать случайное число в шейдере. Проблема заключается в возможности сделать это один раз . Я не нашел способ сделать это и не думаю, что вы можете.
Эта проблема должна решаться с помощью кода на стороне 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);
}
}