private void Generate_CPU(int _RaysCount) { try { tabControlGenerators.Enabled = false; // Half-life basis (Z points outside of the surface, as in normal maps) float3[] basis = new float3[] { new float3((float)Math.Sqrt(2.0 / 3.0), 0.0f, (float)Math.Sqrt(1.0 / 3.0)), new float3((float)-Math.Sqrt(1.0 / 6.0), (float)Math.Sqrt(1.0 / 2.0), (float)Math.Sqrt(1.0 / 3.0)), new float3((float)-Math.Sqrt(1.0 / 6.0), (float)-Math.Sqrt(1.0 / 2.0), (float)Math.Sqrt(1.0 / 3.0)), }; // // 1] Compute normal map // float3 dX = new float3(); // float3 dY = new float3(); // float3 N; // float ddX = floatTrackbarControlPixelSize.Value; // float ddH = floatTrackbarControlHeight.Value; // for ( int Y=0; Y < H; Y++ ) // { // int Y0 = Math.Max( 0, Y-1 ); // int Y1 = Math.Min( H-1, Y+1 ); // for ( int X=0; X < W; X++ ) // { // int X0 = Math.Max( 0, X-1 ); // int X1 = Math.Min( W-1, X+1 ); // // float Hx0 = m_BitmapSource.ContentXYZ[X0,Y].y; // float Hx1 = m_BitmapSource.ContentXYZ[X1,Y].y; // float Hy0 = m_BitmapSource.ContentXYZ[X,Y0].y; // float Hy1 = m_BitmapSource.ContentXYZ[X,Y1].y; // // dX.Set( 2.0f * ddX, 0.0f, ddH * (Hx1 - Hx0) ); // dY.Set( 0.0f, 2.0f * ddX, ddH * (Hy1 - Hy0) ); // // N = dX.Cross( dY ).Normalized; // // m_Normal[X,Y] = new float3( // N.Dot( Basis[0] ), // N.Dot( Basis[1] ), // N.Dot( Basis[2] ) ); // } // // // Update and show progress // UpdateProgress( m_Normal, Y, true ); // } // UpdateProgress( m_Normal, H, true ); float LobeExponent = 4.0f; //floatTrackbarControlLobeExponent.Value; float PixelSize_mm = 1000.0f / floatTrackbarControlPixelDensity.Value; float scale = 0.1f * PixelSize_mm / floatTrackbarControlHeight.Value; // Scale factor to apply to pixel distances so they're renormalized in [0,1], our "heights space"... // Scale *= floatTrackbarControlZFactor.Value; // Cheat Z velocity so AO is amplified! // 2] Build local rays only once int raysCount = integerTrackbarControlRaysCount.Value; float3[,] rays = new float3[3, raysCount]; // Create orthonormal bases to orient the lobe float3 Xr = basis[0].Cross(float3.UnitZ).Normalized; // We can safely use (0,0,1) as the "up" direction since the HL2 basis doesn't have any vertical direction float3 Yr = Xr.Cross(basis[0]); float3 Xg = basis[1].Cross(float3.UnitZ).Normalized; // We can safely use (0,0,1) as the "up" direction since the HL2 basis doesn't have any vertical direction float3 Yg = Xg.Cross(basis[1]); float3 Xb = basis[2].Cross(float3.UnitZ).Normalized; // We can safely use (0,0,1) as the "up" direction since the HL2 basis doesn't have any vertical direction float3 Yb = Xb.Cross(basis[2]); double Exponent = 1.0 / (1.0 + LobeExponent); for (int RayIndex = 0; RayIndex < raysCount; RayIndex++) { // if ( false ) { // double Phi = 2.0 * Math.PI * WMath.SimpleRNG.GetUniform(); // // double Theta = Math.Acos( Math.Pow( WMath.SimpleRNG.GetUniform(), Exponent ) ); // double Theta = Math.PI / 3.0 * WMath.SimpleRNG.GetUniform(); // // float3 RayLocal = new float3( // (float) (Math.Cos( Phi ) * Math.Sin( Theta )), // (float) (Math.Sin( Phi ) * Math.Sin( Theta )), // (float) Math.Cos( Theta ) ); // // Rays[0,RayIndex] = RayLocal.x * Xr + RayLocal.y * Yr + RayLocal.z * Basis[0]; // Rays[1,RayIndex] = RayLocal.x * Xg + RayLocal.y * Yg + RayLocal.z * Basis[1]; // Rays[2,RayIndex] = RayLocal.x * Xb + RayLocal.y * Yb + RayLocal.z * Basis[2]; // } else { double Phi = Math.PI / 3.0 * (2.0 * SimpleRNG.GetUniform() - 1.0); double Theta = 0.49 * Math.PI * SimpleRNG.GetUniform(); rays[0, RayIndex] = new float3( (float)(Math.Cos(Phi) * Math.Sin(Theta)), (float)(Math.Sin(Phi) * Math.Sin(Theta)), (float)Math.Cos(Theta)); Phi = Math.PI / 3.0 * (2.0 * SimpleRNG.GetUniform() - 1.0 + 2.0); Theta = 0.49 * Math.PI * SimpleRNG.GetUniform(); rays[1, RayIndex] = new float3( (float)(Math.Cos(Phi) * Math.Sin(Theta)), (float)(Math.Sin(Phi) * Math.Sin(Theta)), (float)Math.Cos(Theta)); Phi = Math.PI / 3.0 * (2.0 * SimpleRNG.GetUniform() - 1.0 + 4.0); Theta = 0.49 * Math.PI * SimpleRNG.GetUniform(); rays[2, RayIndex] = new float3( (float)(Math.Cos(Phi) * Math.Sin(Theta)), (float)(Math.Sin(Phi) * Math.Sin(Theta)), (float)Math.Cos(Theta)); } rays[0, RayIndex].z *= scale; rays[1, RayIndex].z *= scale; rays[2, RayIndex].z *= scale; } // 3] Compute directional occlusion float4[] scanline = new float4[W]; float4 gammaRGB = float4.Zero; for (uint Y = 0; Y < H; Y++) { for (uint X = 0; X < W; X++) { gammaRGB.x = ComputeAO(0, X, Y, scale, rays); gammaRGB.y = ComputeAO(1, X, Y, scale, rays); gammaRGB.z = ComputeAO(2, X, Y, scale, rays); gammaRGB.w = (gammaRGB.x + gammaRGB.y + gammaRGB.z) / 3.0f; m_sRGBProfile.GammaRGB2LinearRGB(gammaRGB, ref scanline[X]); } m_imageResult.WriteScanline(Y, scanline); // Update and show progress UpdateProgress(m_imageResult, Y, true); } UpdateProgress(m_imageResult, H, true); // m_BitmapResult.Save( "eye_generic_01_disp_hl2.png", ImageFormat.Png ); } catch (Exception _e) { MessageBox("An error occurred during generation:\r\n" + _e.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { tabControlGenerators.Enabled = true; } }