Esempio n. 1
0
 /// <inheritdoc/>
 internal override void OnDraw(GraphicsDevice graphicsDevice, Rectangle rectangle, Vector2F topLeftPosition, Vector2F bottomRightPosition)
 {
     if (Submesh != null)
     {
         Submesh.Draw();
     }
 }
Esempio n. 2
0
        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        /// <summary>
        /// Sets the road mesh and related properties.
        /// </summary>
        /// <param name="submesh">The submesh that represents the road.</param>
        /// <param name="aabb">The axis-aligned bounding box of the mesh.</param>
        /// <param name="roadLength">The length of the road in world space units.</param>
        /// <param name="disposeWithRoadLayer">
        /// <see langword="true" /> to automatically dispose of the mesh when the
        /// <see cref="TerrainRoadLayer"/> is disposed of; otherwise, <see langword="false"/>.
        /// </param>
        /// <remarks>
        /// <see cref="CreateMesh"/> can be used to create a suitable mesh.
        /// </remarks>
        public void SetMesh(Submesh submesh, Aabb aabb, float roadLength, bool disposeWithRoadLayer)
        {
            Submesh      = submesh;
            Aabb         = aabb;
            RoadLength   = roadLength;
            _disposeMesh = disposeWithRoadLayer;
        }
Esempio n. 3
0
        public static Submesh CreateTeapot(GraphicsDevice graphicsDevice, float size, int tessellation)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (tessellation < 1)
            throw new ArgumentOutOfRangeException("tessellation");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
              };

              var teapot = new Teapot(size, tessellation);

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPositionNormal.VertexDeclaration,
            teapot.Vertices.Length,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(teapot.Vertices);

              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            teapot.Indices.Length,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(teapot.Indices);

              submesh.PrimitiveCount = teapot.Indices.Length / 3;

              return submesh;
        }
Esempio n. 4
0
    public void GetMesh(Shape shape, out Submesh submesh, out Matrix44F matrix)
    {
      ThrowIfDisposed();
      if (shape == null)
        throw new ArgumentNullException("shape");

      var index = GetCacheIndex(shape);
      if (index >= 0)
      {
        // Found cache entry!

        var entry = _cache[index];

        Debug.Assert(entry.ShapeWeak.Target == shape, "ShapeMeshCache.GetCacheIndex() returned wrong index.");

        // Get submesh from strong or weak reference.
        submesh = entry.Submesh ?? (Submesh)entry.SubmeshWeak.Target;
        matrix = entry.Matrix;

        if (submesh != null)
        {
          // Recreate submesh if number of triangles in TriangleMeshShape has changed.
          var triangleMeshShape = shape as TriangleMeshShape;
          if (triangleMeshShape != null && triangleMeshShape.Mesh.NumberOfTriangles != submesh.PrimitiveCount)
          {
            DisposeMesh(entry);
            submesh = null;
          }
        }

        // Recreate submesh if necessary.
        if (submesh == null)
          CreateMesh(shape, out submesh, out matrix);

        _cache[index].Submesh = submesh;
        _cache[index].Matrix = matrix;
        _cache[index].Age = 0;
      }
      else
      {
        // No cache entry found.

        // GetCacheIndex returns the bitwise complement of the next index.
        index = ~index;

        // No submesh in cache.
        CreateMesh(shape, out submesh, out matrix);
        var entry = new CacheEntry(shape)
        {
          HashCode = _tempEntry.HashCode,
          Age = 0,
          Submesh = submesh,
          Matrix = matrix,
        };
        _cache.Insert(index, entry);

        // If shape changes, we must invalidate the cache entry:
        shape.Changed += OnCachedShapeChanged;
      }
    }
Esempio n. 5
0
    public SubmeshSample(Microsoft.Xna.Framework.Game game)
      : base(game)
    {
      SampleFramework.IsMouseVisible = false;
      var delegateGraphicsScreen = new DelegateGraphicsScreen(GraphicsService)
      {
        RenderCallback = Render,
      };
      GraphicsService.Screens.Insert(0, delegateGraphicsScreen);

      // Add a custom game object which controls the camera.
      _cameraObject = new CameraObject(Services);
      GameObjectService.Objects.Add(_cameraObject);

      var graphicsDevice = GraphicsService.GraphicsDevice;

      // The MeshHelper class can create submeshes for several basic shapes:
      _sphere = MeshHelper.CreateUVSphere(graphicsDevice, 20);
      _torus = MeshHelper.CreateTorus(graphicsDevice, 0.5f, 0.667f, 16);
      _teapot = MeshHelper.CreateTeapot(graphicsDevice, 1, 8);

      // MeshHelper.CreateBox() returns a new submesh for a box. Instead we can call
      // MeshHelper.GetBox(), which returns a shared submesh. - GetBox() will always 
      // return the same instance.
      _box = MeshHelper.GetBox(GraphicsService);

      // We can also create a submesh that uses line primitives.
      _cone = MeshHelper.GetConeLines(GraphicsService);

      // We use a normal XNA BasicEffect to render the submeshes.
      _effect = new BasicEffect(graphicsDevice) { PreferPerPixelLighting = true };
      _effect.EnableDefaultLighting();
    }
Esempio n. 6
0
        public static TriangleMesh ToTriangleMesh(this Submesh submesh)
        {
            var triangleMesh = new TriangleMesh();

            ToTriangleMesh(submesh, triangleMesh);
            return(triangleMesh);
        }
Esempio n. 7
0
        public static Submesh CreateBoxLines(GraphicsDevice graphicsDevice)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.LineList,
              };

              var vertices = new[]
              {
            new Vector3F(-0.5f, -0.5f, +0.5f),
            new Vector3F(+0.5f, -0.5f, +0.5f),
            new Vector3F(+0.5f, +0.5f, +0.5f),
            new Vector3F(-0.5f, +0.5f, +0.5f),
            new Vector3F(-0.5f, -0.5f, -0.5f),
            new Vector3F(+0.5f, -0.5f, -0.5f),
            new Vector3F(+0.5f, +0.5f, -0.5f),
            new Vector3F(-0.5f, +0.5f, -0.5f)
              };

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPosition.VertexDeclaration,
            vertices.Length,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices);
              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              var indices = new ushort[]
              {
            0, 1,
            1, 2,
            2, 3,
            3, 0,

            4, 5,
            5, 6,
            6, 7,
            7, 4,

            0, 4,
            1, 5,
            2, 6,
            3, 7
              };

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Length,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices);

              submesh.PrimitiveCount = indices.Length / 2;

              return submesh;
        }
        public static Submesh CreateCircleLines(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.LineList,
            };

            // Create vertices for a circle on the floor.
            var vertices = new Vector3F[numberOfSegments];

            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;

                float x = (float)Math.Cos(angle);
                float y = (float)Math.Sin(angle);
                vertices[i] = new Vector3F(x, y, 0);
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPosition.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            // Create indices for base circle.
            var indices = new ushort[2 * numberOfSegments];

            for (int i = 0; i < numberOfSegments; i++)
            {
                indices[2 * i]     = (ushort)i;
                indices[2 * i + 1] = (ushort)(i + 1);
            }

            // Correct last index to be 0 to close circle.
            indices[2 * numberOfSegments - 1] = 0;

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);

            submesh.PrimitiveCount = indices.Length / 2;

            return(submesh);
        }
        public static Submesh CreateIcosphere(GraphicsDevice graphicsDevice, int numberOfSubdivisions)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSubdivisions < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfSubdivisions", "numberOfSegments must be greater than 0");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var mesh             = GeometryHelper.CreateIcosphere(numberOfSubdivisions, false);
            int numberOfVertices = mesh.Vertices.Count;
            var vertexData       = new VertexPositionNormal[numberOfVertices];

            for (int i = 0; i < numberOfVertices; i++)
            {
                Vector3 v = (Vector3)mesh.Vertices[i];
                vertexData[i] = new VertexPositionNormal(v, v);
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertexData.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertexData);

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            int numberOfTriangles = mesh.NumberOfTriangles;
            int numberOfIndices   = mesh.Indices.Count;
            var indexData         = new ushort[numberOfIndices];

            for (int i = 0; i < numberOfTriangles; i++)
            {
                // Flip vertex order. (DigitalRune Geometry uses CCW, XNA uses CW.)
                indexData[3 * i + 0] = (ushort)mesh.Indices[3 * i + 0];
                indexData[3 * i + 2] = (ushort)mesh.Indices[3 * i + 1];
                indexData[3 * i + 1] = (ushort)mesh.Indices[3 * i + 2];
            }

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indexData.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indexData);

            submesh.PrimitiveCount = indexData.Length / 3;

            return(submesh);
        }
Esempio n. 10
0
        public static void Draw(this Submesh submesh)
        {
            if (submesh == null)
            {
                throw new ArgumentNullException("submesh");
            }

            Debug.Assert(!submesh.HasMorphTargets, "Submesh without morph targets expected.");

            var vertexBuffer = submesh.VertexBuffer;

            if (vertexBuffer == null || submesh.VertexCount <= 0)
            {
                return;
            }

            // VertexBuffer.GraphicsDevice is set to null when VertexBuffer is disposed of.
            // Check VertexBuffer.IsDisposed to avoid NullReferenceException.
            if (vertexBuffer.IsDisposed)
            {
                throw new ObjectDisposedException("VertexBuffer", "Cannot draw mesh. The vertex buffer has already been disposed of.");
            }

            var graphicsDevice = vertexBuffer.GraphicsDevice;

            graphicsDevice.SetVertexBuffer(vertexBuffer);

            var indexBuffer = submesh.IndexBuffer;

            if (indexBuffer == null)
            {
                graphicsDevice.DrawPrimitives(
                    submesh.PrimitiveType,
                    submesh.StartVertex,
                    submesh.PrimitiveCount);
            }
            else
            {
                graphicsDevice.Indices = indexBuffer;
#if MONOGAME
                graphicsDevice.DrawIndexedPrimitives(
                    submesh.PrimitiveType,
                    submesh.StartVertex,
                    submesh.StartIndex,
                    submesh.PrimitiveCount);
#else
                graphicsDevice.DrawIndexedPrimitives(
                    submesh.PrimitiveType,
                    submesh.StartVertex,
                    0,
                    submesh.VertexCount,
                    submesh.StartIndex,
                    submesh.PrimitiveCount);
#endif
            }
        }
Esempio n. 11
0
        public static Submesh CreateCircleLines(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (numberOfSegments < 3)
            throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.LineList,
              };

              // Create vertices for a circle on the floor.
              var vertices = new Vector3F[numberOfSegments];
              for (int i = 0; i < numberOfSegments; i++)
              {
            float angle = i * ConstantsF.TwoPi / numberOfSegments;

            float x = (float)Math.Cos(angle);
            float y = (float)Math.Sin(angle);
            vertices[i] = new Vector3F(x, y, 0);
              }

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPosition.VertexDeclaration,
            vertices.Length,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices);
              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              // Create indices for base circle.
              var indices = new ushort[2 * numberOfSegments];
              for (int i = 0; i < numberOfSegments; i++)
              {
            indices[2 * i] = (ushort)i;
            indices[2 * i + 1] = (ushort)(i + 1);
              }

              // Correct last index to be 0 to close circle.
              indices[2 * numberOfSegments - 1] = 0;

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Length,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices);

              submesh.PrimitiveCount = indices.Length / 2;

              return submesh;
        }
Esempio n. 12
0
        public static Submesh CreateIcosphere(GraphicsDevice graphicsDevice, int numberOfSubdivisions)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (numberOfSubdivisions < 1)
            throw new ArgumentOutOfRangeException("numberOfSubdivisions", "numberOfSegments must be greater than 0");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
              };

              var mesh = GeometryHelper.CreateIcosphere(numberOfSubdivisions, false);
              int numberOfVertices = mesh.Vertices.Count;
              var vertexData = new VertexPositionNormal[numberOfVertices];
              for (int i = 0; i < numberOfVertices; i++)
              {
            Vector3 v = (Vector3)mesh.Vertices[i];
            vertexData[i] = new VertexPositionNormal(v, v);
              }

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPositionNormal.VertexDeclaration,
            vertexData.Length,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertexData);

              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              int numberOfTriangles = mesh.NumberOfTriangles;
              int numberOfIndices = mesh.Indices.Count;
              var indexData = new ushort[numberOfIndices];
              for (int i = 0; i < numberOfTriangles; i++)
              {
            // Flip vertex order. (DigitalRune Geometry uses CCW, XNA uses CW.)
            indexData[3* i + 0] = (ushort)mesh.Indices[3 * i + 0];
            indexData[3 * i + 2] = (ushort)mesh.Indices[3 * i + 1];
            indexData[3 * i + 1] = (ushort)mesh.Indices[3 * i + 2];
              }

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indexData.Length,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indexData);

              submesh.PrimitiveCount = indexData.Length / 3;

              return submesh;
        }
Esempio n. 13
0
 public static void GetMesh(IGraphicsService graphicsService, Shape shape, out Submesh submesh, out Matrix44F matrix)
 {
   // Update submesh.
   var graphicsManager = graphicsService as GraphicsManager;
   if (graphicsManager != null)
   {
     graphicsManager.ShapeMeshCache.GetMesh(shape, out submesh, out matrix);
   }
   else
   {
     // This happens if the user has implemented his own graphics manager - 
     // which is very unlikely.
     submesh = MeshHelper.CreateSubmesh(graphicsService.GraphicsDevice, shape.GetMesh(0.05f, 4), MathHelper.ToRadians(70));
     matrix = Matrix44F.Identity;
   }
 }
Esempio n. 14
0
        /// <inheritdoc/>
        protected override void Dispose(bool disposing)
        {
            if (!IsDisposed)
            {
                if (disposing)
                {
                    // Dispose managed resources.
                    if (_disposeMesh)
                    {
                        Submesh.SafeDispose();
                    }
                }

                // Release unmanaged resources.
            }

            base.Dispose(disposing);
        }
Esempio n. 15
0
        public static Submesh CreateTeapot(GraphicsDevice graphicsDevice, float size, int tessellation)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (tessellation < 1)
            {
                throw new ArgumentOutOfRangeException("tessellation");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var teapot = new Teapot(size, tessellation);

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                teapot.Vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(teapot.Vertices);

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                teapot.Indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(teapot.Indices);

            submesh.PrimitiveCount = teapot.Indices.Length / 3;

            return(submesh);
        }
Esempio n. 16
0
        public static Material GetMaterial(this Submesh submesh)
        {
            if (submesh == null)
            {
                throw new ArgumentNullException("submesh");
            }

            var mesh = submesh.Mesh;

            if (mesh == null)
            {
                return(null);
            }

            var index = submesh.MaterialIndex;

            if (0 <= index && index < mesh.Materials.Count)
            {
                return(mesh.Materials[index]);
            }

            return(null);
        }
Esempio n. 17
0
    private void CreateMesh(Shape shape, out Submesh submesh, out Matrix44F matrix)
    {
      // Use a special shared submesh for box shapes.
      var boxShape = shape as BoxShape;
      if (boxShape != null)
      {
        if (_boxSubmesh == null)
          _boxSubmesh = MeshHelper.GetBox(_graphicsService);

        submesh = _boxSubmesh;
        matrix = Matrix44F.CreateScale(boxShape.Extent);
        return;
      }

      var transformedShape = shape as TransformedShape;
      boxShape = (transformedShape != null) ? transformedShape.Child.Shape as BoxShape : null;
      if (boxShape != null)
      {
        if (_boxSubmesh == null)
          _boxSubmesh = MeshHelper.GetBox(_graphicsService);

        submesh = _boxSubmesh;
        matrix = transformedShape.Child.Pose
                 * Matrix44F.CreateScale(transformedShape.Child.Scale * boxShape.Extent);
        return;
      }

      // Create the submesh. Return EmptySubmesh if the MeshHelper returns null.
      var newSubmesh = MeshHelper.CreateSubmesh(
        _graphicsService.GraphicsDevice,
        shape.GetMesh(MeshRelativeError, MeshIterationLimit),
        NormalAngleLimit);

      submesh = newSubmesh ?? EmptySubmesh;
      matrix = Matrix44F.Identity;
    }
Esempio n. 18
0
        public static Submesh CreateCylinder(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var vertices = new List <VertexPositionNormal>();

            // Top cap
            Vector3 normal = Vector3.UnitY;

            vertices.Add(new VertexPositionNormal(new Vector3(0, 1, 0), normal));
            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                float x     = (float)Math.Cos(angle);
                float z     = -(float)Math.Sin(angle);
                vertices.Add(new VertexPositionNormal(new Vector3(x, 1, z), normal));
            }

            // Bottom cap
            normal = -Vector3.UnitY;
            vertices.Add(new VertexPositionNormal(new Vector3(0, -1, 0), normal));
            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                float x     = (float)Math.Cos(angle);
                float z     = -(float)Math.Sin(angle);
                vertices.Add(new VertexPositionNormal(new Vector3(x, -1, z), normal));
            }

            // Side
            int baseIndex = vertices.Count;

            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                float x     = (float)Math.Cos(angle);
                float z     = -(float)Math.Sin(angle);
                vertices.Add(new VertexPositionNormal(new Vector3(x, 1, z), new Vector3(x, 0, z)));
                vertices.Add(new VertexPositionNormal(new Vector3(x, -1, z), new Vector3(x, 0, z)));
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            var indices = new List <ushort>();

            // Top cap
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add(0);
                indices.Add((ushort)(i + 2));
                indices.Add((ushort)(i + 1));
            }

            // Last triangle of top cap.
            indices.Add(0);
            indices.Add(1);
            indices.Add((ushort)numberOfSegments);

            // Bottom cap
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add((ushort)(numberOfSegments + 1));
                indices.Add((ushort)(numberOfSegments + i + 2));
                indices.Add((ushort)(numberOfSegments + i + 3));
            }

            // Last triangle of bottom cap.
            indices.Add((ushort)(numberOfSegments + 1));
            indices.Add((ushort)(numberOfSegments + numberOfSegments + 1));
            indices.Add((ushort)(numberOfSegments + 2));

            // Side
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add((ushort)(baseIndex + 2 * i));
                indices.Add((ushort)(baseIndex + 2 * i + 2));
                indices.Add((ushort)(baseIndex + 2 * i + 1));

                indices.Add((ushort)(baseIndex + 2 * i + 2));
                indices.Add((ushort)(baseIndex + 2 * i + 3));
                indices.Add((ushort)(baseIndex + 2 * i + 1));
            }

            // Indices of last 2 triangle.
            indices.Add((ushort)(baseIndex + numberOfSegments + numberOfSegments - 2));
            indices.Add((ushort)(baseIndex));
            indices.Add((ushort)(baseIndex + numberOfSegments + numberOfSegments - 1));

            indices.Add((ushort)(baseIndex));
            indices.Add((ushort)(baseIndex + 1));
            indices.Add((ushort)(baseIndex + numberOfSegments + numberOfSegments - 1));

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 3;

            return(submesh);
        }
        public static Submesh CreateHemisphere(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            // The number of rings.
            int numberOfRings = numberOfSegments / 4;

            int numberOfVertices = numberOfSegments * numberOfRings + 1;
            var vertices         = new VertexPositionNormal[numberOfVertices];

            // Create rings.
            float angle = ConstantsF.TwoPi / numberOfSegments;

            // Next free index in vertices.
            int i = 0;

            // Top vertex.
            vertices[i++] = new VertexPositionNormal(new Vector3(0, 1, 0), new Vector3(0, 1, 0));

            // Compute vertices for rings from pole to equator and from the x-axis in
            // counterclockwise direction (when viewed from top).
            for (int ring = 0; ring < numberOfRings; ring++)
            {
                float upAngle    = angle * (ring + 1);
                float y          = (float)Math.Cos(upAngle);
                float ringRadius = (float)Math.Sin(upAngle);

                for (int segment = 0; segment < numberOfSegments; segment++)
                {
                    float x = ringRadius * (float)Math.Cos(angle * segment);
                    float z = ringRadius * (float)Math.Sin(angle * segment);
                    vertices[i++] = new VertexPositionNormal(new Vector3(x, y, z), new Vector3(x, y, z));
                }
            }

            Debug.Assert(i == numberOfVertices);

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            // Build array of indices.
            int numberOfTriangles = numberOfSegments // Triangles in top cap.
                                    + numberOfSegments * 2 * (numberOfRings - 1);
            int numberOfIndices = 3 * numberOfTriangles;

            var indices = new ushort[numberOfIndices];

            i = 0;

            // Indices for top cap.
            for (int segment = 0; segment < numberOfSegments; segment++)
            {
                indices[i++] = 0;
                indices[i++] = (ushort)(segment + 1);
                if (segment + 1 < numberOfSegments)
                {
                    indices[i++] = (ushort)(segment + 2);
                }
                else
                {
                    indices[i++] = 1; // Wrap around to first vertex of the first ring.
                }
            }

            // Indices for rings between the caps.
            for (int ring = 1; ring < numberOfRings; ring++)
            {
                for (int segment = 0; segment < numberOfSegments; segment++)
                {
                    // Each segment has 2 triangles.
                    if (segment + 1 < numberOfSegments)
                    {
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
                        indices[i++] = (ushort)(1 + ring * numberOfSegments + segment);
                        indices[i++] = (ushort)(1 + ring * numberOfSegments + segment + 1);

                        indices[i++] = (ushort)(1 + ring * numberOfSegments + segment + 1);
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment + 1);
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
                    }
                    else
                    {
                        // Handle wrap around.
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
                        indices[i++] = (ushort)(1 + ring * numberOfSegments + segment);
                        indices[i++] = (ushort)(1 + ring * numberOfSegments);

                        indices[i++] = (ushort)(1 + ring * numberOfSegments);
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments);
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
                    }
                }
            }

            Debug.Assert(i == numberOfIndices);

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);

            submesh.PrimitiveCount = indices.Length / 3;

            return(submesh);
        }
Esempio n. 20
0
        public static Submesh CreateTorus(GraphicsDevice graphicsDevice, float radius, float thickness, int numberOfSegments)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (numberOfSegments < 3)
            throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
              };

              var vertices = new List<VertexPositionNormal>();
              var indices = new List<ushort>();

              for (int i = 0; i < numberOfSegments; i++)
              {
            float outerAngle = i * MathHelper.TwoPi / numberOfSegments;

            // Create a transformation that will align geometry to slice perpendicularly
            // though the current ring position.
            Matrix transform = Matrix.CreateTranslation(radius, 0, 0) * Matrix.CreateRotationY(outerAngle);

            // Now loop along the other axis, around the side of the tube.
            for (int j = 0; j < numberOfSegments; j++)
            {
              float innerAngle = j * MathHelper.TwoPi / numberOfSegments;

              float dx = (float)Math.Cos(innerAngle);
              float dy = (float)Math.Sin(innerAngle);

              // Create a vertex.
              Vector3 normal = new Vector3(dx, dy, 0);
              Vector3 position = normal * thickness / 2.0f;

              position = Vector3.Transform(position, transform);
              normal = Vector3.TransformNormal(normal, transform);

              vertices.Add(new VertexPositionNormal(position, normal));

              // And create indices for two triangles.
              int nextI = (i + 1) % numberOfSegments;
              int nextJ = (j + 1) % numberOfSegments;

              indices.Add((ushort)(i * numberOfSegments + j));
              indices.Add((ushort)(i * numberOfSegments + nextJ));
              indices.Add((ushort)(nextI * numberOfSegments + j));

              indices.Add((ushort)(i * numberOfSegments + nextJ));
              indices.Add((ushort)(nextI * numberOfSegments + nextJ));
              indices.Add((ushort)(nextI * numberOfSegments + j));
            }
              }

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPositionNormal.VertexDeclaration,
            vertices.Count,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices.ToArray());

              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Count,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices.ToArray());

              submesh.PrimitiveCount = indices.Count / 3;

              return submesh;
        }
        public static Submesh CreateHemisphereLines(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.LineList,
            };

            // Create vertices for a circle on the floor.
            var vertices = new List <Vector3F>();

            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                vertices.Add(new Vector3F((float)Math.Cos(angle), 0, -(float)Math.Sin(angle)));
            }

            // Top vertex of the sphere.
            var topVertexIndex = vertices.Count;

            vertices.Add(new Vector3F(0, 1, 0));

            // 4 quarter arcs. Each arc starts at the base circle and ends at the top vertex. We already
            // have the first and last vertex.
            // Arc from +x to top.
            int firstArcIndex = vertices.Count;

            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                float angle = (i + 1) * ConstantsF.TwoPi / numberOfSegments;
                vertices.Add(new Vector3F((float)Math.Cos(angle), (float)Math.Sin(angle), 0));
            }

            // Arc from -z to top. (Copy from first arc.)
            int secondArcIndex = vertices.Count;

            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                Vector3F p = vertices[firstArcIndex + i];
                vertices.Add(new Vector3F(0, p.Y, -p.X));
            }

            // Arc from -x to top. (Copy from first arc.)
            int thirdArcIndex = vertices.Count;

            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                Vector3F p = vertices[firstArcIndex + i];
                vertices.Add(new Vector3F(-p.X, p.Y, 0));
            }

            // Arc from +z to top. (Copy from first arc.)
            int fourthArcIndex = vertices.Count;

            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                Vector3F p = vertices[firstArcIndex + i];
                vertices.Add(new Vector3F(0, p.Y, p.X));
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPosition.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            var indices = new List <ushort>();

            // Create indices for base circle.
            for (int i = 0; i < numberOfSegments; i++)
            {
                indices.Add((ushort)i);       // Line start (= same as previous line end)
                indices.Add((ushort)(i + 1)); // Line end
            }

            // Correct last index to be 0 to close circle.
            indices[(ushort)(2 * numberOfSegments - 1)] = 0;

            // Indices for first arc.
            indices.Add(0);                       // Line start
            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                indices.Add((ushort)(firstArcIndex + i)); // Line end
                indices.Add((ushort)(firstArcIndex + i)); // Line start (= same as previous line end)
            }
            indices.Add((ushort)topVertexIndex);          // Line end

            // Next arcs
            indices.Add((ushort)(numberOfSegments / 4));
            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                indices.Add((ushort)(secondArcIndex + i));
                indices.Add((ushort)(secondArcIndex + i));
            }
            indices.Add((ushort)topVertexIndex);

            indices.Add((ushort)(2 * numberOfSegments / 4));
            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                indices.Add((ushort)(thirdArcIndex + i));
                indices.Add((ushort)(thirdArcIndex + i));
            }
            indices.Add((ushort)topVertexIndex);

            indices.Add((ushort)(3 * numberOfSegments / 4));
            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                indices.Add((ushort)(fourthArcIndex + i));
                indices.Add((ushort)(fourthArcIndex + i));
            }
            indices.Add((ushort)topVertexIndex);

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 2;

            return(submesh);
        }
Esempio n. 22
0
 //--------------------------------------------------------------
 /// <summary>
 /// Sets the road mesh and related properties.
 /// </summary>
 /// <param name="submesh">The submesh that represents the road.</param>
 /// <param name="aabb">The axis-aligned bounding box of the mesh.</param>
 /// <param name="roadLength">The length of the road in world space units.</param>
 /// <param name="disposeWithRoadLayer">
 /// <see langword="true" /> to automatically dispose of the mesh when the
 /// <see cref="TerrainRoadLayer"/> is disposed of; otherwise, <see langword="false"/>.
 /// </param>
 /// <remarks>
 /// <see cref="CreateMesh"/> can be used to create a suitable mesh.
 /// </remarks>
 public void SetMesh(Submesh submesh, Aabb aabb, float roadLength, bool disposeWithRoadLayer)
 {
     Submesh = submesh;
       Aabb = aabb;
       RoadLength = roadLength;
       _disposeMesh = disposeWithRoadLayer;
 }
        public static void CreateMesh(GraphicsDevice graphicsDevice, Path3F path, float defaultWidth,
                                      int maxNumberOfIterations, float tolerance,
                                      out Submesh submesh, out Aabb aabb, out float roadLength)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }

            // Compute list of line segments. (2 points per line segment!)
            var flattenedPoints = new List <Vector3F>();

            path.Flatten(flattenedPoints, maxNumberOfIterations, tolerance);

            // Abort if path is empty.
            int numberOfLineSegments = flattenedPoints.Count / 2;

            if (numberOfLineSegments <= 0)
            {
                submesh    = null;
                aabb       = new Aabb();
                roadLength = 0;
                return;
            }

            // Compute accumulated lengths. (One entry for each entry in flattenedPoints.)
            float[] accumulatedLengths = new float[flattenedPoints.Count];
            accumulatedLengths[0] = 0;
            for (int i = 1; i < flattenedPoints.Count; i += 2)
            {
                Vector3F previous = flattenedPoints[i - 1];
                Vector3F current  = flattenedPoints[i];
                float    length   = (current - previous).Length;

                accumulatedLengths[i] = accumulatedLengths[i - 1] + length;
                if (i + 1 < flattenedPoints.Count)
                {
                    accumulatedLengths[i + 1] = accumulatedLengths[i];
                }
            }

            // Total road length.
            roadLength = accumulatedLengths[accumulatedLengths.Length - 1];

            // Create a mapping between accumulatedLength and the path key widths.
            // (accumulatedLength --> TerrainRoadPathKey.Width)
            var widthKeys = new List <Pair <float, float> >();
            {
                int index = 0;
                foreach (var key in path)
                {
                    Vector3F position = key.Point;
                    var      roadKey  = key as TerrainRoadPathKey;
                    float    width    = (roadKey != null) ? roadKey.Width : defaultWidth;

                    for (; index < flattenedPoints.Count; index++)
                    {
                        if (Vector3F.AreNumericallyEqual(position, flattenedPoints[index]))
                        {
                            widthKeys.Add(new Pair <float, float>(accumulatedLengths[index], width));
                            break;
                        }

                        bool isLastLineSegment = (index + 2 == flattenedPoints.Count);
                        if (!isLastLineSegment)
                        {
                            index++;
                        }
                    }

                    index++;
                }
            }

            // Create a list of interpolated road widths. (One entry for each entry in flattenedPoints.)
            var widths           = new float[flattenedPoints.Count];
            int previousKeyIndex = 0;
            var previousKey      = widthKeys[0];
            var nextKey          = widthKeys[1];

            widths[0] = widthKeys[0].Second;
            for (int i = 1; i < flattenedPoints.Count; i += 2)
            {
                if (accumulatedLengths[i] > nextKey.First)
                {
                    previousKey = nextKey;
                    previousKeyIndex++;
                    nextKey = widthKeys[previousKeyIndex + 1];
                }

                float p = (accumulatedLengths[i] - previousKey.First) / (nextKey.First - previousKey.First);
                widths[i] = InterpolationHelper.Lerp(previousKey.Second, nextKey.Second, p);

                if (i + 1 < flattenedPoints.Count)
                {
                    widths[i + 1] = widths[i];
                }
            }

            // Compute vertices and indices.
            var      vertices        = new List <TerrainLayerVertex>(numberOfLineSegments * 2 + 2);
            var      indices         = new List <int>(numberOfLineSegments * 6); // Two triangles per line segment.
            Vector3F lastOrthonormal = Vector3F.UnitX;

            aabb = new Aabb(flattenedPoints[0], flattenedPoints[0]);
            bool isClosed = Vector3F.AreNumericallyEqual(flattenedPoints[0], flattenedPoints[flattenedPoints.Count - 1]);

            for (int i = 0; i < flattenedPoints.Count; i++)
            {
                Vector3F start = flattenedPoints[i];

                Vector3F previous;
                bool     isFirstPoint = (i == 0);
                if (!isFirstPoint)
                {
                    previous = flattenedPoints[i - 1];
                }
                else if (isClosed && path.SmoothEnds)
                {
                    previous = flattenedPoints[flattenedPoints.Count - 2];
                }
                else
                {
                    previous = start;
                }

                Vector3F next;
                bool     isLastPoint = (i + 1 == flattenedPoints.Count);
                if (!isLastPoint)
                {
                    next = flattenedPoints[i + 1];
                }
                else if (isClosed && path.SmoothEnds)
                {
                    next = flattenedPoints[1];
                }
                else
                {
                    next = start;
                }

                Vector3F tangent = next - previous;

                Vector3F orthonormal = new Vector3F(tangent.Z, 0, -tangent.X);
                if (!orthonormal.TryNormalize())
                {
                    orthonormal = lastOrthonormal;
                }

                // Add indices to add two triangles between the current and the next vertices.
                if (!isLastPoint)
                {
                    int baseIndex = vertices.Count;

                    //  2      3
                    //   x----x
                    //   |\   |   ^
                    //   | \  |   | road
                    //   |  \ |   | direction
                    //   |   \|   |
                    //   x----x
                    //  0      1

                    indices.Add(baseIndex);
                    indices.Add(baseIndex + 1);
                    indices.Add(baseIndex + 2);

                    indices.Add(baseIndex + 1);
                    indices.Add(baseIndex + 3);
                    indices.Add(baseIndex + 2);
                }

                // Add two vertices.
                Vector3F leftVertex  = start - orthonormal * (widths[i] / 2);
                Vector3F rightVertex = start + orthonormal * (widths[i] / 2);
                vertices.Add(new TerrainLayerVertex(new Vector2(leftVertex.X, leftVertex.Z), new Vector2(0, accumulatedLengths[i])));
                vertices.Add(new TerrainLayerVertex(new Vector2(rightVertex.X, rightVertex.Z), new Vector2(1, accumulatedLengths[i])));

                // Grow AABB
                aabb.Grow(leftVertex);
                aabb.Grow(rightVertex);

                lastOrthonormal = orthonormal;

                // The flattened points list contains 2 points per line segment, which means that there
                // are duplicate intermediate points, which we skip.
                bool isLastLineSegment = (i + 2 == flattenedPoints.Count);
                if (!isLastLineSegment)
                {
                    i++;
                }
            }

            Debug.Assert(vertices.Count == (numberOfLineSegments * 2 + 2));
            Debug.Assert(indices.Count == (numberOfLineSegments * 6));

            // The road is projected onto the terrain, therefore the computed y limits are not correct.
            // (unless the terrain was clamped to the road).
            aabb.Minimum.Y = 0;
            aabb.Maximum.Y = 0;

            // Convert to submesh.
            submesh = new Submesh
            {
                PrimitiveCount = indices.Count / 3,
                PrimitiveType  = PrimitiveType.TriangleList,
                VertexCount    = vertices.Count,
                VertexBuffer   = new VertexBuffer(graphicsDevice, TerrainLayerVertex.VertexDeclaration, vertices.Count, BufferUsage.WriteOnly),
                IndexBuffer    = new IndexBuffer(graphicsDevice, IndexElementSize.ThirtyTwoBits, indices.Count, BufferUsage.WriteOnly)
            };
            submesh.VertexBuffer.SetData(vertices.ToArray());
            submesh.IndexBuffer.SetData(indices.ToArray());
        }
Esempio n. 24
0
        public static Submesh CreateUVSphere(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (numberOfSegments < 3)
            throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
              };

              // The number of slices (horizontal cuts, not including the poles).
              int numberOfSlices = numberOfSegments / 2 - 1;

              // The number of rings (horizontal bands of triangles).
              int numberOfRings = numberOfSegments / 2;

              int numberOfVertices = numberOfSegments * numberOfSlices + 2;
              var vertices = new VertexPositionNormal[numberOfVertices];

              // Create rings.
              float angle = ConstantsF.TwoPi / numberOfSegments;

              // Next free index in vertices.
              int i = 0;

              // Top vertex.
              vertices[i++] = new VertexPositionNormal(new Vector3(0, 1, 0), new Vector3(0, 1, 0));

              // Compute vertices for rings from top to bottom and from the x-axis in
              // clockwise direction (when viewed from top).
              for (int slice = 0; slice < numberOfSlices; slice++)
              {
            float upAngle = angle * (slice + 1);
            float y = (float)Math.Cos(upAngle);
            float ringRadius = (float)Math.Sin(upAngle);

            for (int segment = 0; segment < numberOfSegments; segment++)
            {
              float x = ringRadius * (float)Math.Cos(angle * segment);
              float z = ringRadius * (float)Math.Sin(angle * segment);
              vertices[i++] = new VertexPositionNormal(new Vector3(x, y, z), new Vector3(x, y, z));
            }
              }

              // Bottom vertex.
              vertices[i++] = new VertexPositionNormal(new Vector3(0, -1, 0), new Vector3(0, -1, 0));

              Debug.Assert(i == numberOfVertices);

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPositionNormal.VertexDeclaration,
            vertices.Length,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices);

              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              // Build array of indices.
              int numberOfTriangles = numberOfSegments * 2 // Triangles in top and bottom cap.
                              + numberOfSegments * 2 * (numberOfRings - 2);
              int numberOfIndices = 3 * numberOfTriangles;

              var indices = new ushort[numberOfIndices];
              i = 0;

              // Indices for top cap.
              for (int segment = 0; segment < numberOfSegments; segment++)
              {
            indices[i++] = 0;
            indices[i++] = (ushort)(segment + 1);
            if (segment + 1 < numberOfSegments)
              indices[i++] = (ushort)(segment + 2);
            else
              indices[i++] = 1; // Wrap around to first vertex of the first ring.
              }

              // Indices for rings between the caps.
              for (int ring = 1; ring < numberOfRings - 1; ring++)
              {
            for (int segment = 0; segment < numberOfSegments; segment++)
            {
              // Each segment has 2 triangles.
              if (segment + 1 < numberOfSegments)
              {
            indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
            indices[i++] = (ushort)(1 + ring * numberOfSegments + segment);
            indices[i++] = (ushort)(1 + ring * numberOfSegments + segment + 1);

            indices[i++] = (ushort)(1 + ring * numberOfSegments + segment + 1);
            indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment + 1);
            indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
              }
              else
              {
            // Handle wrap around.
            indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
            indices[i++] = (ushort)(1 + ring * numberOfSegments + segment);
            indices[i++] = (ushort)(1 + ring * numberOfSegments);

            indices[i++] = (ushort)(1 + ring * numberOfSegments);
            indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments);
            indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
              }
            }
              }

              // Index of first vertex on last slice.
              int baseIndex = numberOfVertices - numberOfSegments - 1;

              // Indices for bottom cap.
              for (int segment = 0; segment < numberOfSegments; segment++)
              {
            indices[i++] = (ushort)(numberOfVertices - 1);
            if (segment + 1 < numberOfSegments)
              indices[i++] = (ushort)(baseIndex + segment + 1);
            else
              indices[i++] = (ushort)baseIndex;   // Wrap around to first vertex.

            indices[i++] = (ushort)(baseIndex + segment);
              }

              Debug.Assert(i == numberOfIndices);

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Length,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices);

              submesh.PrimitiveCount = indices.Length / 3;

              return submesh;
        }
Esempio n. 25
0
        public static Submesh CreateCone(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var vertices = new List <VertexPositionNormal>();

            // Base
            Vector3 normal = -Vector3.UnitY;

            vertices.Add(new VertexPositionNormal(new Vector3(0, 0, 0), normal));
            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                float x     = (float)Math.Cos(angle);
                float z     = -(float)Math.Sin(angle);
                vertices.Add(new VertexPositionNormal(new Vector3(x, 0, z), normal));
            }

            // Side
            vertices.Add(new VertexPositionNormal(new Vector3(0, 1, 0), new Vector3(0, 1, 0)));
            for (int i = 0; i < numberOfSegments; i++)
            {
                float       angle = i * ConstantsF.TwoPi / numberOfSegments;
                const float cos45 = 0.707106781f; // cos(45°)
                float       x     = (float)Math.Cos(angle);
                float       z     = -(float)Math.Sin(angle);
                vertices.Add(new VertexPositionNormal(new Vector3(x, 0, z), new Vector3(x * cos45, cos45, z * cos45)));
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            var indices = new List <ushort>();

            // Base
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add(0);
                indices.Add((ushort)(i + 1));
                indices.Add((ushort)(i + 2));
            }

            // Last base triangle.
            indices.Add(0);
            indices.Add((ushort)numberOfSegments);
            indices.Add(1);

            // Side triangle.
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add((ushort)(numberOfSegments + 1));
                indices.Add((ushort)(numberOfSegments + i + 3));
                indices.Add((ushort)(numberOfSegments + i + 2));
            }

            // Last side triangle.
            indices.Add((ushort)(numberOfSegments + 1));
            indices.Add((ushort)(numberOfSegments + 2));
            indices.Add((ushort)(numberOfSegments + numberOfSegments + 1));

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 3;

            return(submesh);
        }
Esempio n. 26
0
        public static Submesh CreateTorus(GraphicsDevice graphicsDevice, float radius, float thickness, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var vertices = new List <VertexPositionNormal>();
            var indices  = new List <ushort>();

            for (int i = 0; i < numberOfSegments; i++)
            {
                float outerAngle = i * MathHelper.TwoPi / numberOfSegments;

                // Create a transformation that will align geometry to slice perpendicularly
                // though the current ring position.
                Matrix transform = Matrix.CreateTranslation(radius, 0, 0) * Matrix.CreateRotationY(outerAngle);

                // Now loop along the other axis, around the side of the tube.
                for (int j = 0; j < numberOfSegments; j++)
                {
                    float innerAngle = j * MathHelper.TwoPi / numberOfSegments;

                    float dx = (float)Math.Cos(innerAngle);
                    float dy = (float)Math.Sin(innerAngle);

                    // Create a vertex.
                    Vector3 normal   = new Vector3(dx, dy, 0);
                    Vector3 position = normal * thickness / 2.0f;

                    position = Vector3.Transform(position, transform);
                    normal   = Vector3.TransformNormal(normal, transform);

                    vertices.Add(new VertexPositionNormal(position, normal));

                    // And create indices for two triangles.
                    int nextI = (i + 1) % numberOfSegments;
                    int nextJ = (j + 1) % numberOfSegments;

                    indices.Add((ushort)(i * numberOfSegments + j));
                    indices.Add((ushort)(i * numberOfSegments + nextJ));
                    indices.Add((ushort)(nextI * numberOfSegments + j));

                    indices.Add((ushort)(i * numberOfSegments + nextJ));
                    indices.Add((ushort)(nextI * numberOfSegments + nextJ));
                    indices.Add((ushort)(nextI * numberOfSegments + j));
                }
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 3;

            return(submesh);
        }
Esempio n. 27
0
    //--------------------------------------------------------------
    #region Properties & Events
    //--------------------------------------------------------------
    #endregion


    //--------------------------------------------------------------
    #region Creation & Cleanup
    //--------------------------------------------------------------

    /// <summary>
    /// Initializes a new instance of the <see cref="FogSphereRenderer"/> class.
    /// </summary>
    /// <param name="graphicsService">The graphics service.</param>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="graphicsService"/> is <see langword="null"/>.
    /// </exception>
    public FogSphereRenderer(IGraphicsService graphicsService)
    {
      if (graphicsService == null)
        throw new ArgumentNullException("graphicsService");

      // Load effect.
      _effect = graphicsService.Content.Load<Effect>("FogSphere");
      _parameterViewportSize = _effect.Parameters["ViewportSize"];
      _parameterWorld = _effect.Parameters["World"];
      _parameterWorldInverse = _effect.Parameters["WorldInverse"];
      _parameterView = _effect.Parameters["View"];
      _parameterProjection = _effect.Parameters["Projection"];
      _parameterCameraPosition = _effect.Parameters["CameraPosition"];
      _parameterCameraFar = _effect.Parameters["CameraFar"];
      _parameterGBuffer0 = _effect.Parameters["GBuffer0"];
      _parameterColor = _effect.Parameters["Color"];
      _parameterBlendMode = _effect.Parameters["BlendMode"];
      _parameterDensity = _effect.Parameters["Density"];
      _parameterFalloff = _effect.Parameters["Falloff"];
      _parameterIntersectionSoftness = _effect.Parameters["IntersectionSoftness"];

      // Get a sphere mesh.
      _submesh = MeshHelper.CreateIcosphere(graphicsService.GraphicsDevice, 2);
    }
Esempio n. 28
0
        public static Submesh CreateBox(GraphicsDevice graphicsDevice)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var vertices = new List <VertexPositionNormal>();
            var indices  = new List <ushort>();

            var p0 = new Vector3(-0.5f, -0.5f, -0.5f);
            var p1 = new Vector3(-0.5f, -0.5f, +0.5f);
            var p2 = new Vector3(-0.5f, +0.5f, -0.5f);
            var p3 = new Vector3(-0.5f, +0.5f, +0.5f);
            var p4 = new Vector3(+0.5f, -0.5f, -0.5f);
            var p5 = new Vector3(+0.5f, -0.5f, +0.5f);
            var p6 = new Vector3(+0.5f, +0.5f, -0.5f);
            var p7 = new Vector3(+0.5f, +0.5f, +0.5f);

            var normal = Vector3.UnitX;

            vertices.Add(new VertexPositionNormal(p4, normal));
            vertices.Add(new VertexPositionNormal(p5, normal));
            vertices.Add(new VertexPositionNormal(p6, normal));
            vertices.Add(new VertexPositionNormal(p7, normal));

            indices.Add(0);
            indices.Add(1);
            indices.Add(2);

            indices.Add(1);
            indices.Add(3);
            indices.Add(2);

            normal = Vector3.UnitY;
            vertices.Add(new VertexPositionNormal(p6, normal));
            vertices.Add(new VertexPositionNormal(p7, normal));
            vertices.Add(new VertexPositionNormal(p2, normal));
            vertices.Add(new VertexPositionNormal(p3, normal));

            indices.Add(4);
            indices.Add(5);
            indices.Add(6);

            indices.Add(5);
            indices.Add(7);
            indices.Add(6);

            normal = Vector3.UnitZ;
            vertices.Add(new VertexPositionNormal(p5, normal));
            vertices.Add(new VertexPositionNormal(p1, normal));
            vertices.Add(new VertexPositionNormal(p7, normal));
            vertices.Add(new VertexPositionNormal(p3, normal));

            indices.Add(8);
            indices.Add(9);
            indices.Add(10);

            indices.Add(9);
            indices.Add(11);
            indices.Add(10);

            normal = -Vector3.UnitX;
            vertices.Add(new VertexPositionNormal(p1, normal));
            vertices.Add(new VertexPositionNormal(p0, normal));
            vertices.Add(new VertexPositionNormal(p3, normal));
            vertices.Add(new VertexPositionNormal(p2, normal));

            indices.Add(12);
            indices.Add(13);
            indices.Add(14);

            indices.Add(13);
            indices.Add(15);
            indices.Add(14);

            normal = -Vector3.UnitY;
            vertices.Add(new VertexPositionNormal(p4, normal));
            vertices.Add(new VertexPositionNormal(p0, normal));
            vertices.Add(new VertexPositionNormal(p5, normal));
            vertices.Add(new VertexPositionNormal(p1, normal));

            indices.Add(16);
            indices.Add(17);
            indices.Add(18);

            indices.Add(17);
            indices.Add(19);
            indices.Add(18);

            normal = -Vector3.UnitZ;
            vertices.Add(new VertexPositionNormal(p0, normal));
            vertices.Add(new VertexPositionNormal(p4, normal));
            vertices.Add(new VertexPositionNormal(p2, normal));
            vertices.Add(new VertexPositionNormal(p6, normal));

            indices.Add(20);
            indices.Add(21);
            indices.Add(22);

            indices.Add(21);
            indices.Add(23);
            indices.Add(22);

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 3;

            return(submesh);
        }
Esempio n. 29
0
        public static Submesh CreateCone(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (numberOfSegments < 3)
            throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
              };

              var vertices = new List<VertexPositionNormal>();

              // Base
              Vector3 normal = -Vector3.UnitY;
              vertices.Add(new VertexPositionNormal(new Vector3(0, 0, 0), normal));
              for (int i = 0; i < numberOfSegments; i++)
              {
            float angle = i * ConstantsF.TwoPi / numberOfSegments;
            float x = (float)Math.Cos(angle);
            float z = -(float)Math.Sin(angle);
            vertices.Add(new VertexPositionNormal(new Vector3(x, 0, z), normal));
              }

              // Side
              vertices.Add(new VertexPositionNormal(new Vector3(0, 1, 0), new Vector3(0, 1, 0)));
              for (int i = 0; i < numberOfSegments; i++)
              {
            float angle = i * ConstantsF.TwoPi / numberOfSegments;
            const float cos45 = 0.707106781f; // cos(45°)
            float x = (float)Math.Cos(angle);
            float z = -(float)Math.Sin(angle);
            vertices.Add(new VertexPositionNormal(new Vector3(x, 0, z), new Vector3(x * cos45, cos45, z * cos45)));
              }

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPositionNormal.VertexDeclaration,
            vertices.Count,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices.ToArray());

              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              var indices = new List<ushort>();

              // Base
              for (int i = 0; i < numberOfSegments - 1; i++)
              {
            indices.Add(0);
            indices.Add((ushort)(i + 1));
            indices.Add((ushort)(i + 2));
              }

              // Last base triangle.
              indices.Add(0);
              indices.Add((ushort)numberOfSegments);
              indices.Add(1);

              // Side triangle.
              for (int i = 0; i < numberOfSegments - 1; i++)
              {
            indices.Add((ushort)(numberOfSegments + 1));
            indices.Add((ushort)(numberOfSegments + i + 3));
            indices.Add((ushort)(numberOfSegments + i + 2));
              }

              // Last side triangle.
              indices.Add((ushort)(numberOfSegments + 1));
              indices.Add((ushort)(numberOfSegments + 2));
              indices.Add((ushort)(numberOfSegments + numberOfSegments + 1));

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Count,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices.ToArray());

              submesh.PrimitiveCount = indices.Count / 3;

              return submesh;
        }
Esempio n. 30
0
        internal static Submesh CreateGrid(GraphicsDevice graphicsDevice, float widthX, float widthY, int numberOfCellsX, int numberOfCellsY)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (widthX <= 0)
            throw new ArgumentOutOfRangeException("widthX", "The number of cells must be greater than 0.");
              if (widthY <= 0)
            throw new ArgumentOutOfRangeException("widthY", "The number of cells must be greater than 0.");
              if (numberOfCellsX < 1)
            throw new ArgumentOutOfRangeException("numberOfCellsX", "The number of cells must be greater than 0.");
              if (numberOfCellsY < 1)
            throw new ArgumentOutOfRangeException("numberOfCellsY", "The number of cells must be greater than 0.");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
              };

              int numberOfVertices = (numberOfCellsX + 1) * (numberOfCellsY + 1);
              var vertices = new VertexPositionNormalTexture[numberOfVertices];

              int index = 0;
              for (int y = 0; y <= numberOfCellsY; y++)
              {
            for (int x = 0; x <= numberOfCellsX; x++)
            {
              vertices[index++] = new VertexPositionNormalTexture(
            new Vector3(x * widthX / numberOfCellsX, y * widthY / numberOfCellsY, 0),
            new Vector3(0, 0, 1),
            new Vector2(x / (float)numberOfCellsX, y / (float)numberOfCellsY));
            }
              }

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPositionNormalTexture.VertexDeclaration,
            vertices.Length,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices);
              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              // Build array of indices.
              int numberOfTriangles = numberOfCellsX * numberOfCellsY * 2;
              int numberOfIndices = 3 * numberOfTriangles;

              if (numberOfIndices < ushort.MaxValue)
              {
            var indices = new ushort[numberOfIndices];

            index = 0;
            for (int y = 0; y < numberOfCellsY; y++)
            {
              for (int x = 0; x < numberOfCellsX; x++)
              {
            int baseIndex = y * (numberOfCellsX + 1) + x;

            indices[index++] = (ushort)baseIndex;
            indices[index++] = (ushort)(baseIndex + numberOfCellsX + 1);
            indices[index++] = (ushort)(baseIndex + 1);

            indices[index++] = (ushort)(baseIndex + 1);
            indices[index++] = (ushort)(baseIndex + numberOfCellsX + 1);
            indices[index++] = (ushort)(baseIndex + numberOfCellsX + 2);
              }
            }

            submesh.IndexBuffer = new IndexBuffer(
              graphicsDevice,
              IndexElementSize.SixteenBits,
              indices.Length,
              BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);
            submesh.PrimitiveCount = indices.Length / 3;
              }
              else
              {
            var indices = new int[numberOfIndices];

            index = 0;
            for (int y = 0; y < numberOfCellsY; y++)
            {
              for (int x = 0; x < numberOfCellsX; x++)
              {
            int baseIndex = y * (numberOfCellsX + 1) + x;

            indices[index++] = baseIndex;
            indices[index++] = (baseIndex + numberOfCellsX + 1);
            indices[index++] = (baseIndex + 1);

            indices[index++] = (baseIndex + 1);
            indices[index++] = (baseIndex + numberOfCellsX + 1);
            indices[index++] = (baseIndex + numberOfCellsX + 2);
              }
            }

            submesh.IndexBuffer = new IndexBuffer(
              graphicsDevice,
              IndexElementSize.ThirtyTwoBits,
              indices.Length,
              BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);
            submesh.PrimitiveCount = indices.Length / 3;
              }

              return submesh;
        }
        public static Submesh CreateHemisphereLines(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (numberOfSegments < 3)
            throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.LineList,
              };

              // Create vertices for a circle on the floor.
              var vertices = new List<Vector3F>();
              for (int i = 0; i < numberOfSegments; i++)
              {
            float angle = i * ConstantsF.TwoPi / numberOfSegments;
            vertices.Add(new Vector3F((float)Math.Cos(angle), 0, -(float)Math.Sin(angle)));
              }

              // Top vertex of the sphere.
              var topVertexIndex = vertices.Count;
              vertices.Add(new Vector3F(0, 1, 0));

              // 4 quarter arcs. Each arc starts at the base circle and ends at the top vertex. We already
              // have the first and last vertex.
              // Arc from +x to top.
              int firstArcIndex = vertices.Count;
              for (int i = 0; i < numberOfSegments / 4 - 1; i++)
              {
            float angle = (i + 1) * ConstantsF.TwoPi / numberOfSegments;
            vertices.Add(new Vector3F((float)Math.Cos(angle), (float)Math.Sin(angle), 0));
              }

              // Arc from -z to top. (Copy from first arc.)
              int secondArcIndex = vertices.Count;
              for (int i = 0; i < numberOfSegments / 4 - 1; i++)
              {
            Vector3F p = vertices[firstArcIndex + i];
            vertices.Add(new Vector3F(0, p.Y, -p.X));
              }

              // Arc from -x to top. (Copy from first arc.)
              int thirdArcIndex = vertices.Count;
              for (int i = 0; i < numberOfSegments / 4 - 1; i++)
              {
            Vector3F p = vertices[firstArcIndex + i];
            vertices.Add(new Vector3F(-p.X, p.Y, 0));
              }

              // Arc from +z to top. (Copy from first arc.)
              int fourthArcIndex = vertices.Count;
              for (int i = 0; i < numberOfSegments / 4 - 1; i++)
              {
            Vector3F p = vertices[firstArcIndex + i];
            vertices.Add(new Vector3F(0, p.Y, p.X));
              }

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPosition.VertexDeclaration,
            vertices.Count,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices.ToArray());

              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              var indices = new List<ushort>();

              // Create indices for base circle.
              for (int i = 0; i < numberOfSegments; i++)
              {
            indices.Add((ushort)i);          // Line start (= same as previous line end)
            indices.Add((ushort)(i + 1));    // Line end
              }

              // Correct last index to be 0 to close circle.
              indices[(ushort)(2 * numberOfSegments - 1)] = 0;

              // Indices for first arc.
              indices.Add(0);                             // Line start
              for (int i = 0; i < numberOfSegments / 4 - 1; i++)
              {
            indices.Add((ushort)(firstArcIndex + i));  // Line end
            indices.Add((ushort)(firstArcIndex + i));  // Line start (= same as previous line end)
              }
              indices.Add((ushort)topVertexIndex);         // Line end

              // Next arcs
              indices.Add((ushort)(numberOfSegments / 4));
              for (int i = 0; i < numberOfSegments / 4 - 1; i++)
              {
            indices.Add((ushort)(secondArcIndex + i));
            indices.Add((ushort)(secondArcIndex + i));
              }
              indices.Add((ushort)topVertexIndex);

              indices.Add((ushort)(2 * numberOfSegments / 4));
              for (int i = 0; i < numberOfSegments / 4 - 1; i++)
              {
            indices.Add((ushort)(thirdArcIndex + i));
            indices.Add((ushort)(thirdArcIndex + i));
              }
              indices.Add((ushort)topVertexIndex);

              indices.Add((ushort)(3 * numberOfSegments / 4));
              for (int i = 0; i < numberOfSegments / 4 - 1; i++)
              {
            indices.Add((ushort)(fourthArcIndex + i));
            indices.Add((ushort)(fourthArcIndex + i));
              }
              indices.Add((ushort)topVertexIndex);

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Count,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices.ToArray());

              submesh.PrimitiveCount = indices.Count / 2;

              return submesh;
        }
Esempio n. 32
0
        internal static Submesh CreateSpherePatch(
            GraphicsDevice graphicsDevice,
            float originRadius, float sphereRadius,
            int numberOfDivisions)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (numberOfDivisions < 1 ||numberOfDivisions > 255)
            throw new ArgumentOutOfRangeException("numberOfDivisions", "numberOfDivisions must be in the range [0, 255].");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
              };

              int numberOfVertices = (numberOfDivisions + 1) * (numberOfDivisions + 1);
              var vertices = new VertexPositionNormalTexture[numberOfVertices];

              float groundPlaneSize = 2 * (float)Math.Sqrt(sphereRadius * sphereRadius - originRadius * originRadius);
              int index = 0;
              for (int i = 0; i <= numberOfDivisions; i++)
              {
            for (int j = 0; j <= numberOfDivisions; j++)
            {
              float x = -groundPlaneSize / 2 + groundPlaneSize / numberOfDivisions * j;
              float z = -groundPlaneSize / 2 + groundPlaneSize / numberOfDivisions * i;

              //float groundDist2 = x * x + z * z;

              var direction = new Vector3(x, originRadius, z);
              direction.Normalize();

              var p = direction * sphereRadius - new Vector3(0, originRadius, 0);

              var t = new Vector2(
            j / (float)numberOfDivisions,
            i / (float)numberOfDivisions);

              vertices[index++] = new VertexPositionNormalTexture(p, new Vector3(0, -1, 0),  t);
            }
              }

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPositionNormalTexture.VertexDeclaration,
            vertices.Length,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices);
              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              // Build array of indices.
              int numberOfTriangles = numberOfDivisions * numberOfDivisions * 2;
              int numberOfIndices = 3 * numberOfTriangles;

              var indices = new ushort[numberOfIndices];

              index = 0;
              for (int i = 0; i < numberOfDivisions; i++)
              {
            for (int j = 0; j < numberOfDivisions; j++)
            {
              int baseIndex = i * (numberOfDivisions + 1) + j;

              indices[index++] = (ushort)baseIndex;
              indices[index++] = (ushort)(baseIndex + numberOfDivisions + 1);
              indices[index++] = (ushort)(baseIndex + 1);

              indices[index++] = (ushort)(baseIndex + 1);
              indices[index++] = (ushort)(baseIndex + numberOfDivisions + 1);
              indices[index++] = (ushort)(baseIndex + numberOfDivisions + 2);
            }
              }

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Length,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices);

              submesh.PrimitiveCount = indices.Length / 3;

              return submesh;
        }
Esempio n. 33
0
        public static Submesh CreateBox(GraphicsDevice graphicsDevice)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
              };

              var vertices = new List<VertexPositionNormal>();
              var indices = new List<ushort>();

              var p0 = new Vector3(-0.5f, -0.5f, -0.5f);
              var p1 = new Vector3(-0.5f, -0.5f, +0.5f);
              var p2 = new Vector3(-0.5f, +0.5f, -0.5f);
              var p3 = new Vector3(-0.5f, +0.5f, +0.5f);
              var p4 = new Vector3(+0.5f, -0.5f, -0.5f);
              var p5 = new Vector3(+0.5f, -0.5f, +0.5f);
              var p6 = new Vector3(+0.5f, +0.5f, -0.5f);
              var p7 = new Vector3(+0.5f, +0.5f, +0.5f);

              var normal = Vector3.UnitX;
              vertices.Add(new VertexPositionNormal(p4, normal));
              vertices.Add(new VertexPositionNormal(p5, normal));
              vertices.Add(new VertexPositionNormal(p6, normal));
              vertices.Add(new VertexPositionNormal(p7, normal));

              indices.Add(0);
              indices.Add(1);
              indices.Add(2);

              indices.Add(1);
              indices.Add(3);
              indices.Add(2);

              normal = Vector3.UnitY;
              vertices.Add(new VertexPositionNormal(p6, normal));
              vertices.Add(new VertexPositionNormal(p7, normal));
              vertices.Add(new VertexPositionNormal(p2, normal));
              vertices.Add(new VertexPositionNormal(p3, normal));

              indices.Add(4);
              indices.Add(5);
              indices.Add(6);

              indices.Add(5);
              indices.Add(7);
              indices.Add(6);

              normal = Vector3.UnitZ;
              vertices.Add(new VertexPositionNormal(p5, normal));
              vertices.Add(new VertexPositionNormal(p1, normal));
              vertices.Add(new VertexPositionNormal(p7, normal));
              vertices.Add(new VertexPositionNormal(p3, normal));

              indices.Add(8);
              indices.Add(9);
              indices.Add(10);

              indices.Add(9);
              indices.Add(11);
              indices.Add(10);

              normal = -Vector3.UnitX;
              vertices.Add(new VertexPositionNormal(p1, normal));
              vertices.Add(new VertexPositionNormal(p0, normal));
              vertices.Add(new VertexPositionNormal(p3, normal));
              vertices.Add(new VertexPositionNormal(p2, normal));

              indices.Add(12);
              indices.Add(13);
              indices.Add(14);

              indices.Add(13);
              indices.Add(15);
              indices.Add(14);

              normal = -Vector3.UnitY;
              vertices.Add(new VertexPositionNormal(p4, normal));
              vertices.Add(new VertexPositionNormal(p0, normal));
              vertices.Add(new VertexPositionNormal(p5, normal));
              vertices.Add(new VertexPositionNormal(p1, normal));

              indices.Add(16);
              indices.Add(17);
              indices.Add(18);

              indices.Add(17);
              indices.Add(19);
              indices.Add(18);

              normal = -Vector3.UnitZ;
              vertices.Add(new VertexPositionNormal(p0, normal));
              vertices.Add(new VertexPositionNormal(p4, normal));
              vertices.Add(new VertexPositionNormal(p2, normal));
              vertices.Add(new VertexPositionNormal(p6, normal));

              indices.Add(20);
              indices.Add(21);
              indices.Add(22);

              indices.Add(21);
              indices.Add(23);
              indices.Add(22);

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPositionNormal.VertexDeclaration,
            vertices.Count,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices.ToArray());

              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Count,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices.ToArray());

              submesh.PrimitiveCount = indices.Count / 3;

              return submesh;
        }
        internal static Submesh CreateSpherePatch(
            GraphicsDevice graphicsDevice,
            float originRadius, float sphereRadius,
            int numberOfDivisions)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfDivisions < 1 || numberOfDivisions > 255)
            {
                throw new ArgumentOutOfRangeException("numberOfDivisions", "numberOfDivisions must be in the range [0, 255].");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            int numberOfVertices = (numberOfDivisions + 1) * (numberOfDivisions + 1);
            var vertices         = new VertexPositionNormalTexture[numberOfVertices];

            float groundPlaneSize = 2 * (float)Math.Sqrt(sphereRadius * sphereRadius - originRadius * originRadius);
            int   index           = 0;

            for (int i = 0; i <= numberOfDivisions; i++)
            {
                for (int j = 0; j <= numberOfDivisions; j++)
                {
                    float x = -groundPlaneSize / 2 + groundPlaneSize / numberOfDivisions * j;
                    float z = -groundPlaneSize / 2 + groundPlaneSize / numberOfDivisions * i;

                    //float groundDist2 = x * x + z * z;

                    var direction = new Vector3(x, originRadius, z);
                    direction.Normalize();

                    var p = direction * sphereRadius - new Vector3(0, originRadius, 0);

                    var t = new Vector2(
                        j / (float)numberOfDivisions,
                        i / (float)numberOfDivisions);

                    vertices[index++] = new VertexPositionNormalTexture(p, new Vector3(0, -1, 0), t);
                }
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormalTexture.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            // Build array of indices.
            int numberOfTriangles = numberOfDivisions * numberOfDivisions * 2;
            int numberOfIndices   = 3 * numberOfTriangles;

            var indices = new ushort[numberOfIndices];

            index = 0;
            for (int i = 0; i < numberOfDivisions; i++)
            {
                for (int j = 0; j < numberOfDivisions; j++)
                {
                    int baseIndex = i * (numberOfDivisions + 1) + j;

                    indices[index++] = (ushort)baseIndex;
                    indices[index++] = (ushort)(baseIndex + numberOfDivisions + 1);
                    indices[index++] = (ushort)(baseIndex + 1);

                    indices[index++] = (ushort)(baseIndex + 1);
                    indices[index++] = (ushort)(baseIndex + numberOfDivisions + 1);
                    indices[index++] = (ushort)(baseIndex + numberOfDivisions + 2);
                }
            }

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);

            submesh.PrimitiveCount = indices.Length / 3;

            return(submesh);
        }
Esempio n. 35
0
        private static void MergeSubmeshes(List <MergeJob> mergeJobs, Mesh mergedMesh,
                                           List <VertexDeclaration> vertexDeclarations,
                                           List <int> totalVertexCounts, int totalIndexCount)
        {
            var graphicsDevice = mergeJobs[0].Submesh.VertexBuffer.GraphicsDevice;

            VertexBuffer vertexBuffer = null;
            IndexBuffer  indexBuffer  = null;

            if (totalIndexCount > ushort.MaxValue)
            {
                indexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.ThirtyTwoBits, totalIndexCount, BufferUsage.None);
            }
            else if (totalIndexCount > 0)
            {
                indexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, totalIndexCount, BufferUsage.None);
            }

            Submesh submesh = null;
            int     vertexDeclarationIndex = -1;
            int     vertexCount            = 0;
            int     indexCount             = 0;
            uint    sortKey = 0;

            for (int jobIndex = 0; jobIndex < mergeJobs.Count; jobIndex++)
            {
                var job = mergeJobs[jobIndex];

                // As long as the sort key is equal we can merge into the current submesh.
                if (submesh != null && job.SortKey != sortKey)
                {
                    submesh = null;
                }

                // We have to begin a new vertex buffer if the vertex declaration has changed.
                if (job.VertexDeclarationIndex != vertexDeclarationIndex)
                {
                    vertexBuffer = null;
                }

                if (vertexBuffer == null)
                {
                    vertexDeclarationIndex = job.VertexDeclarationIndex;
                    vertexCount            = 0;
                    vertexBuffer           = new VertexBuffer(
                        graphicsDevice,
                        vertexDeclarations[vertexDeclarationIndex],
                        totalVertexCounts[vertexDeclarationIndex],
                        BufferUsage.None);
                }

                if (submesh == null)
                {
                    sortKey = job.SortKey;
                    submesh = new Submesh
                    {
                        VertexBuffer  = vertexBuffer,
                        StartVertex   = vertexCount,
                        StartIndex    = indexCount,
                        PrimitiveType = job.Submesh.PrimitiveType,
                        MaterialIndex = job.MergedMaterialIndex,
                        IndexBuffer   = (job.Submesh.IndexBuffer != null) ? indexBuffer : null,
                    };
                    mergedMesh.Submeshes.Add(submesh);
                }

                // ----- Merge indices
                if (job.Submesh.IndexBuffer != null)
                {
                    Debug.Assert(indexBuffer != null);
                    int submeshIndexCount = GetNumberOfIndices(job.Submesh.PrimitiveType, job.Submesh.PrimitiveCount);
                    if (job.Submesh.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits)
                    {
                        ushort[] indices16 = new ushort[submeshIndexCount];
                        job.Submesh.IndexBuffer.GetData(job.Submesh.StartIndex * 2, indices16, 0, submeshIndexCount);

                        if (indexBuffer.IndexElementSize == IndexElementSize.SixteenBits)
                        {
                            for (int i = 0; i < indices16.Length; i++)
                            {
                                indices16[i] = (ushort)(indices16[i] + submesh.VertexCount);
                            }

                            indexBuffer.SetData(indexCount * 2, indices16, 0, indices16.Length);
                        }
                        else
                        {
                            uint[] indices32 = new uint[submeshIndexCount];
                            for (int i = 0; i < indices16.Length; i++)
                            {
                                indices32[i] = (uint)(indices16[i] + submesh.VertexCount);
                            }

                            indexBuffer.SetData(indexCount * 4, indices32, 0, indices32.Length);
                        }
                    }
                    else
                    {
                        uint[] indices32 = new uint[submeshIndexCount];
                        job.Submesh.IndexBuffer.GetData(job.Submesh.StartIndex * 4, indices32, 0, submeshIndexCount);

                        if (indexBuffer.IndexElementSize == IndexElementSize.SixteenBits)
                        {
                            ushort[] indices16 = new ushort[submeshIndexCount];
                            for (int i = 0; i < indices32.Length; i++)
                            {
                                indices16[i] = (ushort)(indices32[i] + submesh.VertexCount);
                            }

                            indexBuffer.SetData(indexCount * 2, indices16, 0, indices16.Length);
                        }
                        else
                        {
                            for (int i = 0; i < indices32.Length; i++)
                            {
                                indices32[i] = (uint)(indices32[i] + submesh.VertexCount);
                            }

                            indexBuffer.SetData(indexCount * 4, indices32, 0, indices32.Length);
                        }
                    }

                    indexCount += submeshIndexCount;
                }

                // ----- Merge vertices
                var vertexDeclaration = vertexBuffer.VertexDeclaration;
                int vertexStride      = vertexDeclaration.VertexStride;

                // Get the whole vertex buffer as byte array.
                byte[] buffer = new byte[job.Submesh.VertexBuffer.VertexCount * vertexStride];
                job.Submesh.VertexBuffer.GetData(buffer);

                // Transform position and normals.
                TransformVertices(buffer, job.Submesh.StartVertex, job.Submesh.VertexCount, vertexDeclaration, job.Scale, job.Pose);

                vertexBuffer.SetData(
                    vertexCount * vertexStride,
                    buffer,
                    job.Submesh.StartVertex * vertexStride,
                    job.Submesh.VertexCount * vertexStride,
                    1);

                submesh.VertexCount    += job.Submesh.VertexCount;
                vertexCount            += job.Submesh.VertexCount;
                submesh.PrimitiveCount += job.Submesh.PrimitiveCount;
            }
        }
        public static Submesh CreateConeLines(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.LineList,
            };

            var vertices = new List <Vector3F>();

            // Base
            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                float x     = (float)Math.Cos(angle);
                float z     = -(float)Math.Sin(angle);
                vertices.Add(new Vector3F(x, 0, z));
            }

            // Tip
            vertices.Add(new Vector3F(0, 1, 0));

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPosition.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            var indices = new List <ushort>();

            // Base circle.
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add((ushort)i);       // Line start (= same as previous line end)
                indices.Add((ushort)(i + 1)); // Line end
            }

            // Last line of base circle.
            indices.Add((ushort)(numberOfSegments - 1));
            indices.Add(0);

            // Side represented by 4 lines.
            for (int i = 0; i < 4; i++)
            {
                indices.Add((ushort)(i * numberOfSegments / 4));
                indices.Add((ushort)numberOfSegments);
            }

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 2;

            return(submesh);
        }
        public static Submesh CreateCylinderLines(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (numberOfSegments < 3)
            throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.LineList,
              };

              var vertices = new List<Vector3F>();

              // Top circle.
              for (int i = 0; i < numberOfSegments; i++)
              {
            float angle = i * ConstantsF.TwoPi / numberOfSegments;
            vertices.Add(new Vector3F((float)Math.Cos(angle), 1, -(float)Math.Sin(angle)));
              }

              // Bottom circle.
              for (int i = 0; i < numberOfSegments; i++)
              {
            Vector3F p = vertices[i];
            vertices.Add(new Vector3F(p.X, -1, p.Z));
              }

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPosition.VertexDeclaration,
            vertices.Count,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices.ToArray());
              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              var indices = new List<ushort>();

              // Top circle.
              for (int i = 0; i < numberOfSegments - 1; i++)
              {
            indices.Add((ushort)i);          // Line start (= same as previous line end)
            indices.Add((ushort)(i + 1));    // Line end
              }

              // Last line of top circle.
              indices.Add((ushort)(numberOfSegments - 1));
              indices.Add(0);

              // Bottom circle.
              for (int i = 0; i < numberOfSegments - 1; i++)
              {
            indices.Add((ushort)(numberOfSegments + i));      // Line start (= same as previous line end)
            indices.Add((ushort)(numberOfSegments + i + 1));  // Line end
              }

              // Last line of bottom circle.
              indices.Add((ushort)(numberOfSegments + numberOfSegments - 1));
              indices.Add((ushort)(numberOfSegments));

              // Side (represented by 4 lines).
              for (int i = 0; i < 4; i++)
              {
            indices.Add((ushort)(i * numberOfSegments / 4));
            indices.Add((ushort)(numberOfSegments + i * numberOfSegments / 4));
              }

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Count,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices.ToArray());

              submesh.PrimitiveCount = indices.Count / 2;

              return submesh;
        }
Esempio n. 38
0
 private static OutlineItem CreateOutlineItem(Submesh submesh)
 {
     var item = new OutlineItem
     {
         Text = "Submesh",
         Icon = MultiColorGlyphs.Mesh,
         ToolTip = ToolTipSceneNode,
         UserData = submesh,
     };
     return item;
 }
Esempio n. 39
0
    public static Mesh CreateMesh(IGraphicsService graphicsService, Texture2D texture)
    {
      if (graphicsService == null)
        throw new ArgumentNullException("graphicsService");
      if (texture == null)
        throw new ArgumentNullException("texture");

      List<Vector3> positions = new List<Vector3>();
      List<ushort> indices = new List<ushort>();

      // Create two rings of vertices around the top and bottom of the cylinder.
      for (int i = 0; i < CylinderSegments; i++)
      {
        float angle = ConstantsF.TwoPi * i / CylinderSegments;

        float x = (float)Math.Cos(angle) * CylinderSize;
        float z = (float)Math.Sin(angle) * CylinderSize;

        positions.Add(new Vector3(x, CylinderSize * 5 / 12, z));
        positions.Add(new Vector3(x, -CylinderSize * 5 / 12, z));
      }

      // Create two center vertices, used for closing the top and bottom.
      positions.Add(new Vector3(0, CylinderSize, 0));
      positions.Add(new Vector3(0, -CylinderSize, 0));

      // Create the individual triangles that make up our skydome.
      List<VertexPositionTexture> vertices = new List<VertexPositionTexture>();
      ushort index = 0;
      for (int i = 0; i < CylinderSegments; i++)
      {
        int j = (i + 1) % CylinderSegments;

        // Calculate texture coordinates for this segment of the cylinder.
        float u1 = (float)i / (float)CylinderSegments;
        float u2 = (float)(i + 1) / (float)CylinderSegments;

        // Two triangles form a quad, one side segment of the cylinder.
        vertices.Add(new VertexPositionTexture(positions[i * 2], new Vector2(u1, TexCoordTop)));
        indices.Add(index++);
        vertices.Add(new VertexPositionTexture(positions[j * 2], new Vector2(u2, TexCoordTop)));
        indices.Add(index++);
        vertices.Add(new VertexPositionTexture(positions[i * 2 + 1], new Vector2(u1, TexCoordBottom)));
        indices.Add(index++);

        vertices.Add(new VertexPositionTexture(positions[j * 2], new Vector2(u2, TexCoordTop)));
        indices.Add(index++);
        vertices.Add(new VertexPositionTexture(positions[j * 2 + 1], new Vector2(u2, TexCoordBottom)));
        indices.Add(index++);
        vertices.Add(new VertexPositionTexture(positions[i * 2 + 1], new Vector2(u1, TexCoordBottom)));
        indices.Add(index++);

        // Triangle fanning inward to fill the top above this segment.
        vertices.Add(new VertexPositionTexture(positions[CylinderSegments * 2], new Vector2(u1, 0)));
        indices.Add(index++);
        vertices.Add(new VertexPositionTexture(positions[j * 2], new Vector2(u2, TexCoordTop)));
        indices.Add(index++);
        vertices.Add(new VertexPositionTexture(positions[i * 2], new Vector2(u1, TexCoordTop)));
        indices.Add(index++);

        // Triangle fanning inward to fill the bottom below this segment.
        vertices.Add(new VertexPositionTexture(positions[CylinderSegments * 2 + 1], new Vector2(u1, 1)));
        indices.Add(index++);
        vertices.Add(new VertexPositionTexture(positions[i * 2 + 1], new Vector2(u1, TexCoordBottom)));
        indices.Add(index++);
        vertices.Add(new VertexPositionTexture(positions[j * 2 + 1], new Vector2(u2, TexCoordBottom)));
        indices.Add(index++);
      }

      // Create the vertex buffer.
      VertexBuffer vertexBuffer = new VertexBuffer(
        graphicsService.GraphicsDevice,
        VertexPositionTexture.VertexDeclaration,
        vertices.Count, BufferUsage.
        None);
      vertexBuffer.SetData(vertices.ToArray());

      // Create the index buffer.
      IndexBuffer indexBuffer = new IndexBuffer(
        graphicsService.GraphicsDevice,
        IndexElementSize.SixteenBits,
        indices.Count,
        BufferUsage.None);
      indexBuffer.SetData(indices.ToArray());

      // Create a submesh, which is a set of primitives which can be rendered in 
      // one draw call.
      Submesh submesh = new Submesh
      {
        PrimitiveCount = indices.Count / 3,
        PrimitiveType = PrimitiveType.TriangleList,
        StartIndex = 0,
        StartVertex = 0,
        VertexCount = vertices.Count,
        VertexBuffer = vertexBuffer,
        IndexBuffer = indexBuffer,
      };

      // Create a mesh (which is collection of submeshes and materials).
      Mesh mesh = new Mesh
      {
        Name = "Sky",
        BoundingShape = new CylinderShape(CylinderSize, 2 * CylinderSize),
      };
      mesh.Submeshes.Add(submesh);

      // Create a BasicEffectBinding which wraps the XNA BasicEffect.
      // An EffectBinding connects an effect with effect parameter values ("effect 
      // parameter binding"). Some of these parameter values are defined here. Others, 
      // like World matrices, light parameters, etc. are automatically updated by 
      // the graphics engine in each frame.
      BasicEffectBinding effectBinding = new BasicEffectBinding(graphicsService, null)
      {
        LightingEnabled = false,
        TextureEnabled = true,
        VertexColorEnabled = false
      };
      effectBinding.Set("Texture", texture);
      effectBinding.Set("SpecularColor", new Vector3(0, 0, 0));

      // Create a material, which is a collection of effect bindings - one effect 
      // binding for each "render pass". The sky mesh should be rendered in the 
      // "Sky" render pass. This render pass name is an arbitrary string that is 
      // used in SampleGraphicsScreen.cs.
      Material material = new Material();
      material.Add("Sky", effectBinding);

      // Assign the material to the submesh.
      submesh.SetMaterial(material);

      return mesh;
    }
Esempio n. 40
0
        public static Submesh CreateBoxLines(GraphicsDevice graphicsDevice)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.LineList,
            };

            var vertices = new[]
            {
                new Vector3F(-0.5f, -0.5f, +0.5f),
                new Vector3F(+0.5f, -0.5f, +0.5f),
                new Vector3F(+0.5f, +0.5f, +0.5f),
                new Vector3F(-0.5f, +0.5f, +0.5f),
                new Vector3F(-0.5f, -0.5f, -0.5f),
                new Vector3F(+0.5f, -0.5f, -0.5f),
                new Vector3F(+0.5f, +0.5f, -0.5f),
                new Vector3F(-0.5f, +0.5f, -0.5f)
            };

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPosition.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            var indices = new ushort[]
            {
                0, 1,
                1, 2,
                2, 3,
                3, 0,

                4, 5,
                5, 6,
                6, 7,
                7, 4,

                0, 4,
                1, 5,
                2, 6,
                3, 7
            };

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);

            submesh.PrimitiveCount = indices.Length / 2;

            return(submesh);
        }
Esempio n. 41
0
        internal static Submesh CreateGrid(GraphicsDevice graphicsDevice, float widthX, float widthY, int numberOfCellsX, int numberOfCellsY)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (widthX <= 0)
            {
                throw new ArgumentOutOfRangeException("widthX", "The number of cells must be greater than 0.");
            }
            if (widthY <= 0)
            {
                throw new ArgumentOutOfRangeException("widthY", "The number of cells must be greater than 0.");
            }
            if (numberOfCellsX < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfCellsX", "The number of cells must be greater than 0.");
            }
            if (numberOfCellsY < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfCellsY", "The number of cells must be greater than 0.");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            int numberOfVertices = (numberOfCellsX + 1) * (numberOfCellsY + 1);
            var vertices         = new VertexPositionNormalTexture[numberOfVertices];

            int index = 0;

            for (int y = 0; y <= numberOfCellsY; y++)
            {
                for (int x = 0; x <= numberOfCellsX; x++)
                {
                    vertices[index++] = new VertexPositionNormalTexture(
                        new Vector3(x * widthX / numberOfCellsX, y * widthY / numberOfCellsY, 0),
                        new Vector3(0, 0, 1),
                        new Vector2(x / (float)numberOfCellsX, y / (float)numberOfCellsY));
                }
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormalTexture.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            // Build array of indices.
            int numberOfTriangles = numberOfCellsX * numberOfCellsY * 2;
            int numberOfIndices   = 3 * numberOfTriangles;

            if (numberOfIndices < ushort.MaxValue)
            {
                var indices = new ushort[numberOfIndices];

                index = 0;
                for (int y = 0; y < numberOfCellsY; y++)
                {
                    for (int x = 0; x < numberOfCellsX; x++)
                    {
                        int baseIndex = y * (numberOfCellsX + 1) + x;

                        indices[index++] = (ushort)baseIndex;
                        indices[index++] = (ushort)(baseIndex + numberOfCellsX + 1);
                        indices[index++] = (ushort)(baseIndex + 1);

                        indices[index++] = (ushort)(baseIndex + 1);
                        indices[index++] = (ushort)(baseIndex + numberOfCellsX + 1);
                        indices[index++] = (ushort)(baseIndex + numberOfCellsX + 2);
                    }
                }

                submesh.IndexBuffer = new IndexBuffer(
                    graphicsDevice,
                    IndexElementSize.SixteenBits,
                    indices.Length,
                    BufferUsage.None);
                submesh.IndexBuffer.SetData(indices);
                submesh.PrimitiveCount = indices.Length / 3;
            }
            else
            {
                var indices = new int[numberOfIndices];

                index = 0;
                for (int y = 0; y < numberOfCellsY; y++)
                {
                    for (int x = 0; x < numberOfCellsX; x++)
                    {
                        int baseIndex = y * (numberOfCellsX + 1) + x;

                        indices[index++] = baseIndex;
                        indices[index++] = (baseIndex + numberOfCellsX + 1);
                        indices[index++] = (baseIndex + 1);

                        indices[index++] = (baseIndex + 1);
                        indices[index++] = (baseIndex + numberOfCellsX + 1);
                        indices[index++] = (baseIndex + numberOfCellsX + 2);
                    }
                }

                submesh.IndexBuffer = new IndexBuffer(
                    graphicsDevice,
                    IndexElementSize.ThirtyTwoBits,
                    indices.Length,
                    BufferUsage.None);
                submesh.IndexBuffer.SetData(indices);
                submesh.PrimitiveCount = indices.Length / 3;
            }

            return(submesh);
        }
        public static Submesh CreateUncappedCylinder(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (numberOfSegments < 3)
            throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");

              var submesh = new Submesh
              {
            PrimitiveType = PrimitiveType.TriangleList,
              };

              // ----- Vertices
              var vertices = new List<VertexPositionNormal>();
              for (int i = 0; i < numberOfSegments; i++)
              {
            float angle = i * ConstantsF.TwoPi / numberOfSegments;
            float x = (float)Math.Cos(angle);
            float z = -(float)Math.Sin(angle);
            vertices.Add(new VertexPositionNormal(new Vector3(x, 1, z), new Vector3(x, 0, z)));
            vertices.Add(new VertexPositionNormal(new Vector3(x, -1, z), new Vector3(x, 0, z)));
              }

              submesh.VertexBuffer = new VertexBuffer(
            graphicsDevice,
            VertexPositionNormal.VertexDeclaration,
            vertices.Count,
            BufferUsage.None);
              submesh.VertexBuffer.SetData(vertices.ToArray());

              submesh.VertexCount = submesh.VertexBuffer.VertexCount;

              // ----- Indices
              var indices = new List<ushort>();
              for (int i = 0; i < numberOfSegments - 1; i++)
              {
            indices.Add((ushort)(2 * i));
            indices.Add((ushort)(2 * i + 2));
            indices.Add((ushort)(2 * i + 1));

            indices.Add((ushort)(2 * i + 2));
            indices.Add((ushort)(2 * i + 3));
            indices.Add((ushort)(2 * i + 1));
              }

              // Indices of last 2 triangle.
              indices.Add((ushort)(numberOfSegments + numberOfSegments - 2));
              indices.Add(0);
              indices.Add((ushort)(numberOfSegments + numberOfSegments - 1));

              indices.Add(0);
              indices.Add(1);
              indices.Add((ushort)(numberOfSegments + numberOfSegments - 1));

              submesh.IndexBuffer = new IndexBuffer(
            graphicsDevice,
            IndexElementSize.SixteenBits,
            indices.Count,
            BufferUsage.None);
              submesh.IndexBuffer.SetData(indices.ToArray());

              submesh.PrimitiveCount = indices.Count / 3;

              return submesh;
        }
Esempio n. 43
0
        public static void ToTriangleMesh(this Submesh submesh, TriangleMesh triangleMesh)
        {
            // This method is similar to TriangleMesh.FromModel().

            if (submesh == null)
            {
                throw new ArgumentNullException("submesh");
            }
            if (triangleMesh == null)
            {
                throw new ArgumentNullException("triangleMesh");
            }

            if (submesh.PrimitiveType != PrimitiveType.TriangleList)
            {
                throw new NotSupportedException("All submeshes must be triangle lists. ToTriangleMesh() does not support other primitive types.");
            }

            if (submesh.VertexBuffer == null)
            {
                return;
            }
            if (triangleMesh.Vertices == null)
            {
                triangleMesh.Vertices = new List <Vector3F>(submesh.VertexCount);
            }
            if (triangleMesh.Indices == null)
            {
                triangleMesh.Indices = new List <int>(submesh.PrimitiveCount * 3);
            }

            // Get vertex element info.
            var vertexDeclaration = submesh.VertexBuffer.VertexDeclaration;
            var vertexElements    = vertexDeclaration.GetVertexElements();

            // Get the vertex positions.
            var positionElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.Position);

            if (positionElement.VertexElementFormat != VertexElementFormat.Vector3)
            {
                throw new NotSupportedException("For vertex positions only VertexElementFormat.Vector3 is supported.");
            }

            Vector3[] positions = new Vector3[submesh.VertexCount];
            submesh.VertexBuffer.GetData(
                submesh.StartVertex * vertexDeclaration.VertexStride + positionElement.Offset,
                positions,
                0,
                submesh.VertexCount,
                vertexDeclaration.VertexStride);

            if (submesh.IndexBuffer != null)
            {
                // Remember the number of vertices already in the mesh.
                int vertexCount = triangleMesh.Vertices.Count;

                // Add the vertices of the current modelMeshPart.
                foreach (Vector3 p in positions)
                {
                    triangleMesh.Vertices.Add((Vector3F)p);
                }

                // Get indices.
                int indexElementSize = (submesh.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits) ? 2 : 4;
                if (indexElementSize == 2)
                {
                    ushort[] indices = new ushort[submesh.PrimitiveCount * 3];
                    submesh.IndexBuffer.GetData(
                        submesh.StartIndex * 2,
                        indices,
                        0,
                        submesh.PrimitiveCount * 3);

                    // Add indices to triangle mesh.
                    for (int i = 0; i < submesh.PrimitiveCount; i++)
                    {
                        // The three indices of the next triangle.
                        // We add 'vertexCount' because the triangleMesh already contains other mesh parts.
                        int i0 = indices[i * 3 + 0] + vertexCount;
                        int i1 = indices[i * 3 + 1] + vertexCount;
                        int i2 = indices[i * 3 + 2] + vertexCount;

                        triangleMesh.Indices.Add(i0);
                        triangleMesh.Indices.Add(i2); // DigitalRune Geometry uses other winding order!
                        triangleMesh.Indices.Add(i1);
                    }
                }
                else
                {
                    Debug.Assert(indexElementSize == 4);
                    int[] indices = new int[submesh.PrimitiveCount * 3];
                    submesh.IndexBuffer.GetData(
                        submesh.StartIndex * 4,
                        indices,
                        0,
                        submesh.PrimitiveCount * 3);

                    // Add indices to triangle mesh.
                    for (int i = 0; i < submesh.PrimitiveCount; i++)
                    {
                        // The three indices of the next triangle.
                        // We add 'vertexCount' because the triangleMesh already contains other mesh parts.
                        int i0 = indices[i * 3 + 0] + vertexCount;
                        int i1 = indices[i * 3 + 1] + vertexCount;
                        int i2 = indices[i * 3 + 2] + vertexCount;

                        triangleMesh.Indices.Add(i0);
                        triangleMesh.Indices.Add(i2); // DigitalRune Geometry uses other winding order!
                        triangleMesh.Indices.Add(i1);
                    }
                }
            }
            else
            {
                // No index buffer:
                int vertexCount = triangleMesh.Vertices.Count;
                for (int i = 0; i < submesh.VertexCount; i += 3)
                {
                    triangleMesh.Vertices.Add((Vector3F)positions[i]);
                    triangleMesh.Vertices.Add((Vector3F)positions[i + 1]);
                    triangleMesh.Vertices.Add((Vector3F)positions[i + 2]);

                    triangleMesh.Indices.Add(i + vertexCount);
                    triangleMesh.Indices.Add(i + 2 + vertexCount); // DigitalRune Geometry uses other winding order!
                    triangleMesh.Indices.Add(i + 1 + vertexCount);
                }
            }
        }
Esempio n. 44
0
        public static void SetMaterial(this Submesh submesh, Material material)
        {
            if (submesh == null)
            {
                throw new ArgumentNullException("submesh");
            }

            var mesh = submesh.Mesh;

            if (mesh == null)
            {
                throw new InvalidOperationException("Cannot add material to submesh. Submesh needs to be added to Mesh first.");
            }
            if (material == null)
            {
                throw new ArgumentNullException("material");
            }

            var oldMaterial = GetMaterial(submesh);

            if (oldMaterial == material)
            {
                return;
            }

            // Find out if the old or new material is used by other submeshes which belong
            // to the same mesh.
            bool oldMaterialStillInUse   = false;
            bool newMaterialAlreadyInUse = false;

            foreach (var otherSubmesh in mesh.Submeshes)
            {
                if (otherSubmesh != submesh)
                {
                    Material otherMaterial = GetMaterial(otherSubmesh);
                    if (otherMaterial == oldMaterial)
                    {
                        oldMaterialStillInUse = true;
                    }
                    else if (otherMaterial == material)
                    {
                        newMaterialAlreadyInUse = true;
                    }
                }
            }

            // Remove old material from parent mesh material collection if it is not used by
            // any submesh.
            int oldIndex = submesh.MaterialIndex;

            if (!oldMaterialStillInUse && oldMaterial != null)
            {
                mesh.Materials.RemoveAt(oldIndex);

                // One material was removed --> Update indices of meshes.
                foreach (var otherSubmesh in mesh.Submeshes)
                {
                    if (otherSubmesh.MaterialIndex > oldIndex)
                    {
                        otherSubmesh.MaterialIndex--;
                    }
                }
            }

            // Add new material to parent mesh material collection if this is the first submesh
            // that uses this material.
            if (newMaterialAlreadyInUse)
            {
                // Get index of the new material.
                submesh.MaterialIndex = mesh.Materials.IndexOf(material);
            }
            else
            {
                // Add new material to the mesh at the end of the material collection.
                mesh.Materials.Add(material);
                submesh.MaterialIndex = mesh.Materials.Count - 1;
            }
        }
        public static void CreateMesh(GraphicsDevice graphicsDevice, Path3F path, float defaultWidth,
            int maxNumberOfIterations, float tolerance,
            out Submesh submesh, out Aabb aabb, out float roadLength)
        {
            if (graphicsDevice == null)
            throw new ArgumentNullException("graphicsDevice");
              if (path == null)
            throw new ArgumentNullException("path");

              // Compute list of line segments. (2 points per line segment!)
              var flattenedPoints = new List<Vector3F>();
              path.Flatten(flattenedPoints, maxNumberOfIterations, tolerance);

              // Abort if path is empty.
              int numberOfLineSegments = flattenedPoints.Count / 2;
              if (numberOfLineSegments <= 0)
              {
            submesh = null;
            aabb = new Aabb();
            roadLength = 0;
            return;
              }

              // Compute accumulated lengths. (One entry for each entry in flattenedPoints.)
              float[] accumulatedLengths = new float[flattenedPoints.Count];
              accumulatedLengths[0] = 0;
              for (int i = 1; i < flattenedPoints.Count; i += 2)
              {
            Vector3F previous = flattenedPoints[i - 1];
            Vector3F current = flattenedPoints[i];
            float length = (current - previous).Length;

            accumulatedLengths[i] = accumulatedLengths[i - 1] + length;
            if (i + 1 < flattenedPoints.Count)
              accumulatedLengths[i + 1] = accumulatedLengths[i];
              }

              // Total road length.
              roadLength = accumulatedLengths[accumulatedLengths.Length - 1];

              // Create a mapping between accumulatedLength and the path key widths.
              // (accumulatedLength --> TerrainRoadPathKey.Width)
              var widthKeys = new List<Pair<float, float>>();
              {
            int index = 0;
            foreach (var key in path)
            {
              Vector3F position = key.Point;
              var roadKey = key as TerrainRoadPathKey;
              float width = (roadKey != null) ? roadKey.Width : defaultWidth;

              for (; index < flattenedPoints.Count; index++)
              {
            if (Vector3F.AreNumericallyEqual(position, flattenedPoints[index]))
            {
              widthKeys.Add(new Pair<float, float>(accumulatedLengths[index], width));
              break;
            }

            bool isLastLineSegment = (index + 2 == flattenedPoints.Count);
            if (!isLastLineSegment)
              index++;
              }

              index++;
            }
              }

              // Create a list of interpolated road widths. (One entry for each entry in flattenedPoints.)
              var widths = new float[flattenedPoints.Count];
              int previousKeyIndex = 0;
              var previousKey = widthKeys[0];
              var nextKey = widthKeys[1];
              widths[0] = widthKeys[0].Second;
              for (int i = 1; i < flattenedPoints.Count; i += 2)
              {
            if (accumulatedLengths[i] > nextKey.First)
            {
              previousKey = nextKey;
              previousKeyIndex++;
              nextKey = widthKeys[previousKeyIndex + 1];
            }

            float p = (accumulatedLengths[i] - previousKey.First) / (nextKey.First - previousKey.First);
            widths[i] = InterpolationHelper.Lerp(previousKey.Second, nextKey.Second, p);

            if (i + 1 < flattenedPoints.Count)
              widths[i + 1] = widths[i];
              }

              // Compute vertices and indices.
              var vertices = new List<TerrainLayerVertex>(numberOfLineSegments * 2 + 2);
              var indices = new List<int>(numberOfLineSegments * 6);  // Two triangles per line segment.
              Vector3F lastOrthonormal = Vector3F.UnitX;
              aabb = new Aabb(flattenedPoints[0], flattenedPoints[0]);
              bool isClosed = Vector3F.AreNumericallyEqual(flattenedPoints[0], flattenedPoints[flattenedPoints.Count - 1]);
              for (int i = 0; i < flattenedPoints.Count; i++)
              {
            Vector3F start = flattenedPoints[i];

            Vector3F previous;
            bool isFirstPoint = (i == 0);
            if (!isFirstPoint)
              previous = flattenedPoints[i - 1];
            else if (isClosed && path.SmoothEnds)
              previous = flattenedPoints[flattenedPoints.Count - 2];
            else
              previous = start;

            Vector3F next;
            bool isLastPoint = (i + 1 == flattenedPoints.Count);
            if (!isLastPoint)
              next = flattenedPoints[i + 1];
            else if (isClosed && path.SmoothEnds)
              next = flattenedPoints[1];
            else
              next = start;

            Vector3F tangent = next - previous;

            Vector3F orthonormal = new Vector3F(tangent.Z, 0, -tangent.X);
            if (!orthonormal.TryNormalize())
              orthonormal = lastOrthonormal;

            // Add indices to add two triangles between the current and the next vertices.
            if (!isLastPoint)
            {
              int baseIndex = vertices.Count;

              //  2      3
              //   x----x
              //   |\   |   ^
              //   | \  |   | road
              //   |  \ |   | direction
              //   |   \|   |
              //   x----x
              //  0      1

              indices.Add(baseIndex);
              indices.Add(baseIndex + 1);
              indices.Add(baseIndex + 2);

              indices.Add(baseIndex + 1);
              indices.Add(baseIndex + 3);
              indices.Add(baseIndex + 2);
            }

            // Add two vertices.
            Vector3F leftVertex = start - orthonormal * (widths[i] / 2);
            Vector3F rightVertex = start + orthonormal * (widths[i] / 2);
            vertices.Add(new TerrainLayerVertex(new Vector2(leftVertex.X, leftVertex.Z), new Vector2(0, accumulatedLengths[i])));
            vertices.Add(new TerrainLayerVertex(new Vector2(rightVertex.X, rightVertex.Z), new Vector2(1, accumulatedLengths[i])));

            // Grow AABB
            aabb.Grow(leftVertex);
            aabb.Grow(rightVertex);

            lastOrthonormal = orthonormal;

            // The flattened points list contains 2 points per line segment, which means that there
            // are duplicate intermediate points, which we skip.
            bool isLastLineSegment = (i + 2 == flattenedPoints.Count);
            if (!isLastLineSegment)
              i++;
              }

              Debug.Assert(vertices.Count == (numberOfLineSegments * 2 + 2));
              Debug.Assert(indices.Count == (numberOfLineSegments * 6));

              // The road is projected onto the terrain, therefore the computed y limits are not correct.
              // (unless the terrain was clamped to the road).
              aabb.Minimum.Y = 0;
              aabb.Maximum.Y = 0;

              // Convert to submesh.
              submesh = new Submesh
              {
            PrimitiveCount = indices.Count / 3,
            PrimitiveType = PrimitiveType.TriangleList,
            VertexCount = vertices.Count,
            VertexBuffer = new VertexBuffer(graphicsDevice, TerrainLayerVertex.VertexDeclaration, vertices.Count, BufferUsage.WriteOnly),
            IndexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.ThirtyTwoBits, indices.Count, BufferUsage.WriteOnly)
              };
              submesh.VertexBuffer.SetData(vertices.ToArray());
              submesh.IndexBuffer.SetData(indices.ToArray());
        }