예제 #1
0
        private void GenerateMesh()
        {
            UOUtility.DestroyChildren(generated);

            _bounds = new Bounds();
            int   i             = 0;
            float textureOffset = 0.0f;

            foreach (CubicBezierCurve curve in spline.GetCurves())
            {
                GameObject go = UOUtility.Create("segment " + i++,
                                                 generated,
                                                 typeof(MeshFilter),
                                                 typeof(MeshRenderer),
                                                 typeof(ExtrusionSegment),
                                                 typeof(MeshCollider));
                go.GetComponent <MeshRenderer>().material = material;
                ExtrusionSegment mb = go.GetComponent <ExtrusionSegment>();
                mb.SetShapeVertices(shapeVertices, false);
                mb.SetLoopAround(loopAround, false);
                mb.SetTextureScale(textureScale, false);
                mb.SetCurve(curve, true);
                mb.SetTextureOffset(textureOffset, true);
                textureOffset += curve.Length;
                _bounds.Encapsulate(go.GetComponent <MeshFilter>().sharedMesh.bounds);
            }
        }
예제 #2
0
        private void Init()
        {
            string generatedName     = "generated by " + GetType().Name;
            var    generatedTranform = transform.Find(generatedName);

            generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject,
                                                                                                    typeof(MeshFilter),
                                                                                                    typeof(MeshRenderer),
                                                                                                    typeof(MeshBender));

            generated.GetComponent <MeshRenderer>().material = material;

            if (generated.GetComponent <DecrepitEffect>() == null)
            {
                generated.AddComponent <DecrepitEffect>();
            }
            meshBender = generated.GetComponent <MeshBender>();
            spline     = GetComponent <Spline>();

            meshBender.Source = SourceMesh.Build(mesh)
                                .Rotate(Quaternion.Euler(rotation))
                                .Scale(scale);
            meshBender.Mode = MeshBender.FillingMode.StretchToInterval;
            meshBender.SetInterval(spline, 0, 0.01f);
        }
예제 #3
0
        private GameObject FindOrCreate(string name)
        {
            var        childTransform = generated.transform.Find(name);
            GameObject res;

            if (childTransform == null)
            {
                res = UOUtility.Create(name,
                                       generated,
                                       typeof(MeshFilter),
                                       typeof(MeshRenderer),
                                       typeof(MeshBender),
                                       typeof(MeshCollider));
                res.isStatic = true;
            }
            else
            {
                res = childTransform.gameObject;
            }
            res.GetComponent <MeshRenderer>().material = material;
            res.GetComponent <MeshCollider>().material = physicMaterial;
            MeshBender mb = res.GetComponent <MeshBender>();

            mb.Source = SourceMesh.Build(mesh)
                        .Translate(translation)
                        .Rotate(Quaternion.Euler(rotation))
                        .Scale(scale);
            mb.Mode = mode;
            return(res);
        }
예제 #4
0
        private void GenerateMesh()
        {
            UOUtility.DestroyChildren(generated);

            int   i             = 0;
            float textureOffset = 0.0f;

            foreach (CubicBezierCurve curve in spline.GetCurves())
            {
                GameObject go = UOUtility.Create("segment " + i++,
                                                 generated,
                                                 typeof(MeshFilter),
                                                 typeof(MeshRenderer),
                                                 typeof(ExtrusionSegment),
                                                 typeof(MeshCollider));
                go.isStatic = true; // TODO Changed
                go.GetComponent <MeshRenderer>().material = material;
                ExtrusionSegment mb = go.GetComponent <ExtrusionSegment>();
                mb.ShapeVertices = shapeVertices;
                mb.TextureScale  = textureScale;
                mb.TextureOffset = textureOffset;
                mb.SampleSpacing = sampleSpacing;
                mb.SetInterval(curve);

                textureOffset += curve.Length;
            }
        }
예제 #5
0
        private GameObject FindOrCreate(string name)
        {
            var        childTransform = generated.transform.Find(name);
            GameObject res;

            if (childTransform == null)
            {
                res = UOUtility.Create(name,
                                       generated,
                                       typeof(MeshFilter),
                                       typeof(MeshRenderer),
                                       typeof(MeshBender),
                                       typeof(MeshCollider));
                res.isStatic = !updateInPlayMode;
            }
            else
            {
                res = childTransform.gameObject;
            }
            res.GetComponent <MeshRenderer>().material = material;
            res.GetComponent <MeshCollider>().material = physicMaterial;
            MeshBender mb = res.GetComponent <MeshBender>();

            mb.Source = SourceMesh.Build(mesh)
                        .Translate(translation)
                        .Rotate(Quaternion.Euler(rotation))
                        .Scale(scale);
            if (null != extraMeshes && 0 < extraMeshes.Length)
            {
                List <Material> materials = new List <Material>();
                materials.Add(material);

                SourceMesh[] extraSourceMeshes = new SourceMesh[extraMeshes.Length];
                for (int i = 0; i < extraMeshes.Length; ++i)
                {
                    var T = translation;
                    var R = rotation;
                    var S = scale;
                    if (extraMeshes[i].useCustomTRS)
                    {
                        T = extraMeshes[i].customTranslation;
                        R = extraMeshes[i].customRotation;
                    }
                    extraSourceMeshes[i] = SourceMesh.Build(extraMeshes[i].mesh)
                                           .Translate(T)
                                           .Rotate(Quaternion.Euler(R))
                                           .Scale(S);
                    extraSourceMeshes[i].placeType   = extraMeshes[i].placeType;
                    extraSourceMeshes[i].placeWeight = extraMeshes[i].placeWeight;
                    materials.Add(extraMeshes[i].material);
                }
                Array.Sort(extraSourceMeshes, (x, y) => (int)x.placeType - (int)y.placeType);
                mb.ExtraSources = extraSourceMeshes;
                res.GetComponent <MeshRenderer>().materials = materials.ToArray();
            }
            mb.Mode = mode;
            return(res);
        }
예제 #6
0
        public void CreateMeshes()
        {
            List <GameObject> used = new List <GameObject>();

            for (int i = 0; i < spline.GetCurves().Count; i++)
            {
                var curve = spline.GetCurves()[i];
                foreach (var tm in segments[i].transformedMeshes)
                {
                    if (tm.mesh == null)
                    {
                        // if there is no mesh specified for this segment, we ignore it.
                        continue;
                    }

                    // we try to find a game object previously generated. this avoids destroying/creating
                    // game objects at each update, wich is faster.
                    var        childName      = "segment " + i + " mesh " + segments[i].transformedMeshes.IndexOf(tm);
                    var        childTransform = generated.transform.Find(childName);
                    GameObject go;
                    if (childTransform == null)
                    {
                        go = UOUtility.Create(childName,
                                              generated,
                                              typeof(MeshFilter),
                                              typeof(MeshRenderer),
                                              typeof(MeshBender),
                                              typeof(MeshCollider));
                        go.isStatic = true;
                    }
                    else
                    {
                        go = childTransform.gameObject;
                    }
                    go.GetComponent <MeshRenderer>().material = tm.material;
                    go.GetComponent <MeshCollider>().material = tm.physicMaterial;

                    // we update the data in the bender. It will decide itself if the bending must be recalculated.
                    MeshBender mb = go.GetComponent <MeshBender>();
                    mb.Source      = tm.mesh;
                    mb.Curve       = curve;
                    mb.Translation = tm.translation;
                    mb.Rotation    = Quaternion.Euler(tm.rotation);
                    mb.Scale       = tm.scale;
                    mb.ComputeIfNeeded();
                    used.Add(go);
                }
            }

            // finally, we destroy the unused objects
            foreach (var go in generated.transform
                     .Cast <Transform>()
                     .Select(child => child.gameObject).Except(used))
            {
                UOUtility.Destroy(go);
            }
        }
예제 #7
0
        private void OnEnable()
        {
            string generatedName     = "generated by " + GetType().Name + GetInstanceID();
            var    generatedTranform = transform.Find(generatedName);

            generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);

            spline = GetComponent <Spline>();
            spline.NodeListChanged += (s, e) => toUpdate = true;
        }
예제 #8
0
        private void OnEnable()
        {
            string generatedName     = "generated by " + GetType().Name;
            var    generatedTranform = transform.Find(generatedName);

            generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject,
                                                                                                    typeof(MeshFilter),
                                                                                                    typeof(MeshRenderer),
                                                                                                    typeof(MeshCollider));

            spline = GetComponentInParent <Spline>();
            spline.NodeListChanged += (s, e) => toUpdate = true;
        }
예제 #9
0
        private void OnEnable()
        {
            // tip : if you name all generated content in the same way, you can easily find all of it
            // at once in the scene view, with a single search.
            string generatedName     = "generated by " + GetType().Name;
            var    generatedTranform = transform.Find(generatedName);

            generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);

            spline = GetComponentInParent <Spline>();

            toUpdate = true;
        }
예제 #10
0
        private void OnEnable()
        {
            string generatedName     = "generated by " + GetType().Name;
            var    generatedTranform = transform.Find(generatedName);

            generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);

            spline = GetComponentInParent <Spline>();
            spline.NodeListChanged += (s, e) => {
                toUpdate = true;
                foreach (CubicBezierCurve curve in spline.GetCurves())
                {
                    curve.Changed.AddListener(() => toUpdate = true);
                }
            };
            foreach (CubicBezierCurve curve in spline.GetCurves())
            {
                curve.Changed.AddListener(() => toUpdate = true);
            }
        }
예제 #11
0
        public void CreateMeshes()
        {
            UOUtility.DestroyChildren(generated);

            int i = 0;

            foreach (CubicBezierCurve curve in spline.GetCurves())
            {
                GameObject go = UOUtility.Create("SplineMesh" + i++, generated,
                                                 typeof(MeshFilter),
                                                 typeof(MeshRenderer),
                                                 typeof(MeshBender));
                go.GetComponent <MeshRenderer>().material = material;
                MeshBender mb = go.GetComponent <MeshBender>();
                mb.Source   = mesh;
                mb.Rotation = Quaternion.Euler(rotation);
                mb.Curve    = curve;
                mb.ComputeIfNeeded();
            }
        }
예제 #12
0
        private void GenerateMesh()
        {
            UOUtility.DestroyChildren(generated);

            int i = 0;

            foreach (CubicBezierCurve curve in spline.GetCurves())
            {
                GameObject go = UOUtility.Create("segment " + i++,
                                                 generated,
                                                 typeof(MeshFilter),
                                                 typeof(MeshRenderer),
                                                 typeof(ExtrusionSegment),
                                                 typeof(MeshCollider));
                go.GetComponent <MeshRenderer>().material = material;
                ExtrusionSegment mb = go.GetComponent <ExtrusionSegment>();
                mb.SetShapeVertices(shapeVertices, false);
                mb.SetTextureScale(textureScale, false);
                mb.SetCurve(curve, true);
            }
        }
예제 #13
0
        private GameObject FindOrCreateRender(string parentName, string name)
        {
            var childTransform = generated.transform.Find(name);

            if (collider)
            {
                var parentTransform = generated.transform.Find(parentName);
                childTransform = parentTransform.Find(name);
            }
            GameObject res;

            if (childTransform == null)
            {
                res = UOUtility.Create(name,
                                       generated,
                                       typeof(MeshFilter),
                                       typeof(MeshRenderer),
                                       typeof(MeshBender));
                res.isStatic = true;
            }
            else
            {
                res = childTransform.gameObject;
            }
            res.GetComponent <MeshRenderer>().material = material;
            MeshBender mb = res.GetComponent <MeshBender>();

            mb.Source = SourceMesh.Build(mesh)
                        .Translate(translation)
                        .Rotate(Quaternion.Euler(rotation))
                        .Scale(scale);
            if (mode == MeshBender.FillingMode.CustomIntervals)
            {
                mb.SetCustomInterval(customIntervalStart, customIntervalEnd);
            }
            mb.Mode = mode;
            return(res);
        }
예제 #14
0
        private void OnEnable()
        {
            string generatedName     = "generated by " + GetType().Name + GetInstanceID();
            var    generatedTranform = transform.Find(generatedName);

            generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);

            spline = GetComponent <Spline>();

            // we listen changes in the spline's node list and we update the list of segment accordingly
            // this way, if we insert a node between two others, a segment will be inserted too and the data won't shift
            while (segments.Count < spline.nodes.Count)
            {
                segments.Add(new TrackSegment());
            }
            while (segments.Count > spline.nodes.Count)
            {
                segments.RemoveAt(segments.Count - 1);
            }
            spline.NodeListChanged += (s, e) => {
                switch (e.type)
                {
                case ListChangeType.Add:
                    segments.Add(new TrackSegment());
                    break;

                case ListChangeType.Remove:
                    segments.RemoveAt(e.removeIndex);
                    break;

                case ListChangeType.Insert:
                    segments.Insert(e.insertIndex, new TrackSegment());
                    break;
                }
                toUpdate = true;
            };
            toUpdate = true;
        }
예제 #15
0
        protected void GenerateMesh()
        {
            UOUtility.DestroyChildren(generated);

            int   i             = 0;
            float textureOffset = 0.0f;

            foreach (CubicBezierCurve curve in spline.GetCurves())
            {
                GameObject go = UOUtility.Create("segment " + i++,
                                                 generated,
                                                 typeof(MeshFilter),
                                                 typeof(MeshRenderer),
                                                 typeof(ExtrusionSegment),
                                                 typeof(MeshCollider));
                MeshRenderer goRenderer = go.GetComponent <MeshRenderer>();
                goRenderer.material = material;
                ExtrusionSegment seg = go.GetComponent <ExtrusionSegment>();
                seg.ShapeVertices = shapeVertices;
                seg.TextureScale  = textureScale;
                seg.TextureOffset = textureOffset;
                seg.SampleSpacing = sampleSpacing;
                seg.SetInterval(curve);
                goRenderer.enabled = visible;
                if (go.TryGetComponent(out MeshCollider meshCollider))
                {
                    meshCollider.enabled = collisionEnabled;
                }
                int layerNum = LayerMask.NameToLayer(layer);
                if (layerNum > -1)
                {
                    go.gameObject.layer = layerNum;
                }

                textureOffset += curve.Length;
            }
        }
        private void Init()
        {
            for (int i = 0; i < meshes.Count; i++)
            {
                string generatedName     = i + ". generated by " + GetType().Name;
                var    generatedTranform = transform.Find(generatedName);

                GameObject generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject,
                                                                                                                   typeof(MeshFilter),
                                                                                                                   typeof(MeshRenderer),
                                                                                                                   typeof(MeshBender));

                // some harmless bug TODO
                if (generatedList.Count < i + 1)
                {
                    generatedList.Add(generated);
                }
                else
                {
                    generatedList[i] = generated;
                }

                generatedList[i].GetComponent <MeshRenderer>().material = materials[i];

                MeshBender meshBender = generatedList[i].GetComponent <MeshBender>();

                if (meshBenders.Count < i + 1)
                {
                    meshBenders.Add(meshBender);
                }
                else
                {
                    meshBenders[i] = meshBender;
                }

                meshBenders[i] = generatedList[i].GetComponent <MeshBender>();
                spline         = GetComponent <Spline>();

                meshBenders[i].Source = SourceMesh.Build(meshes[i])
                                        .Translate(translations[i])
                                        .Rotate(Quaternion.Euler(rotations[i]))
                                        .Scale(scales[i]);
                meshBenders[i].Mode = MeshBender.FillingMode.Repeat;
                meshBenders[i].SetInterval(spline, 0);
            }

            // First mesh determines lenght of generation
            contortionLength = meshBenders[0].Source.Length * ((float)(Repeat) + 0.1f);
        }
예제 #17
0
        private void OnEnable()
        {
            if (!allowMeshRegeneration)
            {
                return;
            }

            meshDataInternal = new MeshData[numOfGeneratedMeshes];

            for (int i = 0; i < meshDataInternal.Length; ++i)
            {
                meshDataInternal[i].meshPrefabs = meshData.meshPrefabs;
            }

            if (lockMeshData == false)
            {
                //for (int i = 0; i < meshData.Length; ++i)
                //{
                //    //MeshData = meshData[i].meshPrefabs.GetComponent<SplineMeshData>().renderMesh;


                //    //meshData[i].meshes = new Meshes[spline.curves.Count];

                //    //meshData[i].meshPrefabs = new Meshes[spline.curves.Count];
                //}
            }

            generated = new GameObject[numOfGeneratedMeshes];

            for (int j = 0; j < numOfGeneratedMeshes; ++j)
            {
                // tip : if you name all generated content in the same way, you can easily find all of it
                // at once in the scene view, with a single search.
                string generatedName     = "generated by " + GetType().Name + j;
                var    generatedTranform = transform.Find(generatedName);
                generated[j] = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);

                spline = GetComponentInParent <Spline>();
                spline.NodeListChanged += (s, e) => toUpdate = true;

                toUpdate = true;
            }
        }
예제 #18
0
        public void CreateMeshes()
        {
            if (null == spline || null == meshInfos || 0 == meshInfos.Length)
            {
                return;
            }

            UpdateSourceMeshes();
            UpdateDecisionParts();

            string generatedName     = "generated by " + GetType().Name;
            var    generatedTranform = transform.Find(generatedName);

            generated          = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);
            generated.isStatic = false == updateInPlayMode;
            generated.layer    = gameObject.layer;

            var generatedChildren = generated.transform.Cast <Transform>().ToList();

            foreach (var child in generatedChildren)
            {
                if (null == child)
                {
                    continue;
                }

                var meshCollider = child.GetComponent <MeshCollider>();
                if (meshCollider)
                {
                    meshCollider.enabled = false;
                }
            }

            var meshChunkDict = new Dictionary <Material, List <MeshChunk> >();
            var sampleCache   = new Dictionary <float, CurveSample>();

            float offset = 0;

            for (int i = 0; i < decisionParts.Count; ++i)
            {
                int index = decisionParts[i];

                if (false == meshChunkDict.ContainsKey(meshInfos[index].material))
                {
                    meshChunkDict.Add(meshInfos[index].material, new List <MeshChunk>());
                }

                var meshChunkList = meshChunkDict[meshInfos[index].material];

                int vertexCount = meshInfos[index].mesh.vertices.Length;

                bool isReachedMaxVertices = 0 < meshChunkList.Count && PerChunkMaxVertices < (meshChunkList.Last().bentVertices.Count + vertexCount);
                bool isReachedMaxLength   = 0 < meshChunkList.Count && PerChunkMaxLength < meshChunkList.Last().length;
                if (0 == meshChunkList.Count || isReachedMaxVertices || isReachedMaxLength)
                {
                    meshChunkList.Add(new MeshChunk()
                    {
                        bentVertices = new List <MeshVertex>(vertexCount),
                        triangles    = new List <int>(vertexCount / 3),
                        uv           = new List <Vector2> [8],
                        length       = 0
                    });
                }

                var meshChunk = meshChunkList.Last();

                ref SourceMesh sourceMesh = ref sourceMeshes[index];

                meshChunk.triangles.AddRange(sourceMesh.Triangles.Select(idx => idx + meshChunk.bentVertices.Count));
                List <Vector2> UV = new List <Vector2>();
                for (int channel = 0; channel < 8; ++channel)
                {
                    UV.Clear();
                    sourceMesh.Mesh.GetUVs(channel, UV);
                    if (0 < UV.Count)
                    {
                        if (null == meshChunk.uv[channel])
                        {
                            meshChunk.uv[channel] = new List <Vector2>();
                        }
                        int fillCount = Mathf.Max(0, (meshChunk.bentVertices.Count - UV.Count) - meshChunk.uv[channel].Count);
                        if (0 < fillCount)
                        {
                            meshChunk.uv[channel].AddRange(Enumerable.Repeat(Vector2.zero, fillCount));
                        }
                        meshChunk.uv[channel].AddRange(UV);
                    }
                }

                foreach (var vertex in sourceMesh.Vertices)
                {
                    var vert = new MeshVertex(vertex.position, vertex.normal, vertex.uv);

                    vert.position.x *= partsScale;

                    float distance = vert.position.x - sourceMesh.MinX * partsScale + offset;

                    distance = Mathf.Clamp(distance, 0, spline.Length);

                    CurveSample sample;
                    if (false == sampleCache.TryGetValue(distance, out sample))
                    {
                        sample = spline.GetSampleAtDistance(distance);
                        if (heightSync)
                        {
                            var        sampleLocationWS = spline.transform.TransformPoint(sample.location);
                            RaycastHit hitInfo;
                            if (Physics.Raycast(sampleLocationWS + Vector3.up * heightSyncTraceRange, -Vector3.up, out hitInfo, heightSyncTraceRange * 2, heightSyncLayerMask))
                            {
                                var newSampleLocation = spline.transform.InverseTransformPoint(hitInfo.point);
                                var newSampleUp       = heightNormalSync ? spline.transform.InverseTransformDirection(hitInfo.normal) : sample.up;
                                sample = new CurveSample(newSampleLocation, sample.tangent, newSampleUp, sample.scale, sample.roll, sample.distanceInCurve, sample.timeInCurve, sample.curve);
                            }
                        }

                        sampleCache.Add(distance, sample);
                    }

                    MeshVertex bentVertex = sample.GetBent(vert);
                    meshChunk.bentVertices.Add(bentVertex);
                }

                offset           += sourceMeshes[index].Length * partsScale;
                meshChunk.length += sourceMeshes[index].Length * partsScale;
            }
예제 #19
0
        private void OnEnable()
        {
            string generatedName     = "generated by " + GetType().Name;
            var    generatedTranform = transform.Find(generatedName);

            generated           = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);
            generated.hideFlags = HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInInspector | HideFlags.HideInHierarchy;

            spline = GetComponentInParent <Spline>();
            if (spline == null)
            {
                return;
            }
            spline.NodeListChanged += (s, e) => toUpdate = true;
        }
예제 #20
0
        private void CreateMeshes()
        {
            if (null == spline)
            {
                return;
            }

            string generatedName     = "generated by " + GetType().Name;
            var    generatedTranform = transform.Find(generatedName);

            generated          = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject);
            generated.isStatic = false == updateInPlayMode;
            generated.layer    = gameObject.layer;

            var generatedChildren = generated.transform.Cast <Transform>().ToList();

            foreach (var child in generatedChildren)
            {
                if (null == child)
                {
                    continue;
                }

                var meshCollider = child.GetComponent <MeshCollider>();
                if (meshCollider)
                {
                    meshCollider.enabled = false;
                }
            }

            List <MeshVertex> sourceVertices = new List <MeshVertex>(2 + Mathf.Max(0, slice - 1));
            float             x_start        = offset - width / 2;
            float             x_end          = offset + width / 2;

            sourceVertices.Add(new MeshVertex(new Vector3(0, 0, x_start), Vector3.up, new Vector2(+textureOffsetScale.x, 0)));
            for (int step = 1; step < slice; ++step)
            {
                float t = (float)step / (float)slice;
                float x = Mathf.Lerp(x_start, x_end, t);
                sourceVertices.Add(new MeshVertex(new Vector3(0, 0, x), Vector3.up, new Vector2(t / textureOffsetScale.z + textureOffsetScale.x, 0)));
            }
            sourceVertices.Add(new MeshVertex(new Vector3(0, 0, x_end), Vector3.up, new Vector2(1 / textureOffsetScale.z + textureOffsetScale.x, 0)));

            if (Mathf.Approximately(sampleSpacing, 0) || sampleSpacing <= 0)
            {
                Debug.LogError("Not enough sampleSpcaing. (must be greater than zero)");
                return;
            }

            int lineCount = 0;
            List <MeshVertex> bentVertices = new List <MeshVertex>();

            for (float d = 0.0f; d <= spline.Length; d += sampleSpacing)
            {
                var sample = spline.GetSampleAtDistance(d);

                if (heightSync)
                {
                    var        sampleLocationWS = spline.transform.TransformPoint(sample.location);
                    RaycastHit hitInfo;
                    if (Physics.Raycast(sampleLocationWS + Vector3.up * heightSyncTraceRange, -Vector3.up, out hitInfo, heightSyncTraceRange * 2, heightSyncLayerMask))
                    {
                        var newSampleLocation = spline.transform.InverseTransformPoint(hitInfo.point);
                        sample = new CurveSample(newSampleLocation, sample.tangent, sample.up, sample.scale, sample.roll, sample.distanceInCurve, sample.timeInCurve, sample.curve);
                    }
                }

                for (int i = 0; i < sourceVertices.Count; ++i)
                {
                    var bentVertex = sample.GetBent(sourceVertices[i]);

                    bentVertex.normal = sample.up;

                    if (heightSync)
                    {
                        var        bentWS = spline.transform.TransformPoint(bentVertex.position);
                        RaycastHit hitInfo;
                        if (Physics.Raycast(bentWS + Vector3.up * heightSyncTraceRange, -Vector3.up, out hitInfo, heightSyncTraceRange * 2, heightSyncLayerMask))
                        {
                            bentVertex.position = spline.transform.InverseTransformPoint(hitInfo.point);
                            if (heightNormalSync)
                            {
                                bentVertex.normal = spline.transform.InverseTransformDirection(hitInfo.normal);
                            }
                        }
                    }

                    bentVertex.uv.y = (d / width) / textureOffsetScale.w + textureOffsetScale.y;

                    bentVertices.Add(bentVertex);
                }

                ++lineCount;
            }

            if (1 >= lineCount)
            {
                Debug.LogError("Not enough line length");
                return;
            }

            List <Transform> newGeneratedTransform = new List <Transform>();

            int        baseIndex         = 0;
            int        lineVerticesCount = 2 + Mathf.Max(0, slice - 1);
            List <int> triangles         = new List <int>((lineVerticesCount - 1) * (lineCount - 1) * 2);

            for (int i = 0; i < lineCount - 1; ++i)
            {
                int nextBaseIndex = baseIndex + lineVerticesCount;
                for (int v = 0; v < lineVerticesCount - 1; ++v)
                {
                    int[] vertices = new int[] {
                        baseIndex + v, baseIndex + v + 1,
                        nextBaseIndex + v, nextBaseIndex + v + 1
                    };
                    triangles.Add(vertices[0]);
                    triangles.Add(vertices[1]);
                    triangles.Add(vertices[2]);
                    triangles.Add(vertices[2]);
                    triangles.Add(vertices[1]);
                    triangles.Add(vertices[3]);
                }

                bool isOverVertices      = nextBaseIndex + lineVerticesCount > PerSegmentMaxVertices;
                bool isEndLine           = (i == lineCount - 2);
                bool needGenerateSegment = isOverVertices || isEndLine;

                if (needGenerateSegment)
                {
                    string    segmentName      = $"{name}-{material.name}-{newGeneratedTransform.Count + 1}";
                    Transform segmentTransform = generated.transform.Find(segmentName);
                    if (null == segmentTransform)
                    {
                        var go = UOUtility.Create(segmentName,
                                                  generated,
                                                  typeof(MeshFilter),
                                                  typeof(MeshRenderer),
                                                  typeof(MeshCollider));
                        segmentTransform = go.transform;
                    }
                    segmentTransform.gameObject.isStatic = generated.isStatic;
                    segmentTransform.gameObject.layer    = generated.layer;

                    newGeneratedTransform.Add(segmentTransform);
                    generatedChildren.Remove(segmentTransform);

                    var meshFilter   = segmentTransform.GetComponent <MeshFilter>();
                    var meshRenderer = segmentTransform.GetComponent <MeshRenderer>();
                    var meshCollider = segmentTransform.GetComponent <MeshCollider>();

                    Mesh mesh = meshFilter.sharedMesh;
                    if (null == mesh || mesh.name != segmentName)
                    {
                        mesh = new Mesh();
                    }
                    else if (mesh.vertexCount != bentVertices.Count)
                    {
                        mesh.Clear();
                    }

                    mesh.name        = segmentName;
                    mesh.hideFlags   = HideFlags.HideInHierarchy;
                    mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt16;

                    var segmentBentVertices = bentVertices.GetRange(0, nextBaseIndex + lineVerticesCount);

                    mesh.SetVertices(segmentBentVertices.Select(b => b.position).ToList());
                    mesh.SetNormals(segmentBentVertices.Select(b => b.normal).ToList());
                    mesh.SetUVs(0, segmentBentVertices.Select(b => b.uv).ToList());
                    mesh.SetTriangles(triangles, 0, false);

                    mesh.RecalculateBounds();
                    mesh.RecalculateTangents();

                    meshFilter.sharedMesh   = mesh;
                    meshRenderer.material   = material;
                    meshCollider.sharedMesh = mesh;

                    meshCollider.enabled = generateCollider;

                    triangles.Clear();
                    bentVertices.RemoveRange(0, nextBaseIndex);

                    nextBaseIndex = 0;
                }

                baseIndex = nextBaseIndex;
            }

            foreach (var deprecatedTransform in generatedChildren)
            {
                if (deprecatedTransform != null)
                {
                    UOUtility.Destroy(deprecatedTransform.gameObject);
                }
            }
        }