HeightmapSample GetSampleInPlanetSpace(HeightmapDefinition definition, int column, int row)
        {
            // Check out "Textures and Modelling - A Procedural Approach" by Ken Musgaves

            // We have several different reference frames to deal with here:
            //   "Quad grid" coordinates which is the column and row index of the vertex in the mesh grid
            //   "Unit plane" coordinates which is the coordinates of the vertex on the unit plane of this quadtree
            //   "Unit sphere" coordinates which is the coordinates of the vertex on the unit sphere arc of this quadtree
            //   "Planet space" coordinates which is the coordinates of the vertex in real units relative to the planet center

            // We start with quad grid coordinates.  We first convert the quad coordinates into a unit plane vector that
            // points to the equivalent point on the quadtree's plane.  Then we project the unit plane to its equivalent unit
            // sphere vector.  We then calculate the terrain height for the vertex and use that information to extend the unit
            // sphere vector to the proper length for the real-space size of our planet.

            var unitPlaneVector   = ConvertToUnitPlaneVector(definition, column, row);
            var unitSphereVector  = unitPlaneVector.ProjectUnitPlaneToUnitSphere();
            var terrainHeight     = _heightGenerator.GetHeight(unitSphereVector, definition.QuadLevel, 8000);
            var planetSpaceVector = ConvertToPlanetSpace(definition, unitSphereVector, terrainHeight);

            return(new HeightmapSample()
            {
                Height = terrainHeight,
                Vector = planetSpaceVector
            });
        }
        DoubleVector3 ConvertToUnitPlaneVector(HeightmapDefinition definition, int column, int row)
        {
            var uDelta          = definition.UVector * (definition.Extents.North + (row * definition.Stride));
            var vDelta          = definition.VVector * (definition.Extents.West + (column * definition.Stride));
            var convertedVector = definition.PlaneNormalVector + uDelta + vDelta;

            return(convertedVector);
        }
        public HeightmapSample[] GenerateHeightmapSamples(HeightmapDefinition definition)
        {
            var samples = new HeightmapSample[definition.GridSize * definition.GridSize];

            for (int row = 0; row < definition.GridSize; row++)
            {
                for (int column = 0; column < definition.GridSize; column++)
                {
                    var sample = GetSampleInPlanetSpace(definition, column, row);
                    samples[row * definition.GridSize + column] = sample;
                }
            }

            return(samples);
        }
 DoubleVector3 ConvertToPlanetSpace(HeightmapDefinition definition, DoubleVector3 sphereUnitVector, double terrainHeight)
 {
     return(sphereUnitVector * (definition.PlanetRadius + terrainHeight));
 }