void Application_Idle(object sender, EventArgs e) { if (m_device == null) { return; } m_CB_Main.m._sourceIndex = (uint)integerTrackbarControlShowQuerySourceIndex.Value; m_CB_Main.m._renderFlags = 0U; m_CB_Main.m._renderFlags |= radioButtonShowBarycentrics.Checked ? 0x1U : 0U; m_CB_Main.m._renderFlags |= radioButtonShowResultsBarycentric.Checked ? 0x2U : 0U; m_CB_Main.m._renderFlags |= radioButtonShowResultsSum.Checked ? 0x4U : 0U; m_CB_Main.m._renderFlags |= checkBoxShowLog.Checked ? 0x10U : 0U; m_CB_Main.m._barycentricDistanceTolerance = floatTrackbarControlResultsTolerance.Value; m_CB_Main.m._barycentricBias = floatTrackbarControlBarycentricBias.Value; m_CB_Main.m._diffusionCoefficient = floatTrackbarControlDiffusionConstant.Value; m_CB_Main.UpdateData(); ////////////////////////////////////////////////////////////////////////// // Simulate heat wave if (checkBoxRun.Checked && m_queryNodes.Length > 0 && m_compute_HeatDiffusion.Use()) { m_SB_HeatSource.SetInput(0); m_SB_HeatTarget.SetOutput(0); m_SB_Nodes.SetInput(1); m_SB_LinkTargets.SetInput(2); m_SB_SourceIndices.SetInput(3); // Simulate heat propagation m_compute_HeatDiffusion.Dispatch((m_nodesCount + 63) >> 6, (uint)m_queryNodes.Length, 1); // Splat heat sources m_compute_SplatHeatSources.Use(); m_compute_SplatHeatSources.Dispatch(((uint)m_queryNodes.Length + 63) >> 6, 1, 1); // Swap source & target StructuredBuffer <float> temp = m_SB_HeatTarget; m_SB_HeatTarget = m_SB_HeatSource; m_SB_HeatSource = temp; m_barycentricsDirty = true; m_sumDirty = true; } ////////////////////////////////////////////////////////////////////////// // Render m_device.Clear(float4.Zero); m_device.ClearDepthStencil(m_device.DefaultDepthStencil, 1.0f, 0, true, false); m_SB_Nodes.SetInput(0); m_SB_LinkTargets.SetInput(1); m_SB_LinkSources.SetInput(2); m_SB_HeatSource.SetInput(3); if (radioButtonShowTemperature.Checked) { m_tex_FalseColors0.Set(5); } else if (radioButtonShowBarycentrics.Checked) { GetBarycentricsBuffer().SetInput(4); m_tex_FalseColors1.Set(5); } else if (radioButtonShowResultsBarycentric.Checked) { GetBarycentricsBuffer().SetInput(4); } else if (radioButtonShowResultsSum.Checked) { GetSumBuffer().SetInput(4); m_tex_FalseColors0.Set(5); } if (m_shader_RenderGraphLink.Use()) { m_device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.READ_WRITE_DEPTH_LESS, BLEND_STATE.DISABLED); m_device.SetRenderTarget(m_device.DefaultTarget, m_device.DefaultDepthStencil); m_device.ScreenQuad.RenderInstanced(m_shader_RenderGraphLink, m_totalLinksCount); } if (m_shader_RenderGraphNode.Use()) { m_device.SetRenderStates(RASTERIZER_STATE.NOCHANGE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.NOCHANGE); m_device.SetRenderTarget(m_device.DefaultTarget, null); m_device.ScreenQuad.RenderInstanced(m_shader_RenderGraphNode, m_nodesCount); } ////////////////////////////////////////////////////////////////////////// // Draw some text if (m_displayText != null && m_displayText.Length > 0 && m_shader_RenderText.Use()) { m_device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.DISABLED); m_device.SetRenderTarget(m_device.DefaultTarget, null); m_tex_FontAtlas.SetPS(0); m_tex_FontRectangle.SetVS(1); // Fill text letters int totalWidth = 0; int totalHeight = (int)m_tex_FontAtlas.Height; for (int i = 0; i < m_displayText.Length; i++) { int letterIndex = m_char2Index[(int)m_displayText[i]]; Rectangle rect = m_fontRectangles[letterIndex]; m_SB_Text.m[i].m_letterIndex = (uint)letterIndex; m_SB_Text.m[i].m_offset = totalWidth; m_SB_Text.m[i].m_ratio = rect.Width; totalWidth += rect.Width; } // Normalize float norm = 1.0f / totalWidth; for (int i = 0; i < m_displayText.Length; i++) { m_SB_Text.m[i].m_offset *= norm; m_SB_Text.m[i].m_ratio *= norm; } m_SB_Text.Write(); m_SB_Text.SetInput(2); // Setup text rectangle const float textHeight_pixels = 20.0f; // What we want the text size to be on screen float textWidth_pixels = totalWidth * textHeight_pixels / totalHeight; float2 textSize_proj = new float2(2.0f * textWidth_pixels / panelOutput.Width, 2.0f * textHeight_pixels / panelOutput.Height); float2 selectedNodePosition_proj = new float2(2.0f * (m_selectedNodePosition.x - m_CB_Main.m._cameraCenter.x) / m_CB_Main.m._cameraSize.x, -2.0f * (m_selectedNodePosition.y - m_CB_Main.m._cameraCenter.y) / m_CB_Main.m._cameraSize.y); m_CB_Text.m._position.Set(selectedNodePosition_proj.x - 0.5f * textSize_proj.x, selectedNodePosition_proj.y + 1.0f * textSize_proj.y); // Horizontal centering on node position, vertical offset so it's above m_CB_Text.m._right.Set(textSize_proj.x, 0.0f); m_CB_Text.m._up.Set(0.0f, textSize_proj.y); m_CB_Text.UpdateData(); m_device.ScreenQuad.RenderInstanced(m_shader_RenderText, (uint)m_displayText.Length); } m_device.Present(false); }
void Application_Idle(object sender, EventArgs e) { if (m_device == null) { return; } m_CB_Simulation.m._deltaTime = floatTrackbarControlDeltaTime.Value; m_CB_Simulation.m._springConstant = floatTrackbarControlSpringConstant.Value; m_CB_Simulation.m._dampingConstant = floatTrackbarControlDampingConstant.Value; m_CB_Simulation.m._restDistance = floatTrackbarControlRestDistance.Value; m_CB_Simulation.m._K.Set(floatTrackbarControlK0.Value, floatTrackbarControlK1.Value, floatTrackbarControlK2.Value, floatTrackbarControlK3.Value); m_CB_Simulation.UpdateData(); // Point clientPos = panelOutput.PointToClient( Control.MousePosition ); // m_CB_Main.m.mousePosition.Set( GRAPH_SIZE * (float) clientPos.X / panelOutput.Width, GRAPH_SIZE * (float) clientPos.Y / panelOutput.Height ); // m_CB_Main.m.mouseButtons = (uint) ((((Control.MouseButtons & MouseButtons.Left) != 0) ? 1 : 0) // // | (((Control.MouseButtons & MouseButtons.Middle) != 0) ? 2 : 0) // | (m_plotSource ? 2 : 0) // | (((Control.MouseButtons & MouseButtons.Right) != 0) ? 4 : 0) // | (Control.ModifierKeys == Keys.Shift ? 8 : 0)); // m_CB_Main.m.diffusionCoefficient = floatTrackbarControlDiffusionCoefficient.Value; // m_CB_Main.m.flags = (uint) ( // (checkBoxShowSearch.Checked ? 1 : 0) // // // 2 bits to select 4 display modes // | (radioButtonShowNormalizedSpace.Checked ? 2 : 0) // | (radioButtonShowResultsSpace.Checked ? 4 : 0) // // | (checkBoxShowLog.Checked ? 8 : 0) // ); // m_CB_Main.m.sourceIndex = (uint) integerTrackbarControlSimulationSourceIndex.Value; // m_CB_Main.m.sourcesCount = (uint) m_simulationHotSpots.Count; // m_CB_Main.m.resultsConfinementDistance = floatTrackbarControlResultsSpaceConfinement.Value; ////////////////////////////////////////////////////////////////////////// // Perform simulation if (checkBoxRun.Checked && m_shader_ComputeForces.Use()) { // Compute forces m_SB_Nodes.SetInput(1); m_SB_Links.SetInput(2); m_SB_NodeSims[0].SetInput(0); // Input positions & velocities m_SB_NodeSims[1].SetOutput(0); // Output positions & velocities m_SB_Forces.SetOutput(1); // Simulation forces uint groupsCount = (m_nodesCount + 255) >> 8; m_shader_ComputeForces.Dispatch(groupsCount, 1, 1); // Apply forces m_shader_Simulate.Use(); m_shader_Simulate.Dispatch(groupsCount, 1, 1); m_SB_NodeSims[0].RemoveFromLastAssignedSlots(); m_SB_NodeSims[1].RemoveFromLastAssignedSlotUAV(); m_SB_Forces.RemoveFromLastAssignedSlotUAV(); // Swap simulation buffers StructuredBuffer <SB_NodeSim> temp = m_SB_NodeSims[0]; m_SB_NodeSims[0] = m_SB_NodeSims[1]; m_SB_NodeSims[1] = temp; } ////////////////////////////////////////////////////////////////////////// // Render #if RENDER_GRAPH_PROPER if (m_shader_RenderGraphLink.Use()) { m_device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.READ_WRITE_DEPTH_LESS, BLEND_STATE.DISABLED); m_device.SetRenderTarget(m_device.DefaultTarget, m_device.DefaultDepthStencil); m_device.Clear(float4.Zero); m_device.ClearDepthStencil(m_device.DefaultDepthStencil, 1.0f, 0, true, false); m_SB_NodeSims[0].SetInput(0); m_SB_Nodes.SetInput(1); m_SB_Links.SetInput(2); m_SB_LinkSources.SetInput(3); m_tex_FalseColors.SetPS(4); m_device.ScreenQuad.RenderInstanced(m_shader_RenderGraphLink, m_totalLinksCount); } if (m_shader_RenderGraphNode.Use()) { m_device.SetRenderStates(RASTERIZER_STATE.NOCHANGE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.NOCHANGE); m_device.SetRenderTarget(m_device.DefaultTarget, null); m_SB_NodeSims[0].SetInput(0); m_SB_Nodes.SetInput(1); m_SB_Links.SetInput(2); m_SB_LinkSources.SetInput(3); m_tex_FalseColors.SetPS(4); m_device.ScreenQuad.RenderInstanced(m_shader_RenderGraphNode, m_nodesCount); } #else m_device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.DISABLED); if (m_shader_RenderGraph.Use()) { m_device.SetRenderTarget(m_device.DefaultTarget, null); m_SB_NodeSims[0].SetInput(0); m_SB_Nodes.SetInput(1); m_tex_FalseColors.SetPS(4); m_device.RenderFullscreenQuad(m_shader_RenderGraph); } #endif ////////////////////////////////////////////////////////////////////////// // Draw some text if (m_displayText != null && m_displayText.Length > 0 && m_shader_RenderText.Use()) { m_device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.DISABLED); m_device.SetRenderTarget(m_device.DefaultTarget, null); m_tex_FontAtlas.SetPS(0); m_tex_FontRectangle.SetVS(1); // Fill text letters int totalWidth = 0; int totalHeight = (int)m_tex_FontAtlas.Height; for (int i = 0; i < m_displayText.Length; i++) { int letterIndex = m_char2Index[(int)m_displayText[i]]; Rectangle rect = m_fontRectangles[letterIndex]; m_SB_Text.m[i].m_letterIndex = (uint)letterIndex; m_SB_Text.m[i].m_offset = totalWidth; m_SB_Text.m[i].m_ratio = rect.Width; totalWidth += rect.Width; } // Normalize float norm = 1.0f / totalWidth; for (int i = 0; i < m_displayText.Length; i++) { m_SB_Text.m[i].m_offset *= norm; m_SB_Text.m[i].m_ratio *= norm; } m_SB_Text.Write(); m_SB_Text.SetInput(2); // Setup text rectangle const float textHeight_pixels = 20.0f; // What we want the text size to be on screen float textWidth_pixels = totalWidth * textHeight_pixels / totalHeight; float2 textSize_proj = new float2(2.0f * textWidth_pixels / panelOutput.Width, 2.0f * textHeight_pixels / panelOutput.Height); float2 selectedNodePosition_proj = new float2(2.0f * (m_selectedNodePosition.x - m_CB_Main.m._cameraCenter.x) / m_CB_Main.m._cameraSize.x, -2.0f * (m_selectedNodePosition.y - m_CB_Main.m._cameraCenter.y) / m_CB_Main.m._cameraSize.y); m_CB_Text.m._position.Set(selectedNodePosition_proj.x - 0.5f * textSize_proj.x, selectedNodePosition_proj.y + 1.0f * textSize_proj.y); // Horizontal centering on node position, vertical offset so it's above m_CB_Text.m._right.Set(textSize_proj.x, 0.0f); m_CB_Text.m._up.Set(0.0f, textSize_proj.y); m_CB_Text.UpdateData(); m_device.ScreenQuad.RenderInstanced(m_shader_RenderText, (uint)m_displayText.Length); } ////////////////////////////////////////////////////////////////////////// // Auto-center camera if (checkBoxAutoCenter.Checked) { m_SB_NodeSims[0].Read(); float2 minPos = new float2(float.MaxValue, float.MaxValue); float2 maxPos = new float2(-float.MaxValue, -float.MaxValue); for (int i = 0; i < m_nodesCount; i++) { float2 P = m_SB_NodeSims[0].m[i].m_position; if (float.IsNaN(P.x) || float.IsNaN(P.y)) { continue; } minPos.Min(P); maxPos.Max(P); } if (minPos.x > maxPos.x || minPos.y > maxPos.y) { minPos.Set(-10, -10); maxPos.Set(10, 10); } float2 size = maxPos - minPos; if (size.x * panelOutput.Height > size.y * panelOutput.Width) { // Fit horizontally size.y = size.x * panelOutput.Height / panelOutput.Width; } else { // Fit vertically size.x = size.y * panelOutput.Width / panelOutput.Height; } m_CB_Main.m._cameraSize = 1.05f * size; m_CB_Main.m._cameraCenter = 0.5f * (minPos + maxPos); m_CB_Main.UpdateData(); } m_device.Present(false); }
void Application_Idle(object sender, EventArgs e) { if (m_Device == null) { return; } DateTime currentTime = DateTime.Now; double time = (float)(currentTime - m_StartTime).TotalSeconds; double deltaTime = (float)(currentTime - m_LastTime).TotalSeconds; m_LastTime = currentTime; ///////////////////////////////////////////////////////////////////////////////////// // Build 4D Camera vectors const float CAMERA_FOV_4D = 60.0f; const float CAMERA_FAR_CLIP = 8.0f; if (checkBoxAuto.Checked) { const float RADIUS = 1.0f; double alpha = 0.5 * time * Math.PI; double beta = 0.3 * time * Math.PI; double gamma = 0.7 * time * Math.PI; m_CameraPosition4D = new float4(RADIUS * (float)(Math.Cos(alpha) * Math.Cos(gamma)), RADIUS * (float)(Math.Cos(beta) * Math.Sin(alpha)), RADIUS * (float)(Math.Cos(beta) * Math.Sin(gamma)), RADIUS * (float)Math.Sin(alpha)); } else { m_CameraPosition4D = new float4(floatTrackbarControlX.Value, floatTrackbarControlY.Value, floatTrackbarControlZ.Value, floatTrackbarControlW.Value); } float4 At = (m_CameraTarget4D - m_CameraPosition4D).Normalized; m_CB_Camera4D.m._CameraPos = m_CameraPosition4D; m_CB_Camera4D.m._CameraTanHalfFOV = (float)Math.Tan(0.5f * Math.PI / 180.0 * CAMERA_FOV_4D); m_CB_Camera4D.m._CameraW = At; m_CB_Camera4D.m._CameraX = Cross4D(m_CameraUp4D, m_CameraOver4D, At).Normalized; m_CB_Camera4D.m._CameraY = Cross4D(m_CameraOver4D, At, m_CB_Camera4D.m._CameraX).Normalized; m_CB_Camera4D.m._CameraZ = Cross4D(At, m_CB_Camera4D.m._CameraX, m_CB_Camera4D.m._CameraY); m_CB_Camera4D.m._CameraX /= CAMERA_FAR_CLIP; m_CB_Camera4D.m._CameraY /= CAMERA_FAR_CLIP; m_CB_Camera4D.m._CameraZ /= CAMERA_FAR_CLIP; m_CB_Camera4D.UpdateData(); ///////////////////////////////////////////////////////////////////////////////////// // Simulate if (m_CS_Simulator.Use()) { m_SB_Points4D[0].RemoveFromLastAssignedSlots(); m_SB_Points4D[0].SetInput(0); m_SB_Velocities4D.SetInput(1); m_SB_Points4D[1].SetOutput(0); float timeStep = floatTrackbarControlTimeStep.Value * (float)(deltaTime / 0.01); // Compensate for variations in delta time based on the default 10ms timer delay m_CB_Simulation.m._Flags = 0; m_CB_Simulation.m._TimeStep = checkBoxSimulate.Checked ? timeStep : 0.0f; m_CB_Simulation.UpdateData(); int groupsCount = POINTS_COUNT >> 8; m_CS_Simulator.Dispatch(groupsCount, 1, 1); StructuredBuffer <float4> Temp = m_SB_Points4D[0]; m_SB_Points4D[0] = m_SB_Points4D[1]; m_SB_Points4D[1] = Temp; } ///////////////////////////////////////////////////////////////////////////////////// // Transform points from 4D to 2D using compute shader if (m_CS_Project4D.Use()) { m_SB_Points2D.RemoveFromLastAssignedSlots(); m_SB_Points4D[0].SetInput(0); m_SB_Points2D.SetOutput(0); int groupsCount = POINTS_COUNT >> 8; m_CS_Project4D.Dispatch(groupsCount, 1, 1); } ///////////////////////////////////////////////////////////////////////////////////// // Render points m_Device.Clear(m_Device.DefaultTarget, float4.Zero); m_Device.ClearDepthStencil(m_Device.DefaultDepthStencil, 1.0f, 0, true, false); if (m_PS_Display.Use()) { m_Device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.READ_WRITE_DEPTH_LESS, BLEND_STATE.DISABLED); m_Device.SetRenderTarget(m_Device.DefaultTarget, m_Device.DefaultDepthStencil); m_SB_Points2D.SetInput(0); m_PrimQuad.RenderInstanced(m_PS_Display, POINTS_COUNT); } // Show! m_Device.Present(false); }
void Application_Idle(object sender, EventArgs e) { if (m_Device == null) { return; } int W = panelOutput.Width; int H = panelOutput.Height; // Timer float lastGameTime = m_CurrentGameTime; m_CurrentGameTime = GetGameTime(); if (m_CurrentGameTime - m_StartFPSTime > 1.0f) { m_AverageFrameTime = (m_CurrentGameTime - m_StartFPSTime) / Math.Max(1, m_SumFrames); m_SumFrames = 0; m_StartFPSTime = m_CurrentGameTime; } m_SumFrames++; m_CB_Global.m._ScreenSize.Set(W, H, 1.0f / W, 1.0f / H); m_CB_Global.m._Time = m_CurrentGameTime; m_CB_Global.UpdateData(); Camera_CameraTransformChanged(m_Camera, EventArgs.Empty); m_Device.ClearDepthStencil(m_Device.DefaultDepthStencil, 1.0f, 0, true, false); m_Tex_Noise.Set(8); m_Tex_Noise4D.Set(9); float sigma_t = floatTrackbarControlExtinction.Value; float sigma_s = floatTrackbarControlExtinction.Value * floatTrackbarControlAlbedo.Value; float phase_g = floatTrackbarControlPhaseAnisotropy.Value; ////////////////////////////////////////////////////////////////////////// // Build Deforming Height Map if (m_Shader_UpdateHeightMap.Use()) { m_Tex_HeightMap.RemoveFromLastAssignedSlots(); m_Tex_HeightMap.SetCSUAV(0); m_Shader_UpdateHeightMap.Dispatch(HEIGHTMAP_SIZE >> 4, HEIGHTMAP_SIZE >> 4, 1); m_Tex_HeightMap.RemoveFromLastAssignedSlotUAV(); m_Tex_HeightMap.Set(11); } ////////////////////////////////////////////////////////////////////////// // Render volume density if (m_shader_GenerateDensity.Use()) { int GroupsCount = VOLUME_SIZE >> 3; m_CB_GenerateDensity.m._wsOffset.Set(0.5f * m_CurrentGameTime, 0, 0); m_CB_GenerateDensity.UpdateData(); m_Tex_VolumeDensity.RemoveFromLastAssignedSlots(); m_Tex_VolumeDensity.SetCSUAV(0); m_shader_GenerateDensity.Dispatch(GroupsCount, GroupsCount, GroupsCount); m_Tex_VolumeDensity.RemoveFromLastAssignedSlotUAV(); } ////////////////////////////////////////////////////////////////////////// // Splat photons { int GroupsCount = PHOTONS_COUNT >> 8; // 256 threads per group m_Tex_AccumPhoton3D.RemoveFromLastAssignedSlots(); m_Tex_AccumPhoton3D.SetCSUAV(2); // Clear if (m_Shader_ClearAccumulator.Use()) { m_Shader_ClearAccumulator.Dispatch(VOLUME_SIZE >> 2, VOLUME_SIZE >> 2, VOLUME_SIZE >> 2); } // Init if (m_Shader_InitPhotons.Use()) { m_SB_PhotonInfos.RemoveFromLastAssignedSlots(); m_SB_Photons[0].RemoveFromLastAssignedSlots(); m_SB_PhotonInfos.SetOutput(0); // m_SB_Photons[0].SetOutput( 1 ); m_Shader_InitPhotons.Dispatch(GroupsCount, 1, 1); } // Trace if (m_Shader_TracePhotons.Use()) { m_CB_TracePhotons.m._Sigma_t = sigma_t; m_CB_TracePhotons.UpdateData(); m_SB_PhotonInfos.SetInput(0); m_SB_Photons[0].SetInput(1); m_Tex_VolumeDensity.Set(10); m_Shader_TracePhotons.Dispatch(GroupsCount, 1, 1); } m_Tex_AccumPhoton3D.RemoveFromLastAssignedSlotUAV(); } ////////////////////////////////////////////////////////////////////////// // Render room if (m_Shader_RenderRoom.Use()) { m_Device.SetRenderStates(RASTERIZER_STATE.CULL_FRONT, DEPTHSTENCIL_STATE.READ_WRITE_DEPTH_LESS, BLEND_STATE.DISABLED); m_Device.SetRenderTarget(m_Tex_TempBackBuffer, m_Device.DefaultDepthStencil); m_CB_RenderRoom.UpdateData(); m_Prim_Cube.Render(m_Shader_RenderRoom); } ////////////////////////////////////////////////////////////////////////// // Render sphere if (m_Shader_RenderSphere.Use()) { m_Device.SetRenderStates(RASTERIZER_STATE.CULL_BACK, DEPTHSTENCIL_STATE.NOCHANGE, BLEND_STATE.NOCHANGE); // m_Device.SetRenderTarget( m_Tex_TempBackBuffer, m_Device.DefaultDepthStencil ); m_CB_RenderSphere.UpdateData(); m_Prim_Sphere.Render(m_Shader_RenderSphere); } ////////////////////////////////////////////////////////////////////////// // Ray-March volume if (m_Shader_RayMarcher.Use()) { m_Device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.DISABLED); m_Device.SetRenderTargets(W, H, new IView[] { m_Tex_Scattering.GetView(0, 1, 0, 1), m_Tex_Scattering.GetView(0, 1, 1, 1) }, null); m_Tex_AccumPhoton3D.Set(1); m_CB_RayMarch.m._Sigma_t = sigma_t; m_CB_RayMarch.m._Sigma_s = sigma_s; m_CB_RayMarch.m._Phase_g = phase_g; m_CB_RayMarch.UpdateData(); m_Prim_Quad.Render(m_Shader_RayMarcher); } ////////////////////////////////////////////////////////////////////////// // Post-process if (m_Shader_PostProcess.Use()) { m_Device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.DISABLED); m_Device.SetRenderTarget(m_Device.DefaultTarget, null); m_CB_PostProcess.UpdateData(); m_Tex_TempBackBuffer.SetPS(0); m_Tex_Scattering.SetPS(1); m_Prim_Quad.Render(m_Shader_PostProcess); m_Tex_Scattering.RemoveFromLastAssignedSlots(); } // Show! m_Device.Present(false); // Update window text Text = "GloubiBoule - Avg. Frame Time " + (1000.0f * m_AverageFrameTime).ToString("G5") + " ms (" + (1.0f / m_AverageFrameTime).ToString("G5") + " FPS)"; }
void Application_Idle(object sender, EventArgs e) { if (m_Device == null || m_closing) { return; } if (m_Tex_CubeMap == null) { return; } m_CB_Main.m._Resolution = new float3(panelOutput.Width, panelOutput.Height, 0); DateTime Now = DateTime.Now; float DeltaTime = (float)(Now - m_lastTime).TotalSeconds; m_lastTime = Now; m_CB_Main.m._GlobalTime = (float)(Now - m_startTime).TotalSeconds; m_CB_Main.UpdateData(); m_Device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.DISABLED); ////////////////////////////////////////////////////////////////////////// // 1] Render to the HDR buffer if (m_Shader_RenderHDR.Use()) { m_Device.SetRenderTarget(m_Tex_HDR, null); if (m_Tex_CubeMap != null) { m_Tex_CubeMap.SetPS(0); } m_Device.RenderFullscreenQuad(m_Shader_RenderHDR); } ////////////////////////////////////////////////////////////////////////// // 2] Compute auto-exposure if (m_Shader_ComputeTallHistogram.Use()) { // Build a 128xH "tall histogram" m_Device.RemoveRenderTargets(); m_Tex_HDR.SetCS(0); m_Tex_TallHistogram.SetCSUAV(0); m_Shader_ComputeTallHistogram.Dispatch(1, m_Tex_TallHistogram.Height, 1); } if (m_Shader_FinalizeHistogram.Use()) { // Build the 128x1 standard histogram m_Tex_Histogram.SetCSUAV(0); m_Tex_TallHistogram.SetCS(0); m_Shader_FinalizeHistogram.Dispatch(128, 1, 1); } if (m_Shader_ComputeAutoExposure.Use()) { // Compute auto-exposure from histogram and last value m_Buffer_AutoExposureSource.SetInput(0); m_Buffer_AutoExposureTarget.SetOutput(0); m_Tex_Histogram.SetCS(1); float EV = floatTrackbarControlExposure.Value; m_CB_AutoExposure.m._delta_time = Math.Max(0.01f, Math.Min(1.0f, DeltaTime)); if (checkBoxEnable.Checked && checkBoxAutoExposureUseWhiteLevel.Checked) { m_CB_AutoExposure.m._white_level = tabControlToneMappingTypes.SelectedIndex == 0 ? floatTrackbarControlIG_WhitePoint.Value : floatTrackbarControlWhitePoint.Value; } else { m_CB_AutoExposure.m._white_level = 1.0f; } m_CB_AutoExposure.m._clip_shadows = 0.0f; // (0.0) Shadow cropping in histogram (first buckets will be ignored, leading to brighter image) m_CB_AutoExposure.m._clip_highlights = 1.0f; // (1.0) Highlights cropping in histogram (last buckets will be ignored, leading to darker image) m_CB_AutoExposure.m._EV = EV; // (0.0) Your typical EV setting m_CB_AutoExposure.m._fstop_bias = 0.0f; // (0.0) F-stop number bias to override automatic computation (NOTE: This will NOT change exposure, only the F number) m_CB_AutoExposure.m._reference_camera_fps = 30.0f; // (30.0) Default camera at 30 FPS m_CB_AutoExposure.m._adapt_min_luminance = m_advancedParmsForm.floatTrackbarControlMinLuminance.Value; // (0.03) Prevents the auto-exposure to adapt to luminances lower than this m_CB_AutoExposure.m._adapt_max_luminance = m_advancedParmsForm.floatTrackbarControlMaxLuminance.Value; // (2000.0) Prevents the auto-exposure to adapt to luminances higher than this m_CB_AutoExposure.m._adapt_speed_up = m_advancedParmsForm.floatTrackbarControlAdaptationSpeedBright.Value; // (0.99) Adaptation speed from low to high luminances m_CB_AutoExposure.m._adapt_speed_down = m_advancedParmsForm.floatTrackbarControlAdaptationSpeedDark.Value; // (0.99) Adaptation speed from high to low luminances m_CB_AutoExposure.UpdateData(); m_Shader_ComputeAutoExposure.Dispatch(1, 1, 1); // Swap source & target for next frame StructuredBuffer <autoExposure_t> temp = m_Buffer_AutoExposureSource; m_Buffer_AutoExposureSource = m_Buffer_AutoExposureTarget; m_Buffer_AutoExposureTarget = temp; } ////////////////////////////////////////////////////////////////////////// // 3] Apply tone mapping if (m_Shader_ToneMapping.Use()) { m_Device.SetRenderTarget(m_Device.DefaultTarget, null); float mouseU = 1.0f; float mouseV = 0.0f; Point clientMousePos = panelOutput.PointToClient(Control.MousePosition); if (clientMousePos.X >= 0 && clientMousePos.X < panelOutput.Width && clientMousePos.Y >= 0 && clientMousePos.Y < panelOutput.Height) { mouseU = (float)clientMousePos.X / panelOutput.Width; mouseV = (float)clientMousePos.Y / panelOutput.Height; } m_CB_ToneMapping.m._Exposure = 1.0f; //(float) Math.Pow( 2, floatTrackbarControlExposure.Value ); m_CB_ToneMapping.m._Flags = (checkBoxEnable.Checked ? 1U : 0U) | (checkBoxDebugLuminanceLevel.Checked ? 2U : 0U) | (checkBoxShowHistogram.Checked ? 4U : 0U) | (tabControlToneMappingTypes.SelectedIndex == 0 ? 0U : 8U) | (checkBoxLuminanceOnly.Checked ? 16U : 0U); if (tabControlToneMappingTypes.SelectedIndex == 0) { m_CB_ToneMapping.m._WhitePoint = floatTrackbarControlIG_WhitePoint.Value; m_CB_ToneMapping.m._A = floatTrackbarControlIG_BlackPoint.Value; m_CB_ToneMapping.m._B = Math.Min(m_CB_ToneMapping.m._WhitePoint - 1e-3f, floatTrackbarControlIG_JunctionPoint.Value); m_CB_ToneMapping.m._C = ComputeToeStrength(); // floatTrackbarControlIG_ToeStrength.Value; m_CB_ToneMapping.m._D = ComputeShoulderStrength(); // floatTrackbarControlIG_ShoulderStrength.Value; // Compute junction factor float b = m_CB_ToneMapping.m._A; float w = m_CB_ToneMapping.m._WhitePoint; float t = m_CB_ToneMapping.m._C; float s = m_CB_ToneMapping.m._D; float c = m_CB_ToneMapping.m._B; m_CB_ToneMapping.m._E = (1.0f - t) * (c - b) / ((1.0f - s) * (w - c) + (1.0f - t) * (c - b)); } else { // Hable Filmic m_CB_ToneMapping.m._WhitePoint = floatTrackbarControlWhitePoint.Value; m_CB_ToneMapping.m._A = floatTrackbarControlA.Value; m_CB_ToneMapping.m._B = floatTrackbarControlB.Value; m_CB_ToneMapping.m._C = floatTrackbarControlC.Value; m_CB_ToneMapping.m._D = floatTrackbarControlD.Value; m_CB_ToneMapping.m._E = floatTrackbarControlE.Value; m_CB_ToneMapping.m._F = floatTrackbarControlF.Value; } m_CB_ToneMapping.m._DebugLuminanceLevel = floatTrackbarControlDebugLuminanceLevel.Value; m_CB_ToneMapping.m._MouseU = mouseU; m_CB_ToneMapping.m._MouseV = mouseV; m_CB_ToneMapping.UpdateData(); m_Buffer_AutoExposureSource.SetInput(0); m_Tex_Histogram.SetPS(1); m_Tex_HDR.SetPS(2); m_Tex_TallHistogram.SetPS(3); m_Device.RenderFullscreenQuad(m_Shader_ToneMapping); m_Tex_TallHistogram.RemoveFromLastAssignedSlots(); m_Tex_Histogram.RemoveFromLastAssignedSlots(); m_Tex_HDR.RemoveFromLastAssignedSlots(); } // Show! m_Device.Present(false); }
private void buttonShootPhotons_Click(object sender, EventArgs e) { ////////////////////////////////////////////////////////////////////////// // 1] Build initial photon positions and directions float3 SunDirection = new float3(0, 1, 0).Normalized; uint InitialDirection = PackPhotonDirection(-SunDirection); uint InitialColor = EncodeRGBE(new float3(1.0f, 1.0f, 1.0f)); int PhotonsPerSize = (int)Math.Floor(Math.Sqrt(PHOTONS_COUNT)); float PhotonCoverageSize = CLOUDSCAPE_SIZE / PhotonsPerSize; for (int PhotonIndex = 0; PhotonIndex < PHOTONS_COUNT; PhotonIndex++) { int Z = PhotonIndex / PhotonsPerSize; int X = PhotonIndex - Z * PhotonsPerSize; float x = ((X + (float)SimpleRNG.GetUniform()) / PhotonsPerSize - 0.5f) * CLOUDSCAPE_SIZE; float z = ((Z + (float)SimpleRNG.GetUniform()) / PhotonsPerSize - 0.5f) * CLOUDSCAPE_SIZE; m_SB_Photons.m[PhotonIndex].Position.Set(x, z); m_SB_Photons.m[PhotonIndex].Direction = InitialDirection; m_SB_Photons.m[PhotonIndex].RGBE = InitialColor; #if DEBUG_INFOS m_SB_Photons.m[PhotonIndex].Infos.Set(0, 0, 0, 0); // Will store scattering events counter, marched length, steps count, etc. #endif } m_SB_Photons.Write(); ////////////////////////////////////////////////////////////////////////// // 2] Initialize layers & textures // 2.1) Fill source bucket with all photons for (int PhotonIndex = 0; PhotonIndex < PHOTONS_COUNT; PhotonIndex++) { m_SB_PhotonLayerIndices.m[PhotonIndex] = 0U; // Starting from top layer, direction is down } m_SB_PhotonLayerIndices.Write(); // 2.2) Clear photon splatting texture m_Device.Clear(m_Tex_PhotonLayers_Flux, new float4(0, 0, 0, 0)); m_Device.Clear(m_Tex_PhotonLayers_Direction, new float4(0, 0, 0, 0)); ////////////////////////////////////////////////////////////////////////// // 3] Prepare buffers & states m_CloudScapeSize.Set(CLOUDSCAPE_SIZE, floatTrackbarControlCloudscapeThickness.Value, CLOUDSCAPE_SIZE); // 3.1) Prepare density field m_Tex_DensityField.SetCS(2); // 3.2) Constant buffer for photon shooting m_CB_PhotonShooterInput.m.LayersCount = LAYERS_COUNT; m_CB_PhotonShooterInput.m.MaxScattering = 30; m_CB_PhotonShooterInput.m.LayerThickness = m_CloudScapeSize.y / LAYERS_COUNT; m_CB_PhotonShooterInput.m.SigmaScattering = floatTrackbarControlSigmaScattering.Value; // 0.04523893421169302263386206471922f; // re=6µm Gamma=2 N0=4e8 Sigma_t = N0 * PI * re² m_CB_PhotonShooterInput.m.CloudScapeSize = m_CloudScapeSize; // 3.3) Prepare photon splatting buffer & states m_CB_SplatPhoton.m.CloudScapeSize = m_CloudScapeSize; m_CB_SplatPhoton.m.SplatSize = 1.0f * (2.0f / m_Tex_PhotonLayers_Flux.Width); m_CB_SplatPhoton.m.SplatIntensity = 1.0f; // 1000.0f / PHOTONS_COUNT; m_Device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.ADDITIVE); // Splatting is additive m_Tex_PhotonLayers_Flux.RemoveFromLastAssignedSlots(); m_Tex_PhotonLayers_Direction.RemoveFromLastAssignedSlots(); ////////////////////////////////////////////////////////////////////////// // 4] Splat initial photons to the top layer m_PS_PhotonSplatter.Use(); m_SB_Photons.SetInput(0); // RO version for splatting m_SB_PhotonLayerIndices.SetInput(1); // RO version for splatting m_CB_SplatPhoton.m.LayerIndex = 0U; m_CB_SplatPhoton.UpdateData(); m_Device.SetRenderTargets(m_Tex_PhotonLayers_Flux.Width, m_Tex_PhotonLayers_Flux.Height, new View3D[] { m_Tex_PhotonLayers_Flux.GetView(0, 0, 0, 1), m_Tex_PhotonLayers_Direction.GetView(0, 0, 0, 1) }, null); m_Prim_Point.RenderInstanced(m_PS_PhotonSplatter, PHOTONS_COUNT); ////////////////////////////////////////////////////////////////////////// // 5] Render loop int BatchesCount = PHOTONS_COUNT / PHOTON_BATCH_SIZE; m_SB_ProcessedPhotonsCounter.SetOutput(2); for (int BounceIndex = 0; BounceIndex < BOUNCES_COUNT; BounceIndex++) { // 5.1] Process every layers from top to bottom m_SB_ProcessedPhotonsCounter.m[0] = 0; m_SB_ProcessedPhotonsCounter.Write(); // Reset processed photons counter for (int LayerIndex = 0; LayerIndex < LAYERS_COUNT; LayerIndex++) { // 5.1.1) Shoot a bunch of photons from layer "LayerIndex" to layer "LayerIndex+1" m_CS_PhotonShooter.Use(); m_CB_PhotonShooterInput.m.LayerIndex = (uint)LayerIndex; m_SB_Photons.RemoveFromLastAssignedSlots(); m_SB_PhotonLayerIndices.RemoveFromLastAssignedSlots(); m_SB_Photons.SetOutput(0); m_SB_PhotonLayerIndices.SetOutput(1); m_SB_Random.SetInput(0); m_SB_PhaseQuantile.SetInput(1); for (int BatchIndex = 0; BatchIndex < BatchesCount; BatchIndex++) { m_CB_PhotonShooterInput.m.BatchIndex = (uint)BatchIndex; m_CB_PhotonShooterInput.UpdateData(); m_CS_PhotonShooter.Dispatch(1, 1, 1); m_Device.Present(true); // Notify of progress progressBar1.Value = progressBar1.Maximum * (1 + BatchIndex + BatchesCount * (LayerIndex + LAYERS_COUNT * BounceIndex)) / (BOUNCES_COUNT * LAYERS_COUNT * BatchesCount); Application.DoEvents(); } #if DEBUG_INFOS //DEBUG Read back photons buffer m_SB_Photons.Read(); // m_SB_PhotonLayerIndices.Read(); // Verify photons have the same energy and were indeed transported to the next layer unaffected (this test is only valid if the density field is filled with 0s) // for ( int PhotonIndex=0; PhotonIndex < PHOTONS_COUNT; PhotonIndex++ ) // { // if ( m_SB_Photons.m[PhotonIndex].RGBE != 0x80FFFFFF ) // throw new Exception( "Intensity changed!" ); // if ( m_SB_PhotonLayerIndices.m[PhotonIndex] != LayerIndex+1 ) // throw new Exception( "Unexpected layer index!" ); // } //DEBUG #endif // 5.1.2) Splat the photons that got through to the 2D texture array m_PS_PhotonSplatter.Use(); m_SB_Photons.SetInput(0); // RO version for splatting m_SB_PhotonLayerIndices.SetInput(1); // RO version for splatting m_CB_SplatPhoton.m.LayerIndex = (uint)(LayerIndex + 1); m_CB_SplatPhoton.UpdateData(); m_Device.SetRenderTargets(m_Tex_PhotonLayers_Flux.Width, m_Tex_PhotonLayers_Flux.Height, new View3D[] { m_Tex_PhotonLayers_Flux.GetView(0, 0, LayerIndex + 1, 1), m_Tex_PhotonLayers_Direction.GetView(0, 0, LayerIndex + 1, 1) }, null); m_Prim_Point.RenderInstanced(m_PS_PhotonSplatter, PHOTONS_COUNT); } m_SB_ProcessedPhotonsCounter.Read(); if (m_SB_ProcessedPhotonsCounter.m[0] < LOW_PHOTONS_COUNT_RATIO * PHOTONS_COUNT) { break; // We didn't shoot a significant number of photons to go on... } // ================================================================================ // 5.2] Process every layers from bottom to top BounceIndex++; if (BounceIndex >= BOUNCES_COUNT) { break; } m_SB_ProcessedPhotonsCounter.m[0] = 0; m_SB_ProcessedPhotonsCounter.Write(); // Reset processed photons counter for (int LayerIndex = LAYERS_COUNT; LayerIndex > 0; LayerIndex--) { // 5.2.1) Shoot a bunch of photons from layer "LayerIndex" to layer "LayerIndex-1" m_CS_PhotonShooter.Use(); m_CB_PhotonShooterInput.m.LayerIndex = (uint)LayerIndex | 0x80000000U; // <= MSB indicates photons are going up m_SB_Photons.RemoveFromLastAssignedSlots(); m_SB_PhotonLayerIndices.RemoveFromLastAssignedSlots(); m_SB_Photons.SetOutput(0); m_SB_PhotonLayerIndices.SetOutput(1); m_SB_Random.SetInput(0); m_SB_PhaseQuantile.SetInput(1); for (int BatchIndex = 0; BatchIndex < BatchesCount; BatchIndex++) { m_CB_PhotonShooterInput.m.BatchIndex = (uint)BatchIndex; m_CB_PhotonShooterInput.UpdateData(); m_CS_PhotonShooter.Dispatch(1, 1, 1); m_Device.Present(true); // Notify of progress progressBar1.Value = progressBar1.Maximum * (1 + BatchIndex + BatchesCount * (LayerIndex + LAYERS_COUNT * BounceIndex)) / (BOUNCES_COUNT * LAYERS_COUNT * BatchesCount); Application.DoEvents(); } // 5.2.2) Splat the photons that got through to the 2D texture array m_PS_PhotonSplatter.Use(); m_SB_Photons.SetInput(0); // RO version for splatting m_SB_PhotonLayerIndices.SetInput(1); // RO version for splatting m_CB_SplatPhoton.m.LayerIndex = (uint)(LayerIndex - 1) | 0x80000000U; // <= MSB indicates photons are going up m_CB_SplatPhoton.UpdateData(); m_Device.SetRenderTargets(m_Tex_PhotonLayers_Flux.Width, m_Tex_PhotonLayers_Flux.Height, new View3D[] { m_Tex_PhotonLayers_Flux.GetView(0, 0, LayerIndex - 1, 0), m_Tex_PhotonLayers_Direction.GetView(0, 0, LayerIndex - 1, 0) }, null); m_Prim_Point.RenderInstanced(m_PS_PhotonSplatter, PHOTONS_COUNT); } m_SB_ProcessedPhotonsCounter.Read(); if (m_SB_ProcessedPhotonsCounter.m[0] < LOW_PHOTONS_COUNT_RATIO * PHOTONS_COUNT) { break; // We didn't shoot a significant number of photons to go on... } } m_Tex_PhotonLayers_Flux.RemoveFromLastAssignedSlots(); m_Tex_PhotonLayers_Direction.RemoveFromLastAssignedSlots(); Render(); }
private void buttonShootPhotons_Click(object sender, EventArgs e) { ////////////////////////////////////////////////////////////////////////// // 1] Shoot the photons and store the result into the structured buffer m_CS_PhotonShooter.Use(); m_SB_Random.SetInput(0); m_SB_PhaseQuantile.SetInput(1); m_SB_PhotonOut.SetOutput(0); m_CB_PhotonShooterInput.m.MaxScattering = 100; m_CB_PhotonShooterInput.m.InitialPosition = new float2(floatTrackbarControlPositionX.Value, floatTrackbarControlPositionZ.Value); // Center of the cube side m_CB_PhotonShooterInput.m.InitialIncidence = new float2(floatTrackbarControlOrientationPhi.Value * (float)Math.PI / 180.0f, floatTrackbarControlOrientationTheta.Value * (float)Math.PI / 180.0f); // Vertical incidence m_CB_PhotonShooterInput.m.CubeSize = floatTrackbarControlCubeSize.Value; // Try a 100m thick cube // m_CB_PhotonShooterInput.m.SigmaScattering = 0.5f; m_CB_PhotonShooterInput.m.SigmaScattering = 0.04523893421169302263386206471922f; // re=6µm Gamma=2 N0=4e8 Sigma_t = N0 * PI * re² m_CB_PhotonShooterInput.m.FullSurface = (uint)(checkBoxFullSurface.Checked ? 1 : 0); // mean free path = 22.1048m int BatchesCount = PHOTONS_COUNT / PHOTON_BATCH_SIZE; for (int BatchIndex = 0; BatchIndex < BatchesCount; BatchIndex++) { m_CB_PhotonShooterInput.m.BatchIndex = (uint)BatchIndex; m_CB_PhotonShooterInput.UpdateData(); m_CS_PhotonShooter.Dispatch(1, 1, 1); m_Device.Present(true); progressBar1.Value = progressBar1.Maximum * (1 + BatchIndex) / BatchesCount; Application.DoEvents(); } m_SB_PhotonOut.RemoveFromLastAssignedSlots(); ////////////////////////////////////////////////////////////////////////// // Splat photons m_Tex_Photons.RemoveFromLastAssignedSlots(); m_Device.Clear(m_Tex_Photons, new float4(0, 0, 0, 0)); m_SB_PhotonOut.SetInput(0); // Splat data m_CB_SplatPhoton.m.SplatSize = 2.0f * (2.0f / m_Tex_Photons.Width); m_CB_SplatPhoton.UpdateData(); m_Device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.ALPHA_BLEND); View2D[] Views = new View2D[] { m_Tex_Photons.GetView(0, 0, 6 * 0, 6), m_Tex_Photons.GetView(0, 0, 6 * 1, 6), m_Tex_Photons.GetView(0, 0, 6 * 2, 6), }; m_Device.SetRenderTargets(m_Tex_Photons.Width, m_Tex_Photons.Height, Views, null); m_PS_PhotonSplatter.Use(); m_Prim_Point.RenderInstanced(m_PS_PhotonSplatter, PHOTONS_COUNT); // Splat additive intensity m_CB_SplatPhoton.m.SplatSize = 8.0f * (2.0f / m_Tex_Photons.Width); m_CB_SplatPhoton.m.SplatIntensity = 1000.0f / PHOTONS_COUNT; m_CB_SplatPhoton.UpdateData(); m_Device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.ADDITIVE); Views = new View2D[] { m_Tex_Photons.GetView(0, 0, 6 * 3, 6) }; m_Device.SetRenderTargets(m_Tex_Photons.Width, m_Tex_Photons.Height, Views, null); m_PS_PhotonSplatter_Intensity.Use(); m_Prim_Point.RenderInstanced(m_PS_PhotonSplatter_Intensity, PHOTONS_COUNT); m_Tex_Photons.RemoveFromLastAssignedSlots(); Render(); }