Example #1
0
    void Update()
    {
        Profiler.BeginSample("Schedule Softbody Work", this);

        int batchSize = 8;

        softbodyData.friction = friction;

        //Transform the points into world space
        JobHandle localToWorldHandle = new ToWorldSpaceJob()
        {
            localToWorld = transform.localToWorldMatrix,
            bodyVerts    = softbodyData.bodyVerts
        }.Schedule(originalVerts.Length, batchSize);

        //Physics - Verlet Integration
        JobHandle verletHandle = new VerletIntegrateJob()
        {
            bodyVerts     = softbodyData.bodyVerts,
            prevBodyVerts = softbodyData.prevBodyVerts,
            scaledGravity = softbodyData.scaledGravity
        }.Schedule(originalVerts.Length, batchSize, dependsOn: localToWorldHandle);

        JobHandle previousHandle = verletHandle;

        for (int i = 0; i < solverIterations; i++)
        {
            //First, ensure that the surface area is what we think it is
            JobHandle applyConstraints;
            if (parallelConstraints)
            {
                JobHandle calculateConstraints = new CalculateDistanceConstraintsJob()
                {
                    bodyVerts = softbodyData.bodyVerts,
                    accumulatedDisplacements = softbodyData.accumulatedDisplacements,
                    constraintsArray         = softbodyData.connectionGraph
                }.Schedule(originalVerts.Length, batchSize, dependsOn: previousHandle);
                applyConstraints = new ApplyAccumulatedConstraintsJob()
                {
                    bodyVerts = softbodyData.bodyVerts,
                    accumulatedDisplacements = softbodyData.accumulatedDisplacements
                }.Schedule(originalVerts.Length, batchSize, dependsOn: calculateConstraints);
            }
            else
            {
                JobHandle accumulateDistances = new AccumulateDistanceConstraintsJob()
                {
                    bodyVerts = softbodyData.bodyVerts,
                    accumulatedDisplacements = softbodyData.accumulatedDisplacements,
                    constraintsArray         = softbodyData.constraintsArray
                }.Schedule(dependsOn: previousHandle);
                applyConstraints = new ApplyAccumulatedConstraintsJob()
                {
                    bodyVerts = softbodyData.bodyVerts,
                    accumulatedDisplacements = softbodyData.accumulatedDisplacements
                }.Schedule(originalVerts.Length, batchSize, dependsOn: accumulateDistances);
            }

            //Next, set the volume of the soft body
            JobHandle calculateNormals;
            if (parallelNormals)
            {
                calculateNormals = new GatherNormalsJob()
                {
                    bodyVerts         = softbodyData.bodyVerts,
                    vertexConnections = softbodyData.triangleGraph,
                    bodyNormals       = softbodyData.bodyNormals
                }.Schedule(originalVerts.Length, batchSize, dependsOn: applyConstraints);
            }
            else
            {
                JobHandle accumulateNormals = new AccumulateNormalsJob()
                {
                    bodyVerts     = softbodyData.bodyVerts,
                    bodyTriangles = softbodyData.bodyTriangles,
                    bodyNormals   = softbodyData.bodyNormals
                }.Schedule(dependsOn: applyConstraints);
                calculateNormals = new NormalizeNormalsJob()
                {
                    bodyNormals = softbodyData.bodyNormals
                }.Schedule(originalVerts.Length, batchSize, dependsOn: accumulateNormals);
            }

            JobHandle calculateDilationDistance;
            if (useAreaVolumeAccumulator)
            {
                JobHandle accumulateDilationDistance = new SurfaceAreaAndVolumeAccumulatorJob()
                {
                    bodyVerts         = softbodyData.bodyVerts,
                    bodyTriangles     = softbodyData.bodyTriangles,
                    volumeAccumulator = softbodyData.volumeAccumulator,
                    areaAccumulator   = softbodyData.areaAccumulator
                }.Schedule(softbodyData.bodyTriangles.Length, batchSize, dependsOn: calculateNormals);

                calculateDilationDistance = new CalculateDilationJob()
                {
                    volumeAccumulator  = softbodyData.volumeAccumulator,
                    areaAccumulator    = softbodyData.areaAccumulator,
                    initialVolume      = softbodyData.initialVolume * inflationAmount,
                    initialSurfaceArea = softbodyData.initialSurfaceArea,
                    dilationDistance   = softbodyData.dilationDistance
                }.Schedule(dependsOn: accumulateDilationDistance);
            }
            else
            {
                JobHandle accumulateDilationDistance = new AccumulateSurfaceAreaAndVolumeJob()
                {
                    bodyVerts            = softbodyData.bodyVerts,
                    bodyTriangles        = softbodyData.bodyTriangles,
                    triangleVolumes      = softbodyData.triangleVolumes,
                    triangleSurfaceAreas = softbodyData.triangleSurfaceAreas
                }.Schedule(softbodyData.bodyTriangles.Length, batchSize, dependsOn: calculateNormals);

                //THIS IS THE LAST BIG ONE
                calculateDilationDistance = new CalculateSurfaceAreaAndVolumeJob()
                {
                    triangleVolumes      = softbodyData.triangleVolumes,
                    triangleSurfaceAreas = softbodyData.triangleSurfaceAreas,
                    initialVolume        = softbodyData.initialVolume * inflationAmount,
                    initialSurfaceArea   = softbodyData.initialSurfaceArea,
                    dilationDistance     = softbodyData.dilationDistance
                }.Schedule(dependsOn: accumulateDilationDistance);
            }

            previousHandle = new ExtrudeNormalsJob()
            {
                bodyVerts        = softbodyData.bodyVerts,
                bodyNormals      = softbodyData.bodyNormals,
                dilationDistance = softbodyData.dilationDistance
            }.Schedule(originalVerts.Length, batchSize, dependsOn: calculateDilationDistance);
        }

        //Also collide with other softbodies
        if (collideWithOtherSoftbodies)
        {
            foreach (SoftbodyJobified softbody in s_softBodies)
            {
                if (softbody != this)
                {
                    Vector3 midPoint = Vector3.Lerp(transform.position, softbody.transform.position, (radius / softbody.radius) * 0.5f);
                    previousHandle = new VoronoiCollideJob()
                    {
                        bodyVerts     = softbodyData.bodyVerts,
                        prevBodyVerts = softbodyData.prevBodyVerts,
                        planePos      = midPoint,
                        planeNormal   = (transform.position - midPoint).normalized,
                        friction      = 0f,
                        velocity      = new Vector3(0f, 0f, 0f)
                    }.Schedule(originalVerts.Length, batchSize, dependsOn: previousHandle);
                }
            }
        }

        //Prepare a batch of raycast commands
        JobHandle raycastPrepareHandle = new RaycastPrepareJob()
        {
            bodyVerts         = softbodyData.bodyVerts,
            prevBodyVerts     = softbodyData.prevBodyVerts,
            preCollisionVerts = softbodyData.preCollisionVerts,
            raycasts          = softbodyData.raycasts,
            bodyNormals       = softbodyData.bodyNormals,
            penetrationDepth  = 0.5f * softbodyData.radius
        }.Schedule(originalVerts.Length, batchSize, dependsOn: previousHandle);

        // Schedule the batch of raycasts
        JobHandle batchRaycastHandle = RaycastCommand.ScheduleBatch(softbodyData.raycasts, softbodyData.raycastHits, batchSize, raycastPrepareHandle);

        //Apply the results of those raycasts
        JobHandle raycastCollisionHandle = new RaycastCollisionJob()
        {
            bodyVerts     = softbodyData.bodyVerts,
            prevBodyVerts = softbodyData.prevBodyVerts,
            raycastHits   = softbodyData.raycastHits,
            bodyNormals   = softbodyData.bodyNormals,
            friction      = softbodyData.friction
        }.Schedule(originalVerts.Length, batchSize, dependsOn: batchRaycastHandle);

        Profiler.EndSample();

        raycastCollisionHandle.Complete();

        //Calculate the impulses on PhysX objects
        float invDT = 1 / Time.deltaTime; float vertexMass = (mass / softbodyData.bodyVerts.Length);

        for (int i = 0; i < softbodyData.raycastHits.Length; i++)
        {
            Rigidbody collidingBody;
            if ((collidingBody = softbodyData.raycastHits[i].rigidbody) != null && !collidingBody.isKinematic)
            {
                Vector3 preCollisionVelocity  = (softbodyData.preCollisionVerts[i] - softbodyData.prevBodyVerts[i]) * invDT;
                Vector3 postCollisionVelocity = (softbodyData.bodyVerts[i] - softbodyData.prevBodyVerts[i]) * invDT;
                Vector3 deltaMomentum         = (postCollisionVelocity - preCollisionVelocity) * vertexMass;
                Vector3 netForce = -deltaMomentum * invDT;
                collidingBody.AddForceAtPosition(netForce, softbodyData.bodyVerts[i], ForceMode.Force);
            }
        }

        //Calculate the the position and rotation of the body
        for (int i = 0; i < softbodyData.bodyVerts.Length; i++)
        {
            softbodyData.kabschVerts[i] = new Vector4(
                softbodyData.bodyVerts[i].x,
                softbodyData.bodyVerts[i].y,
                softbodyData.bodyVerts[i].z, 1f);
        }
        ;
        softbodyData.kabschVerts.CopyTo(kabschVertsArray);
        Matrix4x4 toWorldSpace = kabschSolver.SolveKabsch(originalVerts, kabschVertsArray, transformFollowsRotation);

        transform.position = toWorldSpace.GetVector3();
        transform.rotation = toWorldSpace.GetQuaternion();

        //Move the points into local space for rendering
        JobHandle toLocalHandle = new ToLocalSpaceJob()
        {
            bodyVerts     = softbodyData.bodyVerts,
            bodyNormals   = softbodyData.bodyNormals,
            renderNormals = softbodyData.renderNormals,
            worldToLocal  = transform.worldToLocalMatrix
        }.Schedule(originalVerts.Length, batchSize);

        toLocalHandle.Complete();

        //Graphics
        softbodyData.bodyVerts.CopyTo(bodyVertsArray);
        softbodyData.renderNormals.CopyTo(renderNormalsArray);
        bodyMesh.vertices = bodyVertsArray;
        bodyMesh.normals  = renderNormalsArray;
        bodyMesh.RecalculateBounds();
        bodyMesh.UploadMeshData(false);
    }
    void Update()
    {
        Profiler.BeginSample("Schedule Softbody Work", this);

        int batchSize = 16;

        //Transform the points into world space
        JobHandle localToWorldHandle = new ToWorldSpaceJob()
        {
            localToWorld = transform.localToWorldMatrix,
            bodyVerts    = softbodyData.bodyVerts
        }.Schedule(originalVerts.Length, batchSize);

        //Physics - Verlet Integration
        JobHandle verletHandle = new VerletIntegrateJob()
        {
            bodyVerts     = softbodyData.bodyVerts,
            prevBodyVerts = softbodyData.prevBodyVerts,
            scaledGravity = softbodyData.scaledGravity
        }.Schedule(originalVerts.Length, batchSize, dependsOn: localToWorldHandle);

        JobHandle previousHandle = verletHandle;

        for (int i = 0; i < solverIterations; i++)
        {
            //First, ensure that the surface area is what we think it is
            JobHandle applyConstraints;
            if (parallelConstraints)
            {
                JobHandle calculateConstraints = new CalculateDistanceConstraintsJob()
                {
                    bodyVerts = softbodyData.bodyVerts,
                    accumulatedDisplacements = softbodyData.accumulatedDisplacements,
                    constraintsArray         = softbodyData.connectionGraph
                }.Schedule(originalVerts.Length, batchSize, dependsOn: previousHandle);
                applyConstraints = new ApplyAccumulatedConstraintsJob()
                {
                    bodyVerts = softbodyData.bodyVerts,
                    accumulatedDisplacements = softbodyData.accumulatedDisplacements
                }.Schedule(originalVerts.Length, batchSize, dependsOn: calculateConstraints);
            }
            else
            {
                JobHandle accumulateDistances = new AccumulateDistanceConstraintsJob()
                {
                    bodyVerts = softbodyData.bodyVerts,
                    accumulatedDisplacements = softbodyData.accumulatedDisplacements,
                    constraintsArray         = softbodyData.constraintsArray
                }.Schedule(dependsOn: previousHandle);
                applyConstraints = new ApplyAccumulatedConstraintsJob()
                {
                    bodyVerts = softbodyData.bodyVerts,
                    accumulatedDisplacements = softbodyData.accumulatedDisplacements
                }.Schedule(originalVerts.Length, batchSize, dependsOn: accumulateDistances);
            }

            //Next, set the volume of the soft body
            JobHandle calculateNormals;
            if (parallelNormals)
            {
                calculateNormals = new GatherNormalsJob()
                {
                    bodyVerts         = softbodyData.bodyVerts,
                    vertexConnections = softbodyData.triangleGraph,
                    bodyNormals       = softbodyData.bodyNormals
                }.Schedule(originalVerts.Length, batchSize, dependsOn: applyConstraints);
            }
            else
            {
                JobHandle accumulateNormals = new AccumulateNormalsJob()
                {
                    bodyVerts     = softbodyData.bodyVerts,
                    bodyTriangles = softbodyData.bodyTriangles,
                    bodyNormals   = softbodyData.bodyNormals
                }.Schedule(dependsOn: applyConstraints);
                calculateNormals = new NormalizeNormalsJob()
                {
                    bodyNormals = softbodyData.bodyNormals
                }.Schedule(originalVerts.Length, batchSize, dependsOn: accumulateNormals);
            }

            JobHandle calculateDilationDistance;
            if (useAreaVolumeAccumulator)
            {
                JobHandle accumulateDilationDistance = new SurfaceAreaAndVolumeAccumulatorJob()
                {
                    bodyVerts         = softbodyData.bodyVerts,
                    bodyTriangles     = softbodyData.bodyTriangles,
                    volumeAccumulator = softbodyData.volumeAccumulator,
                    areaAccumulator   = softbodyData.areaAccumulator
                }.Schedule(softbodyData.bodyTriangles.Length, batchSize, dependsOn: calculateNormals);

                calculateDilationDistance = new CalculateDilationJob()
                {
                    volumeAccumulator  = softbodyData.volumeAccumulator,
                    areaAccumulator    = softbodyData.areaAccumulator,
                    initialVolume      = softbodyData.initialVolume * inflationAmount,
                    initialSurfaceArea = softbodyData.initialSurfaceArea,
                    dilationDistance   = softbodyData.dilationDistance
                }.Schedule(dependsOn: accumulateDilationDistance);
            }
            else
            {
                JobHandle accumulateDilationDistance = new AccumulateSurfaceAreaAndVolumeJob()
                {
                    bodyVerts            = softbodyData.bodyVerts,
                    bodyTriangles        = softbodyData.bodyTriangles,
                    triangleVolumes      = softbodyData.triangleVolumes,
                    triangleSurfaceAreas = softbodyData.triangleSurfaceAreas
                }.Schedule(softbodyData.bodyTriangles.Length, batchSize, dependsOn: calculateNormals);

                //THIS IS THE LAST BIG ONE
                calculateDilationDistance = new CalculateSurfaceAreaAndVolumeJob()
                {
                    triangleVolumes      = softbodyData.triangleVolumes,
                    triangleSurfaceAreas = softbodyData.triangleSurfaceAreas,
                    initialVolume        = softbodyData.initialVolume * inflationAmount,
                    initialSurfaceArea   = softbodyData.initialSurfaceArea,
                    dilationDistance     = softbodyData.dilationDistance
                }.Schedule(dependsOn: accumulateDilationDistance);
            }

            previousHandle = new ExtrudeNormalsJob()
            {
                bodyVerts        = softbodyData.bodyVerts,
                bodyNormals      = softbodyData.bodyNormals,
                dilationDistance = softbodyData.dilationDistance
            }.Schedule(originalVerts.Length, batchSize, dependsOn: calculateDilationDistance);
        }

        //Also sneak in a ground plane here:
        JobHandle groundPlaneHandle = new GroundCollideJob()
        {
            bodyVerts         = softbodyData.bodyVerts,
            prevBodyVerts     = softbodyData.prevBodyVerts,
            groundPlanePos    = groundPlane.position,
            groundPlaneNormal = -groundPlane.forward
        }.Schedule(originalVerts.Length, batchSize, dependsOn: previousHandle);

        Profiler.EndSample();

        groundPlaneHandle.Complete();

        //Calculate the the position and rotation of the body
        for (int i = 0; i < softbodyData.bodyVerts.Length; i++)
        {
            softbodyData.kabschVerts[i] = new Vector4(
                softbodyData.bodyVerts[i].x,
                softbodyData.bodyVerts[i].y,
                softbodyData.bodyVerts[i].z, 1f);
        }
        ;
        softbodyData.kabschVerts.CopyTo(kabschVertsArray);
        Matrix4x4 toWorldSpace = kabschSolver.SolveKabsch(originalVerts, kabschVertsArray, transformFollowsRotation);

        transform.position = toWorldSpace.GetVector3();
        transform.rotation = toWorldSpace.GetQuaternion();

        //Move the points into local space for rendering
        JobHandle toLocalHandle = new ToLocalSpaceJob()
        {
            bodyVerts     = softbodyData.bodyVerts,
            bodyNormals   = softbodyData.bodyNormals,
            renderNormals = softbodyData.renderNormals,
            worldToLocal  = transform.worldToLocalMatrix
        }.Schedule(originalVerts.Length, batchSize);

        toLocalHandle.Complete();

        //Graphics
        softbodyData.bodyVerts.CopyTo(bodyVertsArray);
        softbodyData.renderNormals.CopyTo(renderNormalsArray);
        bodyMesh.vertices = bodyVertsArray;
        bodyMesh.normals  = renderNormalsArray;
        bodyMesh.RecalculateBounds();
        bodyMesh.UploadMeshData(false);
    }