Exemplo n.º 1
0
        public void UpdateRenderer(ObiActor actor)
        {
            using (m_UpdateChainRopeRendererChunksPerfMarker.Auto())
            {
                var rope = actor as ObiRopeBase;

                // In case there are no link prefabs to instantiate:
                if (linkPrefabs.Count == 0)
                {
                    return;
                }

                // Regenerate instances if needed:
                if (linkInstances == null || linkInstances.Count < rope.particleCount)
                {
                    CreateChainLinkInstances(rope);
                }

                var blueprint    = rope.blueprint;
                int elementCount = rope.elements.Count;

                float twist = -sectionTwist * elementCount * twistAnchor;

                //we will define and transport a reference frame along the curve using parallel transport method:
                frame.Reset();
                frame.SetTwist(twist);

                int lastParticle = -1;

                for (int i = 0; i < elementCount; ++i)
                {
                    ObiStructuralElement elm = rope.elements[i];

                    Vector3 pos        = rope.GetParticlePosition(elm.particle1);
                    Vector3 nextPos    = rope.GetParticlePosition(elm.particle2);
                    Vector3 linkVector = nextPos - pos;
                    Vector3 tangent    = linkVector.normalized;

                    if (rope.blueprint.usesOrientedParticles)
                    {
                        frame.Transport(nextPos, tangent, rope.GetParticleOrientation(elm.particle1) * Vector3.up, twist);
                        twist += sectionTwist;
                    }
                    else
                    {
                        frame.Transport(nextPos, tangent, sectionTwist);
                    }

                    if (linkInstances[i] != null)
                    {
                        linkInstances[i].SetActive(true);
                        Transform linkTransform = linkInstances[i].transform;
                        linkTransform.position   = pos + linkVector * 0.5f;
                        linkTransform.localScale = rope.GetParticleMaxRadius(elm.particle1) * 2 * linkScale;
                        linkTransform.rotation   = Quaternion.LookRotation(tangent, frame.normal);
                    }

                    lastParticle = elm.particle2;
                }

                for (int i = elementCount; i < linkInstances.Count; ++i)
                {
                    if (linkInstances[i] != null)
                    {
                        linkInstances[i].SetActive(false);
                    }
                }
            }
        }
Exemplo n.º 2
0
        /**
         * Generates smooth curve chunks.
         */
        public void GenerateSmoothChunks(ObiRopeBase actor, uint smoothingLevels)
        {
            using (m_GenerateSmoothChunksPerfMarker.Auto())
            {
                smoothChunks.Clear();
                smoothSections = 0;
                smoothLength   = 0;

                if (!Application.isPlaying)
                {
                    actor.RebuildElementsFromConstraints();
                }

                AllocateRawChunks(actor);

                w2l         = actor.transform.worldToLocalMatrix;
                w2lRotation = w2l.rotation;

                // keep track of the first element of each chunk
                int chunkStart = 0;

                ObiPathFrame frame_0 = new ObiPathFrame(); // "next" frame
                ObiPathFrame frame_1 = new ObiPathFrame(); // current frame
                ObiPathFrame frame_2 = new ObiPathFrame(); // previous frame

                // generate curve for each rope chunk:
                for (int i = 0; i < rawChunks.Count; ++i)
                {
                    int elementCount = rawChunks[i].Count - 1;

                    // Initialize frames:
                    frame_0.Reset();
                    frame_1.Reset();
                    frame_2.Reset();

                    PathFrameFromParticle(actor, ref frame_1, actor.elements[chunkStart].particle1, false);

                    frame_2 = frame_1;

                    for (int m = 1; m <= rawChunks[i].Count; ++m)
                    {
                        int index;
                        if (m >= elementCount)
                        {
                            // second particle of last element in the chunk.
                            index = actor.elements[chunkStart + elementCount - 1].particle2;
                        }
                        else
                        {
                            //first particle of current element.
                            index = actor.elements[chunkStart + m].particle1;
                        }

                        // generate curve frame from particle:
                        PathFrameFromParticle(actor, ref frame_0, index);

                        if (actor.usesOrientedParticles)
                        {
                            // copy frame directly.
                            frame_2 = frame_1;
                        }
                        else
                        {
                            // perform parallel transport, using forward / backward average to calculate tangent.
                            frame_1.tangent = ((frame_1.position - frame_2.position) + (frame_0.position - frame_1.position)).normalized;
                            frame_2.Transport(frame_1, twist);
                        }

                        // in case we wrapped around the rope, average first and last frames:
                        if (chunkStart + m > actor.activeParticleCount)
                        {
                            frame_2 = rawChunks[0][0] = 0.5f * frame_2 + 0.5f * rawChunks[0][0];
                        }

                        frame_1 = frame_0;

                        rawChunks[i][m - 1] = frame_2;
                    }

                    // increment chunkStart by the amount of elements in this chunk:
                    chunkStart += elementCount;

                    // adaptive curvature-based decimation:
                    if (Decimate(rawChunks[i], smoothChunks[i], decimation))
                    {
                        // if any decimation took place, swap raw and smooth chunks:
                        var aux = rawChunks[i];
                        rawChunks[i]    = smoothChunks[i];
                        smoothChunks[i] = aux;
                    }

                    // get smooth curve points:
                    Chaikin(rawChunks[i], smoothChunks[i], smoothingLevels);

                    // count total curve sections and total curve length:
                    smoothSections += smoothChunks[i].Count - 1;
                    smoothLength   += CalculateChunkLength(smoothChunks[i]);
                }
            }
        }
Exemplo n.º 3
0
        protected virtual IEnumerator CreateStretchShearConstraints(List <Vector3> particleNormals)
        {
            stretchShearConstraintsData = new ObiStretchShearConstraintsData();

            stretchShearConstraintsData.AddBatch(new ObiStretchShearConstraintsBatch());
            stretchShearConstraintsData.AddBatch(new ObiStretchShearConstraintsBatch());

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

            frame.Reset();

            for (int i = 0; i < totalParticles - 1; i++)
            {
                var batch = stretchShearConstraintsData.batches[i % 2] as ObiStretchShearConstraintsBatch;

                Vector2Int indices = new Vector2Int(i, i + 1);
                Vector3    d       = positions[indices.y] - positions[indices.x];
                restLengths[i] = d.magnitude;

                frame.Transport(positions[indices.x], d.normalized, 0);

                orientations[i]     = Quaternion.LookRotation(frame.tangent, particleNormals[indices.x]);
                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[indices.y]     = orientations[i];
                restOrientations[indices.y] = orientations[i];

                batch.AddConstraint(indices, indices.x, restLengths[i], Quaternion.identity);
                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 constraint to a new batch to avoid sharing particles.
            if (path.Closed)
            {
                var loopClosingBatch = new ObiStretchShearConstraintsBatch();
                stretchShearConstraintsData.AddBatch(loopClosingBatch);

                Vector2Int indices = new Vector2Int(m_ActiveParticleCount - 1, 0);
                Vector3    d       = positions[indices.y] - positions[indices.x];
                restLengths[m_ActiveParticleCount - 2] = d.magnitude;

                frame.Transport(positions[indices.x], d.normalized, 0);

                orientations[m_ActiveParticleCount - 1]     = Quaternion.LookRotation(frame.tangent, particleNormals[indices.x]);
                restOrientations[m_ActiveParticleCount - 1] = orientations[m_ActiveParticleCount - 1];

                loopClosingBatch.AddConstraint(indices, indices.x, restLengths[m_ActiveParticleCount - 2], Quaternion.identity);
                loopClosingBatch.activeConstraintCount++;
            }

            // Recalculate rest length:
            m_RestLength = 0;
            foreach (float length in restLengths)
            {
                m_RestLength += length;
            }
        }