Beispiel #1
0
        // followed by variable sized convex hull data

        #region Construction

        // Create a convex collider from the given point cloud.
        public static unsafe BlobAssetReference <Collider> Create(
            NativeArray <float3> points, float convexRadius,
            float3?scale = null, CollisionFilter?filter = null, Material?material = null)
        {
            if (convexRadius < 0.0f || !math.isfinite(convexRadius))
            {
                throw new ArgumentException("Tried to create ConvexCollider with invalid convex radius");
            }

            // Build convex hull
            int    verticesCapacity = points.Length;
            int    triangleCapacity = 2 * verticesCapacity;
            var    vertices         = (ConvexHullBuilder.Vertex *)UnsafeUtility.Malloc(verticesCapacity * sizeof(ConvexHullBuilder.Vertex), 16, Allocator.Temp);
            var    triangles        = (ConvexHullBuilder.Triangle *)UnsafeUtility.Malloc(triangleCapacity * sizeof(ConvexHullBuilder.Triangle), 16, Allocator.Temp);
            var    builder          = new ConvexHullBuilder(vertices, verticesCapacity, triangles, triangleCapacity);
            float3 s = scale ?? new float3(1);

            foreach (float3 point in points)
            {
                if (math.any(!math.isfinite(point)))
                {
                    throw new ArgumentException("Tried to create ConvexCollider with invalid points");
                }
                builder.AddPoint(point * s);
            }

            // TODO: shrink by convex radius

            // Build face information
            float maxAngle = 0.1f * (float)math.PI / 180.0f;

            builder.BuildFaceIndices(maxAngle);

            // Simplify the hull until it fits requirements
            // TODO.ma this is just a failsafe. We need to think about user-controlled simplification settings & how to warn the user if their shape is too complex.
            {
                const int maxVertices = 252;    // as per Havok

                float maxSimplificationError = 1e-3f;
                int   iterations             = 0;
                while (builder.Vertices.PeakCount > maxVertices)
                {
                    if (iterations++ > 10) // don't loop forever
                    {
                        Assert.IsTrue(false);
                        return(new BlobAssetReference <Collider>());
                    }
                    builder.SimplifyVertices(maxSimplificationError);
                    builder.BuildFaceIndices();
                    maxSimplificationError *= 2.0f;
                }
            }

            // Convert hull to compact format
            var tempHull = new TempHull(ref builder);

            // Allocate collider
            int totalSize = UnsafeUtility.SizeOf <ConvexCollider>();

            totalSize += tempHull.Vertices.Count * sizeof(float3);
            totalSize  = Math.NextMultipleOf16(totalSize); // planes currently must be aligned for Havok
            totalSize += tempHull.Planes.Count * sizeof(Plane);
            totalSize += tempHull.Faces.Count * sizeof(ConvexHull.Face);
            totalSize += tempHull.FaceVertexIndices.Count * sizeof(short);
            totalSize += tempHull.VertexEdges.Count * sizeof(ConvexHull.Edge);
            totalSize += tempHull.FaceLinks.Count * sizeof(ConvexHull.Edge);
            ConvexCollider *collider = (ConvexCollider *)UnsafeUtility.Malloc(totalSize, 16, Allocator.Temp);

            // Initialize it
            {
                UnsafeUtility.MemClear(collider, totalSize);
                collider->MemorySize = totalSize;

                collider->m_Header.Type          = ColliderType.Convex;
                collider->m_Header.CollisionType = CollisionType.Convex;
                collider->m_Header.Version       = 0;
                collider->m_Header.Magic         = 0xff;
                collider->m_Header.Filter        = filter ?? CollisionFilter.Default;
                collider->m_Header.Material      = material ?? Material.Default;

                ref var hull = ref collider->ConvexHull;

                hull.ConvexRadius = convexRadius;

                // Initialize blob arrays
                {
                    byte *end = (byte *)collider + UnsafeUtility.SizeOf <ConvexCollider>();

                    hull.VerticesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.VerticesBlob.Offset));
                    hull.VerticesBlob.Length = tempHull.Vertices.Count;
                    end += sizeof(float3) * tempHull.Vertices.Count;

                    end = (byte *)Math.NextMultipleOf16((ulong)end); // planes currently must be aligned for Havok

                    hull.FacePlanesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.FacePlanesBlob.Offset));
                    hull.FacePlanesBlob.Length = tempHull.Planes.Count;
                    end += sizeof(Plane) * tempHull.Planes.Count;

                    hull.FacesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.FacesBlob.Offset));
                    hull.FacesBlob.Length = tempHull.Faces.Count;
                    end += sizeof(ConvexHull.Face) * tempHull.Faces.Count;

                    hull.FaceVertexIndicesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.FaceVertexIndicesBlob.Offset));
                    hull.FaceVertexIndicesBlob.Length = tempHull.FaceVertexIndices.Count;
                    end += sizeof(byte) * tempHull.FaceVertexIndices.Count;

                    hull.VertexEdgesBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.VertexEdgesBlob.Offset));
                    hull.VertexEdgesBlob.Length = tempHull.VertexEdges.Count;
                    end += sizeof(ConvexHull.Edge) * tempHull.VertexEdges.Count;

                    hull.FaceLinksBlob.Offset = (int)(end - (byte *)UnsafeUtility.AddressOf(ref hull.FaceLinksBlob.Offset));
                    hull.FaceLinksBlob.Length = tempHull.FaceLinks.Count;
                    end += sizeof(ConvexHull.Edge) * tempHull.FaceLinks.Count;
                }

                // Fill blob arrays
                {
                    for (int i = 0; i < tempHull.Vertices.Count; i++)
                    {
                        hull.Vertices[i]    = tempHull.Vertices[i];
                        hull.VertexEdges[i] = tempHull.VertexEdges[i];
                    }

                    for (int i = 0; i < tempHull.Faces.Count; i++)
                    {
                        hull.Planes[i] = tempHull.Planes[i];
                        hull.Faces[i]  = tempHull.Faces[i];
                    }

                    for (int i = 0; i < tempHull.FaceVertexIndices.Count; i++)
                    {
                        hull.FaceVertexIndices[i] = tempHull.FaceVertexIndices[i];
                        hull.FaceLinks[i]         = tempHull.FaceLinks[i];
                    }
                }

                // Fill mass properties
                {
                    var massProperties = builder.ComputeMassProperties();
                    Math.DiagonalizeSymmetricApproximation(massProperties.InertiaTensor, out float3x3 orientation, out float3 inertia);

                    float maxLengthSquared = 0.0f;
                    foreach (float3 vertex in hull.Vertices)
                    {
                        maxLengthSquared = math.max(maxLengthSquared, math.lengthsq(vertex - massProperties.CenterOfMass));
                    }

                    collider->MassProperties = new MassProperties
                    {
                        MassDistribution = new MassDistribution
                        {
                            Transform     = new RigidTransform(orientation, massProperties.CenterOfMass),
                            InertiaTensor = inertia
                        },
                        Volume = massProperties.Volume,
                        AngularExpansionFactor = math.sqrt(maxLengthSquared)
                    };
                }
            }
Beispiel #2
0
        // Write a set of contact manifolds for a pair of bodies to the given stream.
        public static unsafe void BodyBody(RigidBody rigidBodyA, RigidBody rigidBodyB, MotionVelocity motionVelocityA, MotionVelocity motionVelocityB,
                                           float collisionTolerance, float timeStep, BodyIndexPair pair, ref NativeStream.Writer contactWriter)
        {
            Collider *colliderA = rigidBodyA.Collider;
            Collider *colliderB = rigidBodyB.Collider;

            if (colliderA == null || colliderB == null || !CollisionFilter.IsCollisionEnabled(colliderA->Filter, colliderB->Filter))
            {
                return;
            }

            // Build combined motion expansion
            MotionExpansion expansion;
            {
                MotionExpansion expansionA = motionVelocityA.CalculateExpansion(timeStep);
                MotionExpansion expansionB = motionVelocityB.CalculateExpansion(timeStep);
                expansion = new MotionExpansion
                {
                    Linear  = expansionA.Linear - expansionB.Linear,
                    Uniform = expansionA.Uniform + expansionB.Uniform + collisionTolerance
                };
            }

            var context = new Context
            {
                BodyIndices    = pair,
                BodyCustomTags = new CustomTagsPair {
                    CustomTagsA = rigidBodyA.CustomTags, CustomTagsB = rigidBodyB.CustomTags
                },
                BodiesHaveInfiniteMass =
                    !math.any(motionVelocityA.InverseInertiaAndMass) &&
                    !math.any(motionVelocityB.InverseInertiaAndMass),
                ContactWriter = (NativeStream.Writer *)UnsafeUtility.AddressOf(ref contactWriter)
            };

            var worldFromA = new MTransform(rigidBodyA.WorldFromBody);
            var worldFromB = new MTransform(rigidBodyB.WorldFromBody);

            // Dispatch to appropriate manifold generator
            switch (colliderA->CollisionType)
            {
            case CollisionType.Convex:
                switch (colliderB->CollisionType)
                {
                case CollisionType.Convex:
                    ConvexConvex(context, ColliderKeyPair.Empty, colliderA, colliderB, worldFromA, worldFromB, expansion.MaxDistance, false);
                    break;

                case CollisionType.Composite:
                    ConvexComposite(context, ColliderKey.Empty, colliderA, colliderB, worldFromA, worldFromB, expansion, false);
                    break;

                case CollisionType.Terrain:
                    ConvexTerrain(context, ColliderKeyPair.Empty, colliderA, colliderB, worldFromA, worldFromB, expansion.MaxDistance, false);
                    break;
                }
                break;

            case CollisionType.Composite:
                switch (colliderB->CollisionType)
                {
                case CollisionType.Convex:
                    CompositeConvex(context, colliderA, colliderB, worldFromA, worldFromB, expansion, false);
                    break;

                case CollisionType.Composite:
                    CompositeComposite(context, colliderA, colliderB, worldFromA, worldFromB, expansion, false);
                    break;

                case CollisionType.Terrain:
                    CompositeTerrain(context, colliderA, colliderB, worldFromA, worldFromB, expansion.MaxDistance, false);
                    break;
                }
                break;

            case CollisionType.Terrain:
                switch (colliderB->CollisionType)
                {
                case CollisionType.Convex:
                    TerrainConvex(context, ColliderKeyPair.Empty, colliderA, colliderB, worldFromA, worldFromB, expansion.MaxDistance, false);
                    break;

                case CollisionType.Composite:
                    TerrainComposite(context, colliderA, colliderB, worldFromA, worldFromB, expansion.MaxDistance, false);
                    break;

                case CollisionType.Terrain:
                    UnityEngine.Assertions.Assert.IsTrue(false);
                    break;
                }
                break;
            }
        }
Beispiel #3
0
            internal static unsafe void ExecuteImpl(int2 pair, Tree dynamicTree, ref NativeStream.Writer pairWriter)
            {
                var bodyFilters             = (CollisionFilter *)dynamicTree.BodyFilters.GetUnsafeReadOnlyPtr();
                var bodyRespondsToCollision = (bool *)dynamicTree.RespondsToCollision.GetUnsafeReadOnlyPtr();
                var bufferedPairs           = new BodyPairWriter((NativeStream.Writer *)UnsafeUtility.AddressOf(ref pairWriter), bodyFilters, bodyFilters, bodyRespondsToCollision, bodyRespondsToCollision, 0, 0);

                new BoundingVolumeHierarchy(dynamicTree.Nodes, dynamicTree.NodeFilters).SelfBvhOverlap(ref bufferedPairs, pair.x, pair.y);
                bufferedPairs.Close();
            }
Beispiel #4
0
            void ProcessSmallRange(Range baseRange, ref int freeNodeIndex)
            {
                Range range = baseRange;

                ComputeAxisAndPivot(ref range, out int axis, out float pivot);
                SortRange(axis, ref range);

                Range *subRanges    = stackalloc Range[4];
                int    hasLeftOvers = 1;

                do
                {
                    int numSubRanges = 0;
                    while (range.Length > 4 && numSubRanges < 3)
                    {
                        subRanges[numSubRanges].Start  = range.Start;
                        subRanges[numSubRanges].Length = 4;
                        numSubRanges++;

                        range.Start  += 4;
                        range.Length -= 4;
                    }

                    if (range.Length > 0)
                    {
                        subRanges[numSubRanges].Start  = range.Start;
                        subRanges[numSubRanges].Length = range.Length;

                        numSubRanges++;
                    }

                    hasLeftOvers = 0;
                    CreateChildren(subRanges, numSubRanges, range.Root, ref freeNodeIndex, (Range *)UnsafeUtility.AddressOf(ref range), ref hasLeftOvers);

                    Assert.IsTrue(hasLeftOvers <= 1 /*, "Internal error"*/);
                } while (hasLeftOvers > 0);
            }
            public unsafe static void Execute(ref JacobiansJobData <T> jobData, IntPtr additionalData,
                                              IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex)
            {
                ModifiableJacobianHeader  modifiableHeader;
                ModifiableContactJacobian modifiableContact;
                byte *headerBuffer  = stackalloc byte[JacobianHeader.CalculateSize(JacobianType.Contact, (JacobianFlags)0xff, 4)]; //<todo.eoin.modifier How to verify correct sizes?
                byte *contactBuffer = stackalloc byte[sizeof(ContactJacobian)];

                Havok.Physics.HpGrid *curGrid = jobData.FixedJacobianGrid;
                int *pluginIndexToLocal       = jobData.PluginIndexToLocal->Data;

                for (int g = 0; g < 2; g++)
                {
                    for (int i = 0; i < curGrid->m_size; i++)
                    {
                        HpCsContactJacRange *gridRange = curGrid->m_entries + i;
                        var range = (Havok.Physics.HpLinkedRange *)UnsafeUtility.AddressOf(ref gridRange->m_range);
                        while (range != null)
                        {
                            var reader = new Havok.Physics.HpBlockStreamReader(range);
                            while (reader.HasItems)
                            {
                                var hpHeader = (Havok.Physics.HpJacHeader *)reader.Peek();
                                modifiableHeader                    = new ModifiableJacobianHeader {
                                };
                                modifiableContact                   = new ModifiableContactJacobian {
                                };
                                modifiableHeader.m_Header           = (JacobianHeader *)headerBuffer;
                                modifiableContact.m_ContactJacobian = (ContactJacobian *)contactBuffer;

                                int bodyIndexA = pluginIndexToLocal[hpHeader->m_bodyIdA & 0x00ffffff];
                                int bodyIndexB = pluginIndexToLocal[hpHeader->m_bodyIdB & 0x00ffffff];

                                modifiableHeader.m_Header->BodyPair = new BodyIndexPair
                                {
                                    BodyIndexA = bodyIndexA,
                                    BodyIndexB = bodyIndexB
                                };

                                modifiableHeader.EntityPair = new EntityPair
                                {
                                    EntityA = jobData.Bodies[bodyIndexA].Entity,
                                    EntityB = jobData.Bodies[bodyIndexB].Entity
                                };

                                modifiableHeader.m_Header->Type = JacobianType.Contact;
                                modifiableContact.m_ContactJacobian->BaseJacobian.NumContacts = hpHeader->m_numPoints;
                                modifiableContact.m_ContactJacobian->BaseJacobian.Normal      = hpHeader->m_normal.xyz;
                                Havok.Physics.HPManifoldCollisionCache *manifoldCache = hpHeader->m_manifoldCollisionCache;
                                modifiableContact.m_ContactJacobian->CoefficientOfFriction = manifoldCache->m_friction.Value;

                                // Fill in friction data
                                if (HpJacHeader.hasAnyFriction(hpHeader->m_flagsAndDimB))
                                {
                                    Havok.Physics.HpJac3dFriction *jf = hpHeader->accessJacFriction();
                                    modifiableContact.m_ContactJacobian->Friction0.AngularA       = jf->m_jacDir0_angular0.xyz;
                                    modifiableContact.m_ContactJacobian->Friction0.AngularB       = jf->m_jacDir0_angular1.xyz;
                                    modifiableContact.m_ContactJacobian->Friction1.AngularA       = jf->m_jacDir1_angular0.xyz;
                                    modifiableContact.m_ContactJacobian->Friction1.AngularB       = jf->m_jacDir1_angular1.xyz;
                                    modifiableContact.m_ContactJacobian->AngularFriction.AngularA = jf->m_jacAng_angular0.xyz;
                                    modifiableContact.m_ContactJacobian->AngularFriction.AngularB = jf->m_jacAng_angular1.xyz;
                                }

                                Havok.Physics.HpPerManifoldProperty *cdp = manifoldCache->GetCustomPropertyStorage();
                                modifiableHeader.m_Header->Flags = (JacobianFlags)cdp->m_jacobianFlags;

                                if ((cdp->m_jacobianFlags & (byte)JacobianFlags.EnableMassFactors) != 0)
                                {
                                    modifiableHeader.MassFactors = *hpHeader->accessMassFactors();
                                }

                                for (int p = 0; p < hpHeader->m_numPoints; p++)
                                {
                                    Havok.Physics.HpJacAngular *hpAng = hpHeader->accessJacAngular(p);
                                    var ang = new ContactJacAngAndVelToReachCp
                                    {
                                        Jac = new ContactJacobianAngular
                                        {
                                            AngularA      = hpAng->m_angular0.xyz,
                                            AngularB      = hpAng->m_angular1.xyz,
                                            EffectiveMass = hpAng->m_angular0.w,
                                        },
                                        VelToReachCp = hpAng->m_angular1.w,
                                    };

                                    // Access the angular jacobian from the header directly,
                                    // to avoid the modifiable header marking itself dirty.
                                    modifiableHeader.m_Header->AccessAngularJacobian(p) = ang;
                                }

                                jobData.UserJobData.Execute(ref modifiableHeader, ref modifiableContact);

                                if (((byte)modifiableHeader.Flags & (byte)JacobianFlags.Disabled) != 0)
                                {
                                    // Don't check the "changed" state of the jacobian - this flag is set on the contact
                                    hpHeader->m_flagsAndDimB |= 1 << 10; // JH_MANIFOLD_IS_NOT_NORMAL
                                    hpHeader->m_manifoldType  = 3;       // hknpManifoldType::DISABLED
                                }

                                if (modifiableHeader.AngularChanged || modifiableHeader.ModifiersChanged)
                                {
                                    // Need to disable jacobian caching, since we can't tell what modifications the user has done
                                    manifoldCache->m_qualityFlags &= (0xffff ^ (1 << 10)); //hknpBodyQuality::ENABLE_CONTACT_CACHING
                                }

                                if (modifiableHeader.AngularChanged)
                                {
                                    for (int p = 0; p < hpHeader->m_numPoints; p++)
                                    {
                                        Havok.Physics.HpJacAngular * hpAng = hpHeader->accessJacAngular(p);
                                        ContactJacAngAndVelToReachCp ang   = modifiableHeader.GetAngularJacobian(p);

                                        hpAng->m_angular0 = new float4(ang.Jac.AngularA, ang.Jac.EffectiveMass);
                                        hpAng->m_angular1 = new float4(ang.Jac.AngularB, ang.VelToReachCp);
                                    }
                                }

                                if (modifiableHeader.ModifiersChanged && (cdp->m_jacobianFlags & (byte)JacobianFlags.EnableMassFactors) != 0)
                                {
                                    *hpHeader->accessMassFactors() = modifiableHeader.MassFactors;
                                }

                                if (modifiableHeader.ModifiersChanged && (cdp->m_jacobianFlags & (byte)JacobianFlags.EnableSurfaceVelocity) != 0)
                                {
                                    var surfVel = modifiableHeader.SurfaceVelocity;

                                    float angVelProj = math.dot(surfVel.AngularVelocity, modifiableContact.Normal);
                                    if (manifoldCache != null)
                                    {
                                        float frictionRhs = manifoldCache->getFrictionRhsMultiplierValue();
                                        float frictRhsMul = frictionRhs * jobData.TimeStep;

                                        // Update cached integrated friction rhs
                                        float4 vel  = new float4(-surfVel.LinearVelocity, -angVelProj);
                                        float4 rhs4 = manifoldCache->m_integratedFrictionRhs;
                                        rhs4 += frictRhsMul * vel;
                                        manifoldCache->m_integratedFrictionRhs = rhs4;
                                    }

                                    if (HpJacHeader.hasAnyFriction(hpHeader->m_flagsAndDimB))
                                    {
                                        Math.CalculatePerpendicularNormalized(modifiableContact.Normal, out float3 dir0, out float3 dir1);
                                        float linVel0 = math.dot(surfVel.LinearVelocity, dir0);
                                        float linVel1 = math.dot(surfVel.LinearVelocity, dir1);

                                        // Check JH_SURFACE_VELOCITY_DIRTY flag and clear it if it was set
                                        const ushort jhSurfaceVelocityDirty = 1 << 3;
                                        if ((hpHeader->m_flagsAndDimB & jhSurfaceVelocityDirty) != 0)
                                        {
                                            *hpHeader->accessSurfaceVelocity() = new float3(linVel0, linVel1, angVelProj);
                                            hpHeader->m_flagsAndDimB &= 0xffff ^ jhSurfaceVelocityDirty;
                                        }
                                        else
                                        {
                                            *hpHeader->accessSurfaceVelocity() += new float3(linVel0, linVel1, angVelProj);
                                        }

                                        // Update friction Jacobian
                                        {
                                            Havok.Physics.HpJac3dFriction *jf = hpHeader->accessJacFriction();

                                            float dRhs0 = jf->m_jacDir0_linear0.w;
                                            float dRhs1 = jf->m_jacDir1_linear0.w;
                                            float dRhs  = jf->m_jacAng_angular1.w;

                                            float frictRhsMul = hpHeader->m_manifoldCollisionCache->getFrictionRhsMultiplierValue();
                                            dRhs0 -= frictRhsMul * linVel0;
                                            dRhs1 -= frictRhsMul * linVel1;
                                            dRhs  -= frictRhsMul * angVelProj;

                                            jf->m_jacDir0_linear0.w = dRhs0;
                                            jf->m_jacDir1_linear0.w = dRhs1;
                                            jf->m_jacAng_angular1.w = dRhs;
                                        }
                                    }
                                }

                                if (modifiableContact.Modified)
                                {
                                    hpHeader->m_normal.xyz          = modifiableContact.Normal;
                                    manifoldCache->m_friction.Value = modifiableContact.CoefficientOfFriction;

                                    if (HpJacHeader.hasAnyFriction(hpHeader->m_flagsAndDimB))
                                    {
                                        Havok.Physics.HpJac3dFriction *jf = hpHeader->accessJacFriction();
                                        jf->m_jacDir0_angular0.xyz = modifiableContact.Friction0.AngularA;
                                        jf->m_jacDir0_angular1.xyz = modifiableContact.Friction0.AngularB;
                                        jf->m_jacDir1_angular0.xyz = modifiableContact.Friction1.AngularA;
                                        jf->m_jacDir1_angular1.xyz = modifiableContact.Friction1.AngularB;
                                        jf->m_jacAng_angular0.xyz  = modifiableContact.AngularFriction.AngularA;
                                        jf->m_jacAng_angular1.xyz  = modifiableContact.AngularFriction.AngularB;
                                    }
                                }

                                reader.Advance(hpHeader->m_sizeDiv16 * 16);
                            }

                            range = range->m_next;
                        }
                    }

                    curGrid = jobData.MovingJacobianGrid;
                }
            }