void LateUpdate()
        {
            if (!isActiveAndEnabled || actor.solver == null)
            {
                return;
            }

            for (int i = 0; i < actor.solverIndices.Length; ++i)
            {
                int k     = actor.solverIndices[i];
                int phase = ObiUtils.GetGroupFromPhase(actor.solver.phases[k]);

                actor.solver.colors[k] = ObiUtils.colorAlphabet[phase % ObiUtils.colorAlphabet.Length];
            }
        }
예제 #2
0
        public override void SetSelfCollisions(bool selfCollisions)
        {
            if (solver != null && isLoaded)
            {
                Oni.ParticleFlags particlePhase = Oni.ParticleFlags.Fluid;
                if (emitterBlueprint != null && !(emitterBlueprint is ObiFluidEmitterBlueprint))
                {
                    particlePhase = 0;
                }

                for (int i = 0; i < solverIndices.Length; i++)
                {
                    m_Solver.phases[solverIndices[i]] = ObiUtils.MakePhase(fluidPhase, (selfCollisions ? Oni.ParticleFlags.SelfCollide : 0) | particlePhase);
                }
            }
        }
        private int FilterOutDistantContacts(Oni.Contact[] data, int count)
        {
            int filteredCount = count;

            // simply iterate trough all contacts,
            // moving the ones above the threshold to the end of the array:
            for (int i = count - 1; i >= 0; --i)
            {
                if (data[i].distance > distanceThreshold)
                {
                    ObiUtils.Swap(ref data[i], ref data[--filteredCount]);
                }
            }

            return(filteredCount);
        }
        public static float ScreenPointToCurveMu(ObiPath path, Vector2 screenPoint, Matrix4x4 referenceFrame, int samples = 30)
        {
            if (path.ControlPointCount >= 2)
            {
                samples = Mathf.Max(1, samples);
                float step = 1 / (float)samples;

                float closestMu   = 0;
                float minDistance = float.MaxValue;

                for (int k = 0; k < path.GetSpanCount(); ++k)
                {
                    int nextCP = (k + 1) % path.ControlPointCount;

                    var wp1 = path.points[k];
                    var wp2 = path.points[nextCP];

                    Vector3 _p  = referenceFrame.MultiplyPoint3x4(wp1.position);
                    Vector3 p   = referenceFrame.MultiplyPoint3x4(wp1.outTangentEndpoint);
                    Vector3 p_  = referenceFrame.MultiplyPoint3x4(wp2.inTangentEndpoint);
                    Vector3 p__ = referenceFrame.MultiplyPoint3x4(wp2.position);

                    Vector2 lastPoint = HandleUtility.WorldToGUIPoint(path.m_Points.Evaluate(_p, p, p_, p__, 0));
                    for (int i = 1; i <= samples; ++i)
                    {
                        Vector2 currentPoint = HandleUtility.WorldToGUIPoint(path.m_Points.Evaluate(_p, p, p_, p__, i * step));

                        float mu;
                        float distance = Vector2.SqrMagnitude((Vector2)ObiUtils.ProjectPointLine(screenPoint, lastPoint, currentPoint, out mu) - screenPoint);

                        if (distance < minDistance)
                        {
                            minDistance = distance;
                            closestMu   = (k + (i - 1) * step + mu / samples) / (float)path.GetSpanCount();
                        }
                        lastPoint = currentPoint;
                    }
                }

                return(closestMu);
            }
            else
            {
                Debug.LogWarning("Curve needs at least 2 control points to be defined.");
            }
            return(0);
        }
        protected override void OnAddToSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // Set solver constraint data:
            int[] solverIndices = new int[aerodynamicIndices.Count];
            for (int i = 0; i < aerodynamicNormals.Count; i++)
            {
                solverIndices[i] = actor.particleIndices[aerodynamicIndices[i]];
            }

            indicesOffset = actor.solver.aerodynamicConstraints.aerodynamicNormals.Length;
            ObiUtils.AddRange(ref solver.aerodynamicConstraints.aerodynamicIndices, solverIndices);
            ObiUtils.AddRange(ref solver.aerodynamicConstraints.aerodynamicNormals, aerodynamicNormals.ToArray());
            ObiUtils.AddRange(ref solver.aerodynamicConstraints.wind, wind.ToArray());
            ObiUtils.AddRange(ref solver.aerodynamicConstraints.aerodynamicCoeffs, aerodynamicCoeffs.ToArray());
        }
        protected override void OnAddToSolver(ObiBatchedConstraints constraints)
        {
            // Set solver constraint data:
            solverIndices     = new int[springIndices.Count];
            solverRestLengths = new float[restLengths.Count];
            solverStiffnesses = new Vector3[stiffnesses.Count];
            int j = 0;

            foreach (int i in ObiUtils.BilateralInterleaved(restLengths.Count))
            {
                solverIndices[j * 2]     = constraints.Actor.particleIndices[springIndices[i * 2]];
                solverIndices[j * 2 + 1] = constraints.Actor.particleIndices[springIndices[i * 2 + 1]];
                solverRestLengths[j]     = restLengths[i];
                solverStiffnesses[j]     = stiffnesses[i];
                j++;
            }
        }
        protected override void OnAddToSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // Set solver constraint data:
            int[] solverIndices = new int[tetherIndices.Count];
            for (int i = 0; i < maxLengthsScales.Count; i++)
            {
                solverIndices[i * 2]     = actor.particleIndices[tetherIndices[i * 2]];
                solverIndices[i * 2 + 1] = actor.particleIndices[tetherIndices[i * 2 + 1]];
            }

            indicesOffset = actor.solver.tetherConstraints.maxLengthsScales.Length;
            ObiUtils.AddRange(ref solver.tetherConstraints.tetherIndices, solverIndices);
            ObiUtils.AddRange(ref solver.tetherConstraints.maxLengthsScales, maxLengthsScales.ToArray());
            ObiUtils.AddRange(ref solver.tetherConstraints.stiffnesses, stiffnesses.ToArray());
        }
        protected override void OnAddToSolver(ObiBatchedConstraints constraints)
        {
            // Set solver constraint data:
            solverIndices     = new int[springIndices.Count];
            solverDarboux     = new Quaternion[restDarbouxVectors.Count];
            solverStiffnesses = new Vector3[stiffnesses.Count];
            int j = 0;

            foreach (int i in ObiUtils.BilateralInterleaved(restDarbouxVectors.Count))
            {
                solverIndices[j * 2]     = constraints.Actor.particleIndices[springIndices[i * 2]];
                solverIndices[j * 2 + 1] = constraints.Actor.particleIndices[springIndices[i * 2 + 1]];
                solverDarboux[j]         = restDarbouxVectors[i];
                solverStiffnesses[j]     = stiffnesses[i];
                ++j;
            }
        }
예제 #9
0
        protected virtual IEnumerator CreateBendingConstraints()
        {
            bendConstraintsData = new ObiBendConstraintsData();

            // Add three batches:
            bendConstraintsData.AddBatch(new ObiBendConstraintsBatch());
            bendConstraintsData.AddBatch(new ObiBendConstraintsBatch());
            bendConstraintsData.AddBatch(new ObiBendConstraintsBatch());

            for (int i = 0; i < totalParticles - 2; i++)
            {
                var batch = bendConstraintsData.batches[i % 3] as ObiBendConstraintsBatch;

                Vector3Int indices  = new Vector3Int(i, i + 2, i + 1);
                float      restBend = ObiUtils.RestBendingConstraint(restPositions[indices[0]], restPositions[indices[1]], restPositions[indices[2]]);
                batch.AddConstraint(indices, restBend);

                if (i < m_ActiveParticleCount - 2)
                {
                    batch.activeConstraintCount++;
                }

                if (i % 500 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiRope: generating structural constraints...", i / (float)(totalParticles - 2)));
                }
            }

            // if the path is closed, add the last, loop closing constraints to a new batch to avoid sharing particles.
            if (path.Closed)
            {
                var loopClosingBatch = new ObiBendConstraintsBatch();
                bendConstraintsData.AddBatch(loopClosingBatch);

                Vector3Int indices = new Vector3Int(m_ActiveParticleCount - 2, 0, m_ActiveParticleCount - 1);
                loopClosingBatch.AddConstraint(indices, 0);
                loopClosingBatch.activeConstraintCount++;

                var loopClosingBatch2 = new ObiBendConstraintsBatch();
                bendConstraintsData.AddBatch(loopClosingBatch2);

                indices = new Vector3Int(m_ActiveParticleCount - 1, 1, 0);
                loopClosingBatch2.AddConstraint(indices, 0);
                loopClosingBatch2.activeConstraintCount++;
            }
        }
예제 #10
0
        public float GetClosestMuToPoint(Vector3 point, float samples)
        {
            if (controlPoints.Count >= MinPoints)
            {
                samples = Mathf.Max(1, samples);
                float step     = 1 / (float)samples;
                int   numSpans = GetNumSpans();

                float closestMu   = 0;
                float minDistance = float.MaxValue;

                Matrix4x4 l2w = transform.localToWorldMatrix;

                for (int k = 0; k < controlPoints.Count; ++k)
                {
                    Vector3 _p  = l2w.MultiplyPoint3x4(controlPoints[k].position);
                    Vector3 p   = l2w.MultiplyPoint3x4(controlPoints[k].GetOutTangent());
                    Vector3 p_  = l2w.MultiplyPoint3x4(controlPoints[k + 1].GetInTangent());
                    Vector3 p__ = l2w.MultiplyPoint3x4(controlPoints[k + 1].position);

                    Vector3 lastPoint = Evaluate3D(_p, p, p_, p__, 0);
                    for (int i = 1; i <= samples; ++i)
                    {
                        Vector2 currentPoint = Evaluate3D(_p, p, p_, p__, i * step);

                        float mu;
                        float distance = Vector2.SqrMagnitude(ObiUtils.ProjectPointLine(point, lastPoint, currentPoint, out mu) - point);

                        if (distance < minDistance)
                        {
                            minDistance = distance;
                            closestMu   = ((k - 1) + (i - 1) * step + mu / samples) / (float)numSpans;
                        }
                        lastPoint = currentPoint;
                    }
                }

                return(closestMu);
            }
            else
            {
                Debug.LogWarning("Catmull-Rom spline needs at least 4 control points to be defined.");
            }
            return(0);
        }
예제 #11
0
        protected override void OnRemoveFromSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // subtract our amount of constraints from other actor's offsets:
            for (int i = actor.actorID + 1; i < solver.actors.Count; i++)
            {
                ObiBendingConstraints bc = solver.actors[i].GetComponent <ObiBendingConstraints>();
                if (bc != null)
                {
                    bc.UpdateIndicesOffset(bc.indicesOffset - restBends.Count);
                }
            }

            ObiUtils.RemoveRange(ref solver.bendingConstraints.bendingIndices, indicesOffset * 3, restBends.Count * 3);
            ObiUtils.RemoveRange(ref solver.bendingConstraints.restBends, indicesOffset, restBends.Count);
            ObiUtils.RemoveRange(ref solver.bendingConstraints.bendingStiffnesses, indicesOffset, restBends.Count);
        }
예제 #12
0
        protected override void OnAddToSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // Set solver constraint data:
            int[] solverIndices = new int[bendingIndices.Count];
            for (int i = 0; i < restBends.Count; i++)
            {
                solverIndices[i * 3]     = actor.particleIndices[bendingIndices[i * 3]];
                solverIndices[i * 3 + 1] = actor.particleIndices[bendingIndices[i * 3 + 1]];
                solverIndices[i * 3 + 2] = actor.particleIndices[bendingIndices[i * 3 + 2]];
            }

            indicesOffset = actor.solver.bendingConstraints.restBends.Length;
            ObiUtils.AddRange(ref solver.bendingConstraints.bendingIndices, solverIndices);
            ObiUtils.AddRange(ref solver.bendingConstraints.restBends, restBends.ToArray());
            ObiUtils.AddRange(ref solver.bendingConstraints.bendingStiffnesses, bendingStiffnesses.ToArray());
        }
        protected override void OnRemoveFromSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // Update following actors' indices:
            for (int i = actor.actorID + 1; i < solver.actors.Count; i++)
            {
                ObiTetherConstraints tc = solver.actors[i].GetComponent <ObiTetherConstraints>();
                if (tc != null)
                {
                    tc.UpdateIndicesOffset(tc.indicesOffset - maxLengthsScales.Count);
                }
            }

            ObiUtils.RemoveRange(ref solver.tetherConstraints.tetherIndices, indicesOffset * 2, maxLengthsScales.Count * 2);
            ObiUtils.RemoveRange(ref solver.tetherConstraints.maxLengthsScales, indicesOffset, maxLengthsScales.Count);
            ObiUtils.RemoveRange(ref solver.tetherConstraints.stiffnesses, indicesOffset, maxLengthsScales.Count);
        }
예제 #14
0
        protected override void OnRemoveFromSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // Update following actors' indices:
            for (int i = actor.actorID + 1; i < solver.actors.Count; i++)
            {
                ObiPinConstraints pc = solver.actors[i].GetComponent <ObiPinConstraints>();
                if (pc != null)
                {
                    pc.UpdateIndicesOffset(pc.indicesOffset - pinOffsets.Count);
                }
            }

            ObiUtils.RemoveRange(ref solver.pinConstraints.pinIndices, indicesOffset * 2, pinOffsets.Count * 2);
            ObiUtils.RemoveRange(ref solver.pinConstraints.pinOffsets, indicesOffset, pinOffsets.Count);
            ObiUtils.RemoveRange(ref solver.pinConstraints.stiffnesses, indicesOffset, pinOffsets.Count);
        }
예제 #15
0
        protected override void OnAddToSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // Set solver constraint data:
            int[] solverIndices = new int[springIndices.Count];
            for (int i = 0; i < restLengths.Count; i++)
            {
                solverIndices[i * 2]     = actor.particleIndices[springIndices[i * 2]];
                solverIndices[i * 2 + 1] = actor.particleIndices[springIndices[i * 2 + 1]];
            }

            indicesOffset = actor.solver.distanceConstraints.restLengths.Length;
            ObiUtils.AddRange(ref solver.distanceConstraints.springIndices, solverIndices);
            ObiUtils.AddRange(ref solver.distanceConstraints.restLengths, restLengths.ToArray());
            ObiUtils.AddRange(ref solver.distanceConstraints.stiffnesses, stiffnesses.ToArray());
            ObiUtils.AddRange(ref solver.distanceConstraints.stretching, stretching.ToArray());
        }
예제 #16
0
        public static float ScreenPointToCurveMu(ObiCurve curve, Vector2 screenPoint, int samples = 30)
        {
            if (curve.controlPoints.Count >= curve.MinPoints)
            {
                samples = Mathf.Max(1, samples);
                float step = 1 / (float)samples;

                float closestMu   = 0;
                float minDistance = float.MaxValue;

                Matrix4x4 l2w = curve.transform.localToWorldMatrix;

                for (int k = 0; k < curve.GetNumSpans(); ++k)
                {
                    Vector3 _p  = l2w.MultiplyPoint3x4(curve.controlPoints[k].position);
                    Vector3 p   = l2w.MultiplyPoint3x4(curve.controlPoints[k].GetOutTangent());
                    Vector3 p_  = l2w.MultiplyPoint3x4(curve.controlPoints[(k + 1) % curve.controlPoints.Count].GetInTangent());
                    Vector3 p__ = l2w.MultiplyPoint3x4(curve.controlPoints[(k + 1) % curve.controlPoints.Count].position);

                    Vector2 lastPoint = HandleUtility.WorldToGUIPoint(curve.Evaluate3D(_p, p, p_, p__, 0));
                    for (int i = 1; i <= samples; ++i)
                    {
                        Vector2 currentPoint = HandleUtility.WorldToGUIPoint(curve.Evaluate3D(_p, p, p_, p__, i * step));

                        float mu;
                        float distance = Vector2.SqrMagnitude((Vector2)ObiUtils.ProjectPointLine(screenPoint, lastPoint, currentPoint, out mu) - screenPoint);

                        if (distance < minDistance)
                        {
                            minDistance = distance;
                            closestMu   = (k + (i - 1) * step + mu / samples) / (float)curve.GetNumSpans();
                        }
                        lastPoint = currentPoint;
                    }
                }

                return(closestMu);
            }
            else
            {
                Debug.LogWarning("Curve needs at least 2 control points to be defined.");
            }
            return(0);
        }
예제 #17
0
        protected override void OnAddToSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // Set solver constraint data:
            int[] solverIndices = new int[skinIndices.Count];
            for (int i = 0; i < skinIndices.Count; i++)
            {
                solverIndices[i] = actor.particleIndices[skinIndices[i]];
                solverIndices[i] = actor.particleIndices[skinIndices[i]];
            }

            indicesOffset = actor.solver.skinConstraints.skinIndices.Length;
            ObiUtils.AddRange(ref solver.skinConstraints.skinIndices, solverIndices);
            ObiUtils.AddRange(ref solver.skinConstraints.skinPoints, skinPoints.ToArray());
            ObiUtils.AddRange(ref solver.skinConstraints.skinNormals, skinNormals.ToArray());
            ObiUtils.AddRange(ref solver.skinConstraints.skinRadiiBackstops, skinRadiiBackstop.ToArray());
            ObiUtils.AddRange(ref solver.skinConstraints.skinStiffnesses, skinStiffnesses.ToArray());
        }
예제 #18
0
        protected override void OnRemoveFromSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // Update following actors' indices:
            for (int i = actor.actorID + 1; i < solver.actors.Count; i++)
            {
                ObiDistanceConstraints dc = solver.actors[i].GetComponent <ObiDistanceConstraints>();
                if (dc != null)
                {
                    dc.UpdateIndicesOffset(dc.indicesOffset - restLengths.Count);
                }
            }

            ObiUtils.RemoveRange(ref solver.distanceConstraints.springIndices, indicesOffset * 2, restLengths.Count * 2);
            ObiUtils.RemoveRange(ref solver.distanceConstraints.restLengths, indicesOffset, restLengths.Count);
            ObiUtils.RemoveRange(ref solver.distanceConstraints.stiffnesses, indicesOffset, restLengths.Count);
            ObiUtils.RemoveRange(ref solver.distanceConstraints.stretching, indicesOffset, restLengths.Count);
        }
예제 #19
0
        private bool TopologySplitAttempt(ref int splitActorIndex,
                                          ref int intactActorIndex,
                                          out Vector3 point,
                                          out Vector3 normal,
                                          List <HalfEdgeMesh.Face> updatedFaces,
                                          HashSet <int> updatedHalfEdges)
        {
            int splitSolverIndex  = solverIndices[splitActorIndex];
            int intactSolverIndex = solverIndices[intactActorIndex];

            // we will first try to split the particle with higher mass, so swap them if needed.
            if (m_Solver.invMasses[splitSolverIndex] > m_Solver.invMasses[intactSolverIndex])
            {
                ObiUtils.Swap(ref splitSolverIndex, ref intactSolverIndex);
            }

            // Calculate the splitting plane:
            point = m_Solver.positions[splitSolverIndex];
            Vector3 v2 = m_Solver.positions[intactSolverIndex];

            normal = (v2 - point).normalized;

            // Try to split the vertex at that particle.
            // If we cannot not split the higher mass particle, try the other one. If that fails too, we cannot tear this edge.
            if (m_Solver.invMasses[splitSolverIndex] == 0 ||
                !SplitTopologyAtVertex(splitActorIndex, new Plane(normal, point), updatedFaces, updatedHalfEdges))
            {
                // Try to split the other particle:
                ObiUtils.Swap(ref splitActorIndex, ref intactActorIndex);
                ObiUtils.Swap(ref splitSolverIndex, ref intactSolverIndex);

                point  = m_Solver.positions[splitSolverIndex];
                v2     = m_Solver.positions[intactSolverIndex];
                normal = (v2 - point).normalized;

                if (m_Solver.invMasses[splitSolverIndex] == 0 ||
                    !SplitTopologyAtVertex(splitActorIndex, new Plane(normal, point), updatedFaces, updatedHalfEdges))
                {
                    return(false);
                }
            }
            return(true);
        }
예제 #20
0
        public void OnDrawGizmosSelected()
        {
            Gizmos.matrix = transform.localToWorldMatrix;
            Gizmos.color  = new Color(0, 0.7f, 1, 1);
            Gizmos.DrawWireSphere(Vector3.zero, radius);

            float turb = GetTurbulence(1);

            if (!radial)
            {
                ObiUtils.DrawArrowGizmo(radius + turb, radius * 0.2f, radius * 0.3f, radius * 0.2f);
            }
            else
            {
                Gizmos.DrawLine(new Vector3(0, 0, -radius * 0.5f) * turb, new Vector3(0, 0, radius * 0.5f) * turb);
                Gizmos.DrawLine(new Vector3(0, -radius * 0.5f, 0) * turb, new Vector3(0, radius * 0.5f, 0) * turb);
                Gizmos.DrawLine(new Vector3(-radius * 0.5f, 0, 0) * turb, new Vector3(radius * 0.5f, 0, 0) * turb);
            }
        }
        protected override void OnRemoveFromSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // subtract our amount of constraints from other actor's offsets:
            for (int i = actor.actorID + 1; i < solver.actors.Count; i++)
            {
                ObiAerodynamicConstraints ac = solver.actors[i].GetComponent <ObiAerodynamicConstraints>();
                if (ac != null)
                {
                    ac.UpdateIndicesOffset(ac.indicesOffset - aerodynamicNormals.Count);
                }
            }

            ObiUtils.RemoveRange(ref solver.aerodynamicConstraints.aerodynamicIndices, indicesOffset, aerodynamicIndices.Count);
            ObiUtils.RemoveRange(ref solver.aerodynamicConstraints.aerodynamicNormals, indicesOffset, aerodynamicNormals.Count);
            ObiUtils.RemoveRange(ref solver.aerodynamicConstraints.wind, indicesOffset, wind.Count);
            ObiUtils.RemoveRange(ref solver.aerodynamicConstraints.aerodynamicCoeffs, indicesOffset * 3, aerodynamicCoeffs.Count);
        }
예제 #22
0
        private void RefreshCutawayTexture(ObiDistanceField field)
        {
            if (field == null)
            {
                return;
            }

            Bounds b = field.FieldBounds;

            sampleSize  = field.EffectiveSampleSize;
            sampleCount = (int)(b.size[0] / sampleSize) + 1;

            CreatePlaneMesh(field);
            ResizeTexture();

            float   sweep  = (sampleCount * slice) * sampleSize;
            Vector3 origin = b.center - b.extents;

            for (int x = 0; x < sampleCount; ++x)
            {
                for (int y = 0; y < sampleCount; ++y)
                {
                    Vector3 offset = Vector3.zero;
                    switch (axis)
                    {
                    case Axis.X: offset = new Vector3(sweep, y * sampleSize, x * sampleSize); break;

                    case Axis.Y: offset = new Vector3(x * sampleSize, sweep, y * sampleSize); break;

                    case Axis.Z: offset = new Vector3(x * sampleSize, y * sampleSize, sweep); break;
                    }

                    Vector4 position = origin + offset;
                    float   distance = Oni.SampleDistanceField(field.OniDistanceField, position.x, position.y, position.z);

                    float value = ObiUtils.Remap(distance, -maxDistance, maxDistance, 0, 1);

                    cutawayTexture.SetPixel(x, y, new Color(value, 0, 0));
                }
            }
            cutawayTexture.Apply();
        }
예제 #23
0
        protected override void OnRemoveFromSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // subtract our amount of constraints from other actor's offsets:
            for (int i = actor.actorID + 1; i < solver.actors.Count; i++)
            {
                ObiSkinConstraints dc = solver.actors[i].GetComponent <ObiSkinConstraints>();
                if (dc != null)
                {
                    dc.UpdateIndicesOffset(dc.indicesOffset - skinIndices.Count);
                }
            }

            ObiUtils.RemoveRange(ref solver.skinConstraints.skinIndices, indicesOffset, skinIndices.Count);
            ObiUtils.RemoveRange(ref solver.skinConstraints.skinPoints, indicesOffset, skinIndices.Count);
            ObiUtils.RemoveRange(ref solver.skinConstraints.skinNormals, indicesOffset, skinIndices.Count);
            ObiUtils.RemoveRange(ref solver.skinConstraints.skinRadiiBackstops, indicesOffset * 2, skinIndices.Count * 2);
            ObiUtils.RemoveRange(ref solver.skinConstraints.skinStiffnesses, indicesOffset, skinIndices.Count);
        }
        protected override void OnAddToSolver(object info)
        {
            ObiSolver solver = actor.solver;

            // Set solver constraint data:
            int[] solverIndices = new int[particleIndices.Count];
            for (int i = 0; i < particleIndices.Count; i++)
            {
                solverIndices[i] = actor.particleIndices[particleIndices[i]];
            }

            int[] solverFirstTriangle = new int[firstTriangle.Count];
            for (int i = 0; i < firstTriangle.Count; i++)
            {
                solverFirstTriangle[i] = (int)actor.solver.volumeConstraints.volumeTriangleIndices.Length / 3 + firstTriangle[i];
            }

            int[] solverFirstParticle = new int[firstParticle.Count];
            for (int i = 0; i < firstParticle.Count; i++)
            {
                solverFirstParticle[i] = actor.solver.volumeConstraints.volumeParticleIndices.Length + firstParticle[i];
            }

            indicesOffset         = actor.solver.volumeConstraints.volumeRestVolumes.Length;
            volumeTrianglesOffset = actor.solver.volumeConstraints.volumeTriangleIndices.Length;
            volumeParticlesOffset = actor.solver.volumeConstraints.volumeParticleIndices.Length;

            ObiUtils.AddRange(ref solver.volumeConstraints.volumeTriangleIndices, triangleIndices.ToArray());
            ObiUtils.AddRange(ref solver.volumeConstraints.volumeFirstTriangle, solverFirstTriangle);
            ObiUtils.AddRange(ref solver.volumeConstraints.volumeNumTriangles, numTriangles.ToArray());

            ObiUtils.AddRange(ref solver.volumeConstraints.volumeParticleIndices, solverIndices);
            ObiUtils.AddRange(ref solver.volumeConstraints.volumeFirstParticle, solverFirstParticle);
            ObiUtils.AddRange(ref solver.volumeConstraints.volumeNumParticles, numParticles.ToArray());

            ObiUtils.AddRange(ref solver.volumeConstraints.volumeRestVolumes, restVolumes.ToArray());
            ObiUtils.AddRange(ref solver.volumeConstraints.volumePressureStiffnesses, pressureStiffness.ToArray());
        }
예제 #25
0
        protected virtual IEnumerator CreateBendTwistConstraints()
        {
            bendTwistConstraintsData = new ObiBendTwistConstraintsData();

            // Add two batches:
            bendTwistConstraintsData.AddBatch(new ObiBendTwistConstraintsBatch());
            bendTwistConstraintsData.AddBatch(new ObiBendTwistConstraintsBatch());

            // the last bend constraint couples the last segment and a phantom segment past the last particle.
            for (int i = 0; i < totalParticles - 1; i++)
            {
                var batch = bendTwistConstraintsData.batches[i % 2] as ObiBendTwistConstraintsBatch;

                Vector2Int indices = new Vector2Int(i, i + 1);

                Quaternion darboux = keepInitialShape ? ObiUtils.RestDarboux(orientations[indices.x], orientations[indices.y]) : Quaternion.identity;
                batch.AddConstraint(indices, darboux);
                batch.activeConstraintCount++;

                if (i % 500 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiRod: generating structural constraints...", i / (float)(totalParticles - 1)));
                }
            }

            // if the path is closed, add the last, loop closing constraints to a new batch to avoid sharing particles.
            if (path.Closed)
            {
                var loopClosingBatch = new ObiBendTwistConstraintsBatch();
                bendTwistConstraintsData.AddBatch(loopClosingBatch);

                Vector2Int indices = new Vector2Int(m_ActiveParticleCount - 1, 0);
                Quaternion darboux = keepInitialShape ? ObiUtils.RestDarboux(orientations[indices.x], orientations[indices.y]) : Quaternion.identity;
                loopClosingBatch.AddConstraint(indices, darboux);
                loopClosingBatch.activeConstraintCount++;
            }
        }
예제 #26
0
파일: BIH.cs 프로젝트: Havie/BallTest
        public static float DistanceToSurface(Triangle[] triangles,
                                              Vector3[] vertices,
                                              Vector3[] normals,
                                              BIHNode node,
                                              Vector3 point)
        {
            float minDistance = float.MaxValue;
            int   sign        = 1;

            for (int i = node.start; i < node.start + node.count; ++i)
            {
                Triangle t          = triangles[i];
                Vector3  pointOnTri = ObiUtils.NearestPointOnTri(vertices[t.i1],
                                                                 vertices[t.i2],
                                                                 vertices[t.i3],
                                                                 point);

                Vector3 pointToTri  = point - pointOnTri;
                float   sqrDistance = pointToTri.sqrMagnitude;

                if (sqrDistance < minDistance)
                {
                    Vector3 bary = Vector3.zero;
                    ObiUtils.BarycentricCoordinates(vertices[t.i1], vertices[t.i2], vertices[t.i3], pointOnTri, ref bary);

                    Vector3 interpolatedNormal = ObiUtils.BarycentricInterpolation(normals[t.i1],
                                                                                   normals[t.i2],
                                                                                   normals[t.i3], bary);

                    sign        = ObiUtils.PureSign(Vector3.Dot(pointToTri, interpolatedNormal));
                    minDistance = sqrDistance;
                }
            }

            return(Mathf.Sqrt(minDistance) * sign);
        }
예제 #27
0
        public override void OnInspectorGUI()
        {
            serializedObject.UpdateIfRequiredOrScript();

            Editor.DrawPropertiesExcluding(serializedObject, "m_Script");

            // Get the particle actor editor to retrieve selected particles:
            ObiParticleActorEditor[] editors = (ObiParticleActorEditor[])Resources.FindObjectsOfTypeAll(typeof(ObiParticleActorEditor));

            // If there's any particle actor editor active, we can show pin constraints:
            if (editors.Length > 0)
            {
                List <int> selectedPins = new List <int>();
                List <int> removedPins  = new List <int>();

                if (constraints.GetFirstBatch() != null)
                {
                    ObiPinConstraintBatch batch = constraints.GetFirstBatch();

                    // Get the list of pin constraints from the selected particles:
                    for (int i = 0; i < batch.ConstraintCount; i++)
                    {
                        int particleIndex = batch.pinIndices[i];

                        if (particleIndex >= 0 && particleIndex < ObiParticleActorEditor.selectionStatus.Length &&
                            ObiParticleActorEditor.selectionStatus[particleIndex])
                        {
                            selectedPins.Add(i);
                        }
                    }

                    if (selectedPins.Count > 0)
                    {
                        //Iterate over all constraints:
                        foreach (int i in selectedPins)
                        {
                            GUILayout.BeginVertical("box");

                            GUILayout.BeginHorizontal();

                            EditorGUI.BeginChangeCheck();
                            bool allowSceneObjects = !EditorUtility.IsPersistent(target);
                            batch.pinBodies[i] = EditorGUILayout.ObjectField("Pinned to:", batch.pinBodies[i], typeof(ObiColliderBase), allowSceneObjects) as ObiColliderBase;

                            // Calculate initial pin offset value after changing the rigidbody.
                            if (EditorGUI.EndChangeCheck() && batch.pinBodies[i] != null)
                            {
                                batch.pinOffsets[i]         = batch.pinBodies[i].transform.InverseTransformPoint(constraints.Actor.GetParticlePosition(batch.pinIndices[i]));
                                batch.restDarbouxVectors[i] = ObiUtils.RestDarboux(constraints.Actor.GetParticleOrientation(batch.pinIndices[i]), batch.pinBodies[i].transform.rotation);
                            }

                            Color oldColor = GUI.color;
                            GUI.color = Color.red;
                            if (GUILayout.Button("X", GUILayout.Width(30)))
                            {
                                // Mark this constraint to be removed outside of the loop.
                                removedPins.Add(i);
                                continue;
                            }
                            GUI.color = oldColor;

                            GUILayout.EndHorizontal();

                            batch.pinOffsets[i]         = EditorGUILayout.Vector3Field("Offset:", batch.pinOffsets[i]);
                            batch.pinBreakResistance[i] = EditorGUILayout.DelayedFloatField("Break Resistance:", batch.pinBreakResistance[i]);

                            GUILayout.EndVertical();
                        }
                    }
                    else
                    {
                        EditorGUILayout.HelpBox("No pin constraints for the selected particles.", MessageType.Info);
                    }

                    if (GUILayout.Button("Remove selected"))
                    {
                        for (int i = 0; i < batch.ConstraintCount; i++)
                        {
                            int particleIndex = batch.pinIndices[i];

                            if (particleIndex >= 0 && particleIndex < ObiParticleActorEditor.selectionStatus.Length &&
                                ObiParticleActorEditor.selectionStatus[particleIndex])
                            {
                                removedPins.Add(i);
                            }
                        }
                    }

                    if (GUILayout.Button("Add Pin Constraint"))
                    {
                        Undo.RecordObject(constraints, "Add pin constraints");

                        bool wasInSolver = constraints.InSolver;
                        constraints.RemoveFromSolver(null);

                        for (int i = 0; i < ObiParticleActorEditor.selectionStatus.Length; i++)
                        {
                            if (ObiParticleActorEditor.selectionStatus[i])
                            {
                                batch.AddConstraint(i, null, Vector3.zero, Quaternion.identity, 0);
                            }
                        }

                        if (wasInSolver)
                        {
                            constraints.AddToSolver(null);
                        }
                    }

                    // Remove selected constraint outside of constraint listing loop:
                    if (removedPins.Count > 0)
                    {
                        Undo.RecordObject(constraints, "Remove pin constraints");

                        bool wasInSolver = constraints.InSolver;
                        constraints.RemoveFromSolver(null);

                        // Remove from last to first, to avoid throwing off subsequent indices:
                        foreach (int i in removedPins.OrderByDescending(i => i))
                        {
                            batch.RemoveConstraint(i);
                        }

                        if (wasInSolver)
                        {
                            constraints.AddToSolver(null);
                        }
                    }
                }
            }

            // Apply changes to the serializedProperty
            if (GUI.changed)
            {
                serializedObject.ApplyModifiedProperties();

                constraints.PushDataToSolver();
            }
        }
예제 #28
0
        protected override IEnumerator Initialize()
        {
            if (path.ControlPointCount < 2)
            {
                ClearParticleGroups();
                path.InsertControlPoint(0, Vector3.left, Vector3.left * 0.25f, Vector3.right * 0.25f, Vector3.up, DEFAULT_PARTICLE_MASS, 1, 1, 1, Color.white, "control point");
                path.InsertControlPoint(1, Vector3.right, Vector3.left * 0.25f, Vector3.right * 0.25f, Vector3.up, DEFAULT_PARTICLE_MASS, 1, 1, 1, Color.white, "control point");
            }

            path.RecalculateLenght(Matrix4x4.identity, 0.00001f, 7);

            List <Vector3> particlePositions   = new List <Vector3>();
            List <float>   particleThicknesses = new List <float>();
            List <float>   particleInvMasses   = new List <float>();
            List <int>     particlePhases      = new List <int>();
            List <Color>   particleColors      = new List <Color>();

            // In case the path is open, add a first particle. In closed paths, the last particle is also the first one.
            if (!path.Closed)
            {
                particlePositions.Add(path.points.GetPositionAtMu(path.Closed, 0));
                particleThicknesses.Add(path.thicknesses.GetAtMu(path.Closed, 0));
                particleInvMasses.Add(ObiUtils.MassToInvMass(path.masses.GetAtMu(path.Closed, 0)));
                particlePhases.Add(path.phases.GetAtMu(path.Closed, 0));
                particleColors.Add(path.colors.GetAtMu(path.Closed, 0));
            }

            // Create a particle group for the first control point:
            groups[0].particleIndices.Clear();
            groups[0].particleIndices.Add(0);

            ReadOnlyCollection <float> lengthTable = path.ArcLengthTable;
            int spans = path.GetSpanCount();

            for (int i = 0; i < spans; i++)
            {
                int firstArcLengthSample = i * (path.ArcLengthSamples + 1);
                int lastArcLengthSample  = (i + 1) * (path.ArcLengthSamples + 1);

                float upToSpanLength = lengthTable[firstArcLengthSample];
                float spanLength     = lengthTable[lastArcLengthSample] - upToSpanLength;

                int   particlesInSpan = 1 + Mathf.FloorToInt(spanLength / thickness * resolution);
                float distance        = spanLength / particlesInSpan;

                for (int j = 0; j < particlesInSpan; ++j)
                {
                    float mu = path.GetMuAtLenght(upToSpanLength + distance * (j + 1));
                    particlePositions.Add(path.points.GetPositionAtMu(path.Closed, mu));
                    particleThicknesses.Add(path.thicknesses.GetAtMu(path.Closed, mu));
                    particleInvMasses.Add(ObiUtils.MassToInvMass(path.masses.GetAtMu(path.Closed, mu)));
                    particlePhases.Add(path.phases.GetAtMu(path.Closed, mu));
                    particleColors.Add(path.colors.GetAtMu(path.Closed, mu));
                }

                // Create a particle group for each control point:
                if (!(path.Closed && i == spans - 1))
                {
                    groups[i + 1].particleIndices.Clear();
                    groups[i + 1].particleIndices.Add(particlePositions.Count - 1);
                }

                if (i % 100 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiRope: generating particles...", i / (float)spans));
                }
            }

            m_ActiveParticleCount = particlePositions.Count;
            totalParticles        = m_ActiveParticleCount + pooledParticles;

            int numSegments = m_ActiveParticleCount - (path.Closed ? 0 : 1);

            if (numSegments > 0)
            {
                m_InterParticleDistance = path.Length / (float)numSegments;
            }
            else
            {
                m_InterParticleDistance = 0;
            }

            positions      = new Vector3[totalParticles];
            restPositions  = new Vector4[totalParticles];
            velocities     = new Vector3[totalParticles];
            invMasses      = new float[totalParticles];
            principalRadii = new Vector3[totalParticles];
            phases         = new int[totalParticles];
            colors         = new Color[totalParticles];
            restLengths    = new float[totalParticles];

            for (int i = 0; i < m_ActiveParticleCount; i++)
            {
                invMasses[i]        = particleInvMasses[i];
                positions[i]        = particlePositions[i];
                restPositions[i]    = positions[i];
                restPositions[i][3] = 1; // activate rest position.
                principalRadii[i]   = Vector3.one * particleThicknesses[i] * thickness;
                phases[i]           = ObiUtils.MakePhase(particlePhases[i], 0);
                colors[i]           = particleColors[i];

                if (i % 100 == 0)
                {
                    yield return(new CoroutineJob.ProgressInfo("ObiRope: generating particles...", i / (float)m_ActiveParticleCount));
                }
            }

            //Create distance constraints for the total number of particles, but only activate for the used ones.
            IEnumerator dc = CreateDistanceConstraints();

            while (dc.MoveNext())
            {
                yield return(dc.Current);
            }

            //Create bending constraints:
            IEnumerator bc = CreateBendingConstraints();

            while (bc.MoveNext())
            {
                yield return(bc.Current);
            }

            // Recalculate rest length:
            m_RestLength = 0;
            foreach (float length in restLengths)
            {
                m_RestLength += length;
            }
        }
예제 #29
0
        /**
         * We need to find the barycentric coordinates of point such that the interpolated normal at that point passes trough our target position.
         *
         *            X
         *  \        /  /
         *   \------/--/
         *
         * This is necessary to ensure curvature changes in the surface affect skinned points away from the face plane.
         * To do so, we use an iterative method similar to Newton´s method for root finding:
         *
         * - Project the point on the triangle using an initial normal.
         * - Get interpolated normal at projection.
         * - Intersect line from point and interpolated normal with triangle, to find a new projection.
         * - Repeat.
         */
        BarycentricPoint FindSkinBarycentricCoords(MasterFace triangle,
                                                   Vector3 position,
                                                   int max_iterations,
                                                   float min_convergence)
        {
            BarycentricPoint barycentricPoint = BarycentricPoint.zero;

            // start at center of triangle:
            Vector3 trusted_bary = Vector3.one / 3.0f;
            Vector3 temp_normal  = ObiUtils.BarycentricInterpolation(triangle.n1,
                                                                     triangle.n2,
                                                                     triangle.n3,
                                                                     trusted_bary);

            int   it          = 0;
            float trust       = 1.0f;
            float convergence = float.MaxValue;

            while (it++ < max_iterations)
            {
                Vector3 point;
                if (!Obi.ObiUtils.LinePlaneIntersection(triangle.p1, triangle.faceNormal, position, temp_normal, out point))
                {
                    break;
                }

                // get bary coords at intersection:
                Vector3 bary = Vector3.zero;
                if (!triangle.BarycentricCoords(point, ref bary))
                {
                    break;
                }

                // calculate error:
                Vector3 error = bary - trusted_bary;     // distance from current estimation to last trusted estimation.
                convergence = Vector3.Dot(error, error); // get a single convergence value.

                // weighted sum of bary coords:
                trusted_bary = (1.0f - trust) * trusted_bary + trust * bary;

                // update normal
                temp_normal = ObiUtils.BarycentricInterpolation(triangle.n1,
                                                                triangle.n2,
                                                                triangle.n3,
                                                                trusted_bary);

                if (convergence < min_convergence)
                {
                    break;
                }

                trust *= 0.8f;
            }

            Vector3 pos_on_tri = trusted_bary[0] * triangle.p1 +
                                 trusted_bary[1] * triangle.p2 +
                                 trusted_bary[2] * triangle.p3;

            float height = Vector3.Dot(position - pos_on_tri, temp_normal);

            barycentricPoint.barycentricCoords = trusted_bary;
            barycentricPoint.height            = height;

            return(barycentricPoint);
        }
예제 #30
0
파일: BIH.cs 프로젝트: Havie/BallTest
        public static List <BIHNode> Build(ref IBounded[] elements)
        {
            List <BIHNode> nodes = new List <BIHNode> {
                new BIHNode(0, elements.Length)
            };

            var queue = new Queue <int>();

            queue.Enqueue(0);

            while (queue.Count > 0)
            {
                // get current node:
                int index = queue.Dequeue();
                var node  = nodes[index];

                // if this node contains enough elements, split it:
                if (node.count > 1)
                {
                    int start = node.start;
                    int end   = start + (node.count - 1);

                    // calculate bounding box of all elements:
                    Aabb b = elements[start].GetBounds();
                    for (int k = start + 1; k <= end; ++k)
                    {
                        b.Encapsulate(elements[k].GetBounds());
                    }

                    // determine split axis (longest one):
                    Vector3 size = b.size;
                    int     axis = node.axis = (size.x > size.y) ?
                                               (size.x > size.z ? 0 : 2) :
                                               (size.y > size.z ? 1 : 2);

                    // place split plane at half the longest axis:
                    float pivot = b.min[axis] + size[axis] * 0.5f;

                    // sort elements using the split plane (Hoare's partition algorithm):
                    int  i = start - 1;
                    int  j = end + 1;
                    Aabb bi, bj;
                    while (true)
                    {
                        // iterate over left elements, while they're smaller than the pivot.
                        do
                        {
                            bi = elements[++i].GetBounds();
                            if (bi.center[axis] < pivot)
                            {
                                node.min = Mathf.Max(node.min, bi.max[axis]);
                            }
                        } while (bi.center[axis] < pivot);

                        // iterate over right elements, while they're larger than the pivot.
                        do
                        {
                            bj = elements[--j].GetBounds();
                            if (bj.center[axis] > pivot)
                            {
                                node.max = Mathf.Min(node.max, bj.min[axis]);
                            }
                        } while (bj.center[axis] > pivot);

                        // if element i is larger than the pivot, j smaller than the pivot, swap them.
                        if (i < j)
                        {
                            ObiUtils.Swap(ref elements[i], ref elements[j]);
                            node.min = Mathf.Max(node.min, bj.max[axis]);
                            node.max = Mathf.Min(node.max, bi.min[axis]);
                        }
                        else
                        {
                            break;
                        }
                    }

                    // create two child nodes:
                    var minChild = new BIHNode(start, j - start + 1);
                    var maxChild = new BIHNode(j + 1, end - j);

                    // guard against cases where all elements are on one side of the split plane,
                    // due to all having the same or very similar bounds as the entire group.
                    if (minChild.count > 0 && maxChild.count > 0)
                    {
                        node.firstChild = nodes.Count;
                        nodes[index]    = node;

                        queue.Enqueue(nodes.Count);
                        queue.Enqueue(nodes.Count + 1);

                        // append child nodes to list:
                        nodes.Add(minChild);
                        nodes.Add(maxChild);
                    }
                }
            }

            return(nodes);
        }