mesh generator работет медленно
Я делаю игру с генерацией мира, что-то похожее на майнкрафт, но без возможности разрушать блоки. Cтолкнулся с проблемой, скрипт который отрисовывает часть мира слишком долго думает. Хотел узнать есть ли способы оптимизировать либо уменьшить кол-во вычислений.
Вот код:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider))]
public class AGchunk : MonoBehaviour
{
public AGdata AGdata;
private List<Vector3> verticies = new List<Vector3>();
private List<Vector2> uvs = new List<Vector2>();
private List<int> triangles = new List<int>();
public Blockinfo[] Blocks;
private Mesh chunkMesh;
private float raduis = 94;
private float holeoffset;
AGBlockType[] Blockss = new AGBlockType[AGworld.LvlkWidth + (AGworld.LvlHeight + 2) *
AGworld.LvlkWidthSq + AGworld.LvlkWidth * AGworld.LvlkWidth];
public Vector3Int chankpos;
private int uborka = (AGworld.LvlkWidth / AGworld.ChunkWidth) - 1;
public GameObject Lamppref;
public GameObject HookBlockpref;
public Transform player;
public float VisionDistanse;
private float a;
bool generated;
void Start()
{
player = AGdata.Player;
a = VisionDistanse * 100;
holeoffset = AGworld.LvlkWidth / 2 - raduis ;
Blockss = AGdata.Blocks;
chunkMesh = new Mesh();
//RegenerateMesh();
StartCoroutine(RegenerateMesh());
GetComponent<MeshFilter>().sharedMesh = chunkMesh;
}
private IEnumerator RegenerateMesh()
{
verticies.Clear();
uvs.Clear();
triangles.Clear();
int a = Mathf.FloorToInt(gameObject.transform.position.x );
int b = Mathf.FloorToInt(gameObject.transform.position.z );
for (int y = 1; y < AGworld.ChunkHeight + 1; y++)
{
yield return new WaitForSecondsRealtime(0.005f);
for (int x = 0; x < AGworld.ChunkWidth; x++)
{
for (int z = 0; z < AGworld.ChunkWidth; z++)
{
GenerateBlock(x + a , y , z + b );
}
}
}
chunkMesh.triangles = new int[0];
chunkMesh.vertices = verticies.ToArray();
chunkMesh.uv = uvs.ToArray();
chunkMesh.triangles = triangles.ToArray();
chunkMesh.Optimize();
chunkMesh.RecalculateBounds(); //для коллайдеров и взаимодействия
chunkMesh.RecalculateNormals(); //для хорошего взвимодействия с освещением
GetComponent<MeshCollider>().sharedMesh = chunkMesh;
gameObject.transform.position = new Vector3(0, gameObject.transform.position.y, 0);
}
public void SpawnBlock(Vector3Int Blockpos)
{
int index = Blockpos.x + Blockpos.y * AGworld.LvlkWidthSq + Blockpos.z *
AGworld.LvlkWidth;
Blockss[index] = AGBlockType.Stone;
RegenerateMesh();
}
public void DestroyBlock(Vector3Int Blockpos)
{
int index = Blockpos.x + Blockpos.y * AGworld.LvlkWidthSq + Blockpos.z *
AGworld.LvlkWidth;
Blockss[index] = AGBlockType.Air;
RegenerateMesh();
}
void spawnhook(Vector3Int pos)
{
GameObject hk = Instantiate(HookBlockpref, new Vector3(0, 0, 0),
Quaternion.identity);
hk.transform.SetParent(gameObject.transform.parent.transform);
//Debug.Log("спавн"+ pos.x + " " + pos.y + " " + pos.z);
hk.transform.position = new Vector3(pos.x + 0.5f, pos.y +
gameObject.transform.parent.position.y + 0.5f, pos.z + 0.5f);
//hk.transform.localScale = new Vector3(2,2, 2);
//Renderer rend = hk.GetComponent<MeshRenderer>();
//rend.material = Resources.Load<Material>("AGDebugMat");
//hk.transform.SetParent(gameObject.transform);
if (GetBlockOnPos(pos + Vector3Int.right * 2) != AGBlockType.Air) {
hk.transform.Rotate(0, -90, 0); hk.name = "hook right"; }
else if (GetBlockOnPos(pos + Vector3Int.left * 2) != AGBlockType.Air) { hk.transform.Rotate(0, 90, 0); hk.name = "hook left"; }
else if (GetBlockOnPos(pos + Vector3Int.forward * 2) != AGBlockType.Air) { hk.transform.Rotate(0, 180, 0); hk.name = "hook forward"; }
else if (GetBlockOnPos(pos + Vector3Int.back * 2) != AGBlockType.Air) { hk.transform.Rotate(0, 0, 0); hk.name = "hook back"; }
else
{
Destroy(hk);
}
}
void spawnLamp(Vector3Int pos)
{
GameObject hk = Instantiate(Lamppref, new Vector3(0,0,0), Quaternion.identity);
hk.transform.SetParent(gameObject.transform.parent.transform);
hk.transform.position = new Vector3(pos.x + 0.5f, pos.y + gameObject.transform.parent.position.y + 0.2f, pos.z + 0.5f);
hk.name = "Lamp";
}
private void GenerateBlock(int x, int y, int z)
{
int a = Mathf.FloorToInt(gameObject.transform.position.x);
int b = Mathf.FloorToInt(gameObject.transform.position.z);
var Blockpos = new Vector3Int(x, y, z);
AGBlockType blockType = GetBlockOnPos(Blockpos);
if (blockType == AGBlockType.Air) return; //если в массиве по данным координатам нет блока то продолжаем
if (blockType == AGBlockType.Lamp || blockType == AGBlockType.Hook)
{
if (blockType == AGBlockType.Lamp)
{
spawnLamp(Blockpos);
}
if (blockType == AGBlockType.Hook)
{
spawnhook(Blockpos);
}
}
else
{
if (GetBlockOnPos(Blockpos + Vector3Int.right) == 0)
{
if (x - a == AGworld.ChunkWidth - 1 && chankpos.x == uborka)//или Blockpos.z == 0 убирает ненужные границы блоквоидного мира
{
}
else
{
GenRightSide(Blockpos);//проверка нет ли рядом блока для генерации сторон
AddUvs(GetBlockOnPos(Blockpos));
}
}
if (GetBlockOnPos(Blockpos + Vector3Int.left) == 0)
{
if (x - a == 0 && chankpos.x == 0)//или Blockpos.z == 0
{
}
else
{
GenLeftSide(Blockpos);
AddUvs(GetBlockOnPos(Blockpos));
}
}
if (GetBlockOnPos(Blockpos + Vector3Int.forward) == 0)
{
if (z - b == AGworld.ChunkWidth - 1 && chankpos.z == uborka)//или Blockpos.z == 0
{
}
else
{
GenFrontSide(Blockpos);
AddUvs(GetBlockOnPos(Blockpos));
}
}
if (GetBlockOnPos(Blockpos + Vector3Int.back) == 0)
{
if (z - b == 0 && chankpos.z == 0)//или Blockpos.z == 0
{
}
else
{
GenBackSide(Blockpos);
AddUvs(GetBlockOnPos(Blockpos));
}
}
if (GetBlockOnPos(Blockpos + Vector3Int.up) == 0)//
{
GenTopSide(Blockpos);
AddUvs(GetBlockOnPos(Blockpos));
}
if (GetBlockOnPos(Blockpos + Vector3Int.down) == 0)//&& Blockpos.y > 0
{
GenBottomSide(Blockpos);
AddUvs(GetBlockOnPos(Blockpos));
}
}
}
private AGBlockType GetBlockOnPos(Vector3Int blockposition)//возвращает блок по положению - проверка координат
{
float opt4 = Vector2.Distance(new Vector3(blockposition.x, blockposition.z), Vector2.one * raduis + new Vector2(holeoffset, holeoffset));
if (opt4 >= AGTerrainGenerator.raduis && opt4 >= AGTerrainGenerator.raduis + AGTerrainGenerator.bloksafterradius + 1)
{
return AGBlockType.Stone;
}
else
{
if (blockposition.x >= 0 && blockposition.x < AGworld.LvlkWidth &&
blockposition.y >= 0 && blockposition.y < AGworld.LvlHeight + 2 &&
blockposition.z >= 0 && blockposition.z < AGworld.LvlkWidth)
{
int index = blockposition.x + blockposition.y * AGworld.LvlkWidthSq + blockposition.z * AGworld.LvlkWidth;
return Blockss[index];
}
else
{
return AGBlockType.Air;
}
}
}
private void GenRightSide(Vector3Int blockposition)
{
//вершины квадрата
verticies.Add(new Vector3(1, 0, 0) + blockposition);
verticies.Add(new Vector3(1, 1, 0) + blockposition);
verticies.Add(new Vector3(1, 0, 1) + blockposition);
verticies.Add(new Vector3(1, 1, 1) + blockposition);
AddLastVerticiesSquere();
}
private void GenLeftSide(Vector3Int blockposition)
{
//вершины квадрата
verticies.Add(new Vector3(0, 0, 0) + blockposition);
verticies.Add(new Vector3(0, 0, 1) + blockposition);
verticies.Add(new Vector3(0, 1, 0) + blockposition);
verticies.Add(new Vector3(0, 1, 1) + blockposition);
AddLastVerticiesSquere();
}
private void GenFrontSide(Vector3Int blockposition) //передняя
{
//вершины квадрата
verticies.Add(new Vector3(0, 0, 1) + blockposition);
verticies.Add(new Vector3(1, 0, 1) + blockposition);
verticies.Add(new Vector3(0, 1, 1) + blockposition);
verticies.Add(new Vector3(1, 1, 1) + blockposition);
AddLastVerticiesSquere();
}
private void GenBackSide(Vector3Int blockposition) //передняя
{
//вершины квадрата
verticies.Add(new Vector3(0, 0, 0) + blockposition);
verticies.Add(new Vector3(0, 1, 0) + blockposition);
verticies.Add(new Vector3(1, 0, 0) + blockposition);
verticies.Add(new Vector3(1, 1, 0) + blockposition);
AddLastVerticiesSquere();
}
private void GenTopSide(Vector3Int blockposition) //передняя
{
//вершины квадрата
verticies.Add(new Vector3(0, 1, 0) + blockposition);
verticies.Add(new Vector3(0, 1, 1) + blockposition);
verticies.Add(new Vector3(1, 1, 0) + blockposition);
verticies.Add(new Vector3(1, 1, 1) + blockposition);
AddLastVerticiesSquere();
}
private void GenBottomSide(Vector3Int blockposition) //передняя
{
//вершины квадрата
verticies.Add(new Vector3(0, 0, 0) + blockposition);
verticies.Add(new Vector3(1, 0, 0) + blockposition);
verticies.Add(new Vector3(0, 0, 1) + blockposition);
verticies.Add(new Vector3(1, 0, 1) + blockposition);
AddLastVerticiesSquere();
}
private void AddLastVerticiesSquere()
{
//первый треугольник
triangles.Add(verticies.Count - 4); //0
triangles.Add(verticies.Count - 3); //1
triangles.Add(verticies.Count - 2); //2
//второй треугольник
triangles.Add(verticies.Count - 3); //1
triangles.Add(verticies.Count - 1); //3
triangles.Add(verticies.Count - 2); //2
}
private void AddUvs(AGBlockType blockType)
{
//uvs.Add(new Vector2(0, 0));
//uvs.Add(new Vector2(0, 1));
//uvs.Add(new Vector2(1, 0));
//uvs.Add(new Vector2(1, 1));
Blockinfo info = Blocks.FirstOrDefault(b => b.Type == blockType);
if (info != null)
{
uvs.Add(new Vector2(info.PixelOffset.x / 64, info.PixelOffset.y / 64));
uvs.Add(new Vector2(info.PixelOffset.x / 64, (info.PixelOffset.y + 16f) / 64));
uvs.Add(new Vector2((info.PixelOffset.x + 16f) / 64, info.PixelOffset.y / 64));
uvs.Add(new Vector2((info.PixelOffset.x + 16f) / 64, (info.PixelOffset.y + 16f) / 64));
}
else
{
uvs.Add(new Vector2(16f / 64, 48f / 64));//левая нижняя точка
uvs.Add(new Vector2(16f / 64, 1));//левая верхняя точка
uvs.Add(new Vector2(32f / 64, 48f / 64));//правая нижняя
uvs.Add(new Vector2(32f / 64, 1));//правая верхняя
}
}
}
Источник: Stack Overflow на русском