/// <summary> /// Generates a toroidally tiled noise /// </summary> private static unsafe void GenerateNoise( Texture3dData data, Noise3dTextureBuilderParameters parameters, byte* voxels ) { SimpleNoise3d sNoise = new SimpleNoise3d(); Noise noise = new Noise( ); float nW = parameters.NoiseWidth; float nH = parameters.NoiseHeight; float nD = parameters.NoiseDepth; float nX0 = parameters.NoiseX; float nY0 = parameters.NoiseY; float nZ0 = parameters.NoiseZ; float nXInc = nW / data.Width; float nYInc = nH / data.Height; float nZInc = nD / data.Depth; byte* voxel = voxels; int bytesPerVoxel = TextureFormatInfo.GetSizeInBytes( parameters.Format ); if ( bytesPerVoxel != 3 && bytesPerVoxel != 4 ) { throw new InvalidDataException( string.Format( "Unexpected voxel stride of {0} - expected either 3 or 4 from format {1}", bytesPerVoxel, parameters.Format ) ); } // Check hacked channel expectations... bool hasAlpha = TextureFormatInfo.HasAlphaChannel( parameters.Format ); float nZ = nZ0; float maxNoise = float.MinValue; float minNoise = float.MaxValue; for ( int z = 0; z < parameters.Depth; ++z, nZ += nZInc ) { float nY = nY0; for ( int y = 0; y < parameters.Height; ++y, nY += nYInc ) { float nX = nX0; for ( int x = 0; x < parameters.Width; ++x, nX += nXInc ) { switch ( parameters.GenerationType ) { case NoiseGenerationType.Grayscale : { float n = ( 1.0f + sNoise.GetTilingNoise( nX, nY, nZ, nW, nH, nD ) ) / 2; maxNoise = Math.Max( maxNoise, n ); minNoise = Math.Min( minNoise, n ); // float n = 0.5f + noise.GetNoise( nX, nY, nZ ); voxel[ 0 ] = NoiseToByte( n ); voxel[ 1 ] = voxel[ 0 ]; voxel[ 2 ] = voxel[ 0 ]; if ( hasAlpha ) { voxel[ 3 ] = voxel[ 0 ]; } break; } case NoiseGenerationType.MultiChannel : { float r = noise.GetNoise( nX, nY, nZ ); float g = noise.GetNoise( nX + nW, nY, nZ ); float b = noise.GetNoise( nX, nY + nH, nZ ); voxel[ 0 ] = NoiseToByte( r ); voxel[ 1 ] = NoiseToByte( g ); voxel[ 2 ] = NoiseToByte( b ); if ( hasAlpha ) { float a = noise.GetNoise( nX, nY, nZ + parameters.NoiseDepth ); voxel[ 3 ] = NoiseToByte( a ); } break; } case NoiseGenerationType.TilingGrayscale : { float n = GetTiledNoise( noise, nX, nY, nZ, nX0, nY0, nZ0, nW, nH, nD ); voxel[ 0 ] = NoiseToByte( n ); voxel[ 1 ] = voxel[ 0 ]; voxel[ 2 ] = voxel[ 0 ]; if ( hasAlpha ) { voxel[ 3 ] = voxel[ 0 ]; } break; } case NoiseGenerationType.TilingMultiChannel : { float r = GetTiledNoise( noise, nX, nY, nZ, nX0, nY0, nZ0, nW, nH, nD ); float g = GetTiledNoise( noise, nX + nW, nY, nZ, nX0 + nW, nY0, nZ0, nW, nH, nD ); float b = GetTiledNoise( noise, nX, nY + nH, nZ, nX0, nY0 + nH, nZ0, nW, nH, nD ); voxel[ 0 ] = NoiseToByte( r ); voxel[ 1 ] = NoiseToByte( g ); voxel[ 2 ] = NoiseToByte( b ); if ( hasAlpha ) { float a = GetTiledNoise( noise, nX, nY, nZ + nD, nX0, nY0, nZ0 + nD, nW, nH, nD ); voxel[ 3 ] = NoiseToByte( a ); } break; } case NoiseGenerationType.BigNoise : { float real = 0.5f + GetTiledNoise( noise, nX, nY, nZ, nX0, nY0, nZ0, nW, nH, nD ); float imag = 0.5f + GetTiledNoise( noise, nX + nW, nY + nH, nZ + nD, nX0, nY0, nZ0, nW, nH, nD ); // maxNoise = Math.Max( maxNoise, real ); // minNoise = Math.Min( minNoise, real ); double a = Math.PI + Math.PI * real; voxel[ 0 ] = NoiseToByte( real ); voxel[ 1 ] = NoiseToByte( imag ); voxel[ 2 ] = ( byte )Utils.Clamp( ( Math.Sin( a ) + 1 ) * 127.5, 0, 255 ); voxel[ 3 ] = ( byte )Utils.Clamp( ( Math.Cos( a ) + 1 ) * 127.5, 0, 255 ); break; } default : throw new NotSupportedException( string.Format( "Noise generation type \"{0}\" is not supported yet", parameters.GenerationType ) ); } voxel += bytesPerVoxel; } } } }
private static float GetNoise( Noise noise, float w, float h, float d, float x, float y, float z ) { return noise.GetNoise( x % w, y % h, z % d ); }
/// <summary> /// Gets a tiled noise value /// </summary> private static float GetTiledNoise( Noise noise, float x, float y, float z, float x0, float y0, float z0, float w, float h, float d ) { float orgX = x - x0; float orgY = y - y0; float orgZ = z - z0; float tilX = x - w; float tilY = y - h; float tilZ = z - d; float invX = w - orgX; float invY = h - orgY; float invZ = d - orgZ; float nX0Y0Z0 = GetNoise( noise, w, h, d, x, y, z ) * invX * invY * invZ; float nX0Y1Z0 = GetNoise( noise, w, h, d, x, tilY, z ) * invX * orgY * invZ; float nX0Y0Z1 = GetNoise( noise, w, h, d, x, y, tilZ ) * invX * invY * orgZ; float nX0Y1Z1 = GetNoise( noise, w, h, d, x, tilY, tilZ ) * invX * orgY * orgZ; float nX1Y0Z0 = GetNoise( noise, w, h, d, tilX, y, z ) * orgX * invY * invZ; float nX1Y1Z0 = GetNoise( noise, w, h, d, tilX, tilY, z ) * orgX * orgY * invZ; float nX1Y0Z1 = GetNoise( noise, w, h, d, tilX, y, tilZ ) * orgX * invY * orgZ; float nX1Y1Z1 = GetNoise( noise, w, h, d, tilX, tilY, tilZ ) * orgX * orgY * orgZ; return ( nX0Y0Z0 + nX0Y1Z0 + nX0Y0Z1 + nX0Y1Z1 + nX1Y0Z0 + nX1Y1Z0 + nX1Y0Z1 + nX1Y1Z1 ) / ( w * h * d ); }
/// <summary> /// Forces the next Build() call to create a new height map /// </summary> public void UpdateHeights( ) { m_Noise = new Noise( TimeSeed ); m_HeightMap = null; m_LightMap = null; }