TwoSidedBsdfModels (Standard_False),
RadianceClampingValue (30.0),
RebuildRayTracingShaders (Standard_False),
+ RayTracingTileSize (32),
NbRayTracingTiles (16 * 16),
CameraApertureRadius (0.0f),
CameraFocalPlaneDist (1.0f),
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_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)
+ Standard_Integer RayTracingTileSize; //!< screen tile size, 32 by default (adaptive sampling mode of path tracing);
+ Standard_Integer NbRayTracingTiles; //!< maximum number of screen tiles per frame, 256 by default (adaptive sampling mode of path tracing);
+ //! this parameter limits the number of tiles to be rendered per redraw, increasing Viewer interactivity,
+ //! but also increasing the time for achieving a good quality; -1 means no limit
Standard_ShortReal CameraApertureRadius; //!< aperture radius of perspective camera used for depth-of-field, 0.0 by default (no DOF) (path tracing only)
Standard_ShortReal CameraFocalPlaneDist; //!< focal distance of perspective camera used for depth-of field, 1.0 by default (path tracing only)
FrustumCulling FrustumCullingState; //!< state of frustum culling optimization; FrustumCulling_On by default
Image_PixMap.cxx
Image_PixMap.hxx
Image_PixMapData.hxx
+Image_PixMapTypedData.hxx
Image_VideoRecorder.cxx
Image_VideoRecorder.hxx
}
//! Initializer.
- void Init (const Handle(NCollection_BaseAllocator)& theAlloc,
+ bool Init (const Handle(NCollection_BaseAllocator)& theAlloc,
const Standard_Size theSizeBPP,
const Standard_Size theSizeX,
const Standard_Size theSizeY,
Allocate (mySize);
}
SetTopDown (TopToDown == 1);
+ return !IsEmpty();
+ }
+
+ //! Reset all values to zeros.
+ void ZeroData()
+ {
+ if (myData != NULL)
+ {
+ memset (myData, 0, mySize);
+ }
}
//! @return data pointer to requested row (first column).
--- /dev/null
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Image_PixMapTypedData_Header
+#define _Image_PixMapTypedData_Header
+
+#include <Image_PixMapData.hxx>
+
+//! Structure to manage image buffer with predefined pixel type.
+template<typename PixelType_t>
+class Image_PixMapTypedData : public Image_PixMapData
+{
+public:
+ //! Empty constructor.
+ Image_PixMapTypedData() {}
+
+ //! Initializer.
+ bool Init (const Handle(NCollection_BaseAllocator)& theAlloc,
+ Standard_Size theSizeX,
+ Standard_Size theSizeY,
+ Standard_Size theSizeRowBytes = 0,
+ Standard_Byte* theDataPtr = 0)
+ {
+ const Standard_Size aSizeBPP = sizeof(PixelType_t);
+ return Image_PixMapData::Init (theAlloc, aSizeBPP, theSizeX, theSizeY, theSizeRowBytes, theDataPtr);
+ }
+
+ //! Reset all values to specified one.
+ void Init (const PixelType_t& theValue)
+ {
+ for (Standard_Size aRowIter = 0; aRowIter < SizeY; ++aRowIter)
+ {
+ for (Standard_Size aColIter = 0; aColIter < SizeX; ++aColIter)
+ {
+ ChangeValue (aRowIter, aColIter) = theValue;
+ }
+ }
+ }
+
+ //! @return data pointer to requested row (first column).
+ const PixelType_t* Row (Standard_Size theRow) const { return (const PixelType_t* )Image_PixMapData::Row (theRow); }
+
+ //! @return data pointer to requested row (first column).
+ PixelType_t* ChangeRow (Standard_Size theRow) { return (PixelType_t* )Image_PixMapData::ChangeRow (theRow); }
+
+ //! @return data pointer to requested position.
+ const PixelType_t& Value (Standard_Size theRow, Standard_Size theCol) const { return *(const PixelType_t* )Image_PixMapData::Value (theRow, theCol); }
+
+ //! @return data pointer to requested position.
+ PixelType_t& ChangeValue (Standard_Size theRow, Standard_Size theCol) { return *(PixelType_t* )Image_PixMapData::ChangeValue (theRow, theCol); }
+
+};
+
+#endif // _Image_PixMapTypedData_Header
const Graphic3d_TypeOfTexture theType,
const Image_PixMap* theImage)
{
+ if (theSizeX < 1
+ || theSizeY < 1)
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error: texture of 0 size cannot be created.");
+ Release (theCtx.operator->());
+ return false;
+ }
+
#if !defined(GL_ES_VERSION_2_0)
const GLenum aTarget = theType == Graphic3d_TOT_1D
? GL_TEXTURE_1D
#include <OpenGl_Context.hxx>
#include <OpenGl_TileSampler.hxx>
+#include <Graphic3d_RenderingParams.hxx>
#include <TCollection_ExtendedString.hxx>
-namespace
-{
- //! Scale factor for estimating visual error.
- static const float THE_SCALE_FACTOR = 1.0f / 1e6f;
-}
-
//=======================================================================
//function : OpenGl_TileSampler
//purpose :
//=======================================================================
OpenGl_TileSampler::OpenGl_TileSampler()
-: mySample (0),
- mySizeX (0),
- mySizeY (0),
- myTilesX (0),
- myTilesY (0)
+: myLastSample (0),
+ myScaleFactor(1.0f),
+ myTileSize (0),
+ myViewSize (0, 0)
{
mySampler.initFaure();
}
//function : GrabVarianceMap
//purpose :
//=======================================================================
-void OpenGl_TileSampler::GrabVarianceMap (const Handle(OpenGl_Context)& theContext)
+void OpenGl_TileSampler::GrabVarianceMap (const Handle(OpenGl_Context)& theContext,
+ const Handle(OpenGl_Texture)& theTexture)
{
-#if !defined(GL_ES_VERSION_2_0)
- std::vector<GLint> aRawData (NbTiles(), 0);
+ if (theTexture.IsNull())
+ {
+ return;
+ }
- theContext->core11fwd->glGetTexImage (GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_INT, &aRawData.front());
+ myVarianceRaw.Init (0);
+#if !defined(GL_ES_VERSION_2_0)
+ theTexture->Bind (theContext);
+ theContext->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1);
+ theContext->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
+ theContext->core11fwd->glGetTexImage (GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_INT, myVarianceRaw.ChangeData());
const GLenum anErr = theContext->core11fwd->glGetError();
+ theTexture->Unbind (theContext);
if (anErr != GL_NO_ERROR)
{
theContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_MEDIUM,
"Error! Failed to fetch visual error map from the GPU");
+ return;
}
- else
- {
- for (int aTileIdx = 0, aNbTiles = NbTiles(); aTileIdx < aNbTiles; ++aTileIdx)
- {
- myVarianceMap[aTileIdx] = aRawData[aTileIdx] * THE_SCALE_FACTOR;
- }
+#else
+ // glGetTexImage() is unavailable on OpenGL ES, FBO + glReadPixels() can be used instead
+ (void )theContext;
+#endif
- for (int aX = 0; aX < myTilesX; ++aX)
+ const float aFactor = 1.0f / myScaleFactor;
+ for (Standard_Size aColIter = 0; aColIter < myVarianceMap.SizeX; ++aColIter)
+ {
+ for (Standard_Size aRowIter = 0; aRowIter < myVarianceMap.SizeY; ++aRowIter)
{
- for (int aY = 0; aY < myTilesY; ++aY)
+ const int aRawValue = myVarianceRaw.Value (aRowIter, aColIter);
+ float& aTile = myVarianceMap.ChangeValue (aRowIter, aColIter);
+ aTile = aFactor * float(aRawValue);
+ aTile *= 1.0f / tileArea ((int )aColIter, (int )aRowIter); // average error over the tile
+ if (aRowIter != 0)
{
- ChangeTile (aX, aY) *= 1.0f / TileArea (aX, aY); // average error over the tile
-
- if (aY > 0)
- {
- ChangeTile (aX, aY) += Tile (aX, aY - 1);
- }
+ aTile += myVarianceMap.Value (aRowIter - 1, aColIter);
}
}
+ }
- myMarginalMap.resize (myTilesX); // build marginal distribution
- for (int aX = 0; aX < myTilesX; ++aX)
+ // build marginal distribution
+ for (Standard_Size aX = 0; aX < myVarianceMap.SizeX; ++aX)
+ {
+ myMarginalMap[aX] = myVarianceMap.Value (myVarianceMap.SizeY - 1, aX);
+ if (aX != 0)
{
- myMarginalMap[aX] = Tile (aX, myTilesY - 1);
-
- if (aX > 0)
- myMarginalMap[aX] += myMarginalMap[aX - 1];
+ myMarginalMap[aX] += myMarginalMap[aX - 1];
}
}
-#else
- // glGetTexImage() is unavailable on OpenGL ES, FBO + glReadPixels() can be used instead
- (void )theContext;
-#endif
}
//=======================================================================
-//function : Sample
+//function : nextTileToSample
//purpose :
//=======================================================================
-void OpenGl_TileSampler::Sample (int& theOffsetX,
- int& theOffsetY)
+Graphic3d_Vec2i OpenGl_TileSampler::nextTileToSample()
{
- int aX = 0;
- int aY = 0;
-
- const float aKsiX = mySampler.sample (0, mySample) * myMarginalMap.back();
- for (; aX < myTilesX - 1; ++aX)
+ Graphic3d_Vec2i aTile (0, 0);
+ const float aKsiX = mySampler.sample (0, myLastSample) * myMarginalMap.back();
+ for (; (size_t )aTile.x() < myMarginalMap.size() - 1; ++aTile.x())
{
- if (aKsiX <= myMarginalMap[aX])
+ if (aKsiX <= myMarginalMap[aTile.x()])
{
break;
}
}
- const float aKsiY = mySampler.sample (1, mySample) * Tile (aX, myTilesY - 1);
- for (; aY < myTilesY - 1; ++aY)
+ const float aKsiY = mySampler.sample (1, myLastSample) * myVarianceMap.Value (myVarianceMap.SizeY - 1, aTile.x());
+ for (; (size_t )aTile.y() < myVarianceMap.SizeY - 1; ++aTile.y())
{
- if (aKsiY <= Tile (aX, aY))
+ if (aKsiY <= myVarianceMap.Value (aTile.y(), aTile.x()))
{
break;
}
}
- theOffsetX = aX * TileSize();
- theOffsetY = aY * TileSize();
-
- ++mySample;
+ ++myLastSample;
+ return aTile;
}
//=======================================================================
//function : SetSize
//purpose :
//=======================================================================
-void OpenGl_TileSampler::SetSize (const int theSizeX,
- const int theSizeY)
+void OpenGl_TileSampler::SetSize (const Graphic3d_RenderingParams& theParams,
+ const Graphic3d_Vec2i& theSize)
{
- if (mySizeX == theSizeX
- && mySizeY == theSizeY)
+ if (theSize.x() <= 0
+ || theSize.y() <= 0)
{
return;
}
- mySizeX = theSizeX;
- mySizeY = theSizeY;
+ myViewSize = theSize;
- myTilesX = static_cast<int> (ceilf (static_cast<float> (mySizeX) / TileSize()));
- myTilesY = static_cast<int> (ceilf (static_cast<float> (mySizeY) / TileSize()));
+ const int aTileSize = Max (theParams.RayTracingTileSize, 1);
+ const int aNbTilesX = Max (1, static_cast<int> (ceilf (static_cast<float> (theSize.x()) / aTileSize)));
+ const int aNbTilesY = Max (1, static_cast<int> (ceilf (static_cast<float> (theSize.y()) / aTileSize)));
+ if (myTileSize != aTileSize
+ || (int )myTiles.SizeX != aNbTilesX
+ || (int )myTiles.SizeY != aNbTilesY)
+ {
+ myTileSize = aTileSize;
+ myScaleFactor = 1.0e6f * (1024.0f / float(myTileSize * myTileSize));
- myVarianceMap.resize (myTilesX * myTilesY);
+ Handle(NCollection_BaseAllocator) anAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
+ myTiles.SetTopDown (true);
+ myTiles.Init (anAlloc, aNbTilesX, aNbTilesY);
+ myTiles.Init (1);
+
+ myVarianceMap.SetTopDown (true);
+ myVarianceMap.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
+ myVarianceMap.Init (0.0f);
+
+ myVarianceRaw.SetTopDown (true);
+ myVarianceRaw.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
+ myVarianceRaw.Init (0);
+
+ myOffsets.SetTopDown (true);
+ myOffsets.Init (myTiles.Allocator(), myTiles.SizeX, myTiles.SizeY);
+ myOffsets.Init (Graphic3d_Vec2i (-1, -1));
+
+ myMarginalMap.resize (myTiles.SizeX);
+ myMarginalMap.assign (myMarginalMap.size(), 0.0f);
+ }
+
+ // calculate a size of compact offsets texture optimal for rendering reduced number of tiles
+ Standard_Integer aNbShunkTilesX = (int )myTiles.SizeX, aNbShunkTilesY = (int )myTiles.SizeY;
+ if (theParams.NbRayTracingTiles > 0)
+ {
+ aNbShunkTilesX = 8;
+ aNbShunkTilesY = 8;
+ for (Standard_Integer anIdx = 0; aNbShunkTilesX * aNbShunkTilesY < theParams.NbRayTracingTiles; ++anIdx)
+ {
+ (anIdx % 2 == 0 ? aNbShunkTilesX : aNbShunkTilesY) <<= 1;
+ }
+ }
+ if ((int )myOffsetsShrunk.SizeX != aNbShunkTilesX
+ || (int )myOffsetsShrunk.SizeY != aNbShunkTilesY)
+ {
+ myOffsetsShrunk.SetTopDown (true);
+ myOffsetsShrunk.Init (myTiles.Allocator(), aNbShunkTilesX, aNbShunkTilesY);
+ myOffsetsShrunk.Init (Graphic3d_Vec2i (-1, -1));
+ }
}
//=======================================================================
-//function : Upload
+//function : UploadOffsets
//purpose :
//=======================================================================
-void OpenGl_TileSampler::Upload (const Handle(OpenGl_Context)& theContext,
- const Handle(OpenGl_Texture)& theTexture,
- const int theNbTilesX,
- const int theNbTilesY,
- const bool theAdaptive)
+bool OpenGl_TileSampler::UploadOffsets (const Handle(OpenGl_Context)& theContext,
+ const Handle(OpenGl_Texture)& theOffsetsTexture,
+ const bool theAdaptive)
{
- if (theTexture.IsNull())
+ if (myTiles.IsEmpty())
{
- return;
+ return false;
}
- const int aNbTilesX = theAdaptive ? theNbTilesX : myTilesX;
- 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);
+ myTiles.Init (0);
+ Image_PixMapTypedData<Graphic3d_Vec2i>& anOffsets = theAdaptive ? myOffsetsShrunk : myOffsets;
+ anOffsets.Init (Graphic3d_Vec2i (-1, -1));
+ for (Standard_Size aRowIter = 0; aRowIter < anOffsets.SizeY; ++aRowIter)
+ {
+ for (Standard_Size aColIter = 0; aColIter < anOffsets.SizeX; ++aColIter)
+ {
+ Graphic3d_Vec2i& aRedirectTile = anOffsets.ChangeValue (aRowIter, aColIter);
+ aRedirectTile = theAdaptive ? nextTileToSample() : Graphic3d_Vec2i ((int )aColIter, (int )aRowIter);
+ myTiles.ChangeValue (aRedirectTile.y(), aRedirectTile.x()) += 1;
+ }
+ }
- for (int aX = 0; aX < aNbTilesX; ++aX)
+ bool hasErrors = false;
+ if (!theOffsetsTexture.IsNull())
{
- for (int aY = 0; aY < aNbTilesY; ++aY)
+ if (theOffsetsTexture->SizeX() != (int )anOffsets.SizeX
+ || theOffsetsTexture->SizeY() != (int )anOffsets.SizeY
+ || !theOffsetsTexture->IsValid())
{
- if (!theAdaptive)
+ theOffsetsTexture->Release (theContext.operator->());
+ if (!theOffsetsTexture->Init (theContext, GL_RG32I, GL_RG_INTEGER, GL_INT,
+ (int )anOffsets.SizeX, (int )anOffsets.SizeY, Graphic3d_TOT_2D))
{
- aData[(aY * aNbTilesX + aX) * 2 + 0] = aX * TileSize();
- aData[(aY * aNbTilesX + aX) * 2 + 1] = aY * TileSize();
+ hasErrors = true;
}
- else
+ }
+ if (theOffsetsTexture->IsValid())
+ {
+ theOffsetsTexture->Bind (theContext);
+ theContext->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+ #if !defined(GL_ES_VERSION_2_0)
+ theContext->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+ #endif
+ theContext->core11fwd->glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, (int )anOffsets.SizeX, (int )anOffsets.SizeY, GL_RG_INTEGER, GL_INT, anOffsets.Data());
+ if (theContext->core11fwd->glGetError() != GL_NO_ERROR)
{
- Sample (aData[(aY * aNbTilesX + aX) * 2 + 0],
- aData[(aY * aNbTilesX + aX) * 2 + 1]);
+ hasErrors = true;
+ 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");
}
+ theOffsetsTexture->Unbind (theContext);
}
}
-
- theTexture->Bind (theContext);
-
- theContext->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, GL_RG32I, aNbTilesX, aNbTilesY, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, &aData.front());
-
- if (theContext->core11fwd->glGetError() != GL_NO_ERROR)
- {
- 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");
- }
+ return !hasErrors;
}
#include <OpenGl_Texture.hxx>
#include <OpenGl_HaltonSampler.hxx>
+#include <Image_PixMapTypedData.hxx>
+
#include <vector>
+class Graphic3d_RenderingParams;
+
//! Tool object used for sampling screen tiles according to estimated pixel variance (used in path tracing engine).
//! 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
//! final final image is the same for both cases.
class OpenGl_TileSampler
{
-public:
-
- //! Size of individual tile in pixels.
- static int TileSize() { return 32; }
-
public:
//! Creates new tile sampler.
Standard_EXPORT OpenGl_TileSampler();
- //! Returns width of ray-tracing viewport.
- int SizeX() const { return mySizeX; }
+ //! Size of individual tile in pixels.
+ Graphic3d_Vec2i TileSize() const { return Graphic3d_Vec2i (myTileSize, myTileSize); }
- //! Returns height of ray-tracing viewport.
- int SizeY() const { return mySizeY; }
+ //! Scale factor for quantization of visual error (float) into signed integer.
+ float VarianceScaleFactor() const { return myScaleFactor; }
//! Returns number of tiles in X dimension.
- int NbTilesX() const { return myTilesX; }
+ int NbTilesX() const { return (int)myTiles.SizeX; }
//! Returns number of tiles in Y dimension.
- int NbTilesY() const { return myTilesY; }
+ int NbTilesY() const { return (int)myTiles.SizeY; }
//! Returns total number of tiles in viewport.
- int NbTiles() const { return myTilesX * myTilesY; }
+ int NbTiles() const { return int(myTiles.SizeX * myTiles.SizeY); }
- //! Specifies size of ray-tracing viewport.
- Standard_EXPORT void SetSize (const int theSizeX,
- const int theSizeY);
+ //! Returns ray-tracing viewport.
+ const Graphic3d_Vec2i& ViewSize() const { return myViewSize; }
- //! Returns number of pixels in the given tile.
- int TileArea (const int theX,
- const int theY) const
+ //! Number of tiles within offsets texture.
+ Graphic3d_Vec2i NbOffsetTiles (bool theAdaptive) const
{
- return Min (TileSize(), mySizeX - theX * TileSize())
- * Min (TileSize(), mySizeY - theY * TileSize());
+ return theAdaptive
+ ? Graphic3d_Vec2i ((int )myOffsetsShrunk.SizeX, (int )myOffsetsShrunk.SizeY)
+ : Graphic3d_Vec2i ((int )myOffsets.SizeX, (int )myOffsets.SizeY);
}
+ //! Maximum number of tiles within offsets texture.
+ Graphic3d_Vec2i NbOffsetTilesMax() const { return NbOffsetTiles (true).cwiseMax (NbOffsetTiles (false)); }
+
+ //! Viewport for rendering using offsets texture.
+ Graphic3d_Vec2i OffsetTilesViewport (bool theAdaptive) const { return NbOffsetTiles (theAdaptive) * myTileSize; }
+
+ //! Maximum viewport for rendering using offsets texture.
+ Graphic3d_Vec2i OffsetTilesViewportMax() const { return NbOffsetTilesMax() * myTileSize; }
+
+ //! Specifies size of ray-tracing viewport and recomputes tile size.
+ Standard_EXPORT void SetSize (const Graphic3d_RenderingParams& theParams,
+ const Graphic3d_Vec2i& theSize);
+
//! Fetches current error estimation from the GPU and
//! builds 2D discrete distribution for tile sampling.
- Standard_EXPORT void GrabVarianceMap (const Handle(OpenGl_Context)& theContext);
-
- //! Samples tile location according to estimated error.
- Standard_EXPORT void Sample (int& theOffsetX,
- int& theOffsetY);
+ Standard_EXPORT void GrabVarianceMap (const Handle(OpenGl_Context)& theContext,
+ const Handle(OpenGl_Texture)& theTexture);
- //! Resets tile sampler to initial state.
- void Reset() { mySample = 0; }
+ //! Resets (restart) tile sampler to initial state.
+ void Reset() { myLastSample = 0; }
//! Uploads offsets of sampled tiles to the given OpenGL texture.
- Standard_EXPORT void Upload (const Handle(OpenGl_Context)& theContext,
- const Handle(OpenGl_Texture)& theTexture,
- const int theNbTilesX,
- const int theNbTilesY,
- const bool theAdaptive);
+ Standard_EXPORT bool UploadOffsets (const Handle(OpenGl_Context)& theContext,
+ const Handle(OpenGl_Texture)& theOffsetsTexture,
+ const bool theAdaptive);
protected:
- //! Returns tile value (estimated error).
- float Tile (const int theX,
- const int theY) const
+ //! Returns number of pixels in the given tile.
+ int tileArea (int theX, int theY) const
{
- return myVarianceMap[theY * myTilesX + theX];
+ const int aSizeX = Min (myTileSize, myViewSize.x() - theX * myTileSize);
+ const int aSizeY = Min (myTileSize, myViewSize.y() - theY * myTileSize);
+ return aSizeX * aSizeY;
}
- //! Returns tile value (estimated error).
- float& ChangeTile (const int theX,
- const int theY)
- {
- return myVarianceMap[theY * myTilesX + theX];
- }
+ //! Samples tile location according to estimated error.
+ Standard_EXPORT Graphic3d_Vec2i nextTileToSample();
protected:
- std::vector<float> myVarianceMap; //!< Estimation of visual error per tile
- std::vector<float> myMarginalMap; //!< Marginal distribution of 2D error map
- OpenGl_HaltonSampler mySampler; //!< Halton sequence generator
- int mySample; //!< Index of generated sample
- int mySizeX; //!< Width of ray-tracing viewport
- int mySizeY; //!< Height of ray-tracing viewport
- int myTilesX; //!< Number of tiles in X dimension
- int myTilesY; //!< Number of tiles in Y dimension
+ Image_PixMapTypedData<unsigned int> myTiles; //!< number of samples per tile (initially all 1)
+ Image_PixMapTypedData<float> myVarianceMap; //!< Estimation of visual error per tile
+ Image_PixMapTypedData<int> myVarianceRaw; //!< Estimation of visual error per tile (raw data)
+ Image_PixMapTypedData<Graphic3d_Vec2i> myOffsets; //!< 2D array of tiles redirecting to another tile
+ Image_PixMapTypedData<Graphic3d_Vec2i> myOffsetsShrunk; //!< 2D array of tiles redirecting to another tile (shrunk)
+ std::vector<float> myMarginalMap; //!< Marginal distribution of 2D error map
+ OpenGl_HaltonSampler mySampler; //!< Halton sequence generator
+ unsigned int myLastSample; //!< Index of generated sample
+ float myScaleFactor; //!< scale factor for quantization of visual error (float) into signed integer
+ int myTileSize; //!< tile size
+ Graphic3d_Vec2i myViewSize; //!< ray-tracing viewport
};
// images used by ISS mode
OpenGl_RT_uRenderImage,
OpenGl_RT_uOffsetImage,
+ OpenGl_RT_uTileSize,
+ OpenGl_RT_uVarianceScaleFactor,
// maximum radiance value
OpenGl_RT_uMaxRadiance,
//! Defines OpenGL image samplers.
enum ShaderImageNames
{
- OpenGl_RT_OutputImageLft = 0,
- OpenGl_RT_OutputImageRgh = 1,
- OpenGl_RT_VisualErrorImageLft = 2,
- OpenGl_RT_VisualErrorImageRgh = 3,
- OpenGl_RT_TileOffsetsImageLft = 4,
- OpenGl_RT_TileOffsetsImageRgh = 5
+ OpenGl_RT_OutputImage = 0,
+ OpenGl_RT_VisualErrorImage = 1,
+ OpenGl_RT_TileOffsetsImage = 2,
};
//! Tool class for management of shader sources.
//! Maximum radiance value used for clamping radiance estimation.
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;
//! Enables/disables depth-of-field effect (path tracing, perspective camera).
Standard_Boolean DepthOfField;
AdaptiveScreenSampling (Standard_False),
UseEnvMapForBackground (Standard_False),
RadianceClampingValue (30.0),
- NbTilesX (16),
- NbTilesY (16),
DepthOfField (Standard_False),
ToneMappingMethod (Graphic3d_ToneMappingMethod_Disabled) { }
};
const Handle(OpenGl_ShaderObject)& theFragShader);
//! Initializes OpenGL/GLSL shader programs.
- Standard_Boolean initRaytraceResources (const Handle(OpenGl_Context)& theGlContext);
+ Standard_Boolean initRaytraceResources (const Standard_Integer theSizeX,
+ const Standard_Integer theSizeY,
+ const Handle(OpenGl_Context)& theGlContext);
//! Releases OpenGL/GLSL shader programs.
void releaseRaytraceResources (const Handle(OpenGl_Context)& theGlContext,
const int theWinSizeY);
//! Binds ray-trace textures to corresponding texture units.
- void bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext);
+ void bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext,
+ int theStereoView);
//! Unbinds ray-trace textures from corresponding texture unit.
void unbindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext);
Standard_Boolean runPathtrace (const Standard_Integer theSizeX,
const Standard_Integer theSizeY,
Graphic3d_Camera::Projection theProjection,
- OpenGl_FrameBuffer* theReadDrawFbo,
const Handle(OpenGl_Context)& theGlContext);
+ //! Runs path tracing (global illumination) kernel.
+ Standard_Boolean runPathtraceOut (Graphic3d_Camera::Projection theProjection,
+ OpenGl_FrameBuffer* theReadDrawFbo,
+ const Handle(OpenGl_Context)& theGlContext);
+
//! Redraws the window using OpenGL/GLSL ray-tracing or path tracing.
Standard_Boolean raytrace (const Standard_Integer theSizeX,
const Standard_Integer theSizeY,
// to activate the feature we need OpenGL 4.4 and GL_NV_shader_atomic_float extension
if (theGlContext->IsGlGreaterEqual (4, 4) && theGlContext->CheckExtension ("GL_NV_shader_atomic_float"))
{
- aPrefixString += TCollection_AsciiString ("\n#define ADAPTIVE_SAMPLING") +
- TCollection_AsciiString ("\n#define BLOCK_SIZE ") + TCollection_AsciiString (OpenGl_TileSampler::TileSize());
+ aPrefixString += TCollection_AsciiString ("\n#define ADAPTIVE_SAMPLING");
}
}
// function : initRaytraceResources
// purpose : Initializes OpenGL/GLSL shader programs
// =======================================================================
-Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context)& theGlContext)
+Standard_Boolean OpenGl_View::initRaytraceResources (const Standard_Integer theSizeX,
+ const Standard_Integer theSizeY,
+ const Handle(OpenGl_Context)& theGlContext)
{
if (myRaytraceInitStatus == OpenGl_RT_FAIL)
{
}
}
- 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
|| myRenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows
|| myRenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination
|| myRenderParams.TwoSidedBsdfModels != myRaytraceParameters.TwoSidedBsdfModels
- || myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures
- || aNbTilesX != myRaytraceParameters.NbTilesX
- || aNbTilesY != myRaytraceParameters.NbTilesY)
+ || myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures)
{
myRaytraceParameters.NbBounces = myRenderParams.RaytracingDepth;
myRaytraceParameters.TransparentShadows = myRenderParams.IsTransparentShadowEnabled;
myRaytraceParameters.GlobalIllumination = myRenderParams.IsGlobalIlluminationEnabled;
myRaytraceParameters.TwoSidedBsdfModels = myRenderParams.TwoSidedBsdfModels;
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;
}
+ myTileSampler.SetSize (myRenderParams, myRaytraceParameters.AdaptiveScreenSampling ? Graphic3d_Vec2i (theSizeX, theSizeY) : Graphic3d_Vec2i (0, 0));
const bool toEnableDof = !myCamera->IsOrthographic() && myRaytraceParameters.GlobalIllumination;
if (myRaytraceParameters.DepthOfField != toEnableDof)
aShaderProgram->GetUniformLocation (theGlContext, "uRenderImage");
myUniformLocations[anIndex][OpenGl_RT_uOffsetImage] =
aShaderProgram->GetUniformLocation (theGlContext, "uOffsetImage");
+ myUniformLocations[anIndex][OpenGl_RT_uTileSize] =
+ aShaderProgram->GetUniformLocation (theGlContext, "uTileSize");
+ myUniformLocations[anIndex][OpenGl_RT_uVarianceScaleFactor] =
+ aShaderProgram->GetUniformLocation (theGlContext, "uVarianceScaleFactor");
myUniformLocations[anIndex][OpenGl_RT_uBackColorTop] =
aShaderProgram->GetUniformLocation (theGlContext, "uBackColorTop");
if (myRaytraceParameters.AdaptiveScreenSampling)
{
- const Standard_Integer aSizeX = std::max (myRaytraceParameters.NbTilesX * 64, theSizeX);
- const Standard_Integer aSizeY = std::max (myRaytraceParameters.NbTilesY * 64, theSizeY);
-
- myRaytraceFBO1[0]->InitLazy (theGlContext, aSizeX, aSizeY, GL_RGBA32F, myFboDepthFormat);
- myRaytraceFBO2[0]->InitLazy (theGlContext, aSizeX, aSizeY, GL_RGBA32F, myFboDepthFormat);
-
+ Graphic3d_Vec2i aMaxViewport = myTileSampler.OffsetTilesViewportMax().cwiseMax (Graphic3d_Vec2i (theSizeX, theSizeY));
+ myRaytraceFBO1[0]->InitLazy (theGlContext, aMaxViewport.x(), aMaxViewport.y(), GL_RGBA32F, myFboDepthFormat);
+ myRaytraceFBO2[0]->InitLazy (theGlContext, aMaxViewport.x(), aMaxViewport.y(), GL_RGBA32F, myFboDepthFormat);
if (myRaytraceFBO1[1]->IsValid()) // second FBO not needed
{
myRaytraceFBO1[1]->Release (theGlContext.operator->());
myRaytraceFBO2[1]->Release (theGlContext.operator->());
}
}
- else // non-adaptive mode
+
+ for (int aViewIter = 0; aViewIter < 2; ++aViewIter)
{
- if (myRaytraceFBO1[0]->GetSizeX() != theSizeX
- || myRaytraceFBO1[0]->GetSizeY() != theSizeY)
+ if (myRaytraceTileOffsetsTexture[aViewIter].IsNull())
{
- myAccumFrames = 0; // accumulation should be restarted
+ myRaytraceOutputTexture[aViewIter] = new OpenGl_Texture();
+ myRaytraceVisualErrorTexture[aViewIter] = new OpenGl_Texture();
+ myRaytraceTileOffsetsTexture[aViewIter] = new OpenGl_Texture();
}
- 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
+ if (aViewIter == 1
+ && myCamera->ProjectionType() != Graphic3d_Camera::Projection_Stereo)
{
myRaytraceFBO1[1]->Release (theGlContext.operator->());
myRaytraceFBO2[1]->Release (theGlContext.operator->());
+ myRaytraceOutputTexture[1]->Release (theGlContext.operator->());
+ myRaytraceVisualErrorTexture[1]->Release (theGlContext.operator->());
+ myRaytraceTileOffsetsTexture[1]->Release (theGlContext.operator->());
+ continue;
}
- }
-
- myTileSampler.SetSize (theSizeX, theSizeY);
-
- if (myRaytraceTileOffsetsTexture[0].IsNull()
- || myRaytraceTileOffsetsTexture[1].IsNull())
- {
- myRaytraceOutputTexture[0] = new OpenGl_Texture();
- myRaytraceOutputTexture[1] = new OpenGl_Texture();
-
- myRaytraceTileOffsetsTexture[0] = new OpenGl_Texture();
- myRaytraceTileOffsetsTexture[1] = new OpenGl_Texture();
- myRaytraceVisualErrorTexture[0] = new OpenGl_Texture();
- myRaytraceVisualErrorTexture[1] = new OpenGl_Texture();
- }
-
- if (myRaytraceOutputTexture[0]->SizeX() / 3 != theSizeX
- || myRaytraceOutputTexture[0]->SizeY() / 2 != theSizeY)
- {
- myAccumFrames = 0;
-
- // Due to limitations of OpenGL image load-store extension
- // atomic operations are supported only for single-channel
- // images, so we define GL_R32F image. It is used as array
- // of 6D floating point vectors:
- // 0 - R color channel
- // 1 - G color channel
- // 2 - B color channel
- // 3 - hit time transformed into OpenGL NDC space
- // 4 - luminance accumulated for odd samples only
- myRaytraceOutputTexture[0]->InitRectangle (theGlContext,
- theSizeX * 3, theSizeY * 2, OpenGl_TextureFormat::Create<GLfloat, 1>());
-
- // workaround for some NVIDIA drivers
- myRaytraceVisualErrorTexture[0]->Release (theGlContext.operator->());
- myRaytraceTileOffsetsTexture[0]->Release (theGlContext.operator->());
-
- myRaytraceVisualErrorTexture[0]->Init (theGlContext,
- GL_R32I, GL_RED_INTEGER, GL_INT, myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
- myRaytraceTileOffsetsTexture[0]->Init (theGlContext,
- GL_RG32I, GL_RG_INTEGER, GL_INT, myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
- }
-
- if (myCamera->ProjectionType() == Graphic3d_Camera::Projection_Stereo)
- {
- if (myRaytraceOutputTexture[1]->SizeX() / 3 != theSizeX
- || myRaytraceOutputTexture[1]->SizeY() / 2 != theSizeY)
+ if (myRaytraceParameters.AdaptiveScreenSampling)
{
- myRaytraceOutputTexture[1]->InitRectangle (theGlContext,
- theSizeX * 3, theSizeY * 2, OpenGl_TextureFormat::Create<GLfloat, 1>());
+ if (myRaytraceOutputTexture[aViewIter]->SizeX() / 3 == theSizeX
+ && myRaytraceOutputTexture[aViewIter]->SizeY() / 2 == theSizeY
+ && myRaytraceVisualErrorTexture[aViewIter]->SizeX() == myTileSampler.NbTilesX()
+ && myRaytraceVisualErrorTexture[aViewIter]->SizeY() == myTileSampler.NbTilesY())
+ {
+ continue;
+ }
- myRaytraceVisualErrorTexture[1]->Release (theGlContext.operator->());
- myRaytraceTileOffsetsTexture[1]->Release (theGlContext.operator->());
+ myAccumFrames = 0;
- myRaytraceVisualErrorTexture[1]->Init (theGlContext,
- GL_R32I, GL_RED_INTEGER, GL_INT, myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
+ // Due to limitations of OpenGL image load-store extension
+ // atomic operations are supported only for single-channel
+ // images, so we define GL_R32F image. It is used as array
+ // of 6D floating point vectors:
+ // 0 - R color channel
+ // 1 - G color channel
+ // 2 - B color channel
+ // 3 - hit time transformed into OpenGL NDC space
+ // 4 - luminance accumulated for odd samples only
+ myRaytraceOutputTexture[aViewIter]->InitRectangle (theGlContext, theSizeX * 3, theSizeY * 2, OpenGl_TextureFormat::Create<GLfloat, 1>());
+
+ // workaround for some NVIDIA drivers
+ myRaytraceVisualErrorTexture[aViewIter]->Release (theGlContext.operator->());
+ myRaytraceVisualErrorTexture[aViewIter]->Init (theGlContext, GL_R32I, GL_RED_INTEGER, GL_INT,
+ myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
+ }
+ else // non-adaptive mode
+ {
+ if (myRaytraceFBO1[aViewIter]->GetSizeX() != theSizeX
+ || myRaytraceFBO1[aViewIter]->GetSizeY() != theSizeY)
+ {
+ myAccumFrames = 0; // accumulation should be restarted
+ }
- myRaytraceTileOffsetsTexture[1]->Init (theGlContext,
- GL_RG32I, GL_RG_INTEGER, GL_INT, myTileSampler.NbTilesX(), myTileSampler.NbTilesY(), Graphic3d_TOT_2D);
+ myRaytraceFBO1[aViewIter]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
+ myRaytraceFBO2[aViewIter]->InitLazy (theGlContext, theSizeX, theSizeY, GL_RGBA32F, myFboDepthFormat);
}
}
- else
- {
- myRaytraceOutputTexture[1]->Release (theGlContext.operator->());
- }
-
return Standard_True;
}
// function : bindRaytraceTextures
// purpose : Binds ray-trace textures to corresponding texture units
// =======================================================================
-void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext)
+void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext,
+ int theStereoView)
{
- if (myRaytraceParameters.AdaptiveScreenSampling)
+ if (myRaytraceParameters.AdaptiveScreenSampling
+ && myRaytraceParameters.GlobalIllumination)
{
#if !defined(GL_ES_VERSION_2_0)
- theGlContext->core42->glBindImageTexture (OpenGl_RT_OutputImageLft,
- myRaytraceOutputTexture[0]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
- theGlContext->core42->glBindImageTexture (OpenGl_RT_OutputImageRgh,
- myRaytraceOutputTexture[1]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
-
- theGlContext->core42->glBindImageTexture (OpenGl_RT_VisualErrorImageLft,
- myRaytraceVisualErrorTexture[0]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32I);
- theGlContext->core42->glBindImageTexture (OpenGl_RT_VisualErrorImageRgh,
- myRaytraceVisualErrorTexture[1]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32I);
- theGlContext->core42->glBindImageTexture (OpenGl_RT_TileOffsetsImageLft,
- myRaytraceTileOffsetsTexture[0]->TextureId(), 0, GL_TRUE, 0, GL_READ_ONLY, GL_RG32I);
- theGlContext->core42->glBindImageTexture (OpenGl_RT_TileOffsetsImageRgh,
- myRaytraceTileOffsetsTexture[1]->TextureId(), 0, GL_TRUE, 0, GL_READ_ONLY, GL_RG32I);
-#endif
+ theGlContext->core42->glBindImageTexture (OpenGl_RT_OutputImage,
+ myRaytraceOutputTexture[theStereoView]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
+ theGlContext->core42->glBindImageTexture (OpenGl_RT_VisualErrorImage,
+ myRaytraceVisualErrorTexture[theStereoView]->TextureId(), 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32I);
+ theGlContext->core42->glBindImageTexture (OpenGl_RT_TileOffsetsImage,
+ myRaytraceTileOffsetsTexture[theStereoView]->TextureId(), 0, GL_TRUE, 0, GL_READ_ONLY, GL_RG32I);
+ #else
+ (void )theStereoView;
+ #endif
}
if (!myTextureEnv.IsNull()
if (myRaytraceParameters.GlobalIllumination) // path tracing
{
- aResult &= runPathtrace (theSizeX, theSizeY, theProjection, theReadDrawFbo, theGlContext);
+ aResult &= runPathtrace (theSizeX, theSizeY, theProjection, theGlContext);
+ aResult &= runPathtraceOut (theProjection, theReadDrawFbo, theGlContext);
}
else // Whitted-style ray-tracing
{
{
Standard_Boolean aResult = Standard_True;
- bindRaytraceTextures (theGlContext);
-
- Handle(OpenGl_FrameBuffer) aRenderImageFramebuffer;
- Handle(OpenGl_FrameBuffer) aDepthSourceFramebuffer;
-
// Choose proper set of frame buffers for stereo rendering
- const Standard_Integer aFBOIdx (theProjection == Graphic3d_Camera::Projection_MonoRightEye);
+ const Standard_Integer aFBOIdx = (theProjection == Graphic3d_Camera::Projection_MonoRightEye) ? 1 : 0;
+ bindRaytraceTextures (theGlContext, aFBOIdx);
if (myRenderParams.IsAntialiasingEnabled) // if second FSAA pass is used
{
aFramebuffer->ColorTexture()->Bind (theGlContext, OpenGl_RT_FsaaInputTexture);
}
- aRenderImageFramebuffer = myRaytraceFBO2[aFBOIdx];
- aDepthSourceFramebuffer = myRaytraceFBO1[aFBOIdx];
+ const Handle(OpenGl_FrameBuffer)& aRenderImageFramebuffer = myRaytraceFBO2[aFBOIdx];
+ const Handle(OpenGl_FrameBuffer)& aDepthSourceFramebuffer = myRaytraceFBO1[aFBOIdx];
glEnable (GL_DEPTH_TEST);
Standard_Boolean OpenGl_View::runPathtrace (const Standard_Integer theSizeX,
const Standard_Integer theSizeY,
const Graphic3d_Camera::Projection theProjection,
- OpenGl_FrameBuffer* theReadDrawFbo,
const Handle(OpenGl_Context)& theGlContext)
{
- Standard_Boolean aResult = Standard_True;
-
if (myToUpdateEnvironmentMap) // check whether the map was changed
{
myAccumFrames = myToUpdateEnvironmentMap = 0;
if (myRenderParams.CameraApertureRadius != myPrevCameraApertureRadius
|| myRenderParams.CameraFocalPlaneDist != myPrevCameraFocalPlaneDist)
{
-
myPrevCameraApertureRadius = myRenderParams.CameraApertureRadius;
myPrevCameraFocalPlaneDist = myRenderParams.CameraFocalPlaneDist;
-
myAccumFrames = 0;
}
// Choose proper set of frame buffers for stereo rendering
- const Standard_Integer aFBOIdx (theProjection == Graphic3d_Camera::Projection_MonoRightEye);
+ const Standard_Integer aFBOIdx = (theProjection == Graphic3d_Camera::Projection_MonoRightEye) ? 1 : 0;
if (myRaytraceParameters.AdaptiveScreenSampling)
{
myTileSampler.Reset(); // reset tile sampler to its initial state
// Adaptive sampling is starting at the second frame
- myTileSampler.Upload (theGlContext,
- myRaytraceTileOffsetsTexture[aFBOIdx],
- myRaytraceParameters.NbTilesX,
- myRaytraceParameters.NbTilesY,
- false);
- }
- }
-
- bindRaytraceTextures (theGlContext);
-
- Handle(OpenGl_FrameBuffer) aRenderImageFramebuffer;
- Handle(OpenGl_FrameBuffer) aDepthSourceFramebuffer;
- Handle(OpenGl_FrameBuffer) anAccumImageFramebuffer;
+ myTileSampler.UploadOffsets (theGlContext, myRaytraceTileOffsetsTexture[aFBOIdx], false);
- const Standard_Integer anImageId = (aFBOIdx != 0)
- ? OpenGl_RT_OutputImageRgh
- : OpenGl_RT_OutputImageLft;
-
- const Standard_Integer anErrorId = (aFBOIdx != 0)
- ? OpenGl_RT_VisualErrorImageRgh
- : OpenGl_RT_VisualErrorImageLft;
-
- const Standard_Integer anOffsetId = (aFBOIdx != 0)
- ? OpenGl_RT_TileOffsetsImageRgh
- : OpenGl_RT_TileOffsetsImageLft;
+ #if !defined(GL_ES_VERSION_2_0)
+ theGlContext->core44->glClearTexImage (myRaytraceOutputTexture[aFBOIdx]->TextureId(), 0, GL_RED, GL_FLOAT, NULL);
+ #endif
+ }
- aRenderImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1[aFBOIdx] : myRaytraceFBO2[aFBOIdx];
- anAccumImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO2[aFBOIdx] : myRaytraceFBO1[aFBOIdx];
+ // Clear adaptive screen sampling images
+ #if !defined(GL_ES_VERSION_2_0)
+ theGlContext->core44->glClearTexImage (myRaytraceVisualErrorTexture[aFBOIdx]->TextureId(), 0, GL_RED_INTEGER, GL_INT, NULL);
+ #endif
+ }
- aDepthSourceFramebuffer = aRenderImageFramebuffer;
+ bindRaytraceTextures (theGlContext, aFBOIdx);
+ const Handle(OpenGl_FrameBuffer)& anAccumImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO2[aFBOIdx] : myRaytraceFBO1[aFBOIdx];
anAccumImageFramebuffer->ColorTexture()->Bind (theGlContext, OpenGl_RT_PrevAccumTexture);
- aRenderImageFramebuffer->BindBuffer (theGlContext);
+ // Set frame accumulation weight
+ myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uAccumSamples], myAccumFrames);
+ // Set random number generator seed
if (myAccumFrames == 0)
{
myRNG.SetSeed(); // start RNG from beginning
}
+ myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uFrameRndSeed], static_cast<Standard_Integer> (myRNG.NextInt() >> 2));
- // Clear adaptive screen sampling images
+ // Set image uniforms for render program
if (myRaytraceParameters.AdaptiveScreenSampling)
{
- #if !defined(GL_ES_VERSION_2_0)
- if (myAccumFrames == 0 || (myAccumFrames == 1 && myCamera->IsStereo()))
- {
- theGlContext->core44->glClearTexImage (myRaytraceOutputTexture[aFBOIdx]->TextureId(), 0, GL_RED, GL_FLOAT, NULL);
- }
-
- theGlContext->core44->glClearTexImage (myRaytraceVisualErrorTexture[aFBOIdx]->TextureId(), 0, GL_RED_INTEGER, GL_INT, NULL);
- #endif
+ myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uRenderImage], OpenGl_RT_OutputImage);
+ myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uOffsetImage], OpenGl_RT_TileOffsetsImage);
+ myRaytraceProgram->SetUniform (theGlContext, myUniformLocations[0][OpenGl_RT_uTileSize], myTileSampler.TileSize());
}
- // Set frame accumulation weight
- myRaytraceProgram->SetUniform (theGlContext,
- myUniformLocations[0][OpenGl_RT_uAccumSamples], myAccumFrames);
-
- // Set random number generator seed
- myRaytraceProgram->SetUniform (theGlContext,
- myUniformLocations[0][OpenGl_RT_uFrameRndSeed], static_cast<Standard_Integer> (myRNG.NextInt() >> 2));
-
- // Set image uniforms for render program
- myRaytraceProgram->SetUniform (theGlContext,
- myUniformLocations[0][OpenGl_RT_uRenderImage], anImageId);
- myRaytraceProgram->SetUniform (theGlContext,
- myUniformLocations[0][OpenGl_RT_uOffsetImage], anOffsetId);
-
- glDisable (GL_DEPTH_TEST);
-
- if (myRaytraceParameters.AdaptiveScreenSampling
- && ((myAccumFrames > 0 && !myCamera->IsStereo()) || myAccumFrames > 1))
+ const Handle(OpenGl_FrameBuffer)& aRenderImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1[aFBOIdx] : myRaytraceFBO2[aFBOIdx];
+ aRenderImageFramebuffer->BindBuffer (theGlContext);
+ if (myRaytraceParameters.AdaptiveScreenSampling)
{
- glViewport (0,
- 0,
- myTileSampler.TileSize() * myRaytraceParameters.NbTilesX,
- myTileSampler.TileSize() * myRaytraceParameters.NbTilesY);
+ // extend viewport here, so that tiles at boundaries (cut tile size by target rendering viewport)
+ // redirected to inner tiles (full tile size) are drawn entirely
+ const Graphic3d_Vec2i anOffsetViewport = myTileSampler.OffsetTilesViewport (myAccumFrames > 1); // shrunk offsets texture will be uploaded since 3rd frame
+ glViewport (0, 0, anOffsetViewport.x(), anOffsetViewport.y());
}
// Generate for the given RNG seed
+ glDisable (GL_DEPTH_TEST);
theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
- if (myRaytraceParameters.AdaptiveScreenSampling
- && ((myAccumFrames > 0 && !myCamera->IsStereo()) || myAccumFrames > 1))
+ aRenderImageFramebuffer->UnbindBuffer (theGlContext);
+
+ if (myRaytraceParameters.AdaptiveScreenSampling)
{
- glViewport (0,
- 0,
- theSizeX,
- theSizeY);
+ glViewport (0, 0, theSizeX, theSizeY);
}
+ return true;
+}
+// =======================================================================
+// function : runPathtraceOut
+// purpose :
+// =======================================================================
+Standard_Boolean OpenGl_View::runPathtraceOut (const Graphic3d_Camera::Projection theProjection,
+ OpenGl_FrameBuffer* theReadDrawFbo,
+ const Handle(OpenGl_Context)& theGlContext)
+{
// Output accumulated path traced image
theGlContext->BindProgram (myOutImageProgram);
+ // Choose proper set of frame buffers for stereo rendering
+ const Standard_Integer aFBOIdx = (theProjection == Graphic3d_Camera::Projection_MonoRightEye) ? 1 : 0;
+
if (myRaytraceParameters.AdaptiveScreenSampling)
{
// Set uniforms for display program
- myOutImageProgram->SetUniform (theGlContext, "uRenderImage", anImageId);
+ myOutImageProgram->SetUniform (theGlContext, "uRenderImage", OpenGl_RT_OutputImage);
myOutImageProgram->SetUniform (theGlContext, "uAccumFrames", myAccumFrames);
- myOutImageProgram->SetUniform (theGlContext, "uVarianceImage", anErrorId);
+ myOutImageProgram->SetUniform (theGlContext, "uVarianceImage", OpenGl_RT_VisualErrorImage);
myOutImageProgram->SetUniform (theGlContext, "uDebugAdaptive", myRenderParams.ShowSamplingTiles ? 1 : 0);
+ myOutImageProgram->SetUniform (theGlContext, "uTileSize", myTileSampler.TileSize());
+ myOutImageProgram->SetUniform (theGlContext, "uVarianceScaleFactor", myTileSampler.VarianceScaleFactor());
}
if (myRaytraceParameters.GlobalIllumination)
{
theReadDrawFbo->BindBuffer (theGlContext);
}
- else
- {
- aRenderImageFramebuffer->UnbindBuffer (theGlContext);
- }
+ const Handle(OpenGl_FrameBuffer)& aRenderImageFramebuffer = myAccumFrames % 2 ? myRaytraceFBO1[aFBOIdx] : myRaytraceFBO2[aFBOIdx];
aRenderImageFramebuffer->ColorTexture()->Bind (theGlContext, OpenGl_RT_PrevAccumTexture);
- glEnable (GL_DEPTH_TEST);
-
// Copy accumulated image with correct depth values
+ glEnable (GL_DEPTH_TEST);
theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
aRenderImageFramebuffer->ColorTexture()->Unbind (theGlContext, OpenGl_RT_PrevAccumTexture);
if (myRaytraceParameters.AdaptiveScreenSampling)
{
- myRaytraceVisualErrorTexture[aFBOIdx]->Bind (theGlContext);
-
- // Download visual error map from the GPU and build
- // adjusted tile offsets for optimal image sampling
- myTileSampler.GrabVarianceMap (theGlContext);
-
- myTileSampler.Upload (theGlContext,
- myRaytraceTileOffsetsTexture[aFBOIdx],
- myRaytraceParameters.NbTilesX,
- myRaytraceParameters.NbTilesY,
- myAccumFrames > 0);
+ // Download visual error map from the GPU and build adjusted tile offsets for optimal image sampling
+ myTileSampler.GrabVarianceMap (theGlContext, myRaytraceVisualErrorTexture[aFBOIdx]);
+ myTileSampler.UploadOffsets (theGlContext, myRaytraceTileOffsetsTexture[aFBOIdx], myAccumFrames != 0);
}
unbindRaytraceTextures (theGlContext);
-
theGlContext->BindProgram (NULL);
-
- return aResult;
+ return true;
}
// =======================================================================
OpenGl_FrameBuffer* theReadDrawFbo,
const Handle(OpenGl_Context)& theGlContext)
{
- if (!initRaytraceResources (theGlContext))
+ if (!initRaytraceResources (theSizeX, theSizeY, theGlContext))
{
return Standard_False;
}
if (!toRenderGL)
{
- toRenderGL = !initRaytraceResources (aCtx) ||
- !updateRaytraceGeometry (OpenGl_GUM_CHECK, myId, aCtx);
+ const Standard_Integer aSizeX = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeX() : myWindow->Width();
+ const Standard_Integer aSizeY = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeY() : myWindow->Height();
+
+ toRenderGL = !initRaytraceResources (aSizeX, aSizeY, aCtx)
+ || !updateRaytraceGeometry (OpenGl_GUM_CHECK, myId, aCtx);
toRenderGL |= !myIsRaytraceDataValid; // if no ray-trace data use OpenGL
if (!toRenderGL)
{
- const Standard_Integer aSizeX = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeX() : myWindow->Width();
- const Standard_Integer aSizeY = theReadDrawFbo != NULL ? theReadDrawFbo->GetVPSizeY() : myWindow->Height();
myOpenGlFBO ->InitLazy (aCtx, aSizeX, aSizeY, myFboColorFormat, myFboDepthFormat, 0);
if (theReadDrawFbo != NULL)
//! OpenGL image storing variance of sampled pixels blocks.
volatile restrict layout(size1x32) uniform iimage2D uVarianceImage;
+ //! Scale factor used to quantize visual error (float) into signed integer.
+ uniform float uVarianceScaleFactor;
+
+ //! Screen space tile size.
+ uniform ivec2 uTileSize;
+
#else // ADAPTIVE_SAMPLING
//! Input image.
//! RGB weight factors to calculate luminance.
#define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)
-//! Scale factor used to quantize visual error.
-#define SCALE_FACTOR 1.0e6f
-
// =======================================================================
// function : ToneMappingFilmic
// purpose :
// accumulate visual error to current block; estimated error is written only
// 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)));
+ imageAtomicAdd (uVarianceImage, aPixel / uTileSize,
+ int (mix (uVarianceScaleFactor, anError * uVarianceScaleFactor, aColor.w > 40.f)));
if (uDebugAdaptive == 0) // normal rendering
{
//! OpenGL image storing offsets of sampled pixels blocks.
coherent restrict layout(size2x32) uniform iimage2D uOffsetImage;
+
+ //! Screen space tile size.
+ uniform ivec2 uTileSize;
#endif
//! Top color of gradient background.
ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);
- ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,
- aFragCoord.y / BLOCK_SIZE)).xy;
+ ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;
- aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, BLOCK_SIZE);
+ aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, uTileSize.y);
return mix (uBackColorBot, uBackColorTop, float (aTileXY.y) / uWinSizeY);
#ifdef ADAPTIVE_SAMPLING
- ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,
- aFragCoord.y / BLOCK_SIZE)).xy;
+ ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;
+ if (aTileXY.x < 0) { discard; }
- ivec2 aRealBlockSize = ivec2 (min (uWinSizeX - aTileXY.x, BLOCK_SIZE),
- min (uWinSizeY - aTileXY.y, BLOCK_SIZE));
+ ivec2 aRealBlockSize = ivec2 (min (uWinSizeX - aTileXY.x, uTileSize.x),
+ min (uWinSizeY - aTileXY.y, uTileSize.y));
aFragCoord.x = aTileXY.x + (aFragCoord.x % aRealBlockSize.x);
aFragCoord.y = aTileXY.y + (aFragCoord.y % aRealBlockSize.y);
" //! OpenGL image storing variance of sampled pixels blocks.\n"
" volatile restrict layout(size1x32) uniform iimage2D uVarianceImage;\n"
"\n"
+ " //! Scale factor used to quantize visual error (float) into signed integer.\n"
+ " uniform float uVarianceScaleFactor;\n"
+ "\n"
+ " //! Screen space tile size.\n"
+ " uniform ivec2 uTileSize;\n"
+ "\n"
"#else // ADAPTIVE_SAMPLING\n"
"\n"
" //! Input image.\n"
"//! RGB weight factors to calculate luminance.\n"
"#define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)\n"
"\n"
- "//! Scale factor used to quantize visual error.\n"
- "#define SCALE_FACTOR 1.0e6f\n"
- "\n"
"// =======================================================================\n"
"// function : ToneMappingFilmic\n"
"// purpose :\n"
"\n"
" // accumulate visual error to current block; estimated error is written only\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"
+ " imageAtomicAdd (uVarianceImage, aPixel / uTileSize,\n"
+ " int (mix (uVarianceScaleFactor, anError * uVarianceScaleFactor, aColor.w > 40.f)));\n"
"\n"
" if (uDebugAdaptive == 0) // normal rendering\n"
" {\n"
"\n"
" //! OpenGL image storing offsets of sampled pixels blocks.\n"
" coherent restrict layout(size2x32) uniform iimage2D uOffsetImage;\n"
+ "\n"
+ " //! Screen space tile size.\n"
+ " uniform ivec2 uTileSize;\n"
"#endif\n"
"\n"
"//! Top color of gradient background.\n"
"\n"
" ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);\n"
"\n"
- " ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,\n"
- " aFragCoord.y / BLOCK_SIZE)).xy;\n"
+ " ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;\n"
"\n"
- " aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, BLOCK_SIZE);\n"
+ " aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, uTileSize.y);\n"
"\n"
" return mix (uBackColorBot, uBackColorTop, float (aTileXY.y) / uWinSizeY);\n"
"\n"
"\n"
"#ifdef ADAPTIVE_SAMPLING\n"
"\n"
- " ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,\n"
- " aFragCoord.y / BLOCK_SIZE)).xy;\n"
+ " ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;\n"
+ " if (aTileXY.x < 0) { discard; }\n"
"\n"
- " ivec2 aRealBlockSize = ivec2 (min (uWinSizeX - aTileXY.x, BLOCK_SIZE),\n"
- " min (uWinSizeY - aTileXY.y, BLOCK_SIZE));\n"
+ " ivec2 aRealBlockSize = ivec2 (min (uWinSizeX - aTileXY.x, uTileSize.x),\n"
+ " min (uWinSizeY - aTileXY.y, uTileSize.y));\n"
"\n"
" aFragCoord.x = aTileXY.x + (aFragCoord.x % aRealBlockSize.x);\n"
" aFragCoord.y = aTileXY.y + (aFragCoord.y % aRealBlockSize.y);\n"
theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels ? "on" : "off") << "\n";
theDI << "max radiance: " << aParams.RadianceClampingValue << "\n";
theDI << "nb tiles (iss): " << aParams.NbRayTracingTiles << "\n";
+ theDI << "tile size (iss):" << aParams.RayTracingTileSize << "x" << aParams.RayTracingTileSize << "\n";
theDI << "shadingModel: ";
switch (aView->ShadingModel())
{
}
aParams.ShowSamplingTiles = toEnable;
}
+ else if (aFlag == "-tilesize")
+ {
+ if (toPrint)
+ {
+ theDI << aParams.RayTracingTileSize << " ";
+ continue;
+ }
+ else if (++anArgIter >= theArgNb)
+ {
+ std::cerr << "Error: wrong syntax at argument '" << anArg << "'\n";
+ return 1;
+ }
+
+ const Standard_Integer aTileSize = Draw::Atoi (theArgVec[anArgIter]);
+ if (aTileSize < 1)
+ {
+ std::cerr << "Error: invalid size of ISS tile " << aTileSize << ".\n";
+ return 1;
+ }
+ aParams.RayTracingTileSize = aTileSize;
+ }
else if (aFlag == "-nbtiles")
{
if (toPrint)
}
const Standard_Integer aNbTiles = Draw::Atoi (theArgVec[anArgIter]);
-
- if (aNbTiles < 64)
+ if (aNbTiles < -1)
{
std::cerr << "Error: invalid number of ISS tiles " << aNbTiles << ".\n";
- std::cerr << "Specify value in range [64, 1024].\n";
return 1;
}
- else
+ else if (aNbTiles > 0
+ && (aNbTiles < 64
+ || aNbTiles > 1024))
{
- aParams.NbRayTracingTiles = aNbTiles;
+ std::cerr << "Warning: suboptimal number of ISS tiles " << aNbTiles << ". Recommended range: [64, 1024].\n";
}
+ aParams.NbRayTracingTiles = aNbTiles;
}
else if (aFlag == "-env")
{
"\n '-iss on|off' Enables/disables adaptive screen sampling (PT 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 '-nbtiles 64..1024' Specifies number of screen tiles in ISS mode"
+ "\n '-tileSize 1..4096' Specifies size of screen tiles in ISS mode (32 by default)"
+ "\n '-nbtiles 64..1024' Specifies number of screen tiles per Redraw in ISS mode (256 by default)"
"\n '-rebuildGlsl on|off' Rebuild Ray-Tracing GLSL programs (for debugging)"
"\n '-shadingModel model' Controls shading model from enumeration"
"\n color, flat, gouraud, phong"