Exemple #1
0
        /// <summary>
        /// Reads back a lobe texture histogram into an array
        /// </summary>
        /// <param name="_texHistogram_CPU"></param>
        /// <param name="_scatteringOrder"></param>
        /// <returns></returns>
        public static double[,] HistogramTexture2Array(Texture2D _texHistogram_CPU, int _scatteringOrder)
        {
            int scattMin = _scatteringOrder - 1;                        // Because scattering order 1 is actually stored in first slice of the texture array
            int scattMax = scattMin + 1;                                // To simulate a single scattering order
//			int	scattMax = MAX_SCATTERING_ORDER;	// To simulate all scattering orders accumulated

            int W = _texHistogram_CPU.Width;
            int H = _texHistogram_CPU.Height;

            double[,]       histogramData = new double[W, H];

            for (int scatteringOrder = scattMin; scatteringOrder < scattMax; scatteringOrder++)
            {
                PixelsBuffer Content = _texHistogram_CPU.Map(0, scatteringOrder);
                using (BinaryReader R = Content.OpenStreamRead())
                    for (int Y = 0; Y < H; Y++)
                    {
                        for (int X = 0; X < W; X++)
                        {
                            histogramData[X, Y] += W * H * R.ReadSingle();
                        }
                    }
                Content.CloseStream();
                _texHistogram_CPU.UnMap(0, scatteringOrder);
            }

            return(histogramData);
        }
        private void    FFT_CPUInOut(Complex[,] _input, Complex[,] _output, float _sign)
        {
            try {
                //////////////////////////////////////////////////////////////////////////
                // Load initial content
                PixelsBuffer           loadingBuffer = m_texBufferCPU.MapWrite(0, 0);
                System.IO.BinaryWriter W             = loadingBuffer.OpenStreamWrite();
                for (int Y = 0; Y < m_size; Y++)
                {
                    for (int X = 0; X < m_size; X++)
                    {
                        W.Write((float)_input[X, Y].r);
                        W.Write((float)_input[X, Y].i);
                    }
                }
                loadingBuffer.CloseStream();
                m_texBufferCPU.UnMap(loadingBuffer);
                m_texBufferIn.CopyFrom(m_texBufferCPU);

                //////////////////////////////////////////////////////////////////////////
                // Apply multiple shader passes
                FFT_GPUInOut(_sign);

                //////////////////////////////////////////////////////////////////////////
                // Read back content
                m_texBufferCPU.CopyFrom(m_texBufferOut);

                PixelsBuffer           resultBuffer = m_texBufferCPU.MapRead(0, 0);
                System.IO.BinaryReader R            = resultBuffer.OpenStreamRead();
                for (int Y = 0; Y < m_size; Y++)
                {
                    for (int X = 0; X < m_size; X++)
                    {
                        _output[X, Y].Set(R.ReadSingle(), R.ReadSingle());
                    }
                }
                resultBuffer.CloseStream();
                m_texBufferCPU.UnMap(resultBuffer);
            } catch (Exception _e) {
                throw new Exception("An error occurred while performing the FFT!", _e);
            }
        }
Exemple #3
0
        /// <summary>
        /// Builds the surface texture from an actual image file
        /// </summary>
        /// <param name="_textureFileName"></param>
        /// <param name="_pixelSize">Size of a pixel, assuming the maximum height is 1</param>
        public unsafe void BuildSurfaceFromTexture( string _textureFileName, float _pixelSize )
        {
            if ( m_Tex_Heightfield != null )
                m_Tex_Heightfield.Dispose();	// We will create a new one so dispose of the old one...

            // Read the bitmap
            int			W, H;
            float4[,]	Content = null;
            using ( Bitmap BM = Bitmap.FromFile( _textureFileName ) as Bitmap ) {
                W = BM.Width;
                H = BM.Height;
                Content = new float4[W,H];

                BitmapData	LockedBitmap = BM.LockBits( new Rectangle( 0, 0, W, H ), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb );

                byte	R, G, B, A;
                for ( int Y=0; Y < H; Y++ ) {
                    byte*	pScanline = (byte*) LockedBitmap.Scan0.ToPointer() + Y*LockedBitmap.Stride;
                    for ( int X=0; X < W; X++ ) {

                        // Read in shitty order
                        B = *pScanline++;
                        G = *pScanline++;
                        R = *pScanline++;
                        A = *pScanline++;

            // Use this if you really need RGBA data
            //						Content[X,Y].Set( R / 255.0f, G / 255.0f, B / 255.0f, A / 255.0f );

            // But assuming it's a height field, we only store one component into alpha
                        Content[X,Y].Set( 0, 0, 0, R / 255.0f );	// Use Red as height
                    }
                }
                BM.UnlockBits( LockedBitmap );
            }

            // Build normal (shitty version)
            float	Hx0, Hx1, Hy0, Hy1;
            float3	dNx = new float3( 2.0f * _pixelSize, 0, 0 );
            float3	dNy = new float3( 0, 2.0f * _pixelSize, 0 );
            float3	N;
            for ( int Y=0; Y < H; Y++ ) {
                int	pY = (Y+H-1) % H;
                int	nY = (Y+1) % H;
                for ( int X=0; X < W; X++ ) {
                    int	pX = (X+W-1) % W;
                    int	nX = (X+1) % W;

                    Hx0 = Content[pX,Y].w;
                    Hx1 = Content[nX,Y].w;
                    Hy0 = Content[X,pY].w;
                    Hy1 = Content[X,nY].w;

                    dNx.z = Hx1 - Hx0;
                    dNy.z = Hy0 - Hy1;	// Assuming +Y is upward

                    N = dNx.Cross( dNy );
                    N = N.Normalized;

                    Content[X,Y].x = N.x;
                    Content[X,Y].y = N.y;
                    Content[X,Y].z = N.z;
                }
            }

            // Build the texture from the array
            PixelsBuffer	Buf = new PixelsBuffer( W*H*16 );
            using ( BinaryWriter Writer = Buf.OpenStreamWrite() )
                for ( int Y=0; Y < H; Y++ )
                    for ( int X=0; X < W; X++ ) {
                        float4	pixel = Content[X,Y];
                        Writer.Write( pixel.x );
                        Writer.Write( pixel.y );
                        Writer.Write( pixel.z );
                        Writer.Write( pixel.w );
                    }
            Buf.CloseStream();

            m_Tex_Heightfield = new Texture2D( m_Device, W, H, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, false, new PixelsBuffer[] { Buf } );
        }
Exemple #4
0
        /// <summary>
        /// Builds a heightfield whose heights are distributed according to the following probability (a.k.a. the normal distribution with sigma=1 and µ=0):
        ///		p(height) = exp( -0.5*height^2 ) / sqrt(2PI)
        ///	
        ///	From "2015 Heitz - Generating Procedural Beckmann Surfaces"
        /// </summary>
        /// <param name="_roughness"></param>
        /// <remarks>Only isotropic roughness is supported</remarks>
        public void BuildBeckmannSurfaceTexture( float _roughness )
        {
            m_internalChange = true;	// Shouldn't happen but modifying the slider value may trigger a call to this function again, this flag prevents it

            // Mirror current roughness
            floatTrackbarControlBeckmannRoughness.Value = _roughness;

            // Precompute stuff that resemble a lot to the Box-Muller algorithm to generate normal distribution random values
            WMath.SimpleRNG.SetSeed( 521288629, 362436069 );
            for ( int i=0; i < m_SB_Beckmann.m.Length; i++ ) {
                double	U0 = WMath.SimpleRNG.GetUniform();
                double	U1 = WMath.SimpleRNG.GetUniform();
                double	U2 = WMath.SimpleRNG.GetUniform();

                m_SB_Beckmann.m[i].m_phase = (float) (2.0 * Math.PI * U0);	// Phase

                double	theta = 2.0 * Math.PI * U1;
                double	radius = Math.Sqrt( -Math.Log( U2 ) );
                m_SB_Beckmann.m[i].m_frequencyX = (float) (radius * Math.Cos( theta ) * _roughness);	// Frequency in X direction
                m_SB_Beckmann.m[i].m_frequencyY = (float) (radius * Math.Sin( theta ) * _roughness);	// Frequency in Y direction
            }

            m_SB_Beckmann.Write();
            m_SB_Beckmann.SetInput( 0 );

            #if true
                if ( m_Tex_Heightfield == null )
                    m_Tex_Heightfield = new Texture2D( m_Device, HEIGHTFIELD_SIZE, HEIGHTFIELD_SIZE, 1, 1, PIXEL_FORMAT.RGBA32_FLOAT, false, true, null );

                // Run the CS
                if ( m_Shader_ComputeBeckmannSurface.Use() ) {
                    m_Tex_Heightfield.SetCSUAV( 0 );
                    float	size = floatTrackbarControlBeckmannSizeFactor.Value * HEIGHTFIELD_SIZE;
            //					m_CB_ComputeBeckmann.m._Position_Size.Set( -128.0f, -128.0f, 256.0f, 256.0f );
                    m_CB_ComputeBeckmann.m._Position_Size.Set( -0.5f * size, -0.5f * size, size, size );
                    m_CB_ComputeBeckmann.m._HeightFieldResolution = HEIGHTFIELD_SIZE;
                    m_CB_ComputeBeckmann.m._SamplesCount = (uint) m_SB_Beckmann.m.Length;
                    m_CB_ComputeBeckmann.UpdateData();

                    m_Shader_ComputeBeckmannSurface.Dispatch( HEIGHTFIELD_SIZE >> 4, HEIGHTFIELD_SIZE >> 4, 1 );

                    m_Tex_Heightfield.RemoveFromLastAssignedSlotUAV();
                }
            #else	// CPU version
                PixelsBuffer	Content = new PixelsBuffer( HEIGHTFIELD_SIZE*HEIGHTFIELD_SIZE*System.Runtime.InteropServices.Marshal.SizeOf(typeof(float)) );

                double	scale = Math.Sqrt( 2.0 / N );

                // Generate heights
                float	range = 128.0f;
                float2	pos;
                float	height;
                float	minHeight = float.MaxValue, maxHeight = -float.MaxValue;
                double	accum;
                using ( BinaryWriter W = Content.OpenStreamWrite() ) {
                    for ( int Y=0; Y < HEIGHTFIELD_SIZE; Y++ ) {
                        pos.y = range * (2.0f * Y / (HEIGHTFIELD_SIZE-1) - 1.0f);
                        for ( int X=0; X < HEIGHTFIELD_SIZE; X++ ) {
                            pos.x = range * (2.0f * X / (HEIGHTFIELD_SIZE-1) - 1.0f);

            //						height = (float) WMath.SimpleRNG.GetNormal();
            //						height = (float) GenerateNormalDistributionHeight();

                            accum = 0.0;
                            for ( int i=0; i < N; i++ ) {
                                accum += Math.Cos( m_phi[i] + pos.x * m_fx[i] + pos.y * m_fy[i] );
                            }
                            height = (float) (scale * accum);

                            minHeight = Math.Min( minHeight, height );
                            maxHeight = Math.Max( maxHeight, height );

                            W.Write( height );
                        }
                    }
                }
                Content.CloseStream();

                m_Tex_Heightfield = new Texture2D( m_Device, HEIGHTFIELD_SIZE, HEIGHTFIELD_SIZE, 1, 1, PIXEL_FORMAT.R32_FLOAT, false, false, new PixelsBuffer[] { Content } );
            #endif

            m_internalChange = false;
        }