Example #1
0
        public OutputPanelHammersley(IContainer container)
        {
            container.Add(this);

            InitializeComponent();

            WMath.Hammersley QRNG = new WMath.Hammersley();
            double[,]               Sequence = QRNG.BuildSequence(SAMPLES_COUNT, 2);
            for (int SampleIndex = 0; SampleIndex < SAMPLES_COUNT; SampleIndex++)
            {
                float Angle  = 2.0f * (float)Math.PI * (float)Sequence[SampleIndex, 0];
                float Radius = (float)Math.Sqrt(Sequence[SampleIndex, 1]);                      // Uniform
//				float	Radius = (float) Sequence[SampleIndex,1];

                m_Samples[SampleIndex] = new WMath.Vector2D(Radius * (float)Math.Cos(Angle), Radius * (float)Math.Sin(Angle));
            }

            string Format = "const uint		SHADOW_SAMPLES_COUNT = "+ SAMPLES_COUNT + ";\r\n"
                            + "const float2	SamplesOffset[SHADOW_SAMPLES_COUNT] = {\r\n";

            for (int SampleIndex = 0; SampleIndex < SAMPLES_COUNT; SampleIndex++)
            {
                Format += "	float2( " + m_Samples[SampleIndex].x + ", " + m_Samples[SampleIndex].y + " ),\r\n";
            }

            Format += "};\r\n\r\n";

            OnSizeChanged(EventArgs.Empty);
        }
        public OutputPanelHammersley( IContainer container )
        {
            container.Add( this );

            InitializeComponent();

            WMath.Hammersley	QRNG = new WMath.Hammersley();
            double[,]		Sequence = QRNG.BuildSequence( SAMPLES_COUNT, 2 );
            for ( int SampleIndex=0; SampleIndex < SAMPLES_COUNT; SampleIndex++ )
            {
                float	Angle = 2.0f * (float) Math.PI * (float) Sequence[SampleIndex,0];
                float	Radius = (float) Math.Sqrt( Sequence[SampleIndex,1] );	// Uniform
            //				float	Radius = (float) Sequence[SampleIndex,1];

                m_Samples[SampleIndex] = new WMath.Vector2D( Radius * (float) Math.Cos( Angle ), Radius * (float) Math.Sin( Angle ) );
            }

            string	Format = "const uint		SHADOW_SAMPLES_COUNT = " + SAMPLES_COUNT + ";\r\n"
                           + "const float2	SamplesOffset[SHADOW_SAMPLES_COUNT] = {\r\n";

            for ( int SampleIndex=0; SampleIndex < SAMPLES_COUNT; SampleIndex++ )
            {
                Format += "	float2( " + m_Samples[SampleIndex].x + ", " + m_Samples[SampleIndex].y + " ),\r\n";
            }

            Format += "};\r\n\r\n";

            OnSizeChanged( EventArgs.Empty );
        }
Example #3
0
        private void    GenerateRays(int _RaysCount, float _MaxConeAngle, RendererManaged.StructuredBuffer <RendererManaged.float3> _Target)
        {
            _RaysCount = Math.Min(MAX_THREADS, _RaysCount);

            WMath.Hammersley hammersley = new WMath.Hammersley();
            double[,]                       sequence = hammersley.BuildSequence(_RaysCount, 2);
            WMath.Vector[] rays = hammersley.MapSequenceToSphere(sequence, 0.5f * _MaxConeAngle);
            for (int RayIndex = 0; RayIndex < _RaysCount; RayIndex++)
            {
                WMath.Vector ray = rays[RayIndex];

//              // Scale the ray so we ensure to always walk at least a texel in the texture
//              float	SinTheta = (float) Math.Sqrt( 1.0 - ray.y * ray.y );
//              float	LengthFactor = 1.0f / SinTheta;
//              ray *= LengthFactor;

                _Target.m[RayIndex].Set(ray.x, -ray.z, ray.y);
            }

            _Target.Write();
        }
Example #4
0
        /// <summary>
        /// Following the mathematica notebook found in "D:\Docs\Computer Graphics\Volumetric, Clouds, Participating Medium, Light Scattering, Translucency\2005 Sun, Ramamoorthi.nb"
        ///  this routine generates the tables representing the integral of function Gn depending on 2 parameters.
        /// Several of these tables are generated for different exponents n, the goal is then to find an approximation to generated these tables from an analytical expression.
        /// </summary>
        void    BuildSurfaceRadianceIntegrals()
        {
            BuildPreciseF();

//			string	ResultsPath = @"D:\Docs\Computer Graphics\Volumetric, Clouds, Participating Medium, Light Scattering, Translucency";
            string ResultsPath = @".\";

            const int TABLE_SIZE = 64;

            const int IMPORTANCE_SAMPLES_COUNT = 4096;

            double[,]               QRNG = new WMath.Hammersley().BuildSequence(IMPORTANCE_SAMPLES_COUNT, 2);

            for (int TableIndex = 0; TableIndex < 1; TableIndex++)
            {
                float Exponent = 1.0f + TableIndex;
                double[,]       Table = new double[TABLE_SIZE, TABLE_SIZE];

                // Compute the integral for each parameter
                for (int Y = 0; Y < TABLE_SIZE; Y++)
                {
                    double Theta_s    = 0.5 * Math.PI * Y / (TABLE_SIZE - 1);                           // V in [0,PI/2]
                    double CosTheta_s = Math.Sin(Theta_s);
                    double SinTheta_s = Math.Cos(Theta_s);

                    for (int X = 0; X < TABLE_SIZE; X++)
                    {
                        double Tsp = MAX_U * X / (TABLE_SIZE - 1);                                                      // U in [0,10]

                        // Use importance sampling
                        double Sum = 0.0;
                        for (int SampleIndex = 0; SampleIndex < IMPORTANCE_SAMPLES_COUNT; SampleIndex++)
                        {
                            double X0      = QRNG[SampleIndex, 0];
                            double X1      = QRNG[SampleIndex, 1];
                            double Phi_i   = 2.0 * Math.PI * X0;
                            double Theta_i = Math.Asin(Math.Pow(X1, 1.0 / (1.0 + Exponent)));                                                  // Assuming we're integrating a cos^n(theta)

                            double CosGamma = Math.Cos(Theta_i) * Math.Cos(Theta_s) + Math.Sin(Theta_i) * Math.Sin(Theta_s) * Math.Cos(Phi_i); // Angle between the incoming ray and the source
                            double SinGamma = Math.Sqrt(1 - CosGamma * CosGamma);
                            double Gamma    = Math.Acos(CosGamma);

//                          double	x0 = Math.Sin(Theta_i) * Math.Sin( Phi_i );
//                          double	y0 = Math.Cos(Theta_i);
//                          double	z0 = Math.Sin(Theta_i) * Math.Cos( Phi_i );
//                          double	x1 = SinTheta_s;
//                          double	y1 = CosTheta_s;
//                          Gamma = Math.Acos( x0*x1 + y0*y1 );
//
//                          double	CosGamma = Math.Cos( Gamma );
//                          double	SinGamma = Math.Sin( Gamma );

                            double Extinction = Math.Exp(-Tsp * CosGamma);
                            double DeltaF     = F_Table(Tsp * SinGamma, HALF_PI) - F_Table(Tsp * SinGamma, 0.5 * Gamma);
                            double Term       = (Extinction / SinGamma) * DeltaF;
                            if (double.IsNaN(Term))
                            {
                                throw new Exception();
                            }

                            Sum += Term;
                        }
                        Sum /= IMPORTANCE_SAMPLES_COUNT;


/*						// Use standard numerical integration
 *                                              const double	dPhi = 2.0 * Math.PI / 160;
 *                                              const double	dTheta = 0.5 * Math.PI / 40;
 *
 *                                              double	Sum = 0.0;
 *                                              for ( int ThetaIndex=0; ThetaIndex < 40; ThetaIndex++ ) {
 *                                                      double	Theta_i = 0.5 * Math.PI * (0.5+ThetaIndex) / 40;
 *                                                      double	SolidAngle = Math.Sin( Theta_i ) * dPhi * dTheta;
 *
 *                                                      for ( int PhiIndex=0; PhiIndex < 160; PhiIndex++ ) {
 *                                                              double	Phi_i = Math.PI * PhiIndex / 160.0;
 *
 *                                                              double	CosGamma = Math.Cos( Theta_i )*CosTheta_s + Math.Sin( Theta_i )*SinTheta_s*Math.Cos( Phi_i );	// Angle between the incoming ray and the source
 *
 * //                               double	x0 = Math.Sin(Theta_i)*Math.Cos(Phi_i);
 * //                               double	y0 = Math.Cos(Theta_i);
 * //                               double	z0 = Math.Sin(Theta_i)*Math.Sin(Phi_i);
 * //                               double	x1 = SinTheta_s;
 * //                               double	y1 = CosTheta_s;
 * //                               double	CosGamma = x0*x1 + y0*y1;
 *
 *                                                              double	SinGamma = Math.Sqrt( 1 - CosGamma*CosGamma );
 *                                                              double	Gamma = Math.Acos( CosGamma );
 *
 *                                                              double	Extinction = Math.Exp( -Tsp * CosGamma );
 *                                                              double	DeltaF = F_Table( Tsp * SinGamma, HALF_PI ) - F_Table( Tsp * SinGamma, 0.5 * Gamma );
 *                                                              double	Term = (Extinction / SinGamma) * DeltaF;
 *                                                              if ( double.IsNaN( Term ) )
 *                                                                      throw new Exception();
 *
 *                                                              Sum += Term * Math.Pow( Math.Cos( Theta_i ), Exponent ) * SolidAngle;
 *                                                      }
 *                                              }
 */
                        Table[X, Y] = Sum;
                    }
                }

                // Write the result
                FileInfo TargetFile = new FileInfo(Path.Combine(ResultsPath, "TableG" + TableIndex + ".double"));
                using (FileStream S = TargetFile.Create())
                    using (BinaryWriter W = new BinaryWriter(S)) {
                        for (int Y = 0; Y < TABLE_SIZE; Y++)
                        {
                            for (int X = 0; X < TABLE_SIZE; X++)
                            {
                                W.Write(Table[X, Y]);
                            }
                        }
                    }
            }
        }
Example #5
0
        /// <summary>
        /// Performs a ray-tracing of the surface
        /// Outputs resulting directions into a texture then performs a histogram
        /// 
        /// The surface is assigned a beam of photons, one for each texel of the heightfield texture
        /// At each iteration, the whole beam is offset a little using a Hammersley sequence that guarantees
        ///  we end up ray-tracing the entire surface finely (hopefully, the full surface can be traced using enough terationsi)
        /// </summary>
        /// <param name="_roughness">Surface roughness</param>
        /// <param name="_albedo">Surface albedo for diffuse or F0 for dielectrics</param>
        /// <param name="_surfaceType">Type of surface we're simulating</param>
        /// <param name="_theta">Vertical angle of incidence</param>
        /// <param name="_phi">Azimuthal angle of incidence</param>
        /// <param name="_iterationsCount">Amount of iterations of beam tracing</param>
        public void RayTraceSurface( float _roughness, float _albedoF0, SURFACE_TYPE _surfaceType, float _theta, float _phi, int _iterationsCount )
        {
            float	sinTheta = (float) Math.Sin( _theta );
            float	cosTheta = (float) Math.Cos( _theta );
            float	sinPhi = (float) Math.Sin( _phi );
            float	cosPhi = (float) Math.Cos( _phi );

            m_lastComputedDirection.Set( -sinTheta * cosPhi, -sinTheta * sinPhi, -cosTheta );	// Minus sign because we need the direction pointing TOWARD the surface (i.e. z < 0)
            m_lastComputedRoughness = _roughness;
            m_lastComputedAlbedo = _albedoF0;
            m_lastComputedIOR = Fresnel_IORFromF0( _albedoF0 );
            m_lastComputedSurfaceType = _surfaceType;

            m_lastComputedHistogramIterationsCount = _iterationsCount;

            m_CB_RayTrace.m._Direction = m_lastComputedDirection;
            m_CB_RayTrace.m._Roughness = m_lastComputedRoughness;
            m_CB_RayTrace.m._Albedo = m_lastComputedAlbedo;
            m_CB_RayTrace.m._IOR = m_lastComputedIOR;

            m_Tex_OutgoingDirections_Reflected.RemoveFromLastAssignedSlots();
            m_Tex_OutgoingDirections_Transmitted.RemoveFromLastAssignedSlots();
            m_Tex_LobeHistogram_Reflected.RemoveFromLastAssignedSlots();
            m_Tex_LobeHistogram_Transmitted.RemoveFromLastAssignedSlots();

            m_Device.Clear( m_Tex_LobeHistogram_Reflected_Decimal, float4.Zero );	// Clear counters
            m_Device.Clear( m_Tex_LobeHistogram_Reflected_Integer, float4.Zero );
            m_Device.Clear( m_Tex_LobeHistogram_Transmitted_Decimal, float4.Zero );	// Clear counters
            m_Device.Clear( m_Tex_LobeHistogram_Transmitted_Integer, float4.Zero );

            WMath.Hammersley	pRNG = new WMath.Hammersley();
            double[,]			sequence = pRNG.BuildSequence( _iterationsCount, 2 );
            for ( int iterationIndex=0; iterationIndex < _iterationsCount; iterationIndex++ ) {
                // 1] Ray-trace surface
                switch ( m_lastComputedSurfaceType ) {
                    case SURFACE_TYPE.CONDUCTOR:
                        if ( m_Shader_RayTraceSurface_Conductor.Use() ) {
                            // Update trace offset
                            m_CB_RayTrace.m._Offset.Set( (float) sequence[iterationIndex,0], (float) sequence[iterationIndex,1] );
                            m_CB_RayTrace.UpdateData();

                            m_Device.Clear( m_Tex_OutgoingDirections_Reflected, float4.Zero );	// Clear target directions and weights

                            m_Tex_Heightfield.SetCS( 0 );
                            m_Tex_Random.SetCS( 1 );
                            m_Tex_OutgoingDirections_Reflected.SetCSUAV( 0 );	// New target buffer where to accumulate

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

                            m_Tex_OutgoingDirections_Reflected.RemoveFromLastAssignedSlotUAV();
                        }

                        // 2] Accumulate into target histogram
                        if ( m_Shader_AccumulateOutgoingDirections.Use() ) {
                            m_Tex_OutgoingDirections_Reflected.SetCS( 0 );
                            m_Tex_LobeHistogram_Reflected_Decimal.SetCSUAV( 0 );
                            m_Tex_LobeHistogram_Reflected_Integer.SetCSUAV( 1 );

                            m_Shader_AccumulateOutgoingDirections.Dispatch( HEIGHTFIELD_SIZE >> 4, HEIGHTFIELD_SIZE >> 4, MAX_SCATTERING_ORDER );

             							m_Tex_LobeHistogram_Reflected_Decimal.RemoveFromLastAssignedSlotUAV();
             							m_Tex_LobeHistogram_Reflected_Integer.RemoveFromLastAssignedSlotUAV();
                            m_Tex_OutgoingDirections_Reflected.RemoveFromLastAssignedSlots();
                        }
                        break;

                    case SURFACE_TYPE.DIELECTRIC:
                        if ( m_Shader_RayTraceSurface_Dielectric.Use() ) {
                            // Update trace offset
                            m_CB_RayTrace.m._Offset.Set( (float) sequence[iterationIndex,0], (float) sequence[iterationIndex,1] );
                            m_CB_RayTrace.UpdateData();

                            m_Device.Clear( m_Tex_OutgoingDirections_Reflected, float4.Zero );		// Clear target directions and weights
                            m_Device.Clear( m_Tex_OutgoingDirections_Transmitted, float4.Zero );	// Clear target directions and weights

                            m_Tex_Heightfield.SetCS( 0 );
                            m_Tex_Random.SetCS( 1 );
                            m_Tex_OutgoingDirections_Reflected.SetCSUAV( 0 );	// New target buffer where to accumulate
                            m_Tex_OutgoingDirections_Transmitted.SetCSUAV( 1 );	// New target buffer where to accumulate

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

                            m_Tex_OutgoingDirections_Reflected.RemoveFromLastAssignedSlotUAV();
                            m_Tex_OutgoingDirections_Transmitted.RemoveFromLastAssignedSlotUAV();
                        }

                        // 2] Accumulate into target histogram
                        if ( m_Shader_AccumulateOutgoingDirections.Use() ) {
                            // Accumulated reflections
                            m_Tex_OutgoingDirections_Reflected.SetCS( 0 );
                            m_Tex_LobeHistogram_Reflected_Decimal.SetCSUAV( 0 );
                            m_Tex_LobeHistogram_Reflected_Integer.SetCSUAV( 1 );

                            m_Shader_AccumulateOutgoingDirections.Dispatch( HEIGHTFIELD_SIZE >> 4, HEIGHTFIELD_SIZE >> 4, MAX_SCATTERING_ORDER );

             							m_Tex_LobeHistogram_Reflected_Decimal.RemoveFromLastAssignedSlotUAV();
             							m_Tex_LobeHistogram_Reflected_Integer.RemoveFromLastAssignedSlotUAV();
                            m_Tex_OutgoingDirections_Reflected.RemoveFromLastAssignedSlots();

                            // Accumulated transmissions
                            m_Tex_OutgoingDirections_Transmitted.SetCS( 0 );
                            m_Tex_LobeHistogram_Transmitted_Decimal.SetCSUAV( 0 );
                            m_Tex_LobeHistogram_Transmitted_Integer.SetCSUAV( 1 );

                            m_Shader_AccumulateOutgoingDirections.Dispatch( HEIGHTFIELD_SIZE >> 4, HEIGHTFIELD_SIZE >> 4, MAX_SCATTERING_ORDER );

             							m_Tex_LobeHistogram_Transmitted_Decimal.RemoveFromLastAssignedSlotUAV();
             							m_Tex_LobeHistogram_Transmitted_Integer.RemoveFromLastAssignedSlotUAV();
                            m_Tex_OutgoingDirections_Transmitted.RemoveFromLastAssignedSlots();
                        }
                        break;

                    case SURFACE_TYPE.DIFFUSE:
                        if ( m_Shader_RayTraceSurface_Diffuse.Use() ) {
                            // Update trace offset
                            m_CB_RayTrace.m._Offset.Set( (float) sequence[iterationIndex,0], (float) sequence[iterationIndex,1] );
                            m_CB_RayTrace.UpdateData();

                            m_Device.Clear( m_Tex_OutgoingDirections_Reflected, float4.Zero );	// Clear target directions and weights

                            m_Tex_Heightfield.SetCS( 0 );
                            m_Tex_Random.SetCS( 1 );
                            m_Tex_OutgoingDirections_Reflected.SetCSUAV( 0 );	// New target buffer where to accumulate

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

                            m_Tex_OutgoingDirections_Reflected.RemoveFromLastAssignedSlotUAV();
                        }

                        // 2] Accumulate into target histogram
                        if ( m_Shader_AccumulateOutgoingDirections.Use() ) {
                            m_Tex_OutgoingDirections_Reflected.SetCS( 0 );
                            m_Tex_LobeHistogram_Reflected_Decimal.SetCSUAV( 0 );
                            m_Tex_LobeHistogram_Reflected_Integer.SetCSUAV( 1 );

                            m_Shader_AccumulateOutgoingDirections.Dispatch( HEIGHTFIELD_SIZE >> 4, HEIGHTFIELD_SIZE >> 4, MAX_SCATTERING_ORDER );

             							m_Tex_LobeHistogram_Reflected_Decimal.RemoveFromLastAssignedSlotUAV();
             							m_Tex_LobeHistogram_Reflected_Integer.RemoveFromLastAssignedSlotUAV();
                            m_Tex_OutgoingDirections_Reflected.RemoveFromLastAssignedSlots();
                        }
                        break;

                    default:
                        throw new Exception( "Not implemented!" );
                }
            }

            // 3] Finalize
            if ( m_Shader_FinalizeOutgoingDirections.Use() ) {
                m_Tex_LobeHistogram_Reflected_Decimal.SetCSUAV( 0 );
             				m_Tex_LobeHistogram_Reflected_Integer.SetCSUAV( 1 );
                m_Tex_LobeHistogram_Reflected.SetCSUAV( 2 );

                m_CB_Finalize.m._IterationsCount = (uint) _iterationsCount;
                m_CB_Finalize.UpdateData();

                m_Shader_FinalizeOutgoingDirections.Dispatch( (LOBES_COUNT_PHI + 15) >> 4, (LOBES_COUNT_THETA + 15) >> 4, MAX_SCATTERING_ORDER );

             				m_Tex_LobeHistogram_Reflected_Decimal.RemoveFromLastAssignedSlotUAV();
             				m_Tex_LobeHistogram_Reflected_Integer.RemoveFromLastAssignedSlotUAV();
                m_Tex_LobeHistogram_Reflected.RemoveFromLastAssignedSlotUAV();

                if ( m_lastComputedSurfaceType == SURFACE_TYPE.DIELECTRIC ) {
                    // Finalize transmitted
                    m_Tex_LobeHistogram_Transmitted_Decimal.SetCSUAV( 0 );
             					m_Tex_LobeHistogram_Transmitted_Integer.SetCSUAV( 1 );
                    m_Tex_LobeHistogram_Transmitted.SetCSUAV( 2 );

                    m_Shader_FinalizeOutgoingDirections.Dispatch( (LOBES_COUNT_PHI + 15) >> 4, (LOBES_COUNT_THETA + 15) >> 4, MAX_SCATTERING_ORDER );

             					m_Tex_LobeHistogram_Transmitted_Decimal.RemoveFromLastAssignedSlotUAV();
             					m_Tex_LobeHistogram_Transmitted_Integer.RemoveFromLastAssignedSlotUAV();
                    m_Tex_LobeHistogram_Transmitted.RemoveFromLastAssignedSlotUAV();
                } else {
                    m_Device.Clear( m_Tex_LobeHistogram_Transmitted, float4.Zero );
                }
            }
        }
Example #6
0
		void	ComputeBRDFIntegralImportanceSampling( System.IO.FileInfo _TableFileName0, System.IO.FileInfo _TableFileName1, int _TableSize ) {

			const int		SAMPLES_COUNT = 1024;

			double[,]		Table0 = new double[_TableSize,_TableSize];
			double[,]		Table1 = new double[_TableSize,_TableSize];

			WMath.Hammersley	QRNG = new WMath.Hammersley();
			double[,]			Sequence = QRNG.BuildSequence( SAMPLES_COUNT, 2 );

			float3	View = new float3();
			float3	Light = new float3();
			float3	Half = new float3();
			for ( int Y=0; Y < _TableSize; Y++ ) {
				double	Roughness = Math.Max( 0.01f, (float) Y / (_TableSize-1) );


//Roughness = Math.Pow( 1.0 - Roughness, 4.0 );


				double	r2 = Roughness*Roughness;

				for ( int X=0; X < _TableSize; X++ ) {
					float	CosThetaView = (float) (1+X) / _TableSize;
					float	SinThetaView = (float) Math.Sqrt( 1.0f - CosThetaView*CosThetaView );
					View.x = SinThetaView;
					View.y = CosThetaView;
					View.z = 0.0f;

					double	SumA = 0.0;
					double	SumB = 0.0;
					for ( int SampleIndex=0; SampleIndex < SAMPLES_COUNT; SampleIndex++ ) {

						double	X0 = Sequence[SampleIndex,0];
						double	X1 = Sequence[SampleIndex,1];

						double	PhiH = 2.0 * Math.PI * X0;

						// WARD
						double	ThetaH = Math.Atan( -r2 * Math.Log( 1.0 - X1 ) );
						double	CosThetaH = Math.Cos( ThetaH );
						double	SinThetaH = Math.Sin( ThetaH );

// 						// GGX
// 						double	a = r2;
// 						double	CosThetaH = Math.Sqrt( (1.0 - X1) / (1.0 + (a*a - 1.0) * X1 ) );
// 						double	SinThetaH = Math.Sqrt( 1.0f - CosThetaH * CosThetaH );


						double	CosPhiH = Math.Cos( PhiH );
						double	SinPhiH = Math.Sin( PhiH );

						Half.x = (float) (SinPhiH * SinThetaH);
						Half.y = (float) CosThetaH;
						Half.z = (float) (CosPhiH * SinThetaH);

 						Light = 2.0f * View.Dot( Half ) * Half - View;	// Light is on the other size of the Half vector...


// Intuitively, we should have the same result if we sampled around the reflected view direction
// 						float3	ReflectedView = 2.0f * View.Dot( float3.UnitY ) * float3.UnitY - View;
// 						float3	OrthoY = ReflectedView.Cross( float3.UnitZ ).Normalized;
// 						float3	OrthoX = float3.UnitZ;
//  						Light = Half.x * OrthoX + Half.y * ReflectedView + Half.z * OrthoY;
// 
// 						Half = (View + Light).Normalized;


						if ( Light.y <= 0 )
							continue;

						double	HoN = Half.y;
						double	HoN2 = HoN*HoN;
						double	HoV = Half.Dot( View );
//						float	HoV = Half.x * View.x + Half.y * View.y;	// We know that Z=0 here...
						double	HoL = Half.Dot( Light );
						double	NoL = Light.y;
						double	NoV = View.y;

 						// Apply sampling weight for correct distribution
 						double	SampleWeight = 2.0 / (1.0 + View.y / Light.y);
 						double	BRDF = SampleWeight;





// Try with Unreal's GGX & Smith G term to see if we get the same thing
// 
// 	// GGX NDF
// // double	alpha = r2;
// // double	alpha2 = alpha*alpha;
// // double	D = alpha2 / (Math.PI * Math.Pow( HoN2*(alpha2 - 1.0) + 1.0, 2.0 ));
// 
// 	// Smith masking/shadowing
// double	k = (Roughness + 1)*(Roughness + 1) / 8.0;
// double	Gl = NoL / (NoL * (1-k) + k);
// double	Gv = NoV / (NoV * (1-k) + k);
// double	G = Gl * Gv;
// 
// //double	BRDF = G / (4.0 * View.y);
// //double	BRDF = G * HoV / (HoN * NoV);
// double	BRDF = NoL * GSmith( Roughness, NoV, NoL ) * 4.0f * HoV / HoN;




						// Compute Fresnel terms
						double	Schlick = 1.0 - HoV;
						double	Schlick5 = Schlick * Schlick;
								Schlick5 *= Schlick5 * Schlick;

						double	FresnelA = 1.0f - Schlick5;
						double	FresnelB = Schlick5;

//FresnelA = FresnelB = 1.0;

						SumA += FresnelA * BRDF;
						SumB += FresnelB * BRDF;
					}

// 					SumA *= 1.0 / (SAMPLES_COUNT * Math.PI * r2);
// 					SumB *= 1.0 / (SAMPLES_COUNT * Math.PI * r2);

					SumA /= SAMPLES_COUNT;
					SumB /= SAMPLES_COUNT;

					// For few samples, the sum goes over 1 because we have poor solid angle sampling resolution...
// 					SumA = Math.Min( 1.0, SumA );
// 					SumB = Math.Min( 1.0, SumB );

					Table0[X,Y] = SumA;
					Table1[X,Y] = SumB;
				}
			}

			// Write table 0
			using ( System.IO.FileStream S = _TableFileName0.Create() )
				using ( System.IO.BinaryWriter W = new System.IO.BinaryWriter( S ) )
					for ( int Y=0; Y < _TableSize; Y++ ) {
						for ( int X=0; X < _TableSize; X++ )
							W.Write( Table0[X,Y] );
						}

			// Write table 1
			using ( System.IO.FileStream S = _TableFileName1.Create() )
				using ( System.IO.BinaryWriter W = new System.IO.BinaryWriter( S ) )
					for ( int Y=0; Y < _TableSize; Y++ ) {
						for ( int X=0; X < _TableSize; X++ )
							W.Write( Table1[X,Y] );
						}
		}
Example #7
0
        /// <summary>
        /// Following the mathematica notebook found in "D:\Docs\Computer Graphics\Volumetric, Clouds, Participating Medium, Light Scattering, Translucency\2005 Sun, Ramamoorthi.nb"
        ///  this routine generates the tables representing the integral of function Gn depending on 2 parameters.
        /// Several of these tables are generated for different exponents n, the goal is then to find an approximation to generated these tables from an analytical expression.
        /// </summary>
        void BuildSurfaceRadianceIntegrals()
        {
            BuildPreciseF();

            //			string	ResultsPath = @"D:\Docs\Computer Graphics\Volumetric, Clouds, Participating Medium, Light Scattering, Translucency";
            string	ResultsPath = @".\";

            const int		TABLE_SIZE = 64;

            const int		IMPORTANCE_SAMPLES_COUNT = 4096;
            double[,]		QRNG = new WMath.Hammersley().BuildSequence( IMPORTANCE_SAMPLES_COUNT, 2 );

            for ( int TableIndex=0; TableIndex < 1; TableIndex++ ) {
                float		Exponent = 1.0f + TableIndex;
                double[,]	Table = new double[TABLE_SIZE,TABLE_SIZE];

                // Compute the integral for each parameter
                for ( int Y=0; Y < TABLE_SIZE; Y++ )
                {
                    double	Theta_s = 0.5 * Math.PI * Y / (TABLE_SIZE-1);		// V in [0,PI/2]
                    double	CosTheta_s = Math.Sin(Theta_s);
                    double	SinTheta_s = Math.Cos(Theta_s);

                    for ( int X=0; X < TABLE_SIZE; X++ )
                    {
                        double	Tsp = MAX_U * X / (TABLE_SIZE-1);				// U in [0,10]

                        // Use importance sampling
                        double	Sum = 0.0;
                        for ( int SampleIndex=0; SampleIndex < IMPORTANCE_SAMPLES_COUNT; SampleIndex++ ) {

                            double	X0 = QRNG[SampleIndex,0];
                            double	X1 = QRNG[SampleIndex,1];
                            double	Phi_i = 2.0 * Math.PI * X0;
                            double	Theta_i = Math.Asin( Math.Pow( X1, 1.0 / (1.0 + Exponent) ) );	// Assuming we're integrating a cos^n(theta)

                            double	CosGamma = Math.Cos( Theta_i )*Math.Cos( Theta_s ) + Math.Sin( Theta_i )*Math.Sin( Theta_s )*Math.Cos( Phi_i );	// Angle between the incoming ray and the source
                            double	SinGamma = Math.Sqrt( 1 - CosGamma*CosGamma );
                            double	Gamma = Math.Acos( CosGamma );

            // 							double	x0 = Math.Sin(Theta_i) * Math.Sin( Phi_i );
            // 							double	y0 = Math.Cos(Theta_i);
            // 							double	z0 = Math.Sin(Theta_i) * Math.Cos( Phi_i );
            // 							double	x1 = SinTheta_s;
            // 							double	y1 = CosTheta_s;
            // 							Gamma = Math.Acos( x0*x1 + y0*y1 );
            //
            // 							double	CosGamma = Math.Cos( Gamma );
            // 							double	SinGamma = Math.Sin( Gamma );

                            double	Extinction = Math.Exp( -Tsp * CosGamma );
                            double	DeltaF = F_Table( Tsp * SinGamma, HALF_PI ) - F_Table( Tsp * SinGamma, 0.5 * Gamma );
                            double	Term = (Extinction / SinGamma) * DeltaF;
                            if ( double.IsNaN( Term ) )
                                throw new Exception();

                            Sum += Term;
                        }
                        Sum /= IMPORTANCE_SAMPLES_COUNT;

            /*						// Use standard numerical integration
                        const double	dPhi = 2.0 * Math.PI / 160;
                        const double	dTheta = 0.5 * Math.PI / 40;

                        double	Sum = 0.0;
                        for ( int ThetaIndex=0; ThetaIndex < 40; ThetaIndex++ ) {
                            double	Theta_i = 0.5 * Math.PI * (0.5+ThetaIndex) / 40;
                            double	SolidAngle = Math.Sin( Theta_i ) * dPhi * dTheta;

                            for ( int PhiIndex=0; PhiIndex < 160; PhiIndex++ ) {
                                double	Phi_i = Math.PI * PhiIndex / 160.0;

             								double	CosGamma = Math.Cos( Theta_i )*CosTheta_s + Math.Sin( Theta_i )*SinTheta_s*Math.Cos( Phi_i );	// Angle between the incoming ray and the source

            // 								double	x0 = Math.Sin(Theta_i)*Math.Cos(Phi_i);
            // 								double	y0 = Math.Cos(Theta_i);
            // 								double	z0 = Math.Sin(Theta_i)*Math.Sin(Phi_i);
            // 								double	x1 = SinTheta_s;
            // 								double	y1 = CosTheta_s;
            // 								double	CosGamma = x0*x1 + y0*y1;

                                double	SinGamma = Math.Sqrt( 1 - CosGamma*CosGamma );
                                double	Gamma = Math.Acos( CosGamma );

                                double	Extinction = Math.Exp( -Tsp * CosGamma );
                                double	DeltaF = F_Table( Tsp * SinGamma, HALF_PI ) - F_Table( Tsp * SinGamma, 0.5 * Gamma );
                                double	Term = (Extinction / SinGamma) * DeltaF;
                                if ( double.IsNaN( Term ) )
                                    throw new Exception();

                                Sum += Term * Math.Pow( Math.Cos( Theta_i ), Exponent ) * SolidAngle;
                            }
                        }
            */
                        Table[X,Y] = Sum;
                    }
                }

                // Write the result
                FileInfo	TargetFile = new FileInfo( Path.Combine( ResultsPath, "TableG"+TableIndex+".double" ) );
                using ( FileStream S = TargetFile.Create() )
                    using ( BinaryWriter W = new BinaryWriter( S ) ) {
                        for ( int Y=0; Y < TABLE_SIZE; Y++ )
                            for ( int X=0; X < TABLE_SIZE; X++ )
                                W.Write( Table[X,Y] );
                    }
            }
        }