Создание четырехмерной сетки с помощью скрипта
Для представления плоских поверхностей Unity включает примитивы Plane и Quad GameObjects, которые вы можете инстанционировать в своих сценах. Однако полезно понять, как использовать скрипт для построения четырехсторонней сетки самостоятельно. Это необходимо для процедурного создания сетки.
Примечание: Unity обрабатывает и отображает геометрию в треугольниках, а не в четырехугольниках. Это означает, что примитив Quad состоит из двух треугольников.
Вершинный массив
Первое, что вам нужно сделать, это настроить массив вершин, которые использует ваша форма.
В этом примере предполагается, что четырёхугольник лежит на осях x и y, и что ваш скрипт содержит переменные width и height.
Vector3[] vertices = new Vector3[4]
{
new Vector3(0, 0, 0),
new Vector3(width, 0, 0),
new Vector3(0, height, 0),
new Vector3(width, height, 0)
};
mesh.vertices = vertices;
В этом примере вершины представлены в следующем порядке:
- Внизу слева
- Внизу справа
- Верхний левый
- Вверху справа
Из-за способа, которым Unity извлекает свойства данных Mesh, гораздо эффективнее настроить данные в собственном массиве, а затем назначить массив свойству (например, Mesh.vertices или Mesh.normals), чем получать доступ к массиву свойств через отдельные элементы.
Треугольники
Затем вам нужно настроить треугольники. Четырёхугольник состоит из двух треугольников, каждый из которых состоит из трех точек в массиве вершин, который вы создали ранее. Чтобы указать точки, вы определяете каждый треугольник как три индекса массива вершин. Например, нижний левый треугольник для этого четырёхугольника использует индексы 0, 2, и 1, которые соответствуют координатам (0, 0, 0), (0, высота, 0), и (ширина, 0, 0) из массива вершин. Порядок важен, потому что вы должны упорядочить вершины по часовой стрелке. Верхний правый треугольник использует индексы 2, 3, и 1.
int[] tris = new int[6]
{
// lower left triangle
0, 2, 1,
// upper right triangle
2, 3, 1
};
mesh.triangles = tris;
Нормы
Сетка с вершинами и треугольниками видна в Scene, но Unity не затеняет ее правильно, потому что у нее еще нет нормалей. Нормы для этого примера просты, потому что все они идентичны. Каждая нормаль указывает на отрицательное направление оси z в локальном пространстве квада. Когда вы добавляете нормали, Unity правильно затеняет квад, но вам нужен Свет в Scene, чтобы увидеть эффект.
Vector3[] normals = new Vector3[4]
{
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
mesh.normals = normals;
Если вы не хотите определять нормы сами, вы можете использовать Mesh.RecalculateNormals().
Координаты текстуры
Наконец, чтобы отобразить текстуры на материале сетки правильно, добавьте координаты текстуры к сетке. Координаты текстуры находятся между 0 и 1. Каждая вершина в сетке имеет координату текстуры, которая указывает, где на текстуре материала взять образец. Чтобы показать всю текстуру через четыре, координаты текстуры на каждой вершине должны иметь значения 0 или 1, так что каждый угол четыре соответствует углу текстуры.
Vector2[] uv = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
mesh.uv = uv;
Окончательный скрипт
Следующий скрипт объединяет все вышеизложенное для создания квада в вашем Scene. Чтобы использовать его:
- Создайте новый скрипт C# (меню: Ассеты > Создать > MonoBehaviour Script) и дайте ему имя QuadCreator.
- Откройте скрипт QuadCreator, скопируйте в него примерный код и сохраните скрипт.
- Вернувшись в Редактор, создайте новый GameObject в вашем Scene (меню: GameObject > Создать пустой).
- В Inspector, выберите Добавить компонент > Сценарии > Quad Creator.
- Поместите GameObject туда, где вы хотите в Scene.
- Если вы не можете увидеть квадрант в представлении Scene или Game, убедитесь, что вы смотрите его с правильной стороны; Unity не рендирует заднюю поверхность этой сетки.
using UnityEngine;
public class QuadCreator : MonoBehaviour
{
public float width = 1;
public float height = 1;
public void Start()
{
MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
meshRenderer.sharedMaterial = new Material(Shader.Find("Standard"));
MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
Mesh mesh = new Mesh();
Vector3[] vertices = new Vector3[4]
{
new Vector3(0, 0, 0),
new Vector3(width, 0, 0),
new Vector3(0, height, 0),
new Vector3(width, height, 0)
};
mesh.vertices = vertices;
int[] tris = new int[6]
{
// lower left triangle
0, 2, 1,
// upper right triangle
2, 3, 1
};
mesh.triangles = tris;
Vector3[] normals = new Vector3[4]
{
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
mesh.normals = normals;
Vector2[] uv = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
mesh.uv = uv;
meshFilter.mesh = mesh;
}
}
Примечание: Этот пример кода находится в функции Start, что означает, что она выполняется один раз, когда вы вступаете в режим воспроизведения, и Mesh не меняется в течение всего приложения. Однако вы можете добавить код в функцию Update, чтобы Mesh менялся каждый кадр. Обратите внимание, что это значительно увеличивает ресурсоемкость генерации Mesh.