1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00

0028129: Visualization, Path Tracing - Improve interactivity in "steady" rendering mode

Re-basing the patch on current master.
This commit is contained in:
dbp 2017-01-26 12:56:13 +03:00 committed by apn
parent 952886f056
commit 4eaaf9d812
13 changed files with 278 additions and 96 deletions

View File

@ -62,6 +62,7 @@ public:
TwoSidedBsdfModels (Standard_False), TwoSidedBsdfModels (Standard_False),
RadianceClampingValue (30.0), RadianceClampingValue (30.0),
RebuildRayTracingShaders (Standard_False), RebuildRayTracingShaders (Standard_False),
NbRayTracingTiles (16 * 16),
// stereoscopic parameters // stereoscopic parameters
StereoMode (Graphic3d_StereoMode_QuadBuffer), StereoMode (Graphic3d_StereoMode_QuadBuffer),
AnaglyphFilter (Anaglyph_RedCyan_Optimized), AnaglyphFilter (Anaglyph_RedCyan_Optimized),
@ -105,6 +106,7 @@ public:
Standard_Boolean TwoSidedBsdfModels; //!< forces path tracing to use two-sided versions of original one-sided scattering models Standard_Boolean TwoSidedBsdfModels; //!< forces path tracing to use two-sided versions of original one-sided scattering models
Standard_ShortReal RadianceClampingValue; //!< maximum radiance value used for clamping radiance estimation. Standard_ShortReal RadianceClampingValue; //!< maximum radiance value used for clamping radiance estimation.
Standard_Boolean RebuildRayTracingShaders; //!< forces rebuilding ray tracing shaders at the next frame Standard_Boolean RebuildRayTracingShaders; //!< forces rebuilding ray tracing shaders at the next frame
Standard_Integer NbRayTracingTiles; //!< total number of screen tiles used in adaptive sampling mode (PT only)
Graphic3d_StereoMode StereoMode; //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default Graphic3d_StereoMode StereoMode; //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
Anaglyph AnaglyphFilter; //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default Anaglyph AnaglyphFilter; //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default

View File

@ -150,36 +150,45 @@ void OpenGl_TileSampler::SetSize (const int theSizeX,
//======================================================================= //=======================================================================
void OpenGl_TileSampler::Upload (const Handle(OpenGl_Context)& theContext, void OpenGl_TileSampler::Upload (const Handle(OpenGl_Context)& theContext,
const Handle(OpenGl_Texture)& theTexture, const Handle(OpenGl_Texture)& theTexture,
bool theAdaptive) const int theNbTilesX,
const int theNbTilesY,
const bool theAdaptive)
{ {
if (theTexture.IsNull()) if (theTexture.IsNull())
{ {
return; return;
} }
std::vector<GLint> aData (myTilesX * myTilesY * 2); const int aNbTilesX = theAdaptive ? theNbTilesX : myTilesX;
for (int aX = 0; aX < myTilesX; ++aX) const int aNbTilesY = theAdaptive ? theNbTilesY : myTilesY;
Standard_ASSERT_RAISE (aNbTilesX * aNbTilesY > 0,
"Error! Number of sampling tiles should be positive");
std::vector<GLint> aData (aNbTilesX * aNbTilesY * 2);
for (int aX = 0; aX < aNbTilesX; ++aX)
{ {
for (int aY = 0; aY < myTilesY; ++aY) for (int aY = 0; aY < aNbTilesY; ++aY)
{ {
if (!theAdaptive) if (!theAdaptive)
{ {
aData[(aY * myTilesX + aX) * 2 + 0] = aX * TileSize(); aData[(aY * aNbTilesX + aX) * 2 + 0] = aX * TileSize();
aData[(aY * myTilesX + aX) * 2 + 1] = aY * TileSize(); aData[(aY * aNbTilesX + aX) * 2 + 1] = aY * TileSize();
} }
else else
{ {
Sample (aData[(aY * myTilesX + aX) * 2 + 0], Sample (aData[(aY * aNbTilesX + aX) * 2 + 0],
aData[(aY * myTilesX + aX) * 2 + 1]); aData[(aY * aNbTilesX + aX) * 2 + 1]);
} }
} }
} }
theTexture->Bind (theContext); theTexture->Bind (theContext);
theContext->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, GL_RG32I, myTilesX, myTilesY, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, &aData.front()); theContext->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, GL_RG32I, aNbTilesX, aNbTilesY, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, &aData.front());
const GLenum anErr = theContext->core11fwd->glGetError();
if (anErr != GL_NO_ERROR) if (theContext->core11fwd->glGetError() != GL_NO_ERROR)
{ {
theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM, theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
"Error! Failed to upload tile offset map on the GPU"); "Error! Failed to upload tile offset map on the GPU");

View File

@ -22,7 +22,12 @@
#include <vector> #include <vector>
//! Tool object used for sampling screen tiles according to estimated pixel variance (used in path tracing engine). //! Tool object used for sampling screen tiles according to estimated pixel variance (used in path tracing engine).
//! To improve GPU thread coherency, render window is split into pixel blocks or tiles. //! To improve GPU thread coherency, rendering window is split into pixel blocks or tiles. The important feature of
//! this approach is that it is possible to keep the same number of tiles for any screen resolution (e.g. 256 tiles
//! can be used for both 512 x 512 window and 1920 x 1080 window). So, a smaller number of tiles allows to increase
//! interactivity (FPS), but at the cost of higher per-frame variance ('noise'). On the contrary a larger number of
//! tiles decrease interactivity, but leads to lower per-frame variance. Note that the total time needed to produce
//! final final image is the same for both cases.
class OpenGl_TileSampler class OpenGl_TileSampler
{ {
public: public:
@ -76,7 +81,9 @@ public:
//! Uploads offsets of sampled tiles to the given OpenGL texture. //! Uploads offsets of sampled tiles to the given OpenGL texture.
Standard_EXPORT void Upload (const Handle(OpenGl_Context)& theContext, Standard_EXPORT void Upload (const Handle(OpenGl_Context)& theContext,
const Handle(OpenGl_Texture)& theTexture, const Handle(OpenGl_Texture)& theTexture,
bool theAdaptive); const int theNbTilesX,
const int theNbTilesY,
const bool theAdaptive);
protected: protected:

View File

@ -711,6 +711,12 @@ protected: //! @name data types related to ray-tracing
//! Maximum radiance value used for clamping radiance estimation. //! Maximum radiance value used for clamping radiance estimation.
Standard_ShortReal RadianceClampingValue; Standard_ShortReal RadianceClampingValue;
//! Number of tiles in X dimension (in adaptive sampling mode).
Standard_Integer NbTilesX;
//! Number of tiles in Y dimension (in adaptive sampling mode).
Standard_Integer NbTilesY;
//! Creates default compile-time ray-tracing parameters. //! Creates default compile-time ray-tracing parameters.
RaytracingParams() RaytracingParams()
: StackSize (THE_DEFAULT_STACK_SIZE), : StackSize (THE_DEFAULT_STACK_SIZE),
@ -721,7 +727,9 @@ protected: //! @name data types related to ray-tracing
TwoSidedBsdfModels (Standard_False), TwoSidedBsdfModels (Standard_False),
AdaptiveScreenSampling (Standard_False), AdaptiveScreenSampling (Standard_False),
UseEnvMapForBackground (Standard_False), UseEnvMapForBackground (Standard_False),
RadianceClampingValue (30.0) { } RadianceClampingValue (30.0),
NbTilesX (16),
NbTilesY (16) { }
}; };
//! Describes state of OpenGL structure. //! Describes state of OpenGL structure.
@ -897,9 +905,11 @@ protected: //! @name methods related to ray-tracing
const Handle(OpenGl_Context)& theGlContext); const Handle(OpenGl_Context)& theGlContext);
//! Runs path tracing (global illumination) kernel. //! Runs path tracing (global illumination) kernel.
Standard_Boolean runPathtrace (const Graphic3d_Camera::Projection theProjection, Standard_Boolean runPathtrace (const Standard_Integer theSizeX,
OpenGl_FrameBuffer* theReadDrawFbo, const Standard_Integer theSizeY,
const Handle(OpenGl_Context)& theGlContext); Graphic3d_Camera::Projection theProjection,
OpenGl_FrameBuffer* theReadDrawFbo,
const Handle(OpenGl_Context)& theGlContext);
//! Redraws the window using OpenGL/GLSL ray-tracing or path tracing. //! Redraws the window using OpenGL/GLSL ray-tracing or path tracing.
Standard_Boolean raytrace (const Standard_Integer theSizeX, Standard_Boolean raytrace (const Standard_Integer theSizeX,

View File

@ -1359,11 +1359,21 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
} }
} }
Standard_Integer aNbTilesX = 8;
Standard_Integer aNbTilesY = 8;
for (Standard_Integer anIdx = 0; aNbTilesX * aNbTilesY < myRenderParams.NbRayTracingTiles; ++anIdx)
{
(anIdx % 2 == 0 ? aNbTilesX : aNbTilesY) <<= 1;
}
if (myRenderParams.RaytracingDepth != myRaytraceParameters.NbBounces if (myRenderParams.RaytracingDepth != myRaytraceParameters.NbBounces
|| myRenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows || myRenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows
|| myRenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination || myRenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination
|| myRenderParams.TwoSidedBsdfModels != myRaytraceParameters.TwoSidedBsdfModels || myRenderParams.TwoSidedBsdfModels != myRaytraceParameters.TwoSidedBsdfModels
|| myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures) || myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures
|| aNbTilesX != myRaytraceParameters.NbTilesX
|| aNbTilesY != myRaytraceParameters.NbTilesY)
{ {
myRaytraceParameters.NbBounces = myRenderParams.RaytracingDepth; myRaytraceParameters.NbBounces = myRenderParams.RaytracingDepth;
myRaytraceParameters.TransparentShadows = myRenderParams.IsTransparentShadowEnabled; myRaytraceParameters.TransparentShadows = myRenderParams.IsTransparentShadowEnabled;
@ -1371,6 +1381,18 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
myRaytraceParameters.TwoSidedBsdfModels = myRenderParams.TwoSidedBsdfModels; myRaytraceParameters.TwoSidedBsdfModels = myRenderParams.TwoSidedBsdfModels;
myRaytraceParameters.UseBindlessTextures = myRaytraceGeometry.HasTextures(); myRaytraceParameters.UseBindlessTextures = myRaytraceGeometry.HasTextures();
#ifdef RAY_TRACE_PRINT_INFO
if (aNbTilesX != myRaytraceParameters.NbTilesX
|| aNbTilesY != myRaytraceParameters.NbTilesY)
{
std::cout << "Number of tiles X: " << aNbTilesX << "\n";
std::cout << "Number of tiles Y: " << aNbTilesY << "\n";
}
#endif
myRaytraceParameters.NbTilesX = aNbTilesX;
myRaytraceParameters.NbTilesY = aNbTilesY;
aToRebuildShaders = Standard_True; aToRebuildShaders = Standard_True;
} }
@ -1848,25 +1870,42 @@ Standard_Boolean OpenGl_View::updateRaytraceBuffers (const Standard_Integer
return Standard_True; return Standard_True;
} }
if (myRaytraceFBO1[0]->GetSizeX() != theSizeX if (myRaytraceParameters.AdaptiveScreenSampling)
|| myRaytraceFBO1[0]->GetSizeY() != theSizeY)
{ {
myAccumFrames = 0; const Standard_Integer aSizeX = std::max (myRaytraceParameters.NbTilesX * 64, theSizeX);
} const Standard_Integer aSizeY = std::max (myRaytraceParameters.NbTilesY * 64, theSizeY);
myRaytraceFBO1[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat); myRaytraceFBO1[0]->InitLazy (theGlContext, aSizeX, aSizeY, GL_RGBA32F, myFboDepthFormat);
myRaytraceFBO2[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat); myRaytraceFBO2[0]->InitLazy (theGlContext, aSizeX, aSizeY, GL_RGBA32F, myFboDepthFormat);
// Init second set of buffers for stereographic rendering. if (myRaytraceFBO1[1]->IsValid()) // second FBO not needed
if (myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo) {
{ myRaytraceFBO1[1]->Release (theGlContext.operator->());
myRaytraceFBO1[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat); myRaytraceFBO2[1]->Release (theGlContext.operator->());
myRaytraceFBO2[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat); }
} }
else else // non-adaptive mode
{ {
myRaytraceFBO1[1]->Release (theGlContext.operator->()); if (myRaytraceFBO1[0]->GetSizeX() != theSizeX
myRaytraceFBO2[1]->Release (theGlContext.operator->()); || myRaytraceFBO1[0]->GetSizeY() != theSizeY)
{
myAccumFrames = 0; // accumulation should be restarted
}
myRaytraceFBO1[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
myRaytraceFBO2[0]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
// Init second set of buffers for stereographic rendering
if (myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
{
myRaytraceFBO1[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
myRaytraceFBO2[1]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
}
else if (myRaytraceFBO1[1]->IsValid()) // second FBO not needed
{
myRaytraceFBO1[1]->Release (theGlContext.operator->());
myRaytraceFBO2[1]->Release (theGlContext.operator->());
}
} }
myTileSampler.SetSize (theSizeX, theSizeY); myTileSampler.SetSize (theSizeX, theSizeY);
@ -1883,6 +1922,8 @@ Standard_Boolean OpenGl_View::updateRaytraceBuffers (const Standard_Integer
if (myRaytraceOutputTexture[0]->SizeX() / 3 != theSizeX if (myRaytraceOutputTexture[0]->SizeX() / 3 != theSizeX
|| myRaytraceOutputTexture[0]->SizeY() / 2 != theSizeY) || myRaytraceOutputTexture[0]->SizeY() / 2 != theSizeY)
{ {
myAccumFrames = 0;
// Due to limitations of OpenGL image load-store extension // Due to limitations of OpenGL image load-store extension
// atomic operations are supported only for single-channel // atomic operations are supported only for single-channel
// images, so we define GL_R32F image. It is used as array // images, so we define GL_R32F image. It is used as array
@ -2634,7 +2675,7 @@ Standard_Boolean OpenGl_View::runRaytraceShaders (const Standard_Integer
if (myRaytraceParameters.GlobalIllumination) // path tracing if (myRaytraceParameters.GlobalIllumination) // path tracing
{ {
aResult &= runPathtrace (theProjection, theReadDrawFbo, theGlContext); aResult &= runPathtrace (theSizeX, theSizeY, theProjection, theReadDrawFbo, theGlContext);
} }
else // Whitted-style ray-tracing else // Whitted-style ray-tracing
{ {
@ -2775,7 +2816,9 @@ Standard_Boolean OpenGl_View::runRaytrace (const Standard_Integer theSize
// function : runPathtrace // function : runPathtrace
// purpose : Runs path tracing shader // purpose : Runs path tracing shader
// ======================================================================= // =======================================================================
Standard_Boolean OpenGl_View::runPathtrace (const Graphic3d_Camera::Projection theProjection, Standard_Boolean OpenGl_View::runPathtrace (const Standard_Integer theSizeX,
const Standard_Integer theSizeY,
const Graphic3d_Camera::Projection theProjection,
OpenGl_FrameBuffer* theReadDrawFbo, OpenGl_FrameBuffer* theReadDrawFbo,
const Handle(OpenGl_Context)& theGlContext) const Handle(OpenGl_Context)& theGlContext)
{ {
@ -2793,13 +2836,12 @@ Standard_Boolean OpenGl_View::runPathtrace (const Graphic3d_Camera::Projection
myTileSampler.Reset(); // reset tile sampler to its initial state myTileSampler.Reset(); // reset tile sampler to its initial state
} }
// We upload tile offset texture each 4 frames in order // Adaptive sampling is starting at the second frame
// to minimize overhead of additional memory bandwidth. myTileSampler.Upload (theGlContext,
// Adaptive sampling is starting after first 30 frames. myRaytraceTileOffsetsTexture,
if (myAccumFrames % 4 == 0) myRaytraceParameters.NbTilesX,
{ myRaytraceParameters.NbTilesY,
myTileSampler.Upload (theGlContext, myRaytraceTileOffsetsTexture, myAccumFrames > 30); myAccumFrames > 0);
}
} }
bindRaytraceTextures (theGlContext); bindRaytraceTextures (theGlContext);
@ -2859,9 +2901,25 @@ Standard_Boolean OpenGl_View::runPathtrace (const Graphic3d_Camera::Projection
glDisable (GL_DEPTH_TEST); glDisable (GL_DEPTH_TEST);
if (myRaytraceParameters.AdaptiveScreenSampling && myAccumFrames > 0)
{
glViewport (0,
0,
myTileSampler.TileSize() * myRaytraceParameters.NbTilesX,
myTileSampler.TileSize() * myRaytraceParameters.NbTilesY);
}
// Generate for the given RNG seed // Generate for the given RNG seed
theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6); theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
if (myRaytraceParameters.AdaptiveScreenSampling && myAccumFrames > 0)
{
glViewport (0,
0,
theSizeX,
theSizeY);
}
// Output accumulated path traced image // Output accumulated path traced image
theGlContext->BindProgram (myOutImageProgram); theGlContext->BindProgram (myOutImageProgram);

View File

@ -2,6 +2,8 @@
#extension GL_ARB_shader_image_load_store : require #extension GL_ARB_shader_image_load_store : require
#extension GL_ARB_shader_image_size : enable
//! OpenGL image used for accumulating rendering result. //! OpenGL image used for accumulating rendering result.
volatile restrict layout(size1x32) uniform image2D uRenderImage; volatile restrict layout(size1x32) uniform image2D uRenderImage;
@ -87,8 +89,9 @@ void main (void)
// calculate visual error // calculate visual error
float anError = (aAverRad - aHalfRad) * (aAverRad - aHalfRad); float anError = (aAverRad - aHalfRad) * (aAverRad - aHalfRad);
// accumulate visual error to current block // accumulate visual error to current block; estimated error is written only
imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (anError * SCALE_FACTOR)); // after the first 40 samples and path length has reached 10 bounces or more
imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (mix (SCALE_FACTOR, anError * SCALE_FACTOR, aColor.w > 40.f)));
if (uDebugAdaptive == 0) // normal rendering if (uDebugAdaptive == 0) // normal rendering
{ {
@ -96,7 +99,13 @@ void main (void)
} }
else // showing number of samples else // showing number of samples
{ {
aColor = vec4 (0.5f * aColor.rgb * aSampleWeight + vec3 (0.f, aColor.w / uAccumFrames * 0.35f, 0.f), 1.0); vec2 aRatio = vec2 (1.f, 1.f);
#ifdef GL_ARB_shader_image_size
aRatio = vec2 (imageSize (uRenderImage)) / vec2 (3.f * 512.f, 2.f * 512.f);
#endif
aColor = vec4 (0.5f * aColor.rgb * aSampleWeight + vec3 (0.f, sqrt (aRatio.x * aRatio.y) * aColor.w / uAccumFrames * 0.35f, 0.f), 1.0);
} }
#endif // ADAPTIVE_SAMPLING #endif // ADAPTIVE_SAMPLING

View File

@ -12,9 +12,6 @@
#ifdef PATH_TRACING #ifdef PATH_TRACING
//! Number of previously rendered frames.
uniform int uAccumSamples;
/////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////
// Specific data types // Specific data types
@ -700,17 +697,26 @@ vec3 IntersectLight (in SRay theRay, in int theDepth, in float theHitDistance, o
#define MATERIAL_FRESNEL(index) (18 * index + 16) #define MATERIAL_FRESNEL(index) (18 * index + 16)
#define MATERIAL_ABSORPT(index) (18 * index + 17) #define MATERIAL_ABSORPT(index) (18 * index + 17)
// Enables expiremental russian roulette sampling //! Enables experimental russian roulette sampling path termination.
//! In most cases, it provides faster image convergence with minimal
//! bias, so it is enabled by default.
#define RUSSIAN_ROULETTE #define RUSSIAN_ROULETTE
//! Frame step to increase number of bounces //! Frame step to increase number of bounces. This mode is used
#define FRAME_STEP 5 //! for interaction with the model, when path length is limited
//! for the first samples, and gradually increasing when camera
//! is stabilizing.
#ifdef ADAPTIVE_SAMPLING
#define FRAME_STEP 4
#else
#define FRAME_STEP 5
#endif
//======================================================================= //=======================================================================
// function : PathTrace // function : PathTrace
// purpose : Calculates radiance along the given ray // purpose : Calculates radiance along the given ray
//======================================================================= //=======================================================================
vec4 PathTrace (in SRay theRay, in vec3 theInverse) vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)
{ {
float aRaytraceDepth = MAXFLOAT; float aRaytraceDepth = MAXFLOAT;
@ -867,7 +873,8 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
aSurvive = aDepth < 3 ? 1.f : min (dot (LUMA, aThroughput), 0.95f); aSurvive = aDepth < 3 ? 1.f : min (dot (LUMA, aThroughput), 0.95f);
#endif #endif
if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= uAccumSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF)) // here, we additionally increase path length for non-diffuse bounces
if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= theNbSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))
{ {
aDepth = INVALID_BOUNCES; // terminate path aDepth = INVALID_BOUNCES; // terminate path
} }

View File

@ -8,6 +8,9 @@ uniform int uFrameRndSeed;
//! become structured. Can be used fo final rendering. //! become structured. Can be used fo final rendering.
uniform int uBlockedRngEnabled; uniform int uBlockedRngEnabled;
//! Number of previously rendered frames (used in non-ISS mode).
uniform int uAccumSamples;
#ifndef ADAPTIVE_SAMPLING #ifndef ADAPTIVE_SAMPLING
//! Input image with previously accumulated samples. //! Input image with previously accumulated samples.
uniform sampler2D uAccumTexture; uniform sampler2D uAccumTexture;
@ -57,7 +60,18 @@ void main (void)
#ifdef PATH_TRACING #ifdef PATH_TRACING
vec4 aColor = PathTrace (aRay, aInvDirect); #ifndef ADAPTIVE_SAMPLING
vec4 aColor = PathTrace (aRay, aInvDirect, uAccumSamples);
#else
float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,
2 * aFragCoord.y + 1), 1.0);
vec4 aColor = PathTrace (aRay, aInvDirect, int (aNbSamples));
#endif
if (any (isnan (aColor.rgb))) if (any (isnan (aColor.rgb)))
{ {
@ -78,18 +92,12 @@ void main (void)
imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2, imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,
2 * aFragCoord.y + 1), aColor.w); 2 * aFragCoord.y + 1), aColor.w);
// accumulate number of samples
float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,
2 * aFragCoord.y + 1), 1.0);
if (int (aNbSamples) % 2 == 0) // accumulate luminance for even samples only if (int (aNbSamples) % 2 == 0) // accumulate luminance for even samples only
{ {
imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2, imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,
2 * aFragCoord.y + 0), dot (LUMA, aColor.rgb)); 2 * aFragCoord.y + 0), dot (LUMA, aColor.rgb));
} }
discard; // fragment should not be written to frame buffer
#else #else
if (uAccumSamples == 0) if (uAccumSamples == 0)

View File

@ -5,6 +5,8 @@ static const char Shaders_Display_fs[] =
"\n" "\n"
" #extension GL_ARB_shader_image_load_store : require\n" " #extension GL_ARB_shader_image_load_store : require\n"
"\n" "\n"
" #extension GL_ARB_shader_image_size : enable\n"
"\n"
" //! OpenGL image used for accumulating rendering result.\n" " //! OpenGL image used for accumulating rendering result.\n"
" volatile restrict layout(size1x32) uniform image2D uRenderImage;\n" " volatile restrict layout(size1x32) uniform image2D uRenderImage;\n"
"\n" "\n"
@ -90,8 +92,9 @@ static const char Shaders_Display_fs[] =
" // calculate visual error\n" " // calculate visual error\n"
" float anError = (aAverRad - aHalfRad) * (aAverRad - aHalfRad);\n" " float anError = (aAverRad - aHalfRad) * (aAverRad - aHalfRad);\n"
"\n" "\n"
" // accumulate visual error to current block\n" " // accumulate visual error to current block; estimated error is written only\n"
" imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (anError * SCALE_FACTOR));\n" " // after the first 40 samples and path length has reached 10 bounces or more\n"
" imageAtomicAdd (uVarianceImage, ivec2 (aPixel / vec2 (BLOCK_SIZE)), int (mix (SCALE_FACTOR, anError * SCALE_FACTOR, aColor.w > 40.f)));\n"
"\n" "\n"
" if (uDebugAdaptive == 0) // normal rendering\n" " if (uDebugAdaptive == 0) // normal rendering\n"
" {\n" " {\n"
@ -99,7 +102,13 @@ static const char Shaders_Display_fs[] =
" }\n" " }\n"
" else // showing number of samples\n" " else // showing number of samples\n"
" {\n" " {\n"
" aColor = vec4 (0.5f * aColor.rgb * aSampleWeight + vec3 (0.f, aColor.w / uAccumFrames * 0.35f, 0.f), 1.0);\n" " vec2 aRatio = vec2 (1.f, 1.f);\n"
"\n"
"#ifdef GL_ARB_shader_image_size\n"
" aRatio = vec2 (imageSize (uRenderImage)) / vec2 (3.f * 512.f, 2.f * 512.f);\n"
"#endif\n"
"\n"
" aColor = vec4 (0.5f * aColor.rgb * aSampleWeight + vec3 (0.f, sqrt (aRatio.x * aRatio.y) * aColor.w / uAccumFrames * 0.35f, 0.f), 1.0);\n"
" }\n" " }\n"
"\n" "\n"
"#endif // ADAPTIVE_SAMPLING\n" "#endif // ADAPTIVE_SAMPLING\n"

View File

@ -15,9 +15,6 @@ static const char Shaders_PathtraceBase_fs[] =
"\n" "\n"
"#ifdef PATH_TRACING\n" "#ifdef PATH_TRACING\n"
"\n" "\n"
"//! Number of previously rendered frames.\n"
"uniform int uAccumSamples;\n"
"\n"
"///////////////////////////////////////////////////////////////////////////////////////\n" "///////////////////////////////////////////////////////////////////////////////////////\n"
"// Specific data types\n" "// Specific data types\n"
"\n" "\n"
@ -703,17 +700,26 @@ static const char Shaders_PathtraceBase_fs[] =
"#define MATERIAL_FRESNEL(index) (18 * index + 16)\n" "#define MATERIAL_FRESNEL(index) (18 * index + 16)\n"
"#define MATERIAL_ABSORPT(index) (18 * index + 17)\n" "#define MATERIAL_ABSORPT(index) (18 * index + 17)\n"
"\n" "\n"
"// Enables expiremental russian roulette sampling\n" "//! Enables experimental russian roulette sampling path termination.\n"
"//! In most cases, it provides faster image convergence with minimal\n"
"//! bias, so it is enabled by default.\n"
"#define RUSSIAN_ROULETTE\n" "#define RUSSIAN_ROULETTE\n"
"\n" "\n"
"//! Frame step to increase number of bounces\n" "//! Frame step to increase number of bounces. This mode is used\n"
"#define FRAME_STEP 5\n" "//! for interaction with the model, when path length is limited\n"
"//! for the first samples, and gradually increasing when camera\n"
"//! is stabilizing.\n"
"#ifdef ADAPTIVE_SAMPLING\n"
" #define FRAME_STEP 4\n"
"#else\n"
" #define FRAME_STEP 5\n"
"#endif\n"
"\n" "\n"
"//=======================================================================\n" "//=======================================================================\n"
"// function : PathTrace\n" "// function : PathTrace\n"
"// purpose : Calculates radiance along the given ray\n" "// purpose : Calculates radiance along the given ray\n"
"//=======================================================================\n" "//=======================================================================\n"
"vec4 PathTrace (in SRay theRay, in vec3 theInverse)\n" "vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)\n"
"{\n" "{\n"
" float aRaytraceDepth = MAXFLOAT;\n" " float aRaytraceDepth = MAXFLOAT;\n"
"\n" "\n"
@ -870,7 +876,8 @@ static const char Shaders_PathtraceBase_fs[] =
" aSurvive = aDepth < 3 ? 1.f : min (dot (LUMA, aThroughput), 0.95f);\n" " aSurvive = aDepth < 3 ? 1.f : min (dot (LUMA, aThroughput), 0.95f);\n"
"#endif\n" "#endif\n"
"\n" "\n"
" if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= uAccumSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))\n" " // here, we additionally increase path length for non-diffuse bounces\n"
" if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= theNbSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))\n"
" {\n" " {\n"
" aDepth = INVALID_BOUNCES; // terminate path\n" " aDepth = INVALID_BOUNCES; // terminate path\n"
" }\n" " }\n"

View File

@ -11,6 +11,9 @@ static const char Shaders_RaytraceRender_fs[] =
"//! become structured. Can be used fo final rendering.\n" "//! become structured. Can be used fo final rendering.\n"
"uniform int uBlockedRngEnabled;\n" "uniform int uBlockedRngEnabled;\n"
"\n" "\n"
"//! Number of previously rendered frames (used in non-ISS mode).\n"
"uniform int uAccumSamples;\n"
"\n"
"#ifndef ADAPTIVE_SAMPLING\n" "#ifndef ADAPTIVE_SAMPLING\n"
" //! Input image with previously accumulated samples.\n" " //! Input image with previously accumulated samples.\n"
" uniform sampler2D uAccumTexture;\n" " uniform sampler2D uAccumTexture;\n"
@ -60,7 +63,18 @@ static const char Shaders_RaytraceRender_fs[] =
"\n" "\n"
"#ifdef PATH_TRACING\n" "#ifdef PATH_TRACING\n"
"\n" "\n"
" vec4 aColor = PathTrace (aRay, aInvDirect);\n" "#ifndef ADAPTIVE_SAMPLING\n"
"\n"
" vec4 aColor = PathTrace (aRay, aInvDirect, uAccumSamples);\n"
"\n"
"#else\n"
"\n"
" float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,\n"
" 2 * aFragCoord.y + 1), 1.0);\n"
"\n"
" vec4 aColor = PathTrace (aRay, aInvDirect, int (aNbSamples));\n"
"\n"
"#endif\n"
"\n" "\n"
" if (any (isnan (aColor.rgb)))\n" " if (any (isnan (aColor.rgb)))\n"
" {\n" " {\n"
@ -81,18 +95,12 @@ static const char Shaders_RaytraceRender_fs[] =
" imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,\n" " imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,\n"
" 2 * aFragCoord.y + 1), aColor.w);\n" " 2 * aFragCoord.y + 1), aColor.w);\n"
"\n" "\n"
" // accumulate number of samples\n"
" float aNbSamples = imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 0,\n"
" 2 * aFragCoord.y + 1), 1.0);\n"
"\n"
" if (int (aNbSamples) % 2 == 0) // accumulate luminance for even samples only\n" " if (int (aNbSamples) % 2 == 0) // accumulate luminance for even samples only\n"
" {\n" " {\n"
" imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,\n" " imageAtomicAdd (uRenderImage, ivec2 (3 * aFragCoord.x + 2,\n"
" 2 * aFragCoord.y + 0), dot (LUMA, aColor.rgb));\n" " 2 * aFragCoord.y + 0), dot (LUMA, aColor.rgb));\n"
" }\n" " }\n"
"\n" "\n"
" discard; // fragment should not be written to frame buffer\n"
"\n"
"#else\n" "#else\n"
"\n" "\n"
" if (uAccumSamples == 0)\n" " if (uAccumSamples == 0)\n"

View File

@ -9076,6 +9076,7 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
theDI << "iss debug: " << (aParams.ShowSamplingTiles ? "on" : "off") << "\n"; theDI << "iss debug: " << (aParams.ShowSamplingTiles ? "on" : "off") << "\n";
theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels ? "on" : "off") << "\n"; theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels ? "on" : "off") << "\n";
theDI << "max radiance: " << aParams.RadianceClampingValue << "\n"; theDI << "max radiance: " << aParams.RadianceClampingValue << "\n";
theDI << "nb tiles (iss): " << aParams.NbRayTracingTiles << "\n";
theDI << "shadingModel: "; theDI << "shadingModel: ";
switch (aView->ShadingModel()) switch (aView->ShadingModel())
{ {
@ -9364,6 +9365,32 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
} }
aParams.ShowSamplingTiles = toEnable; aParams.ShowSamplingTiles = toEnable;
} }
else if (aFlag == "-nbtiles")
{
if (toPrint)
{
theDI << aParams.NbRayTracingTiles << " ";
continue;
}
else if (++anArgIter >= theArgNb)
{
std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n";
return 1;
}
const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
if (aNbTiles < 64)
{
std::cerr << "Error: invalid number of ISS tiles " << aNbTiles << ".\n";
std::cerr << "Specify value in range [64, 1024].\n";
return 1;
}
else
{
aParams.NbRayTracingTiles = aNbTiles;
}
}
else if (aFlag == "-env") else if (aFlag == "-env")
{ {
if (toPrint) if (toPrint)
@ -10924,25 +10951,26 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
__FILE__, VRenderParams, group); __FILE__, VRenderParams, group);
theCommands.Add("vrenderparams", theCommands.Add("vrenderparams",
"\n Manages rendering parameters: " "\n Manages rendering parameters: "
"\n '-raster' Disables GPU ray-tracing" "\n '-raster' Disables GPU ray-tracing"
"\n '-msaa 0..4' Specifies number of samples for MSAA" "\n '-msaa 0..4' Specifies number of samples for MSAA"
"\n '-rayTrace' Enables GPU ray-tracing" "\n '-rayTrace' Enables GPU ray-tracing"
"\n '-rayDepth 0..10' Defines maximum ray-tracing depth" "\n '-rayDepth 0..10' Defines maximum ray-tracing depth"
"\n '-shadows on|off' Enables/disables shadows rendering" "\n '-shadows on|off' Enables/disables shadows rendering"
"\n '-reflections on|off' Enables/disables specular reflections" "\n '-reflections on|off' Enables/disables specular reflections"
"\n '-fsaa on|off' Enables/disables adaptive anti-aliasing" "\n '-fsaa on|off' Enables/disables adaptive anti-aliasing"
"\n '-gleam on|off' Enables/disables transparency shadow effects" "\n '-gleam on|off' Enables/disables transparency shadow effects"
"\n '-gi on|off' Enables/disables global illumination effects" "\n '-gi on|off' Enables/disables global illumination effects"
"\n '-brng on|off' Enables/disables blocked RNG (fast coherent PT)" "\n '-brng on|off' Enables/disables blocked RNG (fast coherent PT)"
"\n '-env on|off' Enables/disables environment map background" "\n '-env on|off' Enables/disables environment map background"
"\n '-twoside on|off' Enables/disables two-sided BSDF models (PT mode)" "\n '-twoside on|off' Enables/disables two-sided BSDF models (PT mode)"
"\n '-iss on|off' Enables/disables adaptive screen sampling (PT mode)" "\n '-iss on|off' Enables/disables adaptive screen sampling (PT mode)"
"\n '-issd on|off' Shows screen sampling distribution in ISS mode" "\n '-issd on|off' Shows screen sampling distribution in ISS mode"
"\n '-maxrad > 0.0' Value used for clamping radiance estimation (PT mode)" "\n '-maxrad > 0.0' Value used for clamping radiance estimation (PT mode)"
"\n '-rebuildGlsl on|off' Rebuild Ray-Tracing GLSL programs (for debugging)" "\n '-nbtiles 64..1024' Specifies number of screen tiles in ISS mode"
"\n '-shadingModel model' Controls shading model from enumeration" "\n '-rebuildGlsl on|off' Rebuild Ray-Tracing GLSL programs (for debugging)"
"\n color, flat, gouraud, phong" "\n '-shadingModel model' Controls shading model from enumeration"
"\n '-resolution value' Sets a new pixels density (PPI), defines scaling factor for parameters like text size" "\n color, flat, gouraud, phong"
"\n '-resolution value' Sets a new pixels density (PPI), defines scaling factor for parameters like text size"
"\n Unlike vcaps, these parameters dramatically change visual properties." "\n Unlike vcaps, these parameters dramatically change visual properties."
"\n Command is intended to control presentation quality depending on" "\n Command is intended to control presentation quality depending on"
"\n hardware capabilities and performance.", "\n hardware capabilities and performance.",

View File

@ -0,0 +1,20 @@
puts "============"
puts "Visualization - Path Tracing, Ball sample (ISS mode)"
puts "============"
puts ""
cpulimit 1000
source $env(CSF_OCCTSamplesPath)/tcl/pathtrace_ball.tcl
vrenderparams -iss -nbtiles 64
vfps 1024
vdump $imagedir/${casename}_iss_64.png
vrenderparams -iss -nbtiles 256
vfps 256
vdump $imagedir/${casename}_iss_256.png
vrenderparams -iss -nbtiles 1024
vfps 64
vdump $imagedir/${casename}_iss_1024.png