private void Generate() { try { tabControlGenerators.Enabled = false; ////////////////////////////////////////////////////////////////////////// // 1] Apply bilateral filtering to the input texture as a pre-process ApplyBilateralFiltering( m_textureSourceHeightMap, m_textureTarget0, floatTrackbarControlBilateralRadius.Value, floatTrackbarControlBilateralTolerance.Value, checkBoxWrap.Checked ); ////////////////////////////////////////////////////////////////////////// // 2] Compute directional occlusion m_textureTarget1.RemoveFromLastAssignedSlots(); // Prepare computation parameters m_textureTarget0.SetCS( 0 ); m_textureTarget1.SetCSUAV( 0 ); m_SB_Rays.SetInput( 1 ); m_CB_Input.m.RaysCount = (UInt32) Math.Min( MAX_THREADS, integerTrackbarControlRaysCount.Value ); m_CB_Input.m.MaxStepsCount = (UInt32) integerTrackbarControlMaxStepsCount.Value; m_CB_Input.m.Tile = (uint) (checkBoxWrap.Checked ? 1 : 0); m_CB_Input.m.TexelSize_mm = TextureSize_mm / Math.Max( W, H ); m_CB_Input.m.Displacement_mm = TextureHeight_mm; // Start if ( !m_CS_GenerateSSBumpMap.Use() ) throw new Exception( "Can't generate self-shadowed bump map as compute shader failed to compile!" ); uint h = Math.Max( 1, MAX_LINES*1024 / W ); uint callsCount = (uint) Math.Ceiling( (float) H / h ); for ( uint i=0; i < callsCount; i++ ) { m_CB_Input.m.Y0 = i * h; m_CB_Input.UpdateData(); m_CS_GenerateSSBumpMap.Dispatch( W, h, 1 ); m_device.Present( true ); progressBar.Value = (int) (0.01f * (BILATERAL_PROGRESS + (100-BILATERAL_PROGRESS) * (i+1) / (callsCount)) * progressBar.Maximum); // for ( int a=0; a < 10; a++ ) Application.DoEvents(); } m_textureTarget1.RemoveFromLastAssignedSlotUAV(); // So we can use it as input for next stage progressBar.Value = progressBar.Maximum; // Compute in a single shot (this is madness!) // m_CB_Input.m.y = 0; // m_CB_Input.UpdateData(); // m_CS_GenerateSSBumpMap.Dispatch( W, H, 1 ); ////////////////////////////////////////////////////////////////////////// // 3] Copy target to staging for CPU readback and update the resulting bitmap m_textureTarget_CPU.CopyFrom( m_textureTarget1 ); if ( m_imageResult != null ) m_imageResult.Dispose(); m_imageResult = null; m_imageResult = new ImageUtility.ImageFile( W, H, ImageUtility.ImageFile.PIXEL_FORMAT.RGBA8, m_linearProfile ); float4[] scanline = new float4[W]; PixelsBuffer pixels = m_textureTarget_CPU.Map( 0, 0 ); using ( System.IO.BinaryReader R = pixels.OpenStreamRead() ) for ( uint Y=0; Y < H; Y++ ) { R.BaseStream.Position = Y * pixels.RowPitch; for ( int X=0; X < W; X++ ) { scanline[X].Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); } m_imageResult.WriteScanline( Y, scanline ); } pixels.Dispose(); m_textureTarget_CPU.UnMap( 0, 0 ); // Assign result viewportPanelResult.Image = m_imageResult; } catch ( Exception _e ) { MessageBox( "An error occurred during generation!\r\n\r\nDetails: ", _e ); } finally { tabControlGenerators.Enabled = true; } }
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; } }
private void MixResults( float3 _MixColor ) { if ( m_TextureTargets[0][0] == null ) return; // Nothing to mix yet... if ( !m_CS_Helper_Mix.Use() ) throw new Exception( "Can't mix translucency maps as mixer compute shader failed to compile!" ); ////////////////////////////////////////////////////////////////////////// // 1] Combine m_CB_Helper.m._Width = (uint) W; m_CB_Helper.m._Height = (uint) H; m_CB_Helper.m._Parms = _MixColor; m_CB_Helper.UpdateData(); m_TextureTargets[0][0].SetCS( 0 ); m_TextureTargets[1][0].SetCS( 1 ); m_TextureTargets[2][0].SetCS( 2 ); m_TextureTargetCombined.RemoveFromLastAssignedSlots(); m_TextureTargetCombined.SetCSUAV( 0 ); uint groupsCountX = (W + 15) >> 4; uint groupsCountY = (H + 15) >> 4; m_CS_Helper_Mix.Dispatch( groupsCountX, groupsCountY, 1 ); m_TextureTargetCombined.RemoveFromLastAssignedSlotUAV(); // So we can use it as input for next stage ////////////////////////////////////////////////////////////////////////// // 2] Copy target to staging for CPU readback and update the resulting bitmaps if ( m_imageResultCombined != null ) m_imageResultCombined.Dispose(); m_imageResultCombined = new ImageUtility.ImageFile( W, H, ImageUtility.ImageFile.PIXEL_FORMAT.RGBA8, m_sRGBProfile ); // Copy from GPU to CPU m_TextureTarget_CPU.CopyFrom( m_TextureTargetCombined ); PixelsBuffer Pixels = m_TextureTarget_CPU.Map( 0, 0 ); float4[] scanline = new float4[W]; float4 gammaRGB = float4.Zero; using ( System.IO.BinaryReader R = Pixels.OpenStreamRead() ) for ( uint Y=0; Y < H; Y++ ) { R.BaseStream.Position = Y * Pixels.RowPitch; for ( uint X=0; X < W; X++ ) { gammaRGB.Set( R.ReadSingle(), R.ReadSingle(), R.ReadSingle(), R.ReadSingle() ); m_sRGBProfile.LinearRGB2GammaRGB( gammaRGB, ref scanline[X] ); } m_imageResultCombined.WriteScanline( Y, scanline ); } Pixels.Dispose(); m_TextureTarget_CPU.UnMap( 0, 0 ); // Assign result imagePanelResult3.Image = m_imageResultCombined; }
private void Generate() { try { tabControlGenerators.Enabled = false; ////////////////////////////////////////////////////////////////////////// // 1] Apply bilateral filtering to the input texture as a pre-process ApplyBilateralFiltering(m_textureSourceHeightMap, m_textureTarget0, floatTrackbarControlBilateralRadius.Value, floatTrackbarControlBilateralTolerance.Value, checkBoxWrap.Checked); ////////////////////////////////////////////////////////////////////////// // 2] Compute directional occlusion m_textureTarget1.RemoveFromLastAssignedSlots(); // Prepare computation parameters m_textureTarget0.SetCS(0); m_textureTarget1.SetCSUAV(0); m_SB_Rays.SetInput(1); m_CB_Input.m.RaysCount = (UInt32)Math.Min(MAX_THREADS, integerTrackbarControlRaysCount.Value); m_CB_Input.m.MaxStepsCount = (UInt32)integerTrackbarControlMaxStepsCount.Value; m_CB_Input.m.Tile = (uint)(checkBoxWrap.Checked ? 1 : 0); m_CB_Input.m.TexelSize_mm = TextureSize_mm / Math.Max(W, H); m_CB_Input.m.Displacement_mm = TextureHeight_mm; // Start if (!m_CS_GenerateSSBumpMap.Use()) { throw new Exception("Can't generate self-shadowed bump map as compute shader failed to compile!"); } uint h = Math.Max(1, MAX_LINES * 1024 / W); uint callsCount = (uint)Math.Ceiling((float)H / h); for (uint i = 0; i < callsCount; i++) { m_CB_Input.m.Y0 = i * h; m_CB_Input.UpdateData(); m_CS_GenerateSSBumpMap.Dispatch(W, h, 1); m_device.Present(true); progressBar.Value = (int)(0.01f * (BILATERAL_PROGRESS + (100 - BILATERAL_PROGRESS) * (i + 1) / (callsCount)) * progressBar.Maximum); // for ( int a=0; a < 10; a++ ) Application.DoEvents(); } m_textureTarget1.RemoveFromLastAssignedSlotUAV(); // So we can use it as input for next stage progressBar.Value = progressBar.Maximum; // Compute in a single shot (this is madness!) // m_CB_Input.m.y = 0; // m_CB_Input.UpdateData(); // m_CS_GenerateSSBumpMap.Dispatch( W, H, 1 ); ////////////////////////////////////////////////////////////////////////// // 3] Copy target to staging for CPU readback and update the resulting bitmap m_textureTarget_CPU.CopyFrom(m_textureTarget1); if (m_imageResult != null) { m_imageResult.Dispose(); } m_imageResult = null; m_imageResult = new ImageUtility.ImageFile(W, H, ImageUtility.PIXEL_FORMAT.RGBA8, m_linearProfile); float4[] scanline = new float4[W]; PixelsBuffer pixels = m_textureTarget_CPU.MapRead(0, 0); using (System.IO.BinaryReader R = pixels.OpenStreamRead()) for (uint Y = 0; Y < H; Y++) { R.BaseStream.Position = Y * pixels.RowPitch; for (int X = 0; X < W; X++) { scanline[X].Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); } m_imageResult.WriteScanline(Y, scanline); } m_textureTarget_CPU.UnMap(pixels); // Assign result viewportPanelResult.Image = m_imageResult; } catch (Exception _e) { MessageBox("An error occurred during generation!\r\n\r\nDetails: ", _e); } finally { tabControlGenerators.Enabled = true; } }