private static void GetVertexAndIndexBuffer(out PositionNormalTexture[] vertexBuffer, out int[] indexBuffer)
        {
            vertexBuffer = new PositionNormalTexture[] {
                /*                        Position                     Normal                                   TextureCoordinate */
                new PositionNormalTexture(new Vector3(0f, 50f, 0f), new Vector3(0.0000f, 0.6247f, -0.7809f), new Vector2(0.5f, 0.5f)),
                new PositionNormalTexture(new Vector3(0f, 50f, 0f), new Vector3(0.7809f, 0.6247f, 0.0000f), new Vector2(0.5f, 0.5f)),
                new PositionNormalTexture(new Vector3(0f, 50f, 0f), new Vector3(0.0000f, 0.6247f, 0.7809f), new Vector2(0.5f, 0.5f)),
                new PositionNormalTexture(new Vector3(0f, 50f, 0f), new Vector3(-0.7809f, 0.6247f, 0.0000f), new Vector2(0.5f, 0.5f)),
                new PositionNormalTexture(new Vector3(-40f, 0f, -40f), new Vector3(0.0000f, 0.6247f, -0.7809f), new Vector2(0f, 0f)),
                new PositionNormalTexture(new Vector3(-40f, 0f, -40f), new Vector3(-0.7809f, 0.6247f, 0.0000f), new Vector2(0f, 0f)),
                new PositionNormalTexture(new Vector3(-40f, 0f, -40f), new Vector3(0.0000f, -1.0000f, 0.0000f), new Vector2(0f, 0f)),
                new PositionNormalTexture(new Vector3(40f, 0f, -40f), new Vector3(0.0000f, 0.6247f, -0.7809f), new Vector2(1f, 0f)),
                new PositionNormalTexture(new Vector3(40f, 0f, -40f), new Vector3(0.7809f, 0.6247f, 0.0000f), new Vector2(1f, 0f)),
                new PositionNormalTexture(new Vector3(40f, 0f, -40f), new Vector3(0.0000f, -1.0000f, 0.0000f), new Vector2(1f, 0f)),
                new PositionNormalTexture(new Vector3(40f, 0f, 40f), new Vector3(0.7809f, 0.6247f, 0.0000f), new Vector2(1f, 1f)),
                new PositionNormalTexture(new Vector3(40f, 0f, 40f), new Vector3(0.0000f, 0.6247f, 0.7809f), new Vector2(1f, 1f)),
                new PositionNormalTexture(new Vector3(40f, 0f, 40f), new Vector3(0.0000f, -1.0000f, 0.0000f), new Vector2(1f, 1f)),
                new PositionNormalTexture(new Vector3(-40f, 0f, 40f), new Vector3(0.0000f, 0.6247f, 0.7809f), new Vector2(0f, 1f)),
                new PositionNormalTexture(new Vector3(-40f, 0f, 40f), new Vector3(-0.7809f, 0.6247f, 0.0000f), new Vector2(0f, 1f)),
                new PositionNormalTexture(new Vector3(-40f, 0f, 40f), new Vector3(0.0000f, -1.0000f, 0.0000f), new Vector2(0f, 1f)),
            };

            indexBuffer = new int[]
            {
                0, 7, 4,
                1, 10, 8,
                2, 13, 11,
                3, 5, 14,
                6, 9, 15,
                9, 12, 15,
            };
        }
        public static void CreateMultiMeshBuffer(Vector3 center, Vector3 size, int xCount, int yCount, int zCount, MeshGeometry3D meshGeometry3D,
                                                 out PositionNormalTexture[] vertexBuffer, out int[] indexBuffer)
        {
            // Because we will iterate through Positions, Normals and other collections multiple times,
            // we copy the data into simple arrays because accessing simple arrays is significantly faster then Point3DCollections and other collection
            // (the reason for that is that in each getter in Point3DCollections there is a check if we are on the correct thread - the one that created the collection).
            var positionsCount = meshGeometry3D.Positions.Count;

            var positions = new Point3D[positionsCount];

            meshGeometry3D.Positions.CopyTo(positions, 0);


            if (meshGeometry3D.Normals.Count < positionsCount) // Each position must have its Normal
            {
                throw new Exception("Invalid Normals");
            }

            var normals = new Vector3D[positionsCount];

            meshGeometry3D.Normals.CopyTo(normals, 0);


            // If we do not use textures, we can skip TextureCoordinates
            Point[] textureCoordinates;

            if (meshGeometry3D.TextureCoordinates != null && meshGeometry3D.TextureCoordinates.Count > 0)
            {
                if (meshGeometry3D.TextureCoordinates.Count < positionsCount)
                {
                    throw new Exception("Invalid TextureCoordinates");
                }

                textureCoordinates = new System.Windows.Point[positionsCount];
                meshGeometry3D.TextureCoordinates.CopyTo(textureCoordinates, 0);
            }
            else
            {
                textureCoordinates = null;
            }


            var triangleIndicesCount = meshGeometry3D.TriangleIndices.Count;
            var triangleIndices      = new Int32[triangleIndicesCount];

            meshGeometry3D.TriangleIndices.CopyTo(triangleIndices, 0);



            float xStep = (float)(size.X / xCount);
            float yStep = (float)(size.Y / yCount);
            float zStep = (float)(size.Z / zCount);

            vertexBuffer = new PositionNormalTexture[positionsCount * xCount * yCount * zCount];
            indexBuffer  = new int[triangleIndicesCount * xCount * yCount * zCount];

            int vertexBufferIndex = 0;
            int indexBufferIndex  = 0;

            for (int y = 0; y < yCount; y++)
            {
                float yPos = (float)(center.Y - (size.Y / 2.0) + (y * yStep));

                for (int z = 0; z < zCount; z++)
                {
                    float zPos = (float)(center.Z - (size.Z / 2.0) + (z * zStep));

                    for (int x = 0; x < xCount; x++)
                    {
                        float xPos = (float)(center.X - (size.X / 2.0) + (x * xStep));


                        // Save index for the start of the mesh
                        int vertexBufferStartIndex = vertexBufferIndex;

                        if (textureCoordinates != null)
                        {
                            for (int positionIndex = 0; positionIndex < positionsCount; positionIndex++)
                            {
                                // TODO: We could further optimize this with converting positions, normals and textureCoordinates to Vector3 arrays before entering the loops
                                vertexBuffer[vertexBufferIndex] = new PositionNormalTexture(
                                    new Vector3((float)positions[positionIndex].X + xPos, (float)positions[positionIndex].Y + yPos, (float)positions[positionIndex].Z + zPos),
                                    normals[positionIndex].ToVector3(),
                                    new Vector2((float)textureCoordinates[positionIndex].X, (float)textureCoordinates[positionIndex].Y));

                                vertexBufferIndex++;
                            }
                        }
                        else
                        {
                            for (int positionIndex = 0; positionIndex < positionsCount; positionIndex++)
                            {
                                vertexBuffer[vertexBufferIndex] = new PositionNormalTexture(
                                    new Vector3((float)positions[positionIndex].X + xPos, (float)positions[positionIndex].Y + yPos, (float)positions[positionIndex].Z + zPos),
                                    normals[positionIndex].ToVector3(),
                                    new Vector2(0, 0));

                                vertexBufferIndex++;
                            }
                        }


                        for (int instanceIndex = 0; instanceIndex < triangleIndicesCount; instanceIndex++)
                        {
                            indexBuffer[indexBufferIndex] = triangleIndices[instanceIndex] + vertexBufferStartIndex;
                            indexBufferIndex++;
                        }
                    }
                }
            }
        }
        private void CreateHeightVertexAndIndexBuffer(float[,] heightData, Vector3 centerPosition, Vector3 size, out PositionNormalTexture[] vertexBuffer, out int[] indexBuffer)
        {
            int xCount = heightData.GetUpperBound(0) + 1; // NOTE: This is not length but max element index (so length is GetUpperBound() + 1)
            int yCount = heightData.GetUpperBound(1) + 1;

            float x_step = size.X / ((float)(xCount - 1));
            float z_step = size.Z / ((float)(yCount - 1));


            vertexBuffer = new PositionNormalTexture[xCount * yCount];

            float x_pos   = centerPosition.X - (size.X / 2.0f);
            float yScale  = size.Y;
            float yOffset = centerPosition.Y; // if one value is 0, then it is positioned at the _centerPosition.Y (positive values are above center; negative values below center)

            float xCount1 = (float)(xCount - 1);
            float yCount1 = (float)(yCount - 1);

            int index = 0;

            for (int x = 0; x < xCount; x++)
            {
                float z_pos    = centerPosition.Z - (size.Z / 2.0f);
                float xTexture = ((float)x) / xCount1;

                for (int y = 0; y < yCount; y++)
                {
                    vertexBuffer[index].Position          = new Vector3(x_pos, heightData[x, y] * yScale + yOffset, z_pos);
                    vertexBuffer[index].TextureCoordinate = new Vector2(xTexture, (float)y / yCount1);

                    index++;

                    z_pos += z_step;
                }

                x_pos += x_step;
            }



            indexBuffer = new int[(xCount - 1) * (yCount - 1) * 6];
            index       = 0;

            for (int x = 0; x < xCount - 1; x++)
            {
                for (int y = 0; y < yCount - 1; y++)
                {
                    if ((x + y) % 2 == 1)
                    {
                        indexBuffer[index]     = y + (x * yCount);
                        indexBuffer[index + 1] = (y + 1) + x * yCount;
                        indexBuffer[index + 2] = (y) + ((x + 1) * yCount);

                        indexBuffer[index + 3] = y + ((x + 1) * yCount);
                        indexBuffer[index + 4] = (y + 1) + ((x) * yCount);
                        indexBuffer[index + 5] = (y + 1) + ((x + 1) * yCount);
                    }
                    else
                    {
                        indexBuffer[index]     = y + (x * yCount);
                        indexBuffer[index + 1] = (y + 1) + x * yCount;
                        indexBuffer[index + 2] = (y + 1) + ((x + 1) * yCount);

                        indexBuffer[index + 3] = y + (x * yCount);
                        indexBuffer[index + 4] = (y + 1) + ((x + 1) * yCount);
                        indexBuffer[index + 5] = y + ((x + 1) * yCount);
                    }

                    index += 6;
                }
            }


            // Calculate normals in the vertexBuffer
            CalculateNormals(vertexBuffer, indexBuffer, normalize: true);
        }