示例#1
0
        private void OnDrawGizmos()
        {
            if (_frames != null)
            {
                for (int i = 0; i < ParametrizationCount; ++i)
                {
                    Vector3 pos = _frames[i].Position;

                    Gizmos.color = Color.red;
                    if (DrawTangents)
                    {
                        Gizmos.DrawLine(pos, pos + _frames[i].Tangent * .5f);
                    }

                    Gizmos.color = Color.green;
                    if (DrawNormals)
                    {
                        Gizmos.DrawLine(pos, pos + _frames[i].Normal * .5f);
                    }

                    Gizmos.color = Color.white;
                    Gizmos.DrawWireSphere(pos, .05f);
                }

                if (DrawCurvatures)
                {
                    Gizmos.color = Color.yellow;
                    CurveFrame frame = _frames[CurvatureIndex];

                    float   rad    = 1f / _curvatures[CurvatureIndex];
                    Circle3 circle = new Circle3(frame.Position + frame.Normal * rad, frame.Binormal, rad);
                    DrawCircle(ref circle, 100);
                }
            }
        }
示例#2
0
 public override void TransportFrame(CurveFrame frame, CurveSection section, float sectionTwist)
 {
     if (frame != null)
     {
         frame.Transport(section, sectionTwist);
     }
 }
        /// <summary>
        /// Sets up this control point
        /// </summary>
        public SplineControlPoint( Curve owner, int index )
        {
            m_Owner = owner;
            m_Index	= index;
            m_Frame	= m_Owner.EvaluateFrame( index );

            owner.OnChangedEvent += OnOwnerSplineChanged;
        }
示例#4
0
        public override void UpdateTearPrefab(CurveFrame frame, ref int tearCount, bool reverseLookDirection)
        {
            if (tearPrefabPool != null && tearCount < tearPrefabPool.Length)
            {
                if (!tearPrefabPool[tearCount].activeSelf)
                {
                    tearPrefabPool[tearCount].SetActive(true);
                }

                PlaceObjectAtCurveFrame(frame, tearPrefabPool[tearCount], Space.Self, reverseLookDirection);
                tearCount++;
            }
        }
示例#5
0
 public void PlaceObjectAtCurveFrame(CurveFrame frame, GameObject obj, Space space, bool reverseLookDirection)
 {
     if (space == Space.Self)
     {
         Matrix4x4 l2w = transform.localToWorldMatrix;
         obj.transform.position = l2w.MultiplyPoint3x4(frame.position);
         if (frame.tangent != Vector3.zero)
         {
             obj.transform.rotation = Quaternion.LookRotation(l2w.MultiplyVector(reverseLookDirection ? frame.tangent:-frame.tangent),
                                                              l2w.MultiplyVector(frame.normal));
         }
     }
     else
     {
         obj.transform.position = frame.position;
         if (frame.tangent != Vector3.zero)
         {
             obj.transform.rotation = Quaternion.LookRotation(reverseLookDirection ? frame.tangent:-frame.tangent, frame.normal);
         }
     }
 }
        public void LateUpdate()
        {
            ClearMeshData();

            if (section == null)
            {
                return;
            }

            IList <List <Vector3> > segments = cable.sampledCable.Segments;

            int sectionSegments    = section.Segments;
            int verticesPerSection = sectionSegments + 1;       // the last vertex in each section must be duplicated, due to uv wraparound.

            float vCoord       = -uvScale.y * cable.RestLength; // v texture coordinate.
            int   sectionIndex = 0;

            float strain = cable.sampledCable.Length / cable.RestLength;

            // we will define and transport a reference frame along the curve using parallel transport method:
            if (frame == null)
            {
                frame = new CurveFrame();
            }

            Vector4 texTangent = Vector4.zero;
            Vector2 uv         = Vector2.zero;

            Matrix4x4 w2l = transform.worldToLocalMatrix;

            for (int k = 0; k < segments.Count; ++k)
            {
                List <Vector3> samples = segments[k];

                // Reinitialize frame for each segment.
                frame.Reset();

                for (int i = 0; i < samples.Count; ++i)
                {
                    // Calculate previous and next curve indices:
                    int nextIndex = Mathf.Min(i + 1, samples.Count - 1);
                    int prevIndex = Mathf.Max(i - 1, 0);

                    Vector3 point     = w2l.MultiplyPoint3x4(samples[i]);
                    Vector3 prevPoint = w2l.MultiplyPoint3x4(samples[prevIndex]);
                    Vector3 nextPoint = w2l.MultiplyPoint3x4(samples[nextIndex]);

                    Vector3 nextV   = (nextPoint - point).normalized;
                    Vector3 prevV   = (point - prevPoint).normalized;
                    Vector3 tangent = nextV + prevV;

                    // update frame:
                    frame.Transport(point, tangent, 0);

                    // advance v texcoord:
                    vCoord += uvScale.y * (Vector3.Distance(point, prevPoint) / strain);

                    // Loop around each segment:
                    for (int j = 0; j <= sectionSegments; ++j)
                    {
                        vertices.Add(frame.position + (section.vertices[j].x * frame.normal + section.vertices[j].y * frame.binormal) * thickness);
                        normals.Add(vertices[vertices.Count - 1] - frame.position);
                        texTangent   = -Vector3.Cross(normals[normals.Count - 1], frame.tangent);
                        texTangent.w = 1;
                        tangents.Add(texTangent);

                        uv.Set((j / (float)sectionSegments) * uvScale.x, vCoord);
                        uvs.Add(uv);

                        if (j < sectionSegments && i < samples.Count - 1)
                        {
                            tris.Add(sectionIndex * verticesPerSection + j);
                            tris.Add(sectionIndex * verticesPerSection + (j + 1));
                            tris.Add((sectionIndex + 1) * verticesPerSection + j);

                            tris.Add(sectionIndex * verticesPerSection + (j + 1));
                            tris.Add((sectionIndex + 1) * verticesPerSection + (j + 1));
                            tris.Add((sectionIndex + 1) * verticesPerSection + j);
                        }
                    }

                    sectionIndex++;
                }
            }

            CommitMeshData();
        }
示例#7
0
        /**
         * Updates mesh for one trail segment:
         */
        private void UpdateSegmentMesh(List <Point> input, int start, int end, Vector3 localCamPosition)
        {
            // Get a list of the actual points to render: either the original, unsmoothed points or the smoothed curve.
            List <Point> trail = GetRenderablePoints(input, start, end);

            if (trail.Count > 1)
            {
                float   lenght        = Mathf.Max(GetLenght(trail), epsilon);
                float   partialLenght = 0;
                float   vCoord        = textureMode == TextureMode.Stretch ? 0 : -uvFactor * lenght * tileAnchor;
                Vector4 texTangent    = Vector4.zero;
                Vector2 uv            = Vector2.zero;
                Color   vertexColor;

                bool hqCorners = highQualityCorners && alignment != TrailAlignment.Local;

                // Initialize curve frame using the first two points to calculate the first tangent vector:
                CurveFrame frame = InitializeCurveFrame(trail[trail.Count - 1].position,
                                                        trail[trail.Count - 2].position);

                int va = 1;
                int vb = 0;

                for (int i = trail.Count - 1; i >= 0; --i)
                {
                    // Calculate next and previous point indices:
                    int nextIndex = Mathf.Max(i - 1, 0);
                    int prevIndex = Mathf.Min(i + 1, trail.Count - 1);

                    // Calculate next and previous trail vectors:
                    Vector3 nextV         = trail[nextIndex].position - trail[i].position;
                    Vector3 prevV         = trail[i].position - trail[prevIndex].position;
                    float   sectionLength = nextV.magnitude;

                    nextV.Normalize();
                    prevV.Normalize();

                    // Calculate tangent vector:
                    Vector3 tangent = alignment == TrailAlignment.Local ? trail[i].tangent : (nextV + prevV);
                    tangent.Normalize();

                    // Calculate normal vector:
                    Vector3 normal = trail[i].normal;
                    if (alignment != TrailAlignment.Local)
                    {
                        normal = alignment == TrailAlignment.View ? localCamPosition - trail[i].position: frame.Transport(tangent, trail[i].position);
                    }
                    normal.Normalize();

                    // Calculate bitangent vector:
                    Vector3 bitangent = alignment == TrailAlignment.Velocity ? frame.bitangent : Vector3.Cross(tangent, normal);
                    bitangent.Normalize();

                    // Calculate this point's normalized (0,1) lenght and life.
                    float normalizedLength = partialLenght / lenght;
                    float normalizedLife   = Mathf.Clamp01(1 - trail[i].life / time);
                    partialLenght += sectionLength;

                    // Calulate vertex color:
                    vertexColor = trail[i].color *
                                  colorOverTime.Evaluate(normalizedLife) *
                                  colorOverLenght.Evaluate(normalizedLength);

                    // Update vcoord:
                    vCoord += uvFactor * (textureMode == TextureMode.Stretch ? sectionLength / lenght : sectionLength);

                    // Calulate final thickness:
                    float sectionThickness = thickness * trail[i].thickness * thicknessOverTime.Evaluate(normalizedLife) * thicknessOverLenght.Evaluate(normalizedLength);

                    Quaternion q                    = Quaternion.identity;
                    Vector3    corner               = Vector3.zero;
                    float      curvatureSign        = 0;
                    float      correctedThickness   = sectionThickness;
                    Vector3    prevSectionBitangent = bitangent;

                    // High-quality corners:
                    if (hqCorners)
                    {
                        Vector3 nextSectionBitangent = i == 0 ? bitangent : Vector3.Cross(nextV, Vector3.Cross(bitangent, tangent)).normalized;

                        // If round corners are enabled:
                        if (cornerRoundness > 0)
                        {
                            prevSectionBitangent = i == trail.Count - 1 ? -bitangent : Vector3.Cross(prevV, Vector3.Cross(bitangent, tangent)).normalized;

                            // Calculate "elbow" angle:
                            curvatureSign = (i == 0 || i == trail.Count - 1) ? 1 : Mathf.Sign(Vector3.Dot(nextV, -prevSectionBitangent));
                            float angle = (i == 0 || i == trail.Count - 1) ? Mathf.PI : Mathf.Acos(Mathf.Clamp(Vector3.Dot(nextSectionBitangent, prevSectionBitangent), -1, 1));

                            // Prepare a quaternion for incremental rotation of the corner vector:
                            q      = Quaternion.AngleAxis(Mathf.Rad2Deg * angle / cornerRoundness, normal * curvatureSign);
                            corner = prevSectionBitangent * sectionThickness * curvatureSign;
                        }

                        // Calculate correct thickness by projecting corner bitangent onto the next section bitangent. This prevents "squeezing"
                        if (nextSectionBitangent.sqrMagnitude > 0.1f)
                        {
                            correctedThickness = sectionThickness / Mathf.Max(Vector3.Dot(bitangent, nextSectionBitangent), 0.15f);
                        }
                    }


                    // Append straight section mesh data:

                    if (hqCorners && cornerRoundness > 0)
                    {
                        // bitangents are slightly asymmetrical in case of high-quality round or sharp corners:
                        if (curvatureSign > 0)
                        {
                            vertices.Add(trail[i].position + prevSectionBitangent * sectionThickness);
                            vertices.Add(trail[i].position - bitangent * correctedThickness);
                        }
                        else
                        {
                            vertices.Add(trail[i].position + bitangent * correctedThickness);
                            vertices.Add(trail[i].position - prevSectionBitangent * sectionThickness);
                        }
                    }
                    else
                    {
                        vertices.Add(trail[i].position + bitangent * correctedThickness);
                        vertices.Add(trail[i].position - bitangent * correctedThickness);
                    }

                    normals.Add(-normal);
                    normals.Add(-normal);

                    texTangent   = -bitangent;
                    texTangent.w = 1;
                    tangents.Add(texTangent);
                    tangents.Add(texTangent);

                    vertColors.Add(vertexColor);
                    vertColors.Add(vertexColor);

                    uv.Set(vCoord, 0);
                    uvs.Add(uv);
                    uv.Set(vCoord, 1);
                    uvs.Add(uv);

                    if (i < trail.Count - 1)
                    {
                        int vc = vertices.Count - 1;

                        tris.Add(vc);
                        tris.Add(va);
                        tris.Add(vb);

                        tris.Add(vb);
                        tris.Add(vc - 1);
                        tris.Add(vc);
                    }

                    va = vertices.Count - 1;
                    vb = vertices.Count - 2;

                    // Append smooth corner mesh data:
                    if (hqCorners && cornerRoundness > 0)
                    {
                        for (int p = 0; p <= cornerRoundness; ++p)
                        {
                            vertices.Add(trail[i].position + corner);
                            normals.Add(-normal);
                            tangents.Add(texTangent);
                            vertColors.Add(vertexColor);
                            uv.Set(vCoord, curvatureSign > 0?0:1);
                            uvs.Add(uv);

                            int vc = vertices.Count - 1;

                            tris.Add(vc);
                            tris.Add(va);
                            tris.Add(vb);

                            if (curvatureSign > 0)
                            {
                                vb = vc;
                            }
                            else
                            {
                                va = vc;
                            }

                            // rotate corner point:
                            corner = q * corner;
                        }
                    }
                }
            }
        }
示例#8
0
        /**
         * Generates the particle based physical representation of the rope. This is the initialization method for the rope object
         * and should not be called directly once the object has been created.
         */
        protected override IEnumerator Initialize()
        {
            initialized           = false;
            initializing          = true;
            interParticleDistance = -1;

            RemoveFromSolver(null);

            if (ropePath == null)
            {
                Debug.LogError("Cannot initialize rope. There's no ropePath present. Please provide a spline to define the shape of the rope");
                yield break;
            }

            ropePath.RecalculateSplineLenght(0.00001f, 7);
            closed     = ropePath.closed;
            restLength = ropePath.Length;

            usedParticles  = Mathf.CeilToInt(restLength / thickness * resolution) + (closed ? 0:1);
            totalParticles = usedParticles;

            active              = new bool[totalParticles];
            positions           = new Vector3[totalParticles];
            orientations        = new Quaternion[totalParticles];
            velocities          = new Vector3[totalParticles];
            angularVelocities   = new Vector3[totalParticles];
            invMasses           = new float[totalParticles];
            invRotationalMasses = new float[totalParticles];
            principalRadii      = new Vector3[totalParticles];
            phases              = new int[totalParticles];
            restPositions       = new Vector4[totalParticles];
            restOrientations    = new Quaternion[totalParticles];
            colors              = new Color[totalParticles];

            int numSegments = usedParticles - (closed ? 0:1);

            if (numSegments > 0)
            {
                interParticleDistance = restLength / (float)numSegments;
            }
            else
            {
                interParticleDistance = 0;
            }

            float radius = interParticleDistance * resolution;

            for (int i = 0; i < usedParticles; i++)
            {
                active[i]              = true;
                invMasses[i]           = 1.0f / DEFAULT_PARTICLE_MASS;
                invRotationalMasses[i] = 1.0f / DEFAULT_PARTICLE_ROTATIONAL_MASS;
                float mu = ropePath.GetMuAtLenght(interParticleDistance * i);
                positions[i]      = transform.InverseTransformPoint(ropePath.transform.TransformPoint(ropePath.GetPositionAt(mu)));
                principalRadii[i] = Vector3.one * radius;
                phases[i]         = Oni.MakePhase(1, selfCollisions?Oni.ParticlePhase.SelfCollide:0);
                colors[i]         = Color.white;

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

            StretchShearConstraints.Clear();
            ObiStretchShearConstraintBatch stretchBatch = new ObiStretchShearConstraintBatch(false, false, MIN_YOUNG_MODULUS, MAX_YOUNG_MODULUS);

            StretchShearConstraints.AddBatch(stretchBatch);

            // rotation minimizing frame:
            CurveFrame frame = new CurveFrame();

            frame.Reset();

            for (int i = 0; i < numSegments; i++)
            {
                int next = (i + 1) % (ropePath.closed ? usedParticles:usedParticles + 1);

                float   mu     = ropePath.GetMuAtLenght(interParticleDistance * i);
                Vector3 normal = transform.InverseTransformVector(ropePath.transform.TransformVector(ropePath.GetNormalAt(mu)));

                frame.Transport(positions[i], (positions[next] - positions[i]).normalized, 0);

                orientations[i]     = Quaternion.LookRotation(frame.tangent, normal);
                restOrientations[i] = orientations[i];

                // Also set the orientation of the next particle. If it is not the last one, we will overwrite it.
                // This makes sure that open rods provide an orientation for their last particle (or rather, a phantom segment past the last particle).

                orientations[next]     = orientations[i];
                restOrientations[next] = orientations[i];

                stretchBatch.AddConstraint(i, next, interParticleDistance, Vector3.one);

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

            BendTwistConstraints.Clear();
            ObiBendTwistConstraintBatch twistBatch = new ObiBendTwistConstraintBatch(false, false, MIN_YOUNG_MODULUS, MAX_YOUNG_MODULUS);

            BendTwistConstraints.AddBatch(twistBatch);

            // the last bend constraint couples the last segment and a phantom segment past the last particle.
            for (int i = 0; i < numSegments; i++)
            {
                int next = (i + 1) % (ropePath.closed ? usedParticles:usedParticles + 1);

                Quaternion darboux = keepInitialShape ? ObiUtils.RestDarboux(orientations[i], orientations[next]) : Quaternion.identity;
                twistBatch.AddConstraint(i, next, darboux, Vector3.one);

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

            ChainConstraints.Clear();
            ObiChainConstraintBatch chainBatch = new ObiChainConstraintBatch(false, false, MIN_YOUNG_MODULUS, MAX_YOUNG_MODULUS);

            ChainConstraints.AddBatch(chainBatch);

            int[] indices = new int[usedParticles + (closed ? 1:0)];

            for (int i = 0; i < usedParticles; ++i)
            {
                indices[i] = i;
            }

            // Add the first particle as the last index of the chain, if closed.
            if (closed)
            {
                indices[usedParticles] = 0;
            }

            chainBatch.AddConstraint(indices, interParticleDistance, 1, 1);


            // Initialize tether constraints:
            TetherConstraints.Clear();

            // Initialize pin constraints:
            PinConstraints.Clear();
            ObiPinConstraintBatch pinBatch = new ObiPinConstraintBatch(false, false, MIN_YOUNG_MODULUS, MAX_YOUNG_MODULUS);

            PinConstraints.AddBatch(pinBatch);

            initializing = false;
            initialized  = true;

            RegenerateRestPositions();
        }
示例#9
0
 public abstract void TransportFrame(CurveFrame frame, CurveSection section, float sectionTwist);
示例#10
0
 public virtual void UpdateTearPrefab(CurveFrame frame, ref int tearCount, bool reverseLookDirection)
 {
     return;
 }
 /// <summary>
 /// Delegate, added to the Spline.OnChangedEvent. Re-evaluates the frame of the control point
 /// </summary>
 /// <param name="spline">Spline that changed</param>
 private void OnOwnerSplineChanged( Curve spline )
 {
     m_Frame = spline.EvaluateFrame( m_Index );
 }