private CurveSample getCurvePointAtDistance(float d)
        {
            if (d < 0 || d > Length)
            {
                throw new ArgumentException("Distance must be positive and less than curve length. Length = " + Length + ", given distance was " + d);
            }

            CurveSample previous = samples[0];
            CurveSample next     = null;

            foreach (CurveSample cp in samples)
            {
                if (cp.distance >= d)
                {
                    next = cp;
                    break;
                }
                previous = cp;
            }
            if (next == null)
            {
                throw new Exception("Can't find curve samples.");
            }
            float t = next == previous ? 0 : (d - previous.distance) / (next.distance - previous.distance);

            CurveSample res = new CurveSample();

            res.distance = d;
            res.location = Vector3.Lerp(previous.location, next.location, t);
            res.tangent  = Vector3.Lerp(previous.tangent, next.tangent, t).normalized;
            return(res);
        }
Example #2
0
        public CurveSample GetProjectionSample(Vector3 pointToProject)
        {
            CurveSample closest        = default(CurveSample);
            float       minSqrDistance = float.MaxValue;

            foreach (var curve in curves)
            {
                var projection = curve.GetProjectionSample(pointToProject);
                if (curve == curves[0])
                {
                    closest        = projection;
                    minSqrDistance = (projection.location - pointToProject).sqrMagnitude;
                    continue;
                }

                var sqrDist = (projection.location - pointToProject).sqrMagnitude;
                if (sqrDist < minSqrDistance)
                {
                    minSqrDistance = sqrDist;
                    closest        = projection;
                }
            }

            return(closest);
        }
Example #3
0
    private void returnToTrack()
    {
        Debug.Log("Returning car to track: " + CarInfo?.name);
        var track = FindObjectOfType <SplineMesh.Spline>();

        SplineMesh.CurveSample closest = null;
        float closestDistance          = float.MaxValue;

        for (float i = 0; i < track.Length; i += 0.05f)
        {
            var curveSample = track.GetSampleAtDistance(i);
            var d           = (gameObject.transform.position - 0.048f * Vector3.up - curveSample.location);
            d.y *= 10;
            var distance = d.magnitude;
            if (distance < closestDistance)
            {
                closestDistance = distance;
                closest         = curveSample;
            }
        }

        rigidBody.position = closest.location + 0.1f * Vector3.up;
        rigidBody.rotation = closest.Rotation;
        rigidBody.velocity = Vector3.zero;
        EventBus.Publish(new CarReturnedToTrack(CarInfo));
    }
        private void ComputePoints()
        {
            samples.Clear();
            Length = 0;
            Vector3 previousPosition = GetLocation(0);

            for (float t = 0; t < 1; t += T_STEP)
            {
                CurveSample sample = new CurveSample();
                sample.location = GetLocation(t);
                sample.tangent  = GetTangent(t);
                Length         += Vector3.Distance(previousPosition, sample.location);
                sample.distance = Length;

                previousPosition = sample.location;
                samples.Add(sample);
            }
            CurveSample lastSample = new CurveSample();

            lastSample.location = GetLocation(1);
            lastSample.tangent  = GetTangent(1);
            Length += Vector3.Distance(previousPosition, lastSample.location);
            lastSample.distance = Length;
            samples.Add(lastSample);

            if (Changed != null)
            {
                Changed.Invoke();
            }
        }
Example #5
0
        public CurveSample GetProjectionSample(Vector3 pointToProject)
        {
            CurveSample closest        = default(CurveSample);
            float       minSqrDistance = float.MaxValue;

            for (int i = 0; i < curves.Count; i++)
            {
                var curve      = curves[i];
                var projection = curve.GetProjectionSample(pointToProject);
                if (curve == curves[0])
                {
                    closest        = projection;
                    closest.index  = i;
                    minSqrDistance = (projection.location - pointToProject).sqrMagnitude;
                    continue;
                }
                var sqrDist = (projection.location - pointToProject).sqrMagnitude;
                if (sqrDist < minSqrDistance)
                {
                    minSqrDistance = sqrDist;
                    closest        = projection;
                    closest.index  = i;
                }
            }
            return(closest);
        }
Example #6
0
        /// <summary>
        /// Returns an interpolated sample of the curve, containing all curve data at this distance.
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public CurveSample GetSampleAtDistance(float d)
        {
            if (d < 0 || d > Length)
            {
                throw new ArgumentException("Distance must be positive and less than curve length. Length = " + Length + ", given distance was " + d);
            }

            CurveSample previous = samples[0];

            if (previous == null)
            {
                Debug.LogError(samples.Count.ToString());
            }
            CurveSample next = null;

            foreach (CurveSample cp in samples)
            {
                if (cp.distanceInCurve >= d)
                {
                    next = cp;
                    break;
                }
                previous = cp;
            }
            if (next == null)
            {
                throw new Exception("Can't find curve samples.");
            }
            float t = next == previous ? 0 : (d - previous.distanceInCurve) / (next.distanceInCurve - previous.distanceInCurve);

            return(CurveSample.Lerp(previous, next, t));
        }
        // Update is called once per frame
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.F))
            {
                CurveSample sample = spline.GetSample(0.5f);
                spline.InsertNode(1, (new SplineNode(sample.location + Vector3.left * 3, (spline.nodes[0].Direction + spline.nodes[1].Direction) / 2)));

                GetComponent <SplineMeshTiling>().CreateMeshes();

                Debug.Log(sample.distanceInCurve + "|" + sample.timeInCurve);
            }

            if (Input.GetKeyDown(KeyCode.X))
            {
                spline.RemoveNode(spline.nodes[spline.nodes.Count - 1]);
                GetComponent <SplineMeshTiling>().CreateMeshes();
            }

            if (Input.GetKeyDown(KeyCode.Q))
            {
                CurveSample sample = spline.GetSample(spline.nodes.Count - 2 + 0.5f);
                spline.nodes[spline.nodes.Count - 1].Position = sample.location;
                GetComponent <SplineMeshTiling>().CreateMeshes();
            }
        }
Example #8
0
        /// <summary>
        /// Returns an interpolated sample of the curve, containing all curve data at this distance.
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public CurveSample GetSampleAtDistance(float d)
        {
            if (d < 0 || d > Length)
            {
                throw new ArgumentException("Distance must be positive and less than curve length. Length = " + Length + ", given distance was " + d);
            }

            CurveSample previous = samples[0];
            CurveSample next     = default(CurveSample);
            bool        found    = false;

            foreach (CurveSample cp in samples)
            {
                if (cp.distanceInCurve >= d)
                {
                    next  = cp;
                    found = true;
                    break;
                }
                previous = cp;
            }
            if (!found)
            {
                throw new Exception("Can't find curve samples.");
            }
            float t = next == previous ? 0 : (d - previous.distanceInCurve) / (next.distanceInCurve - previous.distanceInCurve);

            return(CurveSample.Lerp(previous, next, t));
        }
Example #9
0
        /// <summary>
        /// Returns an interpolated sample of the curve, containing all curve data at this time.
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public CurveSample GetSample(float time)
        {
            AssertTimeInBounds(time);
            CurveSample previous = samples[0];
            CurveSample next     = default(CurveSample);
            bool        found    = false;

            foreach (CurveSample cp in samples)
            {
                if (cp.timeInCurve >= time)
                {
                    next  = cp;
                    found = true;
                    break;
                }
                previous = cp;
            }
            if (!found)
            {
                throw new Exception("Can't find curve samples.");
            }
            float t = next == previous ? 0 : (time - previous.timeInCurve) / (next.timeInCurve - previous.timeInCurve);

            return(CurveSample.Lerp(previous, next, t));
        }
 private void PlaceFollower()
 {
     if (generated != null)
     {
         CurveSample sample = spline.GetSample(Rate);
         generated.transform.localPosition = sample.location;
     }
 }
Example #11
0
 private void PlaceFollower()
 {
     if (go != null)
     {
         CurveSample sample = spline.GetSample(rate);
         go.transform.localPosition = sample.location;
         go.transform.localRotation = sample.Rotation;
     }
 }
Example #12
0
        public void Sow()
        {
            UOUtility.DestroyChildren(generated);

            UnityEngine.Random.InitState(randomSeed);
            if (spacing + spacingRange <= 0 ||
                prefab == null)
            {
                return;
            }

            float distance = 0;

            while (distance <= spline.Length)
            {
                CurveSample sample = spline.GetSampleAtDistance(distance);

                GameObject go;
                if (Application.isPlaying)
                {
                    go = Instantiate(prefab, generated.transform);
                }
                else
                {
                    go = (GameObject)UnityEditor.PrefabUtility.InstantiatePrefab((UnityEngine.Object)prefab);
                    go.transform.parent = generated.transform;
                }
                go.transform.localRotation = Quaternion.identity;
                go.transform.localPosition = Vector3.zero;
                go.transform.localScale    = Vector3.one;

                // move along spline, according to spacing + random
                go.transform.localPosition = sample.location;
                // apply scale + random
                float rangedScale = scale + UnityEngine.Random.Range(0, scaleRange);
                go.transform.localScale = new Vector3(rangedScale, rangedScale, rangedScale);
                // rotate with random yaw
                if (isRandomYaw)
                {
                    go.transform.Rotate(0, 0, UnityEngine.Random.Range(-180, 180));
                }
                else
                {
                    go.transform.rotation = sample.Rotation;
                }
                // move orthogonaly to the spline, according to offset + random
                Vector3 binormal = sample.tangent;
                binormal = Quaternion.LookRotation(Vector3.right, Vector3.up) * binormal;
                var localOffset = offset + UnityEngine.Random.Range(0, offsetRange * Math.Sign(offset));
                localOffset           *= sample.scale.x;
                binormal              *= localOffset;
                go.transform.position += binormal;

                distance += spacing + UnityEngine.Random.Range(0, spacingRange);
            }
        }
Example #13
0
 /// <summary>
 /// Linearly interpolates between two curve samples.
 /// </summary>
 /// <param name="a"></param>
 /// <param name="b"></param>
 /// <param name="t"></param>
 /// <returns></returns>
 public static CurveSample Lerp(CurveSample a, CurveSample b, float t)
 {
     return(new CurveSample(
                Vector3.Lerp(a.location, b.location, t),
                Vector3.Lerp(a.tangent, b.tangent, t).normalized,
                Vector3.Lerp(a.up, b.up, t),
                Vector2.Lerp(a.scale, b.scale, t),
                Mathf.Lerp(a.roll, b.roll, t),
                Mathf.Lerp(a.distanceInCurve, b.distanceInCurve, t),
                Mathf.Lerp(a.timeInCurve, b.timeInCurve, t)));
 }
Example #14
0
        public CurveSample GetProjectionSample(Vector3 pointToProject)
        {
            float minSqrDistance = float.PositiveInfinity;
            int   closestIndex   = -1;
            int   i = 0;

            foreach (var sample in samples)
            {
                float sqrDistance = (sample.location - pointToProject).sqrMagnitude;
                if (sqrDistance < minSqrDistance)
                {
                    minSqrDistance = sqrDistance;
                    closestIndex   = i;
                }
                i++;
            }
            CurveSample previous, next;

            if (closestIndex == 0)
            {
                previous = samples[closestIndex];
                next     = samples[closestIndex + 1];
            }
            else if (closestIndex == samples.Count - 1)
            {
                previous = samples[closestIndex - 1];
                next     = samples[closestIndex];
            }
            else
            {
                var toPreviousSample = (pointToProject - samples[closestIndex - 1].location).sqrMagnitude;
                var toNextSample     = (pointToProject - samples[closestIndex + 1].location).sqrMagnitude;
                if (toPreviousSample < toNextSample)
                {
                    previous = samples[closestIndex - 1];
                    next     = samples[closestIndex];
                }
                else
                {
                    previous = samples[closestIndex];
                    next     = samples[closestIndex + 1];
                }
            }

            var onCurve = Vector3.Project(pointToProject - previous.location, next.location - previous.location) + previous.location;
            var rate    = (onCurve - previous.location).sqrMagnitude / (next.location - previous.location).sqrMagnitude;

            rate = Mathf.Clamp(rate, 0, 1);
            var result = CurveSample.Lerp(previous, next, rate);

            return(result);
        }
        private void PlaceFollower()
        {
            if (generated != null)
            {
                CurveSample sample = spline.GetSample(rate);
                generated.transform.localPosition = sample.location;
                generated.transform.localRotation = sample.Rotation;

                if (rate + ViewOffset < spline.nodes.Count - 1)
                {
                    CurveSample viewDirSample = spline.GetSample(rate + ViewOffset);
                    generated.transform.localRotation = viewDirSample.Rotation;
                }
            }
        }
Example #16
0
        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return(false);
            }
            CurveSample other = (CurveSample)obj;

            return(location == other.location &&
                   tangent == other.tangent &&
                   up == other.up &&
                   scale == other.scale &&
                   roll == other.roll &&
                   distanceInCurve == other.distanceInCurve &&
                   timeInCurve == other.timeInCurve);
        }
    public static float GetDistanceFromSample(SplineMesh.Spline spline, SplineMesh.CurveSample sample)
    {
        float cumulatedDistance = 0;

        foreach (SplineMesh.CubicBezierCurve curve in spline.curves)
        {
            if (sample.curve != curve)
            {
                cumulatedDistance += curve.Length;
            }
            else
            {
                cumulatedDistance += sample.distanceInCurve;
                return(cumulatedDistance);
            }
        }
        return(cumulatedDistance);
    }
Example #18
0
        /// <summary>
        /// Get the closest Point on Spline
        /// </summary>
        /// <param name="worldPosition"></param>
        /// <param name="stepsPerUnityUnit"></param>
        /// <returns></returns>
        public Vector3 GetNearestPoint(Vector3 worldPosition, int stepsPerUnityUnit = 10)
        {
            //How Many Steps used Per UnityUnit(Meters)
            float stepSize   = 1f / stepsPerUnityUnit;
            int   stepLenght = Mathf.FloorToInt(Length * stepsPerUnityUnit);

            CurveSample nearestsample = GetSampleAtDistance(0);

            Vector3 rootpos       = transform.position;
            float   smallestDelta = float.MaxValue;

            for (int i = 0; i < stepLenght; i++)
            {
                float delta = (worldPosition - (GetSampleAtDistance(i * stepSize).location + rootpos)).sqrMagnitude;
                if (delta < smallestDelta)
                {
                    smallestDelta = delta;
                    nearestsample = GetSampleAtDistance(i * stepSize);
                }
            }
            return(nearestsample.location + rootpos);
        }
Example #19
0
        void OnSceneGUI()
        {
            Event e = Event.current;

            if (e.type == EventType.MouseDown)
            {
                Undo.RegisterCompleteObjectUndo(se, "change extruded shape");
                // if control key pressed, we will have to create a new vertex if position is changed
                if (e.alt)
                {
                    mustCreateNewNode = true;
                }
            }
            if (e.type == EventType.MouseUp)
            {
                mustCreateNewNode = false;
            }
            var spline = se.GetComponent <Spline>();

            CurveSample startSample = spline.GetSample(0);
            Quaternion  q           = startSample.Rotation;

            foreach (ExtrusionSegment.Vertex v in se.shapeVertices)
            {
                // we create point and normal relative to the spline start where the shape is drawn
                Vector3 point  = se.transform.TransformPoint(q * v.point + startSample.location);
                Vector3 normal = se.transform.TransformPoint(q * (v.point + v.normal) + startSample.location);

                if (v == selection)
                {
                    // draw the handles for selected vertex position and normal
                    float size = HandleUtility.GetHandleSize(point) * 0.3f;
                    float snap = 0.1f;

                    // create a handle for the vertex position
                    Vector3 movedPoint = Handles.Slider2D(0, point, startSample.tangent, Vector3.right, Vector3.up, size, Handles.CircleHandleCap, new Vector2(snap, snap));
                    if (movedPoint != point)
                    {
                        // position has been moved
                        Vector2 newVertexPoint = Quaternion.Inverse(q) * (se.transform.InverseTransformPoint(movedPoint) - startSample.location);
                        if (mustCreateNewNode)
                        {
                            // We must create a new node
                            mustCreateNewNode = false;
                            ExtrusionSegment.Vertex newVertex = new ExtrusionSegment.Vertex(newVertexPoint, v.normal, v.uCoord);
                            int i = se.shapeVertices.IndexOf(v);
                            if (i == se.shapeVertices.Count - 1)
                            {
                                se.shapeVertices.Add(newVertex);
                            }
                            else
                            {
                                se.shapeVertices.Insert(i + 1, newVertex);
                            }
                            selection = newVertex;
                        }
                        else
                        {
                            v.point = newVertexPoint;
                            // normal must be updated if point has been moved
                            normal = se.transform.TransformPoint(q * (v.point + v.normal) + startSample.location);
                        }
                        se.SetToUpdate();
                    }
                    else
                    {
                        // vertex position handle hasn't been moved
                        // create a handle for normal
                        Vector3 movedNormal = Handles.Slider2D(normal, startSample.tangent, Vector3.right, Vector3.up, size, Handles.CircleHandleCap, snap);
                        if (movedNormal != normal)
                        {
                            // normal has been moved
                            v.normal = (Vector2)(Quaternion.Inverse(q) * (se.transform.InverseTransformPoint(movedNormal) - startSample.location)) - v.point;
                            se.SetToUpdate();
                        }
                    }

                    Handles.BeginGUI();
                    DrawQuad(HandleUtility.WorldToGUIPoint(point), CURVE_COLOR);
                    DrawQuad(HandleUtility.WorldToGUIPoint(normal), Color.red);
                    Handles.EndGUI();
                }
                else
                {
                    // we draw a button to allow selection of the vertex
                    Handles.BeginGUI();
                    Vector2 p = HandleUtility.WorldToGUIPoint(point);
                    if (GUI.Button(new Rect(p - new Vector2(QUAD_SIZE / 2, QUAD_SIZE / 2), new Vector2(QUAD_SIZE, QUAD_SIZE)), GUIContent.none))
                    {
                        selection = v;
                    }
                    Handles.EndGUI();
                }

                // draw an arrow from the vertex location to the normal
                Handles.color = Color.red;
                Handles.DrawLine(point, normal);

                // draw a line between that vertex and the next one
                int index     = se.shapeVertices.IndexOf(v);
                int nextIndex = index == se.shapeVertices.Count - 1 ? 0 : index + 1;
                ExtrusionSegment.Vertex next = se.shapeVertices[nextIndex];
                Handles.color = CURVE_COLOR;
                Vector3 vAtSplineEnd = se.transform.TransformPoint(q * next.point + startSample.location);
                Handles.DrawLine(point, vAtSplineEnd);
            }
        }
Example #20
0
        /// <summary>
        /// Split the spline by adding a node at the specific time
        /// the tangents of previous and following node are modified
        /// in order to not alter the curve shape.
        ///
        /// previous and next node tangent type become SplineNode.TangentType.Free
        /// </summary>
        /// <param name="time"></param>
        public void SplitAtTime(float time)
        {
            if (time <= 0f || time >= (float)nodes.Count - 1)
            {
                throw new Exception(string.Format("Can't split at time {0}. Use a value between 0 and {1}", time, (float)nodes.Count - 1));
            }

            CurveSample time_sample        = GetSample(time);
            Vector3     new_point_position = time_sample.location;


            // percent position between two nodes
            float percentage = time % 1;
            int   index      = Mathf.FloorToInt(time);

            /**
             * P0 = starting point
             * P3 = ending point
             *
             * P1 = P0 control point
             * P2 = mirror of P3 control point (we need the inverse, not the real cp)
             */

            SplineNode starting_node = nodes[index];

            Vector3 p0 = starting_node.Position;
            Vector3 p1 = starting_node.DirectionOut;

            SplineNode ending_node = nodes[index + 1];
            Vector3    p3          = ending_node.Position;
            Vector3    p2          = ending_node.DirectionIn;


            // we need to find a positoin at percentage% between P0 and P1
            Vector3 m0 = p0 + (p1 - p0) * percentage;
            Vector3 m1 = p1 + (p2 - p1) * percentage;
            Vector3 m2 = p2 + (p3 - p2) * percentage;

            Vector3 q0 = m0 + (m1 - m0) * percentage;
            Vector3 q1 = m1 + (m2 - m1) * percentage;

            Vector3 new_point_direction_in  = q0;
            Vector3 new_point_direction_out = q1;

            // create the new node with previous calculated params
            SplineNode n = new SplineNode(new_point_position, new_point_direction_out, new_point_direction_in); //time_sample.tangent);

            n.DirectionType = SplineNode.TangentType.Free;


            // we also need to alter the directionOut of the previous point
            // its new direction is  m0
            // in order to alter it, the tangent type must be free
            if (nodes[index].DirectionType != SplineNode.TangentType.Free)
            {
                nodes[index].DirectionType = SplineNode.TangentType.Free;
            }
            nodes[index].DirectionOut = m0;

            // we also need to alter the directionIn of the final point
            // its new direction is  m2
            // in order to alter it, the tangent type must be free
            if (nodes[index + 1].DirectionType != SplineNode.TangentType.Free)
            {
                nodes[index + 1].DirectionType = SplineNode.TangentType.Free;
            }
            nodes[index + 1].DirectionIn = m2;
            InsertNode(index + 1, n);
        }
Example #21
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;
            }
Example #22
0
        public void Sow()
        {
            UOUtility.DestroyChildren(generated);

            UnityEngine.Random.InitState(randomSeed);
            if (spacing + spacingRange <= 0 ||
                prefab == null)
            {
                return;
            }

            float distance = 0;

            while (distance <= spline.Length)
            {
                CurveSample 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);
                    }
                }

                GameObject go;
                go = Instantiate(prefab, generated.transform);
                go.transform.localRotation = Quaternion.identity;
                go.transform.localPosition = Vector3.zero;
                go.transform.localScale    = Vector3.one;

                go.isStatic = false == updateInPlayMode;
                go.layer    = gameObject.layer;
                foreach (var child in go.transform.Cast <Transform>())
                {
                    child.gameObject.layer = go.layer;
                }

                // move along spline, according to spacing + random
                go.transform.localPosition = sample.location;
                // apply scale + random
                float rangedScale = scale + UnityEngine.Random.Range(0, scaleRange);
                go.transform.localScale = new Vector3(rangedScale, rangedScale, rangedScale);
                // rotate with random yaw
                if (isRandomYaw)
                {
                    go.transform.Rotate(0, 0, UnityEngine.Random.Range(-180, 180));
                }
                else
                {
                    go.transform.rotation = sample.Rotation;
                }
                // move orthogonaly to the spline, according to offset + random
                var binormal          = (Quaternion.LookRotation(sample.tangent, sample.up) * Vector3.right).normalized;
                var localWidthOffset  = widthOffset + UnityEngine.Random.Range(0, widthOffsetRange * Math.Sign(widthOffset));
                var localHeightOffset = heightOffset + UnityEngine.Random.Range(0, heightOffsetRange * Math.Sign(heightOffset));

                localWidthOffset      *= sample.scale.x;
                binormal              *= localWidthOffset;
                go.transform.position += binormal + sample.up * localHeightOffset;

                distance += spacing + UnityEngine.Random.Range(0, spacingRange);
            }
        }
Example #23
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);
                }
            }
        }