Buoyancy - плавучие объекты

Лучший способ помочь другим, поделиться своими находками.

Buoyancy - плавучие объекты

Сообщение alexz 05 янв 2011, 04:20

Изображение

Дано: вода, бревно

Задача: заставить бревно реалистично плавать

---------------------------------------------------------------------------------------------------------------------------------------
На бревно в воде действуют две силы: сила тяготения и сила Архимеда, выталкавающая бревно наверх. Тяготение и так уже есть силами Unity, так что остаётся только смоделировать выталкивание.

Известно, что сила Архимеда действует только на погруженную в воду часть тела и численно она равна:

Сила Архимеда = (плотность воды) * (ускорение свободного падения) * (объем тела, погруженный в воду)

Плотность воды ― константа, 1000 кг/(м^3).
Ускорение свободного падения ― тоже константа. Для универсальности её можно прочитать из Physics.gravity.
Объем тела, погруженный в воду ― с этим сложнее. При большом желании его можно было бы расчитать, но во-первых, для произвольного тела это сложно, а во-вторых, заниматься этим в рилтайме в функции обработки физики нехорошо, т.к. долго. Будем прикидывать приблизительно:

Путь у нас будет не бревно, а параллепипед. Разобьём его по всём трём осям на сектора, из каждого сектора будем брать центральную точку и смотреть, находится она над водой или под водой:

Изображение

Синтаксис:
Используется csharp
const int SECTORS = 3;
List<Vector3> points;

var collider = GetComponent<Collider>();
var bounds = collider.bounds;

for (int ix = 0; ix < SECTORS; ix++)
{
        for (int iy = 0; iy < SECTORS; iy++)
        {
                for (int iz = 0; iz < SECTORS; iz++)
                {
                        float x = bounds.min.x + bounds.size.x / SECTORS * (0.5f + ix);
                        float y = bounds.min.y + bounds.size.y / SECTORS * (0.5f + iy);
                        float z = bounds.min.z + bounds.size.z / SECTORS * (0.5f + iz);

                        // Переводим точку из мировой в локальную систему координат
                        var p = transform.InverseTransformPoint(new Vector3(x, y, z));

                        points.Add(p);
                }
        }
}


Сила Архимеда для каждого сектора = 1000 кг/(м^3) * 9,81 м/(c^2) * (объем сектора)
Суммарная сила Архимеда = 1000 * 9,81 * (объем сектора) * (количество секторов под водой)
Если всё тело целиком находится под водой, то сила Архимеда = 1000 * 9,81 * (объем тела)

Где взять объём тела? Высчитывать по сетке объекта не будем (всё равно не каждая сетка это позволит), возьмём грубо половину объёма от bounding box:

Синтаксис:
Используется csharp
var collider = GetComponent<Collider>();
var bounds = collider.bounds;

float volume = bounds.size.x * bounds.size.y * bounds.size.z / 2;


Все сектора у нас одинаковые и нет смысла считать силу Архимеда для каждого из них, потому что она будет равна (силе Архимеда для всего тела) / (количество секторов). Поэтому расчитаем силу только один раз и заранее:

Синтаксис:
Используется csharp
const float WATER_DENSITY = 1000;

float archimedesForceMagnitude = WATER_DENSITY * Mathf.Abs(Physics.gravity.y) * volume;
Vector3 archimedesForce = new Vector3(0, archimedesForceMagnitude, 0);


Теперь все исходные данные у нас есть, можно приступать к прикладыванию силы Архимеда к объекту:
Синтаксис:
Используется csharp
void FixedUpdate()
{
        foreach (var point in points)
        {
                // Переводим точку из локальной в мировую систему координат
                var wp = transform.TransformPoint(point);

                // Функция GetWaterLevel(x,z) возвращает или просто ноль, или высоту воды в заданной позиции, если на воде есть волны.
                var waterLevel = GetWaterLevel(wp.x, wp.z);

                if (wp.y < waterLevel)
                {
                        var force = archimedesForce / points.Count;
                        rigidbody.AddForceAtPosition(force, wp);
                }
        }
}


---------------------------------------------------------------------------------------------------------------------------------------

Практика показала, что оно работает, но есть две проблемки:

1) Если тело падает в воду, то оно из неё выпрыгивает обратно, потом опять падает и так до бесконечности.
2) Если тело дрейфует по воде, оно заметно дёргается вверх-вниз, потому что сила Архимеда, приложенная к объекту, никогда не совпадает точно с силой тяжести, потому что изменяется дискретно. Один сектор ушёл под воду ― сила резко увеличилась, поднялся над водой ― резко уменьшилась.

Первую проблему можно решить демпфером ― будем гасить скорость тем секторам, которые оказались под водой. Будет даже реалистично. Приложим силу, пропорциональную скорости движения, но обратную по направлению:

Синтаксис:
Используется csharp
const float DAMPFER = 100;

var velocity = rigidbody.GetPointVelocity(wp);
var localDampingForce = -velocity * DAMPFER;
 


А чтобы убрать дискретность у силы выталкивания, добавим к ней коэффициент, который будет плавно меняться, когда центр сектора будет около поверхности воды:
Изображение

delta ― это половина высоты сектора.

Синтаксис:
Используется csharp
float delta;

var collider = GetComponent<Collider>();
var bounds = collider.bounds;

if (bounds.size.x < bounds.size.y)
{
        delta = bounds.size.x;
}
else
{
        delta = bounds.size.y;
}

if (bounds.size.z < delta)
{
        delta = bounds.size.z;
}
delta /= 2 * SECTORS;


Когда весь сектор под водой, коэффициент = 1,0 и на сектор будет действовать полная сила Архимеда. Когда только полсектора под водой, то коэффициент = 0,5. Если весь сектор над водой, коэффициент = 0 и сила выталкивания будет равна нулю:

Синтаксис:
Используется csharp
void FixedUpdate()
{
        foreach (var point in points)
        {
                var wp = transform.TransformPoint(point);

                var waterLevel = GetWaterLevel(wp.x, wp.z);

                if (wp.y - delta < waterLevel)
                {
                        var velocity = rigidbody.GetPointVelocity(wp);

                        float k = (waterLevel - wp.y) / (2 * delta) + 0.5f;

                        if (k > 1)
                        {
                                k = 1f;
                        }
                        else if (k < 0)
                        {
                                k = 0f;
                        }

                        var localDampingForce = -velocity * DAMPFER;
                        var localArchimedesForce = Mathf.Sqrt(k) * archimedesForce / points.Count;
                               
                        var force = localDampingForce + localArchimedesForce;

                        rigidbody.AddForceAtPosition(force, wp);
                }
        }
}


Квадратный корень из коэффициента Mathf.Sqrt(k) можно было и не брать, но с ним показалось естественнее.

---------------------------------------------------------------------------------------------------------------------------------------
F ― полный экран
левая кнопка мыши ― бросить бревно
R ― вкл/выкл отражения
С ― «срубить» дерево
левый Shift ― ускорение времени

HTML код для вашего блога :
Код: Выделить всё
<script language='javascript' type="text/javascript"> document.write("<iframe marginheight='0' src='http://unity3d.ru/distribution/player.php?url=http://dl.dropbox.com/u/8203557/island4.unity3d&w=600&h=400&t=false&preview=1' height='"+(400+30)+"' width='600' frameborder='0' scrolling='no'></iframe>"); </script>


---------------------------------------------------------------------------------------------------------------------------------------
Версия 2.1

― Для удобства плотность объекта задаётся вручную; измеряется в кг/(м^3). У воды 1000, у древесины 500―700.
― Умеет работать с вогнутыми объектами.
― В целях отладки умеет рисовать gizmos с точками приложения силы выталкивания.

Изображение Изображение Изображение

Синтаксис:
Используется csharp
// Buoyancy.cs
// by Alex Zhdankin
// Version 2.1
//
// http://forum.unity3d.com/threads/72974-Buoyancy-script
//
// Terms of use: do whatever you like

using System.Collections.Generic;
using UnityEngine;

public class Buoyancy : MonoBehaviour
{
//      public Ocean ocean;

        public float density = 500;
        public int slicesPerAxis = 2;
        public bool isConcave = false;
        public int voxelsLimit = 16;

        private const float DAMPFER = 0.1f;
        private const float WATER_DENSITY = 1000;

        private float voxelHalfHeight;
        private Vector3 localArchimedesForce;
        private List<Vector3> voxels;
        private bool isMeshCollider;
        private List<Vector3[]> forces; // For drawing force gizmos

        /// <summary>
        /// Provides initialization.
        /// </summary>
        private void Start()
        {
                forces = new List<Vector3[]>(); // For drawing force gizmos

                // Store original rotation and position
                var originalRotation = transform.rotation;
                var originalPosition = transform.position;
                transform.rotation = Quaternion.identity;
                transform.position = Vector3.zero;

                // The object must have a collider
                if (collider == null)
                {
                        gameObject.AddComponent<MeshCollider>();
                        Debug.LogWarning(string.Format("[Buoyancy.cs] Object \"{0}\" had no collider. MeshCollider has been added.", name));
                }
                isMeshCollider = GetComponent<MeshCollider>() != null;

                var bounds = collider.bounds;
                if (bounds.size.x < bounds.size.y)
                {
                        voxelHalfHeight = bounds.size.x;
                }
                else
                {
                        voxelHalfHeight = bounds.size.y;
                }
                if (bounds.size.z < voxelHalfHeight)
                {
                        voxelHalfHeight = bounds.size.z;
                }
                voxelHalfHeight /= 2 * slicesPerAxis;

                // The object must have a RidigBody
                if (rigidbody == null)
                {
                        gameObject.AddComponent<Rigidbody>();
                        Debug.LogWarning(string.Format("[Buoyancy.cs] Object \"{0}\" had no Rigidbody. Rigidbody has been added.", name));
                }
                rigidbody.centerOfMass = new Vector3(0, -bounds.extents.y * 0f, 0) + transform.InverseTransformPoint(bounds.center);

                voxels = SliceIntoVoxels(isMeshCollider && isConcave);

                // Restore original rotation and position
                transform.rotation = originalRotation;
                transform.position = originalPosition;

                float volume = rigidbody.mass / density;

                WeldPoints(voxels, voxelsLimit);

                float archimedesForceMagnitude = WATER_DENSITY * Mathf.Abs(Physics.gravity.y) * volume;
                localArchimedesForce = new Vector3(0, archimedesForceMagnitude, 0) / voxels.Count;

                Debug.Log(string.Format("[Buoyancy.cs] Name=\"{0}\" volume={1:0.0}, mass={2:0.0}, density={3:0.0}", name, volume, rigidbody.mass, density));
        }

        /// <summary>
        /// Slices the object into number of voxels represented by their center points.
        /// <param name="concave">Whether the object have a concave shape.</param>
        /// <returns>List of voxels represented by their center points.</returns>
        /// </summary>
        private List<Vector3> SliceIntoVoxels(bool concave)
        {
                var points = new List<Vector3>(slicesPerAxis * slicesPerAxis * slicesPerAxis);

                if (concave)
                {
                        var meshCol = GetComponent<MeshCollider>();

                        var convexValue = meshCol.convex;
                        meshCol.convex = false;

                        // Concave slicing
                        var bounds = collider.bounds;
                        for (int ix = 0; ix < slicesPerAxis; ix++)
                        {
                                for (int iy = 0; iy < slicesPerAxis; iy++)
                                {
                                        for (int iz = 0; iz < slicesPerAxis; iz++)
                                        {
                                                float x = bounds.min.x + bounds.size.x / slicesPerAxis * (0.5f + ix);
                                                float y = bounds.min.y + bounds.size.y / slicesPerAxis * (0.5f + iy);
                                                float z = bounds.min.z + bounds.size.z / slicesPerAxis * (0.5f + iz);

                                                var p = transform.InverseTransformPoint(new Vector3(x, y, z));

                                                if (PointIsInsideMeshCollider(meshCol, p))
                                                {
                                                        points.Add(p);
                                                }
                                        }
                                }
                        }
                        if (points.Count == 0)
                        {
                                points.Add(bounds.center);
                        }

                        meshCol.convex = convexValue;
                }
                else
                {
                        // Convex slicing
                        var bounds = GetComponent<Collider>().bounds;
                        for (int ix = 0; ix < slicesPerAxis; ix++)
                        {
                                for (int iy = 0; iy < slicesPerAxis; iy++)
                                {
                                        for (int iz = 0; iz < slicesPerAxis; iz++)
                                        {
                                                float x = bounds.min.x + bounds.size.x / slicesPerAxis * (0.5f + ix);
                                                float y = bounds.min.y + bounds.size.y / slicesPerAxis * (0.5f + iy);
                                                float z = bounds.min.z + bounds.size.z / slicesPerAxis * (0.5f + iz);

                                                var p = transform.InverseTransformPoint(new Vector3(x, y, z));

                                                points.Add(p);
                                        }
                                }
                        }
                }

                return points;
        }

        /// <summary>
        /// Returns whether the point is inside the mesh collider.
        /// </summary>
        /// <param name="c">Mesh collider.</param>
        /// <param name="p">Point.</param>
        /// <returns>True - the point is inside the mesh collider. False - the point is outside of the mesh collider. </returns>
        private static bool PointIsInsideMeshCollider(Collider c, Vector3 p)
        {
                Vector3[] directions = { Vector3.up, Vector3.down, Vector3.left, Vector3.right, Vector3.forward, Vector3.back };

                foreach (var ray in directions)
                {
                        RaycastHit hit;
                        if (c.Raycast(new Ray(p - ray * 1000, ray), out hit, 1000f) == false)
                        {
                                return false;
                        }
                }

                return true;
        }

        /// <summary>
        /// Returns two closest points in the list.
        /// </summary>
        /// <param name="list">List of points.</param>
        /// <param name="firstIndex">Index of the first point in the list. It's always less than the second index.</param>
        /// <param name="secondIndex">Index of the second point in the list. It's always greater than the first index.</param>
        private static void FindClosestPoints(IList<Vector3> list, out int firstIndex, out int secondIndex)
        {
                float minDistance = float.MaxValue, maxDistance = float.MinValue;
                firstIndex = 0;
                secondIndex = 1;

                for (int i = 0; i < list.Count - 1; i++)
                {
                        for (int j = i + 1; j < list.Count; j++)
                        {
                                float distance = Vector3.Distance(list[i], list[j]);
                                if (distance < minDistance)
                                {
                                        minDistance = distance;
                                        firstIndex = i;
                                        secondIndex = j;
                                }
                                if (distance > maxDistance)
                                {
                                        maxDistance = distance;
                                }
                        }
                }
        }

        /// <summary>
        /// Welds closest points.
        /// </summary>
        /// <param name="list">List of points.</param>
        /// <param name="targetCount">Target number of points in the list.</param>
        private static void WeldPoints(IList<Vector3> list, int targetCount)
        {
                if (list.Count <= 2 || targetCount < 2)
                {
                        return;
                }

                while (list.Count > targetCount)
                {
                        int first, second;
                        FindClosestPoints(list, out first, out second);

                        var mixed = (list[first] + list[second]) * 0.5f;
                        list.RemoveAt(second); // the second index is always greater that the first => removing the second item first
                        list.RemoveAt(first);
                        list.Add(mixed);
                }
        }

        /// <summary>
        /// Returns the water level at given location.
        /// </summary>
        /// <param name="x">x-coordinate</param>
        /// <param name="z">z-coordinate</param>
        /// <returns>Water level</returns>
        private float GetWaterLevel(float x, float z)
        {
//              return ocean == null ? 0.0f : ocean.GetWaterHeightAtLocation(x, z);
                return 0.0f;
        }

        /// <summary>
        /// Calculates physics.
        /// </summary>
        private void FixedUpdate()
        {
                forces.Clear(); // For drawing force gizmos

                foreach (var point in voxels)
                {
                        var wp = transform.TransformPoint(point);
                        float waterLevel = GetWaterLevel(wp.x, wp.z);

                        if (wp.y - voxelHalfHeight < waterLevel)
                        {
                                float k = (waterLevel - wp.y) / (2 * voxelHalfHeight) + 0.5f;
                                if (k > 1)
                                {
                                        k = 1f;
                                }
                                else if (k < 0)
                                {
                                        k = 0f;
                                }

                                var velocity = rigidbody.GetPointVelocity(wp);
                                var localDampingForce = -velocity * DAMPFER * rigidbody.mass;
                                var force = localDampingForce + Mathf.Sqrt(k) * localArchimedesForce;
                                rigidbody.AddForceAtPosition(force, wp);

                                forces.Add(new[] { wp, force }); // For drawing force gizmos
                        }
                }
        }

        /// <summary>
        /// Draws gizmos.
        /// </summary>
        private void OnDrawGizmos()
        {
                if (voxels == null || forces == null)
                {
                        return;
                }

                const float gizmoSize = 0.05f;
                Gizmos.color = Color.yellow;

                foreach (var p in voxels)
                {
                        Gizmos.DrawCube(transform.TransformPoint(p), new Vector3(gizmoSize, gizmoSize, gizmoSize));
                }

                Gizmos.color = Color.cyan;

                foreach (var force in forces)
                {
                        Gizmos.DrawCube(force[0], new Vector3(gizmoSize, gizmoSize, gizmoSize));
                        Gizmos.DrawLine(force[0], force[0] + force[1] / rigidbody.mass);
                }
        }
}
Последний раз редактировалось alexz 07 янв 2011, 21:54, всего редактировалось 7 раз(а).
alexz
UNITрон
 
Сообщения: 270
Зарегистрирован: 16 ноя 2010, 23:37

Re: Buoyancy - плавучие объекты

Сообщение DbIMok 05 янв 2011, 10:30

молодец, что не поленился все расписать, оформить и т.д.
(3A4OT)
чисто по скриншоту ориентируясь, я бы сказал, что бревна слишком сильно притоплены
правильный вопрос - половина ответа. учитесь формулировать вопросы понятно.
Новости > _Telegram чат @unity3d_ru (11.6k/4.8k online) > _Telegram канал @unity_news (4.6k подписчиков) > Телеграм тема > "Спасибо"
Аватара пользователя
DbIMok
Адепт
 
Сообщения: 6372
Зарегистрирован: 31 июл 2009, 14:05

Re: Buoyancy - плавучие объекты

Сообщение Neodrop 05 янв 2011, 12:26

(3A4OT)

Отличная работа. Спасибо за открытость \m/
Добавить neodrop в Skype
Изображение
"Спасибо!" нашему порталу, вы сможете сказать ЗДЕСЬ.
Если проблема не решается честно, нужно её обмануть! || Per stupiditas at Astra!
Страх порождает слабость. Бесстрашных поражают пули.
Протратившись на блядях байтах, на битах не экономят.
Аватара пользователя
Neodrop
Админ
 
Сообщения: 8480
Зарегистрирован: 08 окт 2008, 15:42
Откуда: Питер
Skype: neodrop
  • Сайт

Re: Buoyancy - плавучие объекты

Сообщение sp00n 05 янв 2011, 12:59

(3A4OT) Спасибо огромное!
Ты молод, креативен, талантлив?
Амбициозен, уверен в себе, полон свежих идей?
А делать хоть что-нибудь умеешь?!
sp00n
UNITрон
 
Сообщения: 254
Зарегистрирован: 27 фев 2010, 20:43

Re: Buoyancy - плавучие объекты

Сообщение alexz 05 янв 2011, 18:02

DbIMok писал(а):чисто по скриншоту ориентируясь, я бы сказал, что бревна слишком сильно притоплены

Да, у них большая плотность: 800...1000 кг/(м^3). Если ходить по таким брёвнам, они под тяжестью игрока уходят под воду.

Вот брёвна с плотностью 600..700, примерно такая она у древесины и есть.
Изображение
alexz
UNITрон
 
Сообщения: 270
Зарегистрирован: 16 ноя 2010, 23:37

Re: Buoyancy - плавучие объекты

Сообщение depsemt 05 янв 2011, 18:53

(3A4OT)
Автор, ты очень молодец!!!!))
depsemt
UNIт
 
Сообщения: 73
Зарегистрирован: 26 июл 2010, 04:25

Re: Buoyancy - плавучие объекты

Сообщение ScorpionMax 05 янв 2011, 21:08

Здравствуйте. Я Скопировал скрипт, но на версии 3.1.0.4F не работает, скрипт не виден. Что делать, возможно это из-за того что я создал не в шарпе а в обычном текстовике и вставил скопированный скрипт?
3D max 2011, Photoshop CS и CS5. Game Develop Unity3D...
Аватара пользователя
ScorpionMax
UNIт
 
Сообщения: 61
Зарегистрирован: 28 дек 2010, 11:51

Re: Buoyancy - плавучие объекты

Сообщение alexz 05 янв 2011, 21:20

ScorpionMax писал(а):Здравствуйте. Я Скопировал скрипт, но на версии 3.1.0.4F не работает, скрипт не виден. Что делать, возможно это из-за того что я создал не в шарпе а в обычном текстовике и вставил скопированный скрипт?

Получившийся файл должен называться Buoyancy.cs
Не Buoyancy.txt и не Buoyancy.cs.txt
alexz
UNITрон
 
Сообщения: 270
Зарегистрирован: 16 ноя 2010, 23:37

Re: Buoyancy - плавучие объекты

Сообщение WebWolf 05 янв 2011, 21:53

alexz писал(а):
ScorpionMax писал(а):Здравствуйте. Я Скопировал скрипт, но на версии 3.1.0.4F не работает, скрипт не виден. Что делать, возможно это из-за того что я создал не в шарпе а в обычном текстовике и вставил скопированный скрипт?

Получившийся файл должен называться Buoyancy.cs
Не Buoyancy.txt и не Buoyancy.cs.txt

А можно исходник сцены? :-) (popcorn1)
WTF? _WolfGames3D.com / Все в Tanks Heroes Вконтакте!
Аватара пользователя
WebWolf
Старожил
 
Сообщения: 532
Зарегистрирован: 19 дек 2009, 15:49
Откуда: Russian Federation
  • Сайт
  • ICQ

Re: Buoyancy - плавучие объекты

Сообщение alexz 05 янв 2011, 22:00

150 Мб
Нормально или сделать простенький текстовый проект?
alexz
UNITрон
 
Сообщения: 270
Зарегистрирован: 16 ноя 2010, 23:37

Re: Buoyancy - плавучие объекты

Сообщение ScorpionMax 06 янв 2011, 00:38

alexz писал(а):
ScorpionMax писал(а):Здравствуйте. Я Скопировал скрипт, но на версии 3.1.0.4F не работает, скрипт не виден. Что делать, возможно это из-за того что я создал не в шарпе а в обычном текстовике и вставил скопированный скрипт?

Получившийся файл должен называться Buoyancy.cs
Не Buoyancy.txt и не Buoyancy.cs.txt


У меня все правильно, я умею это делать, и работать с расширениями файлов.
Вот собственно...
Изображение
3D max 2011, Photoshop CS и CS5. Game Develop Unity3D...
Аватара пользователя
ScorpionMax
UNIт
 
Сообщения: 61
Зарегистрирован: 28 дек 2010, 11:51

Re: Buoyancy - плавучие объекты

Сообщение alexz 06 янв 2011, 01:01

А в каком смысле «скрипт не виден»? Его нельзя повесить на объект или можно, но он не работает? Судя по тому, что скрипт успешно компилируется, по крайней мере, его должно быть видно.

Чтобы скрипт делал что-то полезное, у объекта должен быть какой-нибудь коллайдер, Rigidbody и должна быть указана какая-нибудь правдоподобная масса. Для куба размером 1м лучший результат получается, если масса от нескольких сотен килограмм до тонны. Если больше, куб утонет.
alexz
UNITрон
 
Сообщения: 270
Зарегистрирован: 16 ноя 2010, 23:37

Re: Buoyancy - плавучие объекты

Сообщение ScorpionMax 06 янв 2011, 01:17

alexz писал(а):А в каком смысле «скрипт не виден»? Его нельзя повесить на объект или можно, но он не работает? Судя по тому, что скрипт успешно компилируется, по крайней мере, его должно быть видно.

Чтобы скрипт делал что-то полезное, у объекта должен быть какой-нибудь коллайдер, Rigidbody и должна быть указана какая-нибудь правдоподобная масса. Для куба размером 1м лучший результат получается, если масса от нескольких сотен килограмм до тонны. Если больше, куб утонет.


Я все сделал, теперь скрипт виден, назначается обьекту, но он исчезает при касание с терайном и водой...
3D max 2011, Photoshop CS и CS5. Game Develop Unity3D...
Аватара пользователя
ScorpionMax
UNIт
 
Сообщения: 61
Зарегистрирован: 28 дек 2010, 11:51

Re: Buoyancy - плавучие объекты

Сообщение alexz 06 янв 2011, 01:35

ScorpionMax писал(а):Я все сделал, теперь скрипт виден, назначается обьекту, но он исчезает при касание с терайном и водой...

Какие у объекта размеры, масса?

---
Немного обновил скрипт в первом сообщении:
1) Теперь он сам добавляет коллайдер и rigidbody, если их нет, и предупреждает об этом в логах.
2) Для гашения скорости движущихся объектов сделал поправку на их массу. Иначе для тяжёлых объектов, типа брёвен, всё работало хорошо, а маленькие легкие при попадании в воду останавливались чуть ли ни мгновенно, как будто это кисель, а не вода.
alexz
UNITрон
 
Сообщения: 270
Зарегистрирован: 16 ноя 2010, 23:37

Re: Buoyancy - плавучие объекты

Сообщение ScorpionMax 06 янв 2011, 12:55

Все стандартое, как из деки Bootcamp, имею в виду размеры, масса 1 кг...
Сейчас скрипт новый погляжу...
3D max 2011, Photoshop CS и CS5. Game Develop Unity3D...
Аватара пользователя
ScorpionMax
UNIт
 
Сообщения: 61
Зарегистрирован: 28 дек 2010, 11:51

След.

Вернуться в Исходники (Копилка)

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1