public Plane Set(float3 _p0, float3 _p1, float3 _p2) { // Compute two vectors from the three points float3 v0 = _p1 - _p0, v1 = _p2 - _p0; // Compute the normal to the plane n = v0.Cross(v1); n.Normalize(); d = -_p0.Dot(n); return(this); }
// Helpers // Intersection between a plane and a ray public bool Intersect(Ray _Ray, ref float3 _intersection) { float fGradient = n.Dot(_Ray.Aim); if ((float)System.Math.Abs(fGradient) < float.Epsilon) { return(false); // It cannot hit! (or very far away at least!) } _Ray.Length = (-d - _Ray.Pos.Dot(n)) / fGradient; _intersection = _Ray.GetHitPos(); return(true); }
// From http://www.iquilezles.org/www/articles/noacos/noacos.htm public float3x3 MakeRot(float3 _from, float3 _to) { float3 v = _from.Cross(_to); float c = _from.Dot(_to); float k = 1.0f / (1.0f + c); m[0, 0] = v.x * v.x * k + c; m[0, 1] = v.x * v.y * k + v.z; m[0, 2] = v.x * v.z * k - v.y; m[1, 0] = v.y * v.x * k - v.z; m[1, 1] = v.y * v.y * k + c; m[1, 2] = v.y * v.z * k + v.x; m[2, 0] = v.z * v.x * k + v.y; m[2, 1] = v.z * v.y * k - v.x; m[2, 2] = v.z * v.z * k + c; return(this); }
public float Distance( float3 _p ) { return _p.Dot(n) + d; }
public Plane Set( float3 _p0, float3 _p1, float3 _p2 ) { // Compute two vectors from the three points float3 v0 = _p1 - _p0, v1 = _p2 - _p0; // Compute the normal to the plane n = v0.Cross( v1 ); n.Normalize(); d = -_p0.Dot(n); return this; }
public Plane Set( float3 _p, float3 _n ) { n = _n; d = -_p.Dot( n ); return this; }
public float Distance(float3 _p) { return(_p.Dot(n) + d); }
public Plane Set(float3 _p, float3 _n) { n = _n; d = -_p.Dot(n); return(this); }
public Ray Bend ( float3 _Axis, float _fBendFactor ) { m_Aim += _fBendFactor * m_Aim.Dot(_Axis) * _Axis; m_Aim.Normalize(); return this; }
float3 XYZ2RGB( float3 _XYZ ) { return new float3( _XYZ.Dot( new float3( 3.2406f, -1.5372f, -0.4986f ) ), _XYZ.Dot( new float3( -0.9689f, 1.8758f, 0.0415f ) ), _XYZ.Dot( new float3( 0.0557f, -0.2040f, 1.0570f ) ) ); }
// Conversions sRGB RGB <=> CIE XYZ using D65 illuminant (sRGB white point) float3 RGB2XYZ( float3 _RGB ) { return new float3( _RGB.Dot( new float3( 0.4124f, 0.3576f, 0.1805f ) ), _RGB.Dot( new float3( 0.2126f, 0.7152f, 0.0722f ) ), // <= Y component is the LUMINANCE defined above _RGB.Dot( new float3( 0.0193f, 0.1192f, 0.9505f ) ) ); }
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] ); } }
// From http://www.iquilezles.org/www/articles/noacos/noacos.htm public float3x3 MakeRot( float3 _from, float3 _to ) { float3 v = _from.Cross( _to ); float c = _from.Dot( _to ); float k = 1.0f / (1.0f + c); m[0, 0] = v.x*v.x*k + c; m[0, 1] = v.x*v.y*k + v.z; m[0, 2] = v.x*v.z*k - v.y; m[1, 0] = v.y*v.x*k - v.z; m[1, 1] = v.y*v.y*k + c; m[1, 2] = v.y*v.z*k + v.x; m[2, 0] = v.z*v.x*k + v.y; m[2, 1] = v.z*v.y*k - v.x; m[2, 2] = v.z*v.z*k + c; return this; }