Beispiel #1
0
        /**
         * Iterative version of the Ramer-Douglas-Peucker path decimation algorithm.
         */
        private bool Decimate(ObiList <ObiPathFrame> input, ObiList <ObiPathFrame> output, float threshold)
        {
            // no decimation, no work to do, just return:
            if (threshold < 0.00001f || input.Count < 3)
            {
                return(false);
            }

            float scaledThreshold = threshold * threshold * 0.01f;

            stack.Push(new Vector2Int(0, input.Count - 1));
            var bitArray = new BitArray(input.Count, true);

            while (stack.Count > 0)
            {
                var range = stack.Pop();

                float dmax  = 0;
                int   index = range.x;
                float mu    = 0;

                for (int i = index + 1; i < range.y; ++i)
                {
                    if (bitArray[i])
                    {
                        float d = Vector3.SqrMagnitude(ObiUtils.ProjectPointLine(input[i].position, input[range.x].position, input[range.y].position, out mu) - input[i].position);

                        if (d > dmax)
                        {
                            index = i;
                            dmax  = d;
                        }
                    }
                }

                if (dmax > scaledThreshold)
                {
                    stack.Push(new Vector2Int(range.x, index));
                    stack.Push(new Vector2Int(index, range.y));
                }
                else
                {
                    for (int i = range.x + 1; i < range.y; ++i)
                    {
                        bitArray[i] = false;
                    }
                }
            }

            output.Clear();
            for (int i = 0; i < bitArray.Count; ++i)
            {
                if (bitArray[i])
                {
                    output.Add(input[i]);
                }
            }

            return(true);
        }
Beispiel #2
0
        public ObiPathFrame GetSectionAt(float mu)
        {
            float edgeMu    = smoothSections * Mathf.Clamp01(mu);
            int   index     = (int)edgeMu;
            float sectionMu = edgeMu - index;

            int counter      = 0;
            int chunkIndex   = -1;
            int indexInChunk = -1;

            for (int i = 0; i < smoothChunks.Count; ++i)
            {
                if (counter + smoothChunks[i].Count > index)
                {
                    chunkIndex   = i;
                    indexInChunk = index - counter;
                }
                counter += smoothChunks[i].Count;
            }

            ObiList <ObiPathFrame> chunk = smoothChunks[chunkIndex];
            ObiPathFrame           s1    = chunk[indexInChunk];
            ObiPathFrame           s2    = chunk[Mathf.Min(indexInChunk + 1, chunk.Count - 1)];

            return((1 - sectionMu) * s1 + sectionMu * s2);
        }
Beispiel #3
0
        private float CalculateChunkLength(ObiList <ObiPathFrame> chunk)
        {
            float length = 0;

            for (int i = 1; i < chunk.Count; ++i)
            {
                length += Vector3.Distance(chunk[i].position, chunk[i - 1].position);
            }
            return(length);
        }
Beispiel #4
0
        protected float CalculateCurveLength(ObiList <ObiCurveSection> curve)
        {
            float length = 0;

            for (int i = 1; i < curve.Count; ++i)
            {
                length += Vector3.Distance(curve[i].positionAndRadius, curve[i - 1].positionAndRadius);
            }
            return(length);
        }
Beispiel #5
0
        /**
         * This method uses a variant of Chainkin's algorithm to produce a smooth curve from a set of control points. It is specially fast
         * because it directly calculates subdivision level k, instead of recursively calculating levels 1..k.
         */
        private void Chaikin(ObiList <ObiPathFrame> input, ObiList <ObiPathFrame> output, uint k)
        {
            // no subdivision levels, no work to do. just copy the input to the output:
            if (k == 0 || input.Count < 3)
            {
                output.SetCount(input.Count);
                for (int i = 0; i < input.Count; ++i)
                {
                    output[i] = input[i];
                }
                return;
            }

            // calculate amount of new points generated by each inner control point:
            int pCount = (int)Mathf.Pow(2, k);

            // precalculate some quantities:
            int   n0 = input.Count - 1;
            float twoRaisedToMinusKPlus1   = Mathf.Pow(2, -(k + 1));
            float twoRaisedToMinusK        = Mathf.Pow(2, -k);
            float twoRaisedToMinus2K       = Mathf.Pow(2, -2 * k);
            float twoRaisedToMinus2KMinus1 = Mathf.Pow(2, -2 * k - 1);

            // allocate ouput:
            output.SetCount((n0 - 1) * pCount + 2);

            // calculate initial curve points:
            output[0] = (0.5f + twoRaisedToMinusKPlus1) * input[0] + (0.5f - twoRaisedToMinusKPlus1) * input[1];
            output[pCount * n0 - pCount + 1] = (0.5f - twoRaisedToMinusKPlus1) * input[n0 - 1] + (0.5f + twoRaisedToMinusKPlus1) * input[n0];

            // calculate internal points:
            for (int j = 1; j <= pCount; ++j)
            {
                // precalculate coefficients:
                float F = 0.5f - twoRaisedToMinusKPlus1 - (j - 1) * (twoRaisedToMinusK - j * twoRaisedToMinus2KMinus1);
                float G = 0.5f + twoRaisedToMinusKPlus1 + (j - 1) * (twoRaisedToMinusK - j * twoRaisedToMinus2K);
                float H = (j - 1) * j * twoRaisedToMinus2KMinus1;

                for (int i = 1; i < n0; ++i)
                {
                    ObiPathFrame.WeightedSum(F, G, H,
                                             ref input.Data[i - 1],
                                             ref input.Data[i],
                                             ref input.Data[i + 1],
                                             ref output.Data[(i - 1) * pCount + j]);
                }
            }

            // make first and last curve points coincide with original points:
            output[0] = input[0];
            output[output.Count - 1] = input[input.Count - 1];
        }
Beispiel #6
0
        /**
         * Generate a list of smooth curves using particles as control points. Will take into account cuts in the rope,
         * generating one curve for each continuous piece of rope.
         */
        public void SmoothCurvesFromParticles()
        {
            curves.Clear();

            curveSections = 0;
            curveLength   = 0;

            // count amount of segments in each rope chunk:
            CountContinuousSegments();

            ObiDistanceConstraintBatch distanceBatch = DistanceConstraints.GetFirstBatch();
            Matrix4x4 w2l = transform.worldToLocalMatrix;

            int firstSegment = 0;

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

                // allocate memory for the curve:
                ObiList <CurveSection> controlPoints = rawCurves[i];

                // get control points position:
                for (int m = 0; m < segments; ++m)
                {
                    int particleIndex = distanceBatch.springIndices[(firstSegment + m) * 2];
                    controlPoints[m] = new CurveSection(w2l.MultiplyPoint3x4(GetParticlePosition(particleIndex)),
                                                        solidRadii[particleIndex],
                                                        (this.colors != null && particleIndex < this.colors.Length) ? this.colors[particleIndex] : Color.white);

                    // last segment adds its second particle too:
                    if (m == segments - 1)
                    {
                        particleIndex        = distanceBatch.springIndices[(firstSegment + m) * 2 + 1];
                        controlPoints[m + 1] = new CurveSection(w2l.MultiplyPoint3x4(GetParticlePosition(particleIndex)),
                                                                solidRadii[particleIndex],
                                                                (this.colors != null && particleIndex < this.colors.Length) ? this.colors[particleIndex] : Color.white);
                    }
                }

                firstSegment += segments;

                // get smooth curve points:
                ChaikinSmoothing(controlPoints, curves[i], smoothing);

                // count total curve sections and total curve length:
                curveSections += curves[i].Count - 1;
                curveLength   += CalculateCurveLength(curves[i]);
            }
        }
        // Update is called once per frame
        void UpdatePlugs(ObiActor actor)
        {
            var rope = actor as ObiRopeBase;

            // cache the rope's transform matrix/quaternion:
            Matrix4x4  l2w    = rope.transform.localToWorldMatrix;
            Quaternion l2wRot = l2w.rotation;

            int instanceIndex = 0;

            // place prefabs at the start/end of each curve:
            for (int c = 0; c < smoother.smoothChunks.Count; ++c)
            {
                ObiList <ObiPathFrame> curve = smoother.smoothChunks[c];

                if ((plugTears && c > 0) ||
                    (plugStart && c == 0))
                {
                    var instance = GetOrCreatePrefabInstance(instanceIndex++);
                    instance.SetActive(true);

                    ObiPathFrame frame = curve[0];
                    instance.transform.position   = l2w.MultiplyPoint3x4(frame.position);
                    instance.transform.rotation   = l2wRot * (Quaternion.LookRotation(-frame.tangent, frame.binormal));
                    instance.transform.localScale = instanceScale;
                }

                if ((plugTears && c < smoother.smoothChunks.Count - 1) ||
                    (plugEnd && c == smoother.smoothChunks.Count - 1))
                {
                    var instance = GetOrCreatePrefabInstance(instanceIndex++);
                    instance.SetActive(true);

                    ObiPathFrame frame = curve[curve.Count - 1];
                    instance.transform.position   = l2w.MultiplyPoint3x4(frame.position);
                    instance.transform.rotation   = l2wRot * (Quaternion.LookRotation(frame.tangent, frame.binormal));
                    instance.transform.localScale = instanceScale;
                }
            }

            // deactivate remaining instances:
            for (int i = instanceIndex; i < instances.Count; ++i)
            {
                instances[i].SetActive(false);
            }
        }
Beispiel #8
0
        /**
         * Generate a list of smooth curves using particles as control points. Will take into account cuts in the rope,
         * generating one curve for each continuous piece of rope.
         */
        public void SmoothCurvesFromParticles()
        {
            curves.Clear();

            curveSections = 0;
            curveLength   = 0;

            // count amount of segments in each rope chunk:
            CountContinuousSegments();

            Matrix4x4  w2l            = transform.worldToLocalMatrix;
            Quaternion matrixRotation = Quaternion.LookRotation(
                w2l.GetColumn(2),
                w2l.GetColumn(1));
            int firstSegment = 0;

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

                // allocate memory for the curve:
                ObiList <ObiCurveSection> controlPoints = rawCurves[i];

                // get control points position:
                int lastParticle = -1;
                int particle1 = -1, particle2 = -1;
                for (int m = 0; m < segments; ++m)
                {
                    if (GetStructuralConstraintParticles(firstSegment + m, ref particle1, ref particle2))
                    {
                        if (m == 0)
                        {
                            lastParticle = particle1;
                        }

                        // Find next and previous vectors:
                        Vector3 nextV = GetParticlePosition(particle2) - GetParticlePosition(particle1);
                        Vector3 prevV = GetParticlePosition(particle1) - GetParticlePosition(lastParticle);

                        Vector3    pos     = w2l.MultiplyPoint3x4(GetParticlePosition(particle1));
                        Quaternion orient  = matrixRotation * Quaternion.SlerpUnclamped(GetParticleOrientation(lastParticle), GetParticleOrientation(particle1), 0.5f);
                        Vector3    tangent = w2l.MultiplyVector(prevV + nextV).normalized;
                        Color      color   = (this.colors != null && particle1 < this.colors.Length) ? this.colors[particle1] : Color.white;

                        controlPoints[m] = new ObiCurveSection(new Vector4(pos.x, pos.y, pos.z, principalRadii[particle1][0]), tangent, orient * Vector3.up, color);

                        lastParticle = particle1;
                    }
                }

                // last segment adds its second particle too:
                if (segments > 0)
                {
                    Vector3    pos     = w2l.MultiplyPoint3x4(GetParticlePosition(particle2));
                    Quaternion orient  = matrixRotation * GetParticleOrientation(particle1);
                    Vector3    tangent = w2l.MultiplyVector(GetParticlePosition(particle2) - GetParticlePosition(particle1)).normalized;
                    Color      color   = (this.colors != null && particle2 < this.colors.Length) ? this.colors[particle2] : Color.white;

                    controlPoints[segments] = new ObiCurveSection(new Vector4(pos.x, pos.y, pos.z, principalRadii[particle2][0]), tangent, orient * Vector3.up, color);
                }

                firstSegment += segments;

                // get smooth curve points:
                ObiCurveFrame.Chaikin(controlPoints, curves[i], smoothing);

                // count total curve sections and total curve length:
                curveSections += curves[i].Count - 1;
                curveLength   += CalculateCurveLength(curves[i]);
            }
        }
        public void UpdateRenderer(ObiActor actor)
        {
            using (m_UpdateExtrudedRopeRendererChunksPerfMarker.Auto())
            {
                if (section == null)
                {
                    return;
                }

                var rope = actor as ObiRopeBase;

                CreateMeshIfNeeded();
                ClearMeshData();

                int   sectionIndex            = 0;
                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 * rope.restLength * uvAnchor; // v texture coordinate.
                float actualToRestLengthRatio = smoother.SmoothLength / rope.restLength;

                Vector3 vertex = Vector3.zero, normal = Vector3.zero;
                Vector4 texTangent = Vector4.zero;
                Vector2 uv         = Vector2.zero;

                for (int c = 0; c < smoother.smoothChunks.Count; ++c)
                {
                    ObiList <ObiPathFrame> curve = smoother.smoothChunks[c];

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

                        // advance v texcoord:
                        vCoord += uvScale.y * (Vector3.Distance(curve.Data[i].position, curve.Data[prevIndex].position) /
                                               (normalizeV ? smoother.SmoothLength : actualToRestLengthRatio));

                        // calculate section thickness and scale the basis vectors by it:
                        float sectionThickness = curve.Data[i].thickness * thicknessScale;

                        // Loop around each segment:
                        int nextSectionIndex = sectionIndex + 1;
                        for (int j = 0; j <= sectionSegments; ++j)
                        {
                            // make just one copy of the section vertex:
                            Vector2 sectionVertex = section.vertices[j];

                            // calculate normal using section vertex, curve normal and binormal:
                            normal.x = (sectionVertex.x * curve.Data[i].normal.x + sectionVertex.y * curve.Data[i].binormal.x) * sectionThickness;
                            normal.y = (sectionVertex.x * curve.Data[i].normal.y + sectionVertex.y * curve.Data[i].binormal.y) * sectionThickness;
                            normal.z = (sectionVertex.x * curve.Data[i].normal.z + sectionVertex.y * curve.Data[i].binormal.z) * sectionThickness;

                            // offset curve position by normal:
                            vertex.x = curve.Data[i].position.x + normal.x;
                            vertex.y = curve.Data[i].position.y + normal.y;
                            vertex.z = curve.Data[i].position.z + normal.z;

                            // cross(normal, curve tangent)
                            texTangent.x = normal.y * curve.Data[i].tangent.z - normal.z * curve.Data[i].tangent.y;
                            texTangent.y = normal.z * curve.Data[i].tangent.x - normal.x * curve.Data[i].tangent.z;
                            texTangent.z = normal.x * curve.Data[i].tangent.y - normal.y * curve.Data[i].tangent.x;
                            texTangent.w = -1;

                            uv.x = (j / (float)sectionSegments) * uvScale.x;
                            uv.y = vCoord;

                            vertices.Add(vertex);
                            normals.Add(normal);
                            tangents.Add(texTangent);
                            vertColors.Add(curve.Data[i].color);
                            uvs.Add(uv);

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

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

                CommitMeshData();
            }
        }
Beispiel #10
0
        public void UpdateRenderer(ObiActor actor)
        {
            using (m_UpdateMeshRopeRendererChunksPerfMarker.Auto())
            {
                if (mesh == null)
                {
                    return;
                }

                if (smoother.smoothChunks.Count == 0)
                {
                    return;
                }

                ObiList <ObiPathFrame> curve = smoother.smoothChunks[0];

                if (curve.Count < 2)
                {
                    return;
                }

                var rope = actor as ObiRopeBase;

                float actualToRestLengthRatio = stretchWithRope ? smoother.SmoothLength / rope.restLength : 1;

                // squashing factor, makes mesh thinner when stretched and thicker when compresssed.
                float squashing = Mathf.Clamp(1 + volumeScaling * (1 / Mathf.Max(actualToRestLengthRatio, 0.01f) - 1), 0.01f, 2);

                // Calculate scale along swept axis so that the mesh spans the entire lenght of the rope if required.
                Vector3 actualScale = scale;
                if (spanEntireLength)
                {
                    actualScale[(int)axis] = rope.restLength / meshSizeAlongAxis;
                }

                float previousVertexValue = 0;
                float meshLength          = 0;
                int   index            = 0;
                int   nextIndex        = 1;
                int   prevIndex        = 0;
                float sectionMagnitude = Vector3.Distance(curve[index].position, curve[nextIndex].position);

                // basis matrix for deforming the mesh:
                Matrix4x4 basis = curve[0].ToMatrix(axis);

                for (int i = 0; i < orderedVertices.Length; ++i)
                {
                    int   vIndex      = orderedVertices[i];
                    float vertexValue = inputVertices[vIndex][(int)axis] * actualScale[(int)axis] + offset;

                    // Calculate how much we've advanced in the sort axis since the last vertex:
                    meshLength         += (vertexValue - previousVertexValue) * actualToRestLengthRatio;
                    previousVertexValue = vertexValue;

                    // If we have advanced to the next section of the curve:
                    while (meshLength > sectionMagnitude && sectionMagnitude > Mathf.Epsilon)
                    {
                        meshLength -= sectionMagnitude;
                        index       = Mathf.Min(index + 1, curve.Count - 1);

                        // Calculate previous and next curve indices:
                        nextIndex = Mathf.Min(index + 1, curve.Count - 1);
                        prevIndex = Mathf.Max(index - 1, 0);

                        // Calculate current tangent as the vector between previous and next curve points:
                        sectionMagnitude = Vector3.Distance(curve[index].position, curve[nextIndex].position);

                        // Update basis matrix:
                        basis = curve[index].ToMatrix(axis);
                    }

                    float sectionThickness = curve[index].thickness;

                    // calculate deformed vertex position:
                    Vector3 offsetFromCurve = Vector3.Scale(inputVertices[vIndex], actualScale * sectionThickness * squashing);
                    offsetFromCurve[(int)axis] = meshLength;

                    vertices[vIndex]   = curve[index].position + basis.MultiplyVector(offsetFromCurve);
                    normals[vIndex]    = basis.MultiplyVector(inputNormals[vIndex]);
                    tangents[vIndex]   = basis * inputTangents[vIndex]; // avoids expensive implicit conversion from Vector4 to Vector3.
                    tangents[vIndex].w = inputTangents[vIndex].w;
                }

                CommitMeshData();
            }
        }
        public override void UpdateRenderer(object sender, EventArgs e)
        {
            if (section == null || extrudedMesh == null)
            {
                return;
            }

            rope.SmoothCurvesFromParticles();

            CreateMeshIfNeeded();
            ClearMeshData();

            float actualToRestLengthRatio = rope.SmoothLength / rope.RestLength;

            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 * rope.RestLength * uvAnchor;       // v texture coordinate.
            int   sectionIndex = 0;
            int   tearCount    = 0;

            // we will define and transport a reference frame along the curve using parallel transport method:
            if (frame == null)
            {
                frame = new ObiRope.CurveFrame();
            }
            frame.Reset();
            frame.SetTwist(-sectionTwist * rope.SmoothSections * uvAnchor);

            // for closed curves, last frame of the last curve must be equal to first frame of first curve.
            Vector3 firstTangent = Vector3.forward;

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

            for (int c = 0; c < rope.curves.Count; ++c)
            {
                ObiList <ObiRope.CurveSection> curve = rope.curves[c];

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

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

                    // Calculate current tangent as the vector between previous and next curve points:
                    //Vector3 nextV;

                    // The next tangent of the last segment of the last curve in a closed rope, is the first tangent again:

                    /*if (rope.Closed && c == rope.curves.Count-1 && i == curve.Count-1 )
                     *      nextV = firstTangent;
                     * else
                     *      nextV = curve[nextIndex].positionAndRadius - curve[i].positionAndRadius;*/

                    //Vector3 prevV = curve[i].positionAndRadius - curve[prevIndex].positionAndRadius;
                    //Vector3 tangent = nextV + prevV;

                    // update frame:
                    rope.TransportFrame(frame, curve[i], sectionTwist);                  //curve[i].positionAndRadius,tangent,rope.sectionTwist);

                    // update tear prefabs (first segment of not first curve, last segment of not last curve)
                    if (c > 0 && i == 0)
                    {
                        rope.UpdateTearPrefab(frame, ref tearCount, false);
                    }
                    if (c < rope.curves.Count - 1 && i == curve.Count - 1)
                    {
                        rope.UpdateTearPrefab(frame, ref tearCount, true);
                    }

                    // update start/end prefabs:
                    if (c == 0 && i == 0)
                    {
                        // store first tangent of the first curve (for closed ropes):
                        firstTangent = frame.tangent;

                        if (rope.startPrefabInstance != null && !rope.Closed)
                        {
                            rope.PlaceObjectAtCurveFrame(frame, rope.startPrefabInstance, Space.Self, false);
                        }
                    }
                    else if (c == rope.curves.Count - 1 && i == curve.Count - 1 && rope.endPrefabInstance != null && !rope.Closed)
                    {
                        rope.PlaceObjectAtCurveFrame(frame, rope.endPrefabInstance, Space.Self, true);
                    }

                    // advance v texcoord:
                    vCoord += uvScale.y * (Vector3.Distance(curve[i].positionAndRadius, curve[prevIndex].positionAndRadius) /
                                           (normalizeV ? rope.SmoothLength : actualToRestLengthRatio));

                    // calculate section thickness (either constant, or particle radius based):
                    float sectionThickness = (rope.thicknessFromParticles ? curve[i].positionAndRadius.w : rope.thickness) * sectionThicknessScale;

                    // 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) * sectionThickness);
                        normals.Add(vertices[vertices.Count - 1] - frame.position);
                        texTangent   = -Vector3.Cross(normals[normals.Count - 1], frame.tangent);
                        texTangent.w = 1;
                        tangents.Add(texTangent);

                        vertColors.Add(curve[i].color);
                        uv.Set((j / (float)sectionSegments) * uvScale.x, vCoord);
                        uvs.Add(uv);

                        if (j < sectionSegments && i < curve.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();
        }
        public void UpdateRenderer(Camera camera)
        {
            if (camera == null || !rope.gameObject.activeInHierarchy)
            {
                return;
            }

            rope.SmoothCurvesFromParticles();

            CreateMeshIfNeeded();
            ClearMeshData();

            float actualToRestLengthRatio = rope.SmoothLength / rope.RestLength;

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

            Vector3 localSpaceCamera = rope.transform.InverseTransformPoint(camera.transform.position);

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

            // for closed curves, last frame of the last curve must be equal to first frame of first curve.
            Vector3 firstTangent = Vector3.forward;

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

            for (int c = 0; c < rope.curves.Count; ++c)
            {
                ObiList <ObiRope.CurveSection> curve = rope.curves[c];

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

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

                    // Calculate current tangent as the vector between previous and next curve points:

                    /*Vector3 nextV;
                     *
                     * // The next tangent of the last segment of the last curve in a closed rope, is the first tangent again:
                     * if (rope.Closed && c == rope.curves.Count-1 && i == curve.Count-1 )
                     *      nextV = firstTangent;
                     * else
                     *      nextV = curve[nextIndex].positionAndRadius - curve[i].positionAndRadius;
                     *
                     * Vector3 prevV = curve[i].positionAndRadius - curve[prevIndex].positionAndRadius;
                     * Vector3 tangent = nextV + prevV;*/

                    // update frame:
                    frame.Transport(curve[i], 0);

                    // update tear prefabs:
                    if (c > 0 && i == 0)
                    {
                        rope.UpdateTearPrefab(frame, ref tearCount, false);
                    }
                    if (c < rope.curves.Count - 1 && i == curve.Count - 1)
                    {
                        rope.UpdateTearPrefab(frame, ref tearCount, true);
                    }

                    // update start/end prefabs:
                    if (c == 0 && i == 0)
                    {
                        // store first tangent of the first curve (for closed ropes):
                        firstTangent = frame.tangent;

                        if (rope.startPrefabInstance != null && !rope.Closed)
                        {
                            rope.PlaceObjectAtCurveFrame(frame, rope.startPrefabInstance, Space.Self, false);
                        }
                    }
                    else if (c == rope.curves.Count - 1 && i == curve.Count - 1 && rope.endPrefabInstance != null && !rope.Closed)
                    {
                        rope.PlaceObjectAtCurveFrame(frame, rope.endPrefabInstance, Space.Self, true);
                    }

                    // advance v texcoord:
                    vCoord += uvScale.y * (Vector3.Distance(curve[i].positionAndRadius, curve[prevIndex].positionAndRadius) /
                                           (normalizeV?rope.SmoothLength:actualToRestLengthRatio));

                    // calculate section thickness (either constant, or particle radius based):
                    float sectionThickness = (rope.thicknessFromParticles ? curve[i].positionAndRadius.w : rope.thickness) * sectionThicknessScale;

                    Vector3 normal = frame.position - localSpaceCamera;
                    normal.Normalize();

                    Vector3 bitangent = Vector3.Cross(frame.tangent, normal);
                    bitangent.Normalize();

                    vertices.Add(frame.position + bitangent * sectionThickness);
                    vertices.Add(frame.position - bitangent * sectionThickness);

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

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

                    vertColors.Add(curve[i].color);
                    vertColors.Add(curve[i].color);

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

                    if (i < curve.Count - 1)
                    {
                        tris.Add(sectionIndex * 2);
                        tris.Add(sectionIndex * 2 + 1);
                        tris.Add((sectionIndex + 1) * 2);

                        tris.Add(sectionIndex * 2 + 1);
                        tris.Add((sectionIndex + 1) * 2 + 1);
                        tris.Add((sectionIndex + 1) * 2);
                    }

                    sectionIndex++;
                }
            }

            CommitMeshData();
        }
Beispiel #13
0
        public void UpdateRenderer(Camera camera)
        {
            using (m_UpdateLineRopeRendererChunksPerfMarker.Auto())
            {
                if (camera == null || !rope.gameObject.activeInHierarchy)
                {
                    return;
                }

                CreateMeshIfNeeded();
                ClearMeshData();

                float actualToRestLengthRatio = smoother.SmoothLength / rope.restLength;

                float vCoord       = -uvScale.y * rope.restLength * uvAnchor; // v texture coordinate.
                int   sectionIndex = 0;

                Vector3 localSpaceCamera = rope.transform.InverseTransformPoint(camera.transform.position);
                Vector3 vertex = Vector3.zero, normal = Vector3.zero;
                Vector4 bitangent = Vector4.zero;
                Vector2 uv = Vector2.zero;

                for (int c = 0; c < smoother.smoothChunks.Count; ++c)
                {
                    ObiList <ObiPathFrame> curve = smoother.smoothChunks[c];

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

                        // advance v texcoord:
                        vCoord += uvScale.y * (Vector3.Distance(curve.Data[i].position, curve.Data[prevIndex].position) /
                                               (normalizeV ? smoother.SmoothLength : actualToRestLengthRatio));

                        // calculate section thickness (either constant, or particle radius based):
                        float sectionThickness = curve.Data[i].thickness * thicknessScale;


                        normal.x = curve.Data[i].position.x - localSpaceCamera.x;
                        normal.y = curve.Data[i].position.y - localSpaceCamera.y;
                        normal.z = curve.Data[i].position.z - localSpaceCamera.z;
                        normal.Normalize();

                        bitangent.x = -(normal.y * curve.Data[i].tangent.z - normal.z * curve.Data[i].tangent.y);
                        bitangent.y = -(normal.z * curve.Data[i].tangent.x - normal.x * curve.Data[i].tangent.z);
                        bitangent.z = -(normal.x * curve.Data[i].tangent.y - normal.y * curve.Data[i].tangent.x);
                        bitangent.w = 0;
                        bitangent.Normalize();

                        vertex.x = curve.Data[i].position.x - bitangent.x * sectionThickness;
                        vertex.y = curve.Data[i].position.y - bitangent.y * sectionThickness;
                        vertex.z = curve.Data[i].position.z - bitangent.z * sectionThickness;
                        vertices.Add(vertex);

                        vertex.x = curve.Data[i].position.x + bitangent.x * sectionThickness;
                        vertex.y = curve.Data[i].position.y + bitangent.y * sectionThickness;
                        vertex.z = curve.Data[i].position.z + bitangent.z * sectionThickness;
                        vertices.Add(vertex);

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

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

                        vertColors.Add(curve.Data[i].color);
                        vertColors.Add(curve.Data[i].color);

                        uv.x = 0; uv.y = vCoord;
                        uvs.Add(uv);
                        uv.x = 1;
                        uvs.Add(uv);

                        if (i < curve.Count - 1)
                        {
                            tris.Add(sectionIndex * 2);
                            tris.Add((sectionIndex + 1) * 2);
                            tris.Add(sectionIndex * 2 + 1);

                            tris.Add(sectionIndex * 2 + 1);
                            tris.Add((sectionIndex + 1) * 2);
                            tris.Add((sectionIndex + 1) * 2 + 1);
                        }

                        sectionIndex++;
                    }
                }

                CommitMeshData();
            }
        }
Beispiel #14
0
        public override void Update(Camera camera)
        {
            if (mesh == null || rope.ropeMesh == null)
            {
                return;
            }

            rope.SmoothCurvesFromParticles();

            if (rope.curves.Count == 0)
            {
                return;
            }

            ObiList <ObiRope.CurveSection> curve = rope.curves[0];

            if (curve.Count < 2)
            {
                return;
            }

            float actualToRestLengthRatio = stretchWithRope ? rope.SmoothLength / rope.RestLength : 1;

            // Calculate scale along swept axis so that the mesh spans the entire lenght of the rope if required.
            Vector3 actualScale = scale;

            if (spanEntireLength)
            {
                actualScale[(int)axis] = rope.RestLength / meshSizeAlongAxis;
            }

            float   previousVertexValue = 0;
            float   meshLength          = 0;
            int     index            = 0;
            int     nextIndex        = 1;
            int     prevIndex        = 0;
            Vector3 nextV            = curve[nextIndex].positionAndRadius - curve[index].positionAndRadius;
            Vector3 prevV            = curve[index].positionAndRadius - curve[prevIndex].positionAndRadius;
            Vector3 tangent          = (nextV + prevV).normalized;
            float   sectionMagnitude = nextV.magnitude;

            // we will define and transport a reference frame along the curve using parallel transport method:
            if (frame == null)
            {
                frame = new ObiRope.CurveFrame();
            }
            frame.Reset();
            frame.SetTwistAndTangent(-rope.sectionTwist * rope.SmoothSections * rope.uvAnchor, tangent);

            // set frame's initial position:
            frame.position = curve[index].positionAndRadius;

            // basis matrix for deforming the mesh, also calculate column offsets based on swept axis:
            Matrix4x4 basis = new Matrix4x4();
            int       xo    = ((int)axis) % 3 * 4;
            int       yo    = ((int)axis + 1) % 3 * 4;
            int       zo    = ((int)axis + 2) % 3 * 4;

            basis[xo]     = frame.tangent[0];
            basis[xo + 1] = frame.tangent[1];
            basis[xo + 2] = frame.tangent[2];

            basis[yo]     = frame.normal[0];
            basis[yo + 1] = frame.normal[1];
            basis[yo + 2] = frame.normal[2];

            basis[zo]     = frame.binormal[0];
            basis[zo + 1] = frame.binormal[1];
            basis[zo + 2] = frame.binormal[2];

            for (int i = 0; i < orderedVertices.Length; ++i)
            {
                int   vIndex      = orderedVertices[i];
                float vertexValue = inputVertices[vIndex][(int)axis] * actualScale[(int)axis] + offset;

                // Calculate how much we've advanced in the sort axis since the last vertex:
                meshLength         += (vertexValue - previousVertexValue) * actualToRestLengthRatio;
                previousVertexValue = vertexValue;

                // If we have advanced to the next section of the curve:
                while (meshLength > sectionMagnitude && sectionMagnitude > Mathf.Epsilon)
                {
                    meshLength -= sectionMagnitude;
                    index       = Mathf.Min(index + 1, curve.Count - 1);

                    // Calculate previous and next curve indices:
                    nextIndex = Mathf.Min(index + 1, curve.Count - 1);
                    prevIndex = Mathf.Max(index - 1, 0);

                    // Calculate current tangent as the vector between previous and next curve points:
                    nextV            = curve[nextIndex].positionAndRadius - curve[index].positionAndRadius;
                    prevV            = curve[index].positionAndRadius - curve[prevIndex].positionAndRadius;
                    tangent          = (nextV + prevV).normalized;
                    sectionMagnitude = nextV.magnitude;

                    // Transport frame:
                    frame.Transport(curve[index].positionAndRadius, tangent, rope.sectionTwist);

                    // Update basis matrix:
                    basis[xo]     = frame.tangent[0];
                    basis[xo + 1] = frame.tangent[1];
                    basis[xo + 2] = frame.tangent[2];

                    basis[yo]     = frame.normal[0];
                    basis[yo + 1] = frame.normal[1];
                    basis[yo + 2] = frame.normal[2];

                    basis[zo]     = frame.binormal[0];
                    basis[zo + 1] = frame.binormal[1];
                    basis[zo + 2] = frame.binormal[2];
                }

                // calculate deformed vertex position:
                Vector3 offsetFromCurve = Vector3.Scale(inputVertices[vIndex], actualScale);
                offsetFromCurve[(int)axis] = meshLength;

                vertices[vIndex]   = frame.position + basis.MultiplyVector(offsetFromCurve);
                normals[vIndex]    = basis.MultiplyVector(inputNormals[vIndex]);
                tangents[vIndex]   = basis * inputTangents[vIndex];               // avoids expensive implicit conversion from Vector4 to Vector3.
                tangents[vIndex].w = inputTangents[vIndex].w;
            }

            CommitMeshData();
        }
        public void UpdateRenderer(Camera camera)
        {
            using (m_UpdateLineRopeRendererChunksPerfMarker.Auto())
            {
                if (camera == null || !rope.gameObject.activeInHierarchy)
                {
                    return;
                }

                CreateMeshIfNeeded();
                ClearMeshData();

                float actualToRestLengthRatio = smoother.SmoothLength / rope.restLength;

                float vCoord       = -uvScale.y * rope.restLength * uvAnchor; // v texture coordinate.
                int   sectionIndex = 0;

                Vector3 localSpaceCamera = rope.transform.InverseTransformPoint(camera.transform.position);

                // for closed curves, last frame of the last curve must be equal to first frame of first curve.
                Vector3 firstTangent = Vector3.forward;

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

                for (int c = 0; c < smoother.smoothChunks.Count; ++c)
                {
                    ObiList <ObiPathFrame> curve = smoother.smoothChunks[c];

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

                        // update start/end prefabs:
                        if (c == 0 && i == 0)
                        {
                            // store first tangent of the first curve (for closed ropes):
                            firstTangent = curve[i].tangent;
                        }

                        // advance v texcoord:
                        vCoord += uvScale.y * (Vector3.Distance(curve[i].position, curve[prevIndex].position) /
                                               (normalizeV ? smoother.SmoothLength : actualToRestLengthRatio));

                        // calculate section thickness (either constant, or particle radius based):
                        float sectionThickness = curve[i].thickness * thicknessScale;

                        Vector3 normal = curve[i].position - localSpaceCamera;
                        normal.Normalize();

                        Vector3 bitangent = Vector3.Cross(normal, curve[i].tangent);
                        bitangent.Normalize();

                        vertices.Add(curve[i].position + bitangent * sectionThickness);
                        vertices.Add(curve[i].position - bitangent * sectionThickness);

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

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

                        vertColors.Add(curve[i].color);
                        vertColors.Add(curve[i].color);

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

                        if (i < curve.Count - 1)
                        {
                            tris.Add(sectionIndex * 2);
                            tris.Add((sectionIndex + 1) * 2);
                            tris.Add(sectionIndex * 2 + 1);

                            tris.Add(sectionIndex * 2 + 1);
                            tris.Add((sectionIndex + 1) * 2);
                            tris.Add((sectionIndex + 1) * 2 + 1);
                        }

                        sectionIndex++;
                    }
                }

                CommitMeshData();
            }
        }
Beispiel #16
0
        public void UpdateRenderer(ObiActor actor)
        {
            using (m_UpdateExtrudedRopeRendererChunksPerfMarker.Auto())
            {
                if (section == null)
                {
                    return;
                }

                var rope = actor as ObiRopeBase;

                CreateMeshIfNeeded();
                ClearMeshData();

                float actualToRestLengthRatio = smoother.SmoothLength / rope.restLength;

                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 * rope.restLength * uvAnchor; // v texture coordinate.
                int   sectionIndex = 0;

                // for closed curves, last frame of the last curve must be equal to first frame of first curve.
                Vector3 vertex, normal, scaledNormal, scaledBinormal;

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

                for (int c = 0; c < smoother.smoothChunks.Count; ++c)
                {
                    ObiList <ObiPathFrame> curve = smoother.smoothChunks[c];

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

                        // advance v texcoord:
                        vCoord += uvScale.y * (Vector3.Distance(curve[i].position, curve[prevIndex].position) /
                                               (normalizeV ? smoother.SmoothLength : actualToRestLengthRatio));

                        // calculate section thickness and scale the basis vectors by it:
                        float sectionThickness = curve[i].thickness * thicknessScale;
                        scaledNormal   = curve[i].normal * sectionThickness;
                        scaledBinormal = curve[i].binormal * sectionThickness;

                        // Loop around each segment:
                        int nextSectionIndex = sectionIndex + 1;
                        for (int j = 0; j <= sectionSegments; ++j)
                        {
                            normal       = section.vertices[j].x * scaledNormal + section.vertices[j].y * scaledBinormal;
                            vertex       = curve[i].position + normal;
                            texTangent   = Vector3.Cross(normal, curve[i].tangent);
                            texTangent.w = -1;
                            uv.Set((j / (float)sectionSegments) * uvScale.x, vCoord);

                            vertices.Add(vertex);
                            normals.Add(normal);
                            tangents.Add(texTangent);
                            vertColors.Add(curve[i].color);
                            uvs.Add(uv);

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

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

                CommitMeshData();
            }
        }