My rigidbody starts to jitter and go crazy the more I build my raft

Hi there,

I an building a ocean survival game where you build up your raft plank by plank and as I add more pieces it begins to jitter and wobble slightly, this gets worse if I add more until it eventually flies off and goes out of unity’s range.

the raft is the main gameobject and has the rigidbody, the planks and all future items goes on as child objects in the position the player has chosen, with box colliders and the raft then recalculates the points used for the buoyancy calculations.

I can not for the life of me figure out why it starts to go wonky. no child objects have rigidbodies attached so it should be treating the whole raft as one object with a compound collider.

Do the other objects have Rigidbodies before adding them to the raft? Check to make sure those rigidbodies are being deactivated properly at runtime.

Check if the rotational inertia tensor is recalculated when you add colliders. As your compound object grows, so should the inertia tensor. If it stays the same, buoyancy forces added far away from the center of mass lead to large angular accelerations. I assume your also adding mass to the rigidbody as your raft grows?

next issue could be the fluid dynamics drag. I assume you’re adding some dampening force. Realistically, they should be proportional to v^2, but this can introduce numeric instability. I also had that and switched to linear drag, which is not physically correct, but looks believable too and doesn’t make your physics explode. You can also use v^2 and clamp it to some reasonable value. I haven’t tested that but I strongly assume it might work too.

Thanks for the replies

None of the parts have rigidbodies, I have different prefabs for each part, and the built prefabs don’t have any rigidbodies attached.

Thanks I never knew about inertia tensor, I have now added ResetInertiaTensor(); each time.
This seems to help a little but it seems to still do it now and then, I think its doing it when the floating script increases the drag and angular drag. This works to give the individual pieces a more realistic buoyancy. I’m not sure why this would make it freak out but i’ll not increase those on the raft rigidbody and see.
I will add my buoyancy script here, in case there is something funky i’m doing in it. If you have the time to read through it and see what you think it would be appreciated.

From my building script:

private void BuildIt()//Place the piece
    {
        GameObject builtObject = Instantiate(hitItemBuilding.builtPiecePrefab, previewGameObjectChild.position, previewGameObjectChild.rotation, raft.transform);
        //previewScript.Place(hitGameObject);
        Destroy(previewGameObject);
        previewGameObject = null;
        //previewScript = null;
        previewGameObjectChild = null;
        //isBuilding = false;
        canSnap = false;
        andRotating = false;
        selected = false;
        selectable = false;
        previewing = false;
        shifting = false;

        if (carryingAmount == 1)
        {
            print("remove " + carryingAmount);
            Destroy(carryingGO[0]);
            carryingGO.RemoveAt(0);
            carryingAmount--;
            amCarrying = false;
            carryingItem = null;
            carryingGO.Clear();
            amCarryingName = null;
            canBuild = false;
        }

        if (carryingAmount > 1)
        {
            print("remove " + carryingAmount);
            //int tmporary = carryingAmount - 1;
            Destroy(carryingGO[carryingAmount - 1]);
            carryingGO.RemoveAt(carryingAmount - 1);
            carryingAmount--;
        }

        //isRotZ = false;
        //isRotY = false;
        //translateOffset = 0f;
        //AddMeshCollider(raft);
        raft.GetComponent<Rigidbody>().ResetInertiaTensor();
        raft.GetComponent<FloatStuff>().Recalculate();
        //raft.GetComponent<FloatStuff>().enabled = true;
    }

My buoyancy script:

// Buoyancy.cs
// by Alex Zhdankin, modified for my purpouse.
// Version 2.1.1?
//
// https://forum.unity3d.com/threads/buoyancy-script.72974/
//
// Terms of use: do whatever you like

using System.Collections.Generic;
using UnityEngine;
using System.Linq;

[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(Collider))]
public class FloatStuff : MonoBehaviour
{
    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 Bounds bounds;
    private List<Vector3[]> forces; // For drawing force gizmos

    private Rigidbody rigidBody;
    private Collider thecollider;
    public List<Collider> allColliders = new List<Collider>();
    private List<Bounds> allBounds = new List<Bounds>();
    private List<float> allVoxelHalfHeight = new List<float>();
    [SerializeField]
    public List<List<Vector3>> allVoxels = new List<List<Vector3>>();

    private Ocean ocean;
    public float waterLevel;
    public bool children;
    private float volume;
    private float allMass;
    public int allVoxelsCount = 0;
    public List<Vector3> allCofM;
    private int subVoxelsCount;

    //private int weights;

    /// <summary>
    /// Provides initialization.
    /// </summary>
    private void Start()
    {
        forces = new List<Vector3[]>(); // For drawing force gizmos
        rigidBody = GetComponent<Rigidbody>();
        thecollider = GetComponent<Collider>();
        allColliders.Clear();

        foreach (Transform child in transform)
        {
            if (child.CompareTag("BuildingMaterial"))
            {
                allColliders.Add(child.GetComponent<Collider>());
                allMass += child.GetComponent<MyWeight>().myWeight;
            }
        }

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

        ocean = Ocean.Singleton;

        if (!children)
        {
            isMeshCollider = GetComponent<MeshCollider>() != null;

            bounds = thecollider.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;
            rigidBody.centerOfMass = new Vector3(0, -bounds.extents.y * 0f, 0) + transform.InverseTransformPoint(bounds.center);

            voxels = SliceIntoVoxels(isMeshCollider && isConcave);
            transform.rotation = originalRotation;
            transform.position = originalPosition;

            WeldPoints(voxels, voxelsLimit);
            volume = rigidBody.mass / density;
            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));
        }
        //allVoxelsCount = 0;
        else if (children)
        {          
            for (int i = 0; i < allColliders.Count; i++)
            {
                allBounds.Insert(i, allColliders[i].bounds);
                if (allBounds[i].size.x < allBounds[i].size.y)
                {
                    allVoxelHalfHeight.Insert(i, allBounds[i].size.x);
                }
                else
                {
                    allVoxelHalfHeight.Insert(i, allBounds[i].size.y);
                }
                if (allBounds[i].size.z < allVoxelHalfHeight[i])
                {
                    allVoxelHalfHeight.RemoveAt(i);
                    allVoxelHalfHeight.Insert(i, allBounds[i].size.z);
                }

                float tmpHalfHeight = allVoxelHalfHeight[i];
                allVoxelHalfHeight.RemoveAt(i);
                allVoxelHalfHeight.Insert(i, tmpHalfHeight /= 2 * slicesPerAxis);
                //print(i);
                Vector3 tmp = new Vector3(allColliders[i].transform.localPosition.x, allColliders[i].transform.localPosition.y, allColliders[i].transform.localPosition.z);
                print(tmp);
                allCofM.Add(tmp);

                //allMass = weights;
                //rigidBody.mass = 80;

                allVoxels.Insert(i, SliceIntoVoxels(isMeshCollider && isConcave, allColliders[i], i));
                subVoxelsCount = allVoxels[i].Count;
                allVoxelsCount += subVoxelsCount;
            }
            //allVoxelsCount += allVoxels.Count;
            print(allVoxelsCount);
            var average = allCofM.Aggregate(new Vector3(0, 0, 0), (s, v) => s + v) / allCofM.Count;
            print(average);
            rigidBody.centerOfMass = average; //new Vector3(0, -average.y * 0f, 0); /// + transform.InverseTransformPoint(bounds.center);
            //transform.rotation = originalRotation;
            //transform.position = originalPosition;

            for (int j = 0; j < allVoxels.Count; j++)
            {
                foreach (Vector3 tmpVoxels in allVoxels[j])
                {
                    voxels = SliceIntoVoxels(isMeshCollider && isConcave);
                    transform.rotation = originalRotation;
                    transform.position = originalPosition;

                    WeldPoints(voxels, voxelsLimit);
                    WeldPoints(allVoxels[j], voxelsLimit);
                }
            }
            rigidBody.mass = allMass;
            volume = rigidBody.mass / density;

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

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

        }            
    }

    public void Recalculate()
    {
        allColliders.Clear();
        allMass = 0;

        foreach (Transform child in transform)
        {
            if (child.CompareTag("BuildingMaterial"))
            {
                allColliders.Add(child.GetComponent<Collider>());
                allMass += child.GetComponent<MyWeight>().myWeight;
            }
        }

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

        //ocean = Ocean.Singleton;

        if (!children)
        {
            isMeshCollider = GetComponent<MeshCollider>() != null;

            bounds = thecollider.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;
            rigidBody.centerOfMass = new Vector3(0, -bounds.extents.y * 0f, 0) + transform.InverseTransformPoint(bounds.center);

            voxels = SliceIntoVoxels(isMeshCollider && isConcave);
            transform.rotation = originalRotation;
            transform.position = originalPosition;

            WeldPoints(voxels, voxelsLimit);
            volume = rigidBody.mass / density;
            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));
        }
        //allVoxelsCount = 0;
        else if (children)
        {          
            for (int i = 0; i < allColliders.Count; i++)
            {
                allBounds.Insert(i, allColliders[i].bounds);
                if (allBounds[i].size.x < allBounds[i].size.y)
                {
                    allVoxelHalfHeight.Insert(i, allBounds[i].size.x);
                }
                else
                {
                    allVoxelHalfHeight.Insert(i, allBounds[i].size.y);
                }
                if (allBounds[i].size.z < allVoxelHalfHeight[i])
                {
                    allVoxelHalfHeight.RemoveAt(i);
                    allVoxelHalfHeight.Insert(i, allBounds[i].size.z);
                }

                float tmpHalfHeight = allVoxelHalfHeight[i];
                allVoxelHalfHeight.RemoveAt(i);
                allVoxelHalfHeight.Insert(i, tmpHalfHeight /= 2 * slicesPerAxis);
                //print(i);
                Vector3 tmp = new Vector3(allColliders[i].transform.localPosition.x, allColliders[i].transform.localPosition.y, allColliders[i].transform.localPosition.z);
                print(tmp);
                allCofM.Add(tmp);

                //allMass = weights;
                //rigidBody.mass = 80;

                allVoxels.Insert(i, SliceIntoVoxels(isMeshCollider && isConcave, allColliders[i], i));
                subVoxelsCount = allVoxels[i].Count;
                allVoxelsCount += subVoxelsCount;
            }
            //allVoxelsCount += allVoxels.Count;
            print(allVoxelsCount);
            var average = allCofM.Aggregate(new Vector3(0, 0, 0), (s, v) => s + v) / allCofM.Count;
            print(average);
            rigidBody.centerOfMass = average; //new Vector3(0, -average.y * 0f, 0); /// + transform.InverseTransformPoint(bounds.center);
            //transform.rotation = originalRotation;
            //transform.position = originalPosition;

            for (int j = 0; j < allVoxels.Count; j++)
            {
                foreach (Vector3 tmpVoxels in allVoxels[j])
                {
                    voxels = SliceIntoVoxels(isMeshCollider && isConcave);
                    transform.rotation = originalRotation;
                    transform.position = originalPosition;

                    WeldPoints(voxels, voxelsLimit);
                    WeldPoints(allVoxels[j], voxelsLimit);
                }
            }
            rigidBody.mass = allMass;
            volume = rigidBody.mass / density;

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

            Debug.Log(string.Format("[Buoyancy.cs] Name=\"{0}\" volume={1:0.0}, mass={2:0.0}, density={3:0.0}", name, volume, allMass, 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 = thecollider.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>
    /// 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, Collider coll, int index)
    {
        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 = coll.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 = coll.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.GetHeightChoppyAtLocation2(x, z);
        //return 5.0f;
    }

    /// <summary>
    /// Calculates physics.
    /// </summary>
    private void FixedUpdate()
    {
        forces.Clear(); // For drawing force gizmos
        if (!children)
        {
            foreach (var point in voxels)
            {
                var wp = transform.TransformPoint(point);
                waterLevel = GetWaterLevel(wp.x, wp.z);
                if ((transform.position.y - 0.01f) <= waterLevel)
                {
                    rigidBody.drag = 1f;
                    rigidBody.angularDrag = 1f;
                }
                else
                {
                    rigidBody.drag = 0f;
                    rigidBody.angularDrag = 0.05f;
                }


                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
                }
            }
        }
        else if (children)
        {
            foreach (var pointlist in allVoxels)
            {
                foreach (var point in pointlist)
                {
                    var wp = transform.TransformPoint(point);
                    waterLevel = GetWaterLevel(wp.x, wp.z);
                    if ((transform.position.y - 0.01f) <= waterLevel)
                    {
                        rigidBody.drag = 1f;
                        rigidBody.angularDrag = 1f;
                    }
                    else
                    {
                        rigidBody.drag = 0f;
                        rigidBody.angularDrag = 0.05f;
                    }


                    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 (!children)
        {
            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);
            }
        }
        else if (children)
        {
            foreach (var voxellist in allVoxels)
            {
                if (voxellist == null || forces == null)
                {
                    return;
                }

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

                foreach (var p in voxellist)
                {
                    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);
                }
            }

            //Gizmos.color = Color.red;
            //Gizmos.DrawSphere( rigidBody.centerOfMass, 0.2f);
        }
    }
}

What a mess :smile:

From what I understood from skimming through the code is that you create a bunch of points (voxels) and check if they’re immersed or not. From that, you generate a buoyancy force per voxel. You decide if the drag and angularDrag should be very low or high by checking the transform position y against the water level.

What I don’t get is why for each voxel (foreach loop L.534) you check the rafts transform.position.y against the water level. transform.position.y doesn’t describe the geometry of the raft sufficiently. So I guess that might be a typo and you actually wanted to check against wp.y.

It still doesn’t make sense though: You only have one rigidbody and possibly hundreds of voxels. Checking each of their immersions and setting rigidbody.drag/angularDrag just creates a race condition: If the last point in the voxels-array is above the water, drag will be low. If the last voxel is in the water, drag will be high.

I can see that you’re adding a linear damping force in L.563, but you’re multiplying by the rigidbodies mass. Consider this: the force exerted by a single voxel increases as your raft grows. Why so? You keep adding parts of the raft on one end, but force at another position get’s higher and higher. Try removing the multiplication with rigidbody.mass. You might have to adjust “DAMPFER” (did you mean Dämpfer? Or damper?). I’d also try removing lines 538-547 as they’re not needed for the way you modelled the physics but might cover underlying problems.

Hi there, I haven’t been on recently to give feedback.

You got me thinking and indeed it was a mess, so I got down to writing the code over.

This got me thinking further and i suddenly realized that i can split the work and let the child objects work out their own voxels and data points and forces for each point, by its weight and not the rafts entire weight. and then pass the force on to the parent rigidbody.

the parent then calculates the aggregate of all the children’s CoM to get a good average of the raft’s CoM and recalculates the InertiaTensor.

So far so good and is working like a charm.

It also ends up more realistic because different parts of the raft can now have different densities and be more buoyant than other parts :smile:.

If I get a chance I’ll post a link to a video.

Thanks for your help.

I’m glad I could help:)

please do! I’m working on something similar :slight_smile: