суббота, 19 апреля 2014 г.
пятница, 11 апреля 2014 г.
Разрушение объектов на кусочки. Mesh destruction
Привет юнити девелопер ! Сегодня хочу поделится своим опытом в создании интересного эффекта для игры.
Игра называется AlcoInvaders, поэтому события происходят в космосе.
Особенностью игры должны стать визуальные эффекты и разрушение всего,что в игре можно увидеть . Поэтому реалистичные взрывы - очень важная часть игры.
Update:
Речь пойдет о том, как сделать эффект разрушения объекта на части (mesh destruction) . В этом мне помог плагин Exploder (asset store link). При желании его можно найти и на других сайтах.
Сам плагин неплохо взрывает объекты, но когда нужно взрывать много моделей, то начинаются проблемы с производительностью. Взрывы начинают подвисать и играть становится сложно.
Чтобы решить эту проблему я немного переписал код плагина. Главная идея в том, чтобы сохранять полученные кусочки модели как ассеты и потом заменять ими модель во время взрыва. Это очень улучшает производительность и уменьшения FPS практически нету.
Вот как выглядят полученные кусочки изначально :
Чтобы создать такой взрыв - создаем в сцене объект со скриптом ExploderObject. Нужную модель отмечаем тегом "Explode" и вызываем функцию Explode() у ExploderObject. Вот его параметры.
Если поставить Force > 0 то частички будут разлетаться как при взрыве ( на скриншоте) . Но если Force =0 то частички останутся на своих местах и их можно будет сохранить. Также лучше заблокировать движение частиц через параметры Freeze Position X,Y,Z и Freeze Rotation X,Y,Z .
Для этого я изменил код скрипта FragmentPool. Ее можно вызывать сразу после разрушения нужного мэша.
public void SaveMeshes()
{
int count=0;
string folder_name="fragment"+Random.RandomRange(1,1000);
AssetDatabase.CreateFolder("Assets/fragments", folder_name);
foreach (Fragment frag in pool)
{
if (frag.gameObject.activeInHierarchy)
{
GameObject obj=PrefabUtility.CreatePrefab("Assets/fragments/" + folder_name + "/part" + count + ".prefab", frag.gameObject);
obj.GetComponent<MeshFilter>().mesh = frag.meshFilter.sharedMesh;
AssetDatabase.CreateAsset(frag.meshFilter.sharedMesh,"Assets/fragments/"+folder_name+"/part"+folder_name+count+".asset");
AssetDatabase.SaveAssets();
count++;
}
}
}
Функция будет сохранять кусочки всех взорванных моделей. Поэтому для сохранения фрагментов каждого объекта лучше перезапускать сцену.
В результате полученные кусочки можно сохранить для дальнейшего использования.
В полученных фрагментах лучше убрать все скрипты и MeshCollider заменить на SphereCollider. Также частички можно пометить как отдельный layer и выключить его столкновения друг с другом (Project Setting-> Physics )
После этого все фрагменты можно объединить в один объект и прикрепить к нему скрипт взрыва. Например такой :
void Start () {
Time.timeScale = 1f;
Collider[] MeshList=gameobject.transform.GetComponentsInChildren<Collider>();
foreach (Collider m in MeshList)
{
m.rigidbody.AddExplosionForce(Random.Range(1500f,3000f), m.transform.position, 100f, 0f);
}
}
У нас получился объект взрыва частичек. Его нужно создавать в сцене сразу при взрыве модели ( в моем случае корабля ). Результат будет примерно такой:
- Для оптимизации можно создать low-poly модель разрушаемого обьекта и разрушать ее. При взрыве разницу будет мало заметно, даже если уменьшить колличество полигонов в 3-4 раза
(например в Maya через Polygon>Cleanup а потом Polygon>Reduce )
- Для всех полученных кусочков старайтесь использовать один и тот же материал. Это значительно уменьшит колличество Drawcall.
- Для тех, кто дочитал до конца - даю прямую ссылку на сам плагин :) Exploder 1.2
Спасибо за интерес к материалу. Подписывайтесь в twitter @Oxygamer . Буду рад любым предложениям и вопросам.
среда, 9 апреля 2014 г.
Подписаться на:
Сообщения (Atom)