From: isk Date: Wed, 10 Feb 2016 08:39:18 +0000 (+0300) Subject: 0026432: Improving Path Tracing functionality X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=33238608fb8328055480c0fa289454b80a2fd8e0;p=occt-copy.git 0026432: Improving Path Tracing functionality Samples per pixel parameter added. Simple filtering added. Lights fixed. Max radiance parameter. --- diff --git a/src/Graphic3d/Graphic3d_RenderingParams.hxx b/src/Graphic3d/Graphic3d_RenderingParams.hxx index 8e0f231332..17483ba2ff 100644 --- a/src/Graphic3d/Graphic3d_RenderingParams.hxx +++ b/src/Graphic3d/Graphic3d_RenderingParams.hxx @@ -61,6 +61,9 @@ public: IsTransparentShadowEnabled (Standard_False), UseEnvironmentMapBackground (Standard_False), CoherentPathTracingMode (Standard_False), + IsGIFilteringEnabled (Standard_False), + RadianceClampValue (10.0), + // stereoscopic parameters StereoMode (Graphic3d_StereoMode_QuadBuffer), AnaglyphFilter (Anaglyph_RedCyan_Optimized), @@ -99,6 +102,8 @@ public: Standard_Boolean IsTransparentShadowEnabled; //!< enables/disables light propagation through transparent media, False by default Standard_Boolean UseEnvironmentMapBackground; //!< enables/disables environment map background Standard_Boolean CoherentPathTracingMode; //!< enables/disables 'coherent' tracing mode (single RNG seed within 16x16 image blocks) + Standard_Boolean IsGIFilteringEnabled; //!< enables/disables post-processing of GI rendering results + Standard_Real RadianceClampValue; //!< maximum radiance value which will not be clamped. Graphic3d_StereoMode StereoMode; //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default Anaglyph AnaglyphFilter; //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index eff171c3ef..6bc13a2488 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -673,10 +673,12 @@ protected: //! @name data types related to ray-tracing OpenGl_RT_uSphereMapForBack, OpenGl_RT_uTexSamplersArray, OpenGl_RT_uBlockedRngEnabled, + OpenGl_RT_uMaxRadiance, // sampled frame params OpenGl_RT_uSampleWeight, OpenGl_RT_uFrameRndSeed, + OpenGl_RT_uBilateralEnabled, // adaptive FSAA params OpenGl_RT_uOffsetX, diff --git a/src/OpenGl/OpenGl_View_Raytrace.cxx b/src/OpenGl/OpenGl_View_Raytrace.cxx index ecc26ac7be..5875738817 100644 --- a/src/OpenGl/OpenGl_View_Raytrace.cxx +++ b/src/OpenGl/OpenGl_View_Raytrace.cxx @@ -1553,6 +1553,8 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context aShaderProgram->GetUniformLocation (theGlContext, "uSampleWeight"); myUniformLocations[anIndex][OpenGl_RT_uFrameRndSeed] = aShaderProgram->GetUniformLocation (theGlContext, "uFrameRndSeed"); + myUniformLocations[anIndex][OpenGl_RT_uMaxRadiance] = + aShaderProgram->GetUniformLocation (theGlContext, "uMaxRadiance"); myUniformLocations[anIndex][OpenGl_RT_uBackColorTop] = aShaderProgram->GetUniformLocation (theGlContext, "uBackColorTop"); @@ -1562,6 +1564,9 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context theGlContext->BindProgram (myOutImageProgram); + myUniformLocations[0][OpenGl_RT_uBilateralEnabled] = + myOutImageProgram->GetUniformLocation (theGlContext, "uBilateralEnabled"); + myOutImageProgram->SetSampler (theGlContext, "uInputTexture", OpenGl_RT_PrevAccumTexture); @@ -2398,14 +2403,53 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Standard_Integer // Set frame accumulation weight myRaytraceProgram->SetUniform (theGlContext, - myUniformLocations[0][OpenGl_RT_uSampleWeight], 1.f / (myAccumFrames + 1)); + myUniformLocations[0][OpenGl_RT_uMaxRadiance], static_cast (theCView.RenderParams.RadianceClampValue)); // Set random number generator seed myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uFrameRndSeed], static_cast (myRNG.NextInt() >> 2)); - } - theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6); + Standard_Integer aSamplesPerPixel = theCView.RenderParams.SamplesPerPixel; + + if (aSamplesPerPixel == 0) + { + // Set frame accumulation weight + myRaytraceProgram->SetUniform (theGlContext, + myUniformLocations[0][OpenGl_RT_uSampleWeight], 1.f / (myAccumFrames + 1)); + + theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6); + } + else + { + for (int aPassIndex = 0; aPassIndex < aSamplesPerPixel; ++aPassIndex) + { + aRenderFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1 : myRaytraceFBO2; + anAccumFramebuffer = myAccumFrames % 2 ? myRaytraceFBO2 : myRaytraceFBO1; + + aRenderFramebuffer->BindBuffer (theGlContext); + + anAccumFramebuffer->ColorTexture()->Bind ( + theGlContext, GL_TEXTURE0 + OpenGl_RT_PrevAccumTexture); + + // Set frame accumulation weight + myRaytraceProgram->SetUniform (theGlContext, + myUniformLocations[0][OpenGl_RT_uSampleWeight], 1.f / (myAccumFrames + 1)); + + // Set random number generator seed + myRaytraceProgram->SetUniform (theGlContext, + myUniformLocations[0][OpenGl_RT_uFrameRndSeed], static_cast (myRNG.NextInt() >> 2)); + + theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6); + ++myAccumFrames; + glFinish(); + } + } + } + else + { + theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6); + ++myAccumFrames; + } if (myRaytraceParameters.GlobalIllumination) { @@ -2427,6 +2471,9 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Standard_Integer aRenderFramebuffer->DepthStencilTexture()->Bind ( theGlContext, GL_TEXTURE0 + OpenGl_RT_DepthTexture); + myOutImageProgram->SetUniform (theGlContext, + myUniformLocations[0][OpenGl_RT_uBilateralEnabled], theCView.RenderParams.IsGIFilteringEnabled ? 1 : 0); + theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6); aRenderFramebuffer->DepthStencilTexture()->Unbind ( diff --git a/src/Shaders/Display.fs b/src/Shaders/Display.fs index 85ebec20e0..66b71181da 100644 --- a/src/Shaders/Display.fs +++ b/src/Shaders/Display.fs @@ -4,16 +4,59 @@ uniform sampler2D uInputTexture; //! Ray tracing depth image. uniform sampler2D uDepthTexture; +uniform int uBilateralEnabled; + //! Output pixel color. out vec4 OutColor; +const float rI = 0.270 * 1.0f; // The intensity radius (in pixels). +const float rL = 1.71 * 0.5f; // The geometric radius (in pixels). +const int WindowSize = 8; // The window size (in pixels). + +float gaussian (float theL, float theR) +{ + return exp (-theL * theL / (2.0f * theR * theR)); +} + +vec4 bilateral() +{ + // Get the sizes + int aWindow = WindowSize / 2; + vec4 anOutCol = vec4 (0.f, 0.f, 0.f, 0.f); + vec4 aRefCol = texelFetch (uInputTexture, ivec2 (gl_FragCoord.xy), 0); + float aNorm = 0.f; + + // Compute the kernel + for (int i = -aWindow; i <= aWindow; i++) + { + for (int j = -aWindow; j <= aWindow; j++) + { + vec4 aCol = texelFetch (uInputTexture, ivec2 (gl_FragCoord.xy) + ivec2 (j, i), 0); + float A = gaussian (distance (aCol, aRefCol), rI); + float B = gaussian (length (vec2(j, i)), rL); + anOutCol += aCol * A * B; + aNorm += A * B; + } + } + return anOutCol * (1.f / aNorm); +} + void main (void) { - vec4 aColor = texelFetch (uInputTexture, ivec2 (gl_FragCoord.xy), 0); + vec4 aColor; + + if (bool (uBilateralEnabled)) + { + aColor = bilateral(); + } + else + { + aColor = texelFetch (uInputTexture, ivec2 (gl_FragCoord.xy), 0); + } float aDepth = texelFetch (uDepthTexture, ivec2 (gl_FragCoord.xy), 0).r; gl_FragDepth = aDepth; // apply gamma correction (we use gamma = 2) OutColor = vec4 (sqrt (aColor.rgb), aColor.a); -} +} \ No newline at end of file diff --git a/src/Shaders/PathtraceBase.fs b/src/Shaders/PathtraceBase.fs index a9c2e10931..276b8d384d 100644 --- a/src/Shaders/PathtraceBase.fs +++ b/src/Shaders/PathtraceBase.fs @@ -473,7 +473,7 @@ void sampleMaterial (in SMaterial theMaterial, theBounce = SPEC_REFLECT_BOUNCE; // specular bounce } - else // specular transmission + else if (aKsi < aReflection) // specular transmission { theWeight *= theMaterial.Kt.rgb * (aReflection / aPt) * sampleSpecularTransmission (theOutput, theInput, theBounce, theWeight, theMaterial.Fresnel); @@ -493,12 +493,12 @@ void sampleMaterial (in SMaterial theMaterial, //======================================================================= float handlePointLight (in vec3 theInput, in vec3 theToLight, in float theRadius, in float theDistance) { - float aDistance = dot (theToLight, theToLight); + float aSquareLightDist = dot (theToLight, theToLight); - float aCosMax = inversesqrt (1.f + theRadius * theRadius / aDistance); + float aCosMax = inversesqrt (1.f + theRadius * theRadius / aSquareLightDist); - return float (aDistance < theDistance * theDistance) * - step (aCosMax, dot (theToLight, theInput) * inversesqrt (aDistance)); + return float (aSquareLightDist < theDistance * theDistance) * + step (aCosMax, dot (theToLight, theInput) * inversesqrt (aSquareLightDist)); } //======================================================================= @@ -514,13 +514,12 @@ float handleDirectLight (in vec3 theInput, in vec3 theToLight, in float theCosMa // function : sampleLight // purpose : general sampling function for directional and point lights //======================================================================= -vec3 sampleLight (in vec3 theToLight, in bool isDirectional, in float theSmoothness, inout float thePDF) +vec3 sampleLight (in vec3 theToLight, in float theDistance, in bool isDirectional, in float theSmoothness, inout float thePDF) { SLocalSpace aSpace = LocalSpace (theToLight); // for point lights smoothness defines radius - float aCosMax = isDirectional ? theSmoothness : - inversesqrt (1.f + theSmoothness * theSmoothness / dot (theToLight, theToLight)); + float aCosMax = inversesqrt (1.f + theSmoothness * theSmoothness / (theDistance * theDistance)); float aKsi1 = RandFloat(); float aKsi2 = RandFloat(); @@ -593,8 +592,8 @@ vec3 intersectLight (in SRay theRay, in bool isViewRay, in int theBounce, in flo return aRadiance; } -#define MIN_THROUGHPUT vec3 (0.02f) -#define MIN_CONTRIBUTION vec3 (0.01f) +#define MIN_THROUGHPUT vec3 (2.0e-2f) +#define MIN_CONTRIBUTION vec3 (0.5e-2f) #define MATERIAL_KD(index) (18 * index + 11) #define MATERIAL_KR(index) (18 * index + 12) @@ -732,7 +731,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse) float aPDF = 1.f / uLightCount, aDistance = length (aLight.xyz); - aLight.xyz = sampleLight (aLight.xyz * (1.f / aDistance), + aLight.xyz = sampleLight (aLight.xyz * (1.f / aDistance), aDistance, aLight.w == 0.f /* is infinite */, aParam.w /* angle cosine */, aPDF); vec3 aContrib = (1.f / aPDF) * aParam.rgb /* Le */ * handleMaterial ( diff --git a/src/Shaders/RaytraceRender.fs b/src/Shaders/RaytraceRender.fs index 25c9bbec19..a8ce317863 100644 --- a/src/Shaders/RaytraceRender.fs +++ b/src/Shaders/RaytraceRender.fs @@ -13,7 +13,8 @@ uniform sampler2D uAccumTexture; //! Increases performance up to 4 times, but noise becomes structured. uniform int uBlockedRngEnabled; -#define MAX_RADIANCE vec3 (10.f) +//! Maximum value for radiance clamping. +uniform float uMaxRadiance; // ======================================================================= // function : main @@ -46,7 +47,7 @@ void main (void) aColor.rgb = ZERO; } - aColor.rgb = min (aColor.rgb, MAX_RADIANCE); + aColor.rgb = min (aColor.rgb, vec3 (uMaxRadiance)); OutColor = mix (texture2D (uAccumTexture, vPixel), aColor, uSampleWeight); #else diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index f882441b80..ceeefb8558 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -8301,6 +8301,8 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, theDI << "reflections: " << (aParams.IsReflectionEnabled ? "on" : "off") << "\n"; theDI << "gleam: " << (aParams.IsTransparentShadowEnabled ? "on" : "off") << "\n"; theDI << "GI: " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n"; + theDI << "samples: " << aParams.SamplesPerPixel << "\n"; + theDI << "filtering: " << (aParams.IsGIFilteringEnabled ? "on" : "off") << "\n"; theDI << "blocked RNG: " << (aParams.CoherentPathTracingMode ? "on" : "off") << "\n"; theDI << "shadingModel: "; switch (aView->ShadingModel()) @@ -8424,6 +8426,48 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, aParams.RaytracingDepth = aDepth; } } + else if (aFlag == "-maxrad" + || aFlag == "-rclamp") + { + if (toPrint) + { + theDI << aParams.RadianceClampValue << " "; + continue; + } + else if (++anArgIter >= theArgNb) + { + std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n"; + return 1; + } + + aParams.RadianceClampValue = Draw::Atoi (theArgVec[anArgIter]); + } + else if (aFlag == "-samples" + || aFlag == "-spp") + { + if (toPrint) + { + theDI << aParams.SamplesPerPixel << " "; + continue; + } + else if (++anArgIter >= theArgNb) + { + std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n"; + return 1; + } + + const Standard_Integer aSamples = Draw::Atoi (theArgVec[anArgIter]); + + if (aSamples < 0) + { + std::cerr << "Error: invalid ray-tracing samples per pixel " << aSamples << ". SPP should be a positive number.\n"; + return 1; + } + else + { + aParams.SamplesPerPixel = aSamples; + } + } else if (aFlag == "-shad" || aFlag == "-shadows") { @@ -8510,6 +8554,22 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10); } } + else if (aFlag == "-filter" || aFlag == "-pp" ) + { + if (toPrint) + { + theDI << (aParams.IsGIFilteringEnabled ? "on" : "off") << " "; + continue; + } + + Standard_Boolean toEnable = Standard_True; + if (++anArgIter < theArgNb + && !parseOnOff (theArgVec[anArgIter], toEnable)) + { + --anArgIter; + } + aParams.IsGIFilteringEnabled = toEnable; + } else if (aFlag == "-blockedrng" || aFlag == "-brng") { diff --git a/tests/v3d/raytrace/2_light_box b/tests/v3d/raytrace/2_light_box new file mode 100644 index 0000000000..71f5ce8205 --- /dev/null +++ b/tests/v3d/raytrace/2_light_box @@ -0,0 +1,40 @@ +puts "========" +puts "Ray Tracing - check PT lights correctness" +puts "========" + +pload ALL +vinit +vsetdispmode 1 +vvbo 0 + +box b 500 500 1 +box b1 2 50 20 + +vdisplay b +vdisplay b1 + +vsetlocation b -250 -250 0 +vsetlocation b1 -1 -25 0 + +vlight del 0 +vlight del 0 + +vlight add positional head 0 pos -10 0 20 +vlight change 0 sm 5.0 + +vrenderparams -ray -gi +vsetmaterial b plaster +vsetmaterial b1 plaster + +vviewparams -scale 23.40302443511418 -proj 3.1690307533723025e-006 -0.053740375441171516 0.99855494192227556 -up 0.00011815109169240122 0.99855493498157033 0.05374037461975216 -at -0.039728087058276865 17.658749465576971 0.40052090530867673 -eye -0.038141096586915293 -9.2534108729671232 500.45788900604856 + +vlight change 0 int 20 + +psphere s 5.0 +vdisplay s +vsetlocation s 10 0 20 + +vbsdf s -Kd 0.0 -Ks 0.0 -Kr 0.0 -Kt 0.0 +vbsdf s -Le 20.0 + +vfps 500 diff --git a/tests/v3d/raytrace/2_light_sphere b/tests/v3d/raytrace/2_light_sphere new file mode 100644 index 0000000000..9eca3a2427 --- /dev/null +++ b/tests/v3d/raytrace/2_light_sphere @@ -0,0 +1,37 @@ +puts "========" +puts "Ray Tracing - check PT lights correctness" +puts "========" + +pload ALL +vinit +vsetdispmode 1 +vvbo 0 + +box b 500 500 1 +psphere s 6.0 + +vdisplay b +vdisplay s + +vsetlocation b -250 -250 0 +vsetlocation s 0.0 0.0 7.0 + +vlight del 0 +vlight del 0 + +vlight add positional head 0 pos -15 0 20 sm 4.0 int 20 + +vrenderparams -ray -gi -rayDepth 12 +vsetmaterial b plaster +vsetmaterial s glass + +psphere ls 4.0 +vdisplay ls +vsetlocation ls 15 0 20 + +vbsdf ls -Kd 0.0 -Ks 0.0 -Kr 0.0 -Kt 0.0 +vbsdf ls -Le 20.0 + +vviewparams -scale 23.40302443511418 -proj 3.1690307533720754e-006 -0.053740375441171412 0.99855494192227556 -up 0.00011815108764545944 0.99855493500381731 0.053740374206389462 -at 0.062905867278332972 2.1147318213590474 -0.43602962811169049 -eye 0.064492857749694432 -24.79742851718504 499.62133847262908 + +vfps 400