Как оптимизировать физику на Unity?
Через Profiler на Unity я посмотрел что больше всего нагружает физика, а физичный объект у меня только вода. У меня есть пластины с динамическим мешом который изменяется с помощью perlinNoise каждый кадр и динамическим меш-колайдером который меняется с помощью этого куска:
Mesh myMesh = this.GetComponent<MeshFilter>().mesh;
DestroyImmediate(this.GetComponent<MeshCollider>());
gameObject.AddComponent<MeshCollider>();
GetComponent<MeshCollider>().sharedMesh = myMesh;
Edit: Вот сам код который генерирует воду:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WaterNoise : MonoBehaviour
{
public float power = 3;
public float scale = 1;
public float timeScale = 1;
float offsetX;
float offsetY;
MeshFilter mf;
private void Start()
{
mf = GetComponent<MeshFilter>();
GenNoise();
}
private void FixedUpdate()
{
GenNoise();
offsetX += Time.deltaTime * timeScale;
offsetY += Time.deltaTime * timeScale;
}
void GenNoise()
{
Vector3 myPos = transform.localPosition;
Vector3[] vertices = mf.mesh.vertices;
for(int i = 0; i < vertices.Length; i++)
{
vertices[i].y = CalculateHeight(vertices[i].x + myPos.x, vertices[i].z + myPos.z) * power;
}
Mesh myMesh = this.GetComponent<MeshFilter>().mesh;
DestroyImmediate(this.GetComponent<MeshCollider>());
gameObject.AddComponent<MeshCollider>();
GetComponent<MeshCollider>().sharedMesh = myMesh;
mf.mesh.vertices = vertices;
}
float CalculateHeight(float x, float y)
{
float xCoord = x * scale + offsetX;
float yCoord = y * scale + offsetY;
return Mathf.PerlinNoise(xCoord, yCoord);
}
}
Приложение однопоточное.
Никогда, нет, не так. НИКОГДА не изменяйте меш коллайдера в рантайме. Физический движок работает не так, как кажется со стороны. Чтобы меш действительно правильно и, главное, быстро просчитывал столкновения, движок производит некоторые достаточно дорогие манипуляции, которые происходят на этапе инициализации компонента MeshCollider.
Решение? Не делать то, что вы пытаетесь сделать.
Зачем каждый фрейм уничтожать компоненты и тут же создавать их заново?
Mesh myMesh = this.GetComponent<MeshFilter>().mesh; // копия меши
DestroyImmediate(this.GetComponent<MeshCollider>()); // уничтожения оригинального коллайдера
gameObject.AddComponent<MeshCollider>(); // добавление нового коллайдера
GetComponent<MeshCollider>().sharedMesh = myMesh; // обновление нового коллайдера
Mesh.vertices возвращает копию массива вершинReturns a copy of the vertex positions or assigns a new vertex positions array.
Поскольку меш изменяет только этот скрипт, то можно просто закэшировать этот массив 1 раз и не вызывать каждый физический фрейм Mesh.vertices, GC скажет вам спасибо:
private Mesh _sharedMesh;
private Vector3[] _vertices;
private MeshCollider _meshCollider;
private void Awake()
{
_sharedMesh = GetComponent<MeshFilter>().sharedMesh;
_vertices = _sharedMesh.vertices;
_meshCollider = GetComponent<MeshCollider>();
}
private void FixedUpdate()
{
// изменяем _vertices
// изменяем полигональную сетку
_sharedMesh.vertices = _vertices;
_sharedMesh.RecalculateBounds();
// отдаем эту сетку физическому движку
// это побудит его заново пересчитать сетку для физических взаимодействий
_meshCollider.sharedMesh = _sharedMesh;
}
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости