Beispiel #1
0
        //Methods
        //--------------------------------------------

        public Level()
        {
            _spline = new BezierSpline.BezierSpline();
        }
Beispiel #2
0
        /// <inheritdoc />
        public LevelNodeChunk.MeshData GetMesh(BezierSpline.BezierSpline spline, IShaper previous, int offset, int length)
        {
            Debug.Assert(offset + length <= spline.Length, "Trying to generate mesh that is longer than the spline it is based on! " + (offset + length) + " > " + spline.Length);

            var mesh = new LevelNodeChunk.MeshData();

            List <Vector3> vertices  = new List <Vector3>();
            List <int>     triangles = new List <int>();
            List <Vector2> UVs       = new List <Vector2>();

            var meshResolutionParallel = Config.Instance.Global.Level.Mesh.Resolution.Parallel;
            var meshResolutionNormal   = Config.Instance.Global.Level.Mesh.Resolution.Normal;
            var radius = Config.Instance.Global.Level.Mesh.Radius;
            //we have to save our old normal so we can use that as a second vector for our normal calculation
            Vector3 oldNormal = previous.LastNormal;

            for (int i = 0; i < length; i++)
            {
                for (int x = 0; x <= meshResolutionParallel; x++)
                {
                    float   u       = offset + i + ((float)x / meshResolutionParallel);
                    Vector3 center  = spline.Evaluate(u);
                    Vector3 tangent = spline.GetDerivative(u, 1);
                    Vector3 normal  = spline.GetNormal(u).normalized;

                    //for the first ring we have to use the last shapers values
                    if (i == 0 && x == 0)
                    {
                        oldNormal = previous.LastNormal;
                        normal    = previous.LastNormal;
                        center    = previous.LastPoint;
                        tangent   = previous.LastDirection;
                    }
                    else
                    {
                        // project normal onto tangent plane so the rotation stays somewhat within that plane
                        Plane p = new Plane(tangent, Vector3.zero);

                        // rotate toward target normal
                        Vector3 newNormal = Vector3.RotateTowards(oldNormal, normal, Mathf.Deg2Rad * 10.0f / meshResolutionParallel, 0);
                        //then rotate to plane
                        newNormal = Vector3.RotateTowards(newNormal, p.ClosestPointOnPlane(oldNormal), Mathf.Deg2Rad * 10.0f, 0);

                        // check if all vectors are planar. We don't want that
                        if (newNormal != normal && Vector3.Cross(Vector3.Cross(tangent, oldNormal), Vector3.Cross(tangent, newNormal)) == Vector3.zero)
                        {
                            newNormal = Quaternion.AngleAxis(10, tangent) * oldNormal;                             // rotate the normal out of the same plane as tangent and targetnormal
                        }
                        oldNormal = newNormal;
                        normal    = newNormal;

                        LastPoint     = center;
                        LastDirection = tangent;
                        LastNormal    = normal;
                    }


                    Debug.Assert(Vector3.Cross(normal, tangent) != Vector3.zero, "Tangent and Normal are parallel. something went wrong when calculating the normal.");
                    Debug.Assert(tangent != Vector3.zero, "Tangent is zero! Do you have a duplicate pont in the spline?");
                    if (Vector3.Cross(normal, tangent) == Vector3.zero)
                    {
                        Vector3.Cross(normal, tangent);
                    }

                    //Generate tube segment. We need to overlap the first and the last vertices because we need UV 0 and 1 on the same spot
                    for (int n = 0; n <= meshResolutionNormal; n++)
                    {
                        //rotate the normal arount the center
                        Vector3 vert = center + Quaternion.AngleAxis(n * 360.0f / meshResolutionNormal, tangent) * normal.normalized * radius;
                        vertices.Add(vert);
                        float xUV = (float)(i * meshResolutionParallel + x) / (spline.Points.Count * meshResolutionParallel);
                        float yUV = (float)n / meshResolutionNormal;
                        UVs.Add(new Vector2(xUV, yUV));
                    }
                    //connect tube segment to last one
                    if (i != 0 || x > 0)                    //do not do this for the very first segment
                    {
                        //calculate stride per segment
                        int segmentFirstIndex     = (i * meshResolutionParallel + x) * (meshResolutionNormal + 1);
                        int lastSegmentFirstIndex = segmentFirstIndex - (meshResolutionNormal + 1);

                        for (int n = 1; n <= meshResolutionNormal + 1; n++)
                        {
                            //generate double faced quad between tube segments
                            //using modulo to connect last vertex to first
                            triangles.AddRange(MakeQuad(
                                                   lastSegmentFirstIndex + n % (meshResolutionNormal + 1),
                                                   lastSegmentFirstIndex + (n - 1) % (meshResolutionNormal + 1),
                                                   segmentFirstIndex + (n - 1) % (meshResolutionNormal + 1),
                                                   segmentFirstIndex + n % (meshResolutionNormal + 1)
                                                   )
                                               );
                        }
                    }
                }
            }

            mesh.Vertices  = vertices;
            mesh.Triangles = triangles;
            mesh.UVs       = UVs;

            return(mesh);
        }