From: dbp Date: Thu, 9 Apr 2015 05:58:10 +0000 (+0300) Subject: 0025885: Visualization, ray tracing - Improve layer processing X-Git-Tag: V6_9_0_beta1~29 X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=91c60b57908b0daaaef6f5262180c67793e92bb0;p=occt-copy.git 0025885: Visualization, ray tracing - Improve layer processing Move Ray-tracing core from OpenGl_Workspace to OpenGl_View. This patch also contains a number of useful architectural changes. --- diff --git a/src/NCollection/NCollection_Vec2.hxx b/src/NCollection/NCollection_Vec2.hxx index 9027e4d9b1..5515a637a1 100644 --- a/src/NCollection/NCollection_Vec2.hxx +++ b/src/NCollection/NCollection_Vec2.hxx @@ -175,6 +175,25 @@ public: v[1] > theVec.v[1] ? v[1] : theVec.v[1]); } + //! Compute component-wise modulus of the vector. + NCollection_Vec2 cwiseAbs() const + { + return NCollection_Vec2 (std::abs (v[0]), + std::abs (v[1])); + } + + //! Compute maximum component of the vector. + Element_t maxComp() const + { + return v[0] > v[1] ? v[0] : v[1]; + } + + //! Compute minimum component of the vector. + Element_t minComp() const + { + return v[0] < v[1] ? v[0] : v[1]; + } + //! Compute per-component multiplication by scale factor. NCollection_Vec2& operator*= (const Element_t theFactor) { diff --git a/src/NCollection/NCollection_Vec3.hxx b/src/NCollection/NCollection_Vec3.hxx index 35cb9e2538..e0568a25c8 100644 --- a/src/NCollection/NCollection_Vec3.hxx +++ b/src/NCollection/NCollection_Vec3.hxx @@ -250,6 +250,28 @@ public: v[2] > theVec.v[2] ? v[2] : theVec.v[2]); } + //! Compute component-wise modulus of the vector. + NCollection_Vec3 cwiseAbs() const + { + return NCollection_Vec3 (std::abs (v[0]), + std::abs (v[1]), + std::abs (v[2])); + } + + //! Compute maximum component of the vector. + Element_t maxComp() const + { + return v[0] > v[1] ? (v[0] > v[2] ? v[0] : v[2]) + : (v[1] > v[2] ? v[1] : v[2]); + } + + //! Compute minimum component of the vector. + Element_t minComp() const + { + return v[0] < v[1] ? (v[0] < v[2] ? v[0] : v[2]) + : (v[1] < v[2] ? v[1] : v[2]); + } + //! Compute per-component division by scale factor. NCollection_Vec3& operator/= (const Element_t theInvFactor) { diff --git a/src/NCollection/NCollection_Vec4.hxx b/src/NCollection/NCollection_Vec4.hxx index 45aa2b013a..65b38ebf15 100644 --- a/src/NCollection/NCollection_Vec4.hxx +++ b/src/NCollection/NCollection_Vec4.hxx @@ -302,6 +302,33 @@ public: v[3] > theVec.v[3] ? v[3] : theVec.v[3]); } + //! Compute component-wise modulus of the vector. + NCollection_Vec4 cwiseAbs() const + { + return NCollection_Vec4 (std::abs (v[0]), + std::abs (v[1]), + std::abs (v[2]), + std::abs (v[3])); + } + + //! Compute maximum component of the vector. + Element_t maxComp() const + { + const Element_t aMax1 = v[0] > v[1] ? v[0] : v[1]; + const Element_t aMax2 = v[2] > v[3] ? v[2] : v[3]; + + return aMax1 > aMax2 ? aMax1 : aMax2; + } + + //! Compute minimum component of the vector. + Element_t minComp() const + { + const Element_t aMin1 = v[0] < v[1] ? v[0] : v[1]; + const Element_t aMin2 = v[2] < v[3] ? v[2] : v[3]; + + return aMin1 < aMin2 ? aMin1 : aMin2; + } + //! Compute per-component division by scale factor. NCollection_Vec4& operator/= (const Element_t theInvFactor) { diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index 26a4872c63..37d3e63a1f 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -108,6 +108,7 @@ OpenGl_GlCore43.hxx OpenGl_GlCore44.hxx OpenGl_LayerList.cxx OpenGl_LayerList.hxx +OpenGl_LayerFilter.hxx OpenGl_IndexBuffer.hxx OpenGl_IndexBuffer.cxx OpenGl_Layer.cxx @@ -146,7 +147,7 @@ Handle_OpenGl_ShaderProgram.hxx Handle_OpenGl_ShaderManager.hxx OpenGl_SceneGeometry.hxx OpenGl_SceneGeometry.cxx -OpenGl_Workspace_Raytrace.cxx +OpenGl_View_Raytrace.cxx OpenGl_Flipper.hxx OpenGl_Flipper.cxx OpenGl_BVHTreeSelector.hxx diff --git a/src/OpenGl/OpenGl_LayerFilter.hxx b/src/OpenGl/OpenGl_LayerFilter.hxx new file mode 100644 index 0000000000..1860431946 --- /dev/null +++ b/src/OpenGl/OpenGl_LayerFilter.hxx @@ -0,0 +1,28 @@ +// Created on: 2015-03-20 +// Created by: Denis BOGOLEPOV +// Copyright (c) 2012-2014 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 _OpenGl_LayerFilter_H__ +#define _OpenGl_LayerFilter_H__ + +//! Tool object to specify processed OpenGL layers. +enum OpenGl_LayerFilter +{ + OpenGl_LF_All, //!< process all layers + OpenGl_LF_Upper, //!< process only top layers + OpenGl_LF_Bottom, //!< process only bottom layer + OpenGl_LF_Default //!< process only default layer +}; + +#endif //_OpenGl_LayerFilter_H__ diff --git a/src/OpenGl/OpenGl_LayerList.cxx b/src/OpenGl/OpenGl_LayerList.cxx index 712a51c87f..485b6e91ec 100644 --- a/src/OpenGl/OpenGl_LayerList.cxx +++ b/src/OpenGl/OpenGl_LayerList.cxx @@ -357,7 +357,8 @@ void OpenGl_LayerList::SetLayerSettings (const Graphic3d_ZLayerId theLaye //purpose : //======================================================================= void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace, - const Standard_Boolean theToDrawImmediate) const + const Standard_Boolean theToDrawImmediate, + const OpenGl_LayerFilter theLayersToProcess) const { OpenGl_GlobalLayerSettings aDefaultSettings; @@ -365,9 +366,22 @@ void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace, aCtx->core11fwd->glGetIntegerv (GL_DEPTH_FUNC, &aDefaultSettings.DepthFunc); aCtx->core11fwd->glGetBooleanv (GL_DEPTH_WRITEMASK, &aDefaultSettings.DepthMask); - Standard_Integer aSeqId = myLayers.Lower(); + Standard_Integer aSeqId = myLayers.Lower(), aMainId = myLayerIds.Find (Graphic3d_ZLayerId_Default); for (OpenGl_SequenceOfLayers::Iterator anIts (myLayers); anIts.More(); anIts.Next(), ++aSeqId) { + if (theLayersToProcess == OpenGl_LF_Bottom) + { + if (aSeqId >= aMainId) continue; + } + else if (theLayersToProcess == OpenGl_LF_Upper) + { + if (aSeqId <= aMainId) continue; + } + else if (theLayersToProcess == OpenGl_LF_Default) + { + if (aSeqId != aMainId) continue; + } + const OpenGl_Layer& aLayer = anIts.Value(); if (aLayer.NbStructures() < 1) { diff --git a/src/OpenGl/OpenGl_LayerList.hxx b/src/OpenGl/OpenGl_LayerList.hxx index e7c20accf8..8d077fa708 100644 --- a/src/OpenGl/OpenGl_LayerList.hxx +++ b/src/OpenGl/OpenGl_LayerList.hxx @@ -17,6 +17,7 @@ #define _OpenGl_LayerList_Header #include +#include #include @@ -89,7 +90,8 @@ public: //! Render this element void Render (const Handle(OpenGl_Workspace)& theWorkspace, - const Standard_Boolean theToDrawImmediate) const; + const Standard_Boolean theToDrawImmediate, + const OpenGl_LayerFilter theLayersToProcess) const; //! Returns the set of OpenGL Z-layers. const OpenGl_SequenceOfLayers& Layers() const { return myLayers; } diff --git a/src/OpenGl/OpenGl_ShaderProgram.hxx b/src/OpenGl/OpenGl_ShaderProgram.hxx index 79a65b3e73..bb6d0ba1df 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.hxx +++ b/src/OpenGl/OpenGl_ShaderProgram.hxx @@ -132,7 +132,7 @@ const int MaxStateTypes = 6; //! Wrapper for OpenGL program object. class OpenGl_ShaderProgram : public OpenGl_Resource { - friend class OpenGl_Workspace; + friend class OpenGl_View; public: diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index edfa8a5657..96940797b3 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -73,10 +73,15 @@ OpenGl_View::OpenGl_View (const CALL_DEF_VIEWCONTEXT &AContext, myModelViewState (0), myStateCounter (theCounter), myLastLightSourceState (0, 0), - myModificationState (1), // initial state myTextureParams (new OpenGl_AspectFace()), myBgGradientArray (new OpenGl_BackgroundArray (Graphic3d_TOB_GRADIENT)), - myBgTextureArray (new OpenGl_BackgroundArray (Graphic3d_TOB_TEXTURE)) + myBgTextureArray (new OpenGl_BackgroundArray (Graphic3d_TOB_TEXTURE)), + // ray-tracing fields initialization + myRaytraceInitStatus (OpenGl_RT_NONE), + myIsRaytraceDataValid (Standard_False), + myIsRaytraceWarnTextures (Standard_False), + myToUpdateEnvironmentMap (Standard_False), + myLayersModificationStatus (0) { myCurrLightSourceState = myStateCounter->Increment(); } @@ -114,6 +119,8 @@ void OpenGl_View::ReleaseGlResources (const Handle(OpenGl_Context)& theCtx) { myBgTextureArray->Release (theCtx.operator->()); } + + releaseRaytraceResources (theCtx); } void OpenGl_View::SetTextureEnv (const Handle(OpenGl_Context)& theCtx, @@ -135,14 +142,14 @@ void OpenGl_View::SetTextureEnv (const Handle(OpenGl_Context)& theCtx, if (!anImage.IsNull()) myTextureEnv->Init (theCtx, *anImage.operator->(), theTexture->Type()); - myModificationState++; + myToUpdateEnvironmentMap = Standard_True; } void OpenGl_View::SetSurfaceDetail (const Visual3d_TypeOfSurfaceDetail theMode) { mySurfaceDetail = theMode; - myModificationState++; + myToUpdateEnvironmentMap = Standard_True; } // ======================================================================= diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index 3bddb4acfb..03dc77af3a 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -213,17 +213,17 @@ class OpenGl_View : public MMgt_TShared || myZLayers.NbImmediateStructures() != 0; } - //! Returns modification state for ray-tracing. - Standard_Size ModificationState() const { return myModificationState; } - protected: void RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, + const Graphic3d_CView& theCView, const Standard_Boolean theToDrawImmediate); + void RedrawLayer2d (const Handle(OpenGl_PrinterContext)& thePrintContext, - const Handle(OpenGl_Workspace) &theWorkspace, + const Handle(OpenGl_Workspace)& theWorkspace, const Graphic3d_CView& theCView, const Aspect_CLayer2d& theCLayer); + void RedrawTrihedron (const Handle(OpenGl_Workspace) &theWorkspace); //! Redraw contents of model scene: clipping planes, @@ -232,6 +232,7 @@ protected: //! matrices supplied by 3d view. void RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintContext, const Handle(OpenGl_Workspace)& theWorkspace, + const Graphic3d_CView& theCView, const Standard_Boolean theToDrawImmediate); Handle(OpenGl_LineAttributes) myLineAttribs; @@ -286,14 +287,398 @@ protected: //! Is needed for selection of overlapping objects and storage of the current view volume OpenGl_BVHTreeSelector myBVHSelector; - Standard_Size myModificationState; - protected: //! @name Background parameters OpenGl_AspectFace* myTextureParams; //!< Stores texture and its parameters for textured background OpenGl_BackgroundArray* myBgGradientArray; //!< Primitive array for gradient background OpenGl_BackgroundArray* myBgTextureArray; //!< Primitive array for texture background +protected: //! @name data types related to ray-tracing + + //! Result of OpenGL shaders initialization. + enum RaytraceInitStatus + { + OpenGl_RT_NONE, + OpenGl_RT_INIT, + OpenGl_RT_FAIL + }; + + //! Describes update mode (state). + enum RaytraceUpdateMode + { + OpenGl_GUM_CHECK, //!< check geometry state + OpenGl_GUM_PREPARE, //!< collect unchanged objects + OpenGl_GUM_REBUILD //!< rebuild changed and new objects + }; + + //! Defines frequently used shader variables. + enum ShaderVariableIndex + { + OpenGl_RT_aPosition, + + OpenGl_RT_uOriginLT, + OpenGl_RT_uOriginLB, + OpenGl_RT_uOriginRT, + OpenGl_RT_uOriginRB, + OpenGl_RT_uDirectLT, + OpenGl_RT_uDirectLB, + OpenGl_RT_uDirectRT, + OpenGl_RT_uDirectRB, + OpenGl_RT_uUnviewMat, + + OpenGl_RT_uSceneRad, + OpenGl_RT_uSceneEps, + OpenGl_RT_uLightAmbnt, + OpenGl_RT_uLightCount, + + OpenGl_RT_uShadEnabled, + OpenGl_RT_uReflEnabled, + OpenGl_RT_uEnvMapEnable, + + OpenGl_RT_uOffsetX, + OpenGl_RT_uOffsetY, + OpenGl_RT_uSamples, + OpenGl_RT_uWinSizeX, + OpenGl_RT_uWinSizeY, + + OpenGl_RT_uTextures, + + OpenGl_RT_NbVariables // special field + }; + + //! Defines texture samplers. + enum ShaderSamplerNames + { + OpenGl_RT_SceneNodeInfoTexture = 0, + OpenGl_RT_SceneMinPointTexture = 1, + OpenGl_RT_SceneMaxPointTexture = 2, + OpenGl_RT_SceneTransformTexture = 3, + + OpenGl_RT_GeometryVertexTexture = 4, + OpenGl_RT_GeometryNormalTexture = 5, + OpenGl_RT_GeometryTexCrdTexture = 6, + OpenGl_RT_GeometryTriangTexture = 7, + + OpenGl_RT_EnvironmentMapTexture = 8, + + OpenGl_RT_RaytraceMaterialTexture = 9, + OpenGl_RT_RaytraceLightSrcTexture = 10, + + OpenGl_RT_FSAAInputTexture = 11, + + OpenGl_RT_OpenGlColorTexture = 12, + OpenGl_RT_OpenGlDepthTexture = 13 + }; + + //! Tool class for management of shader sources. + class ShaderSource + { + public: + + //! Creates new uninitialized shader source. + ShaderSource() + { + // + } + + //! Creates new shader source from specified file. + ShaderSource (const TCollection_AsciiString& theFileName) + { + Load (&theFileName, 1); + } + + public: + + //! Returns prefix to insert before the source. + const TCollection_AsciiString& Prefix() const + { + return myPrefix; + } + + //! Sets prefix to insert before the source. + void SetPrefix (const TCollection_AsciiString& thePrefix) + { + myPrefix = thePrefix; + } + + //! Returns shader source combined with prefix. + TCollection_AsciiString Source() const; + + //! Loads shader source from specified files. + void Load (const TCollection_AsciiString* theFileNames, const Standard_Integer theCount); + + private: + + TCollection_AsciiString mySource; //!< Source string of the shader object + TCollection_AsciiString myPrefix; //!< Prefix to insert before the source + + }; + + //! Default ray-tracing depth. + static const Standard_Integer THE_DEFAULT_NB_BOUNCES = 3; + + //! Default size of traversal stack. + static const Standard_Integer THE_DEFAULT_STACK_SIZE = 24; + + //! Compile-time ray-tracing parameters. + struct RaytracingParams + { + //! Actual size of traversal stack in shader program. + Standard_Integer StackSize; + + //! Actual ray-tracing depth (number of ray bounces). + Standard_Integer NbBounces; + + //! Sets light propagation through transparent media. + Standard_Boolean TransparentShadows; + + //! Creates default compile-time ray-tracing parameters. + RaytracingParams() + : StackSize (THE_DEFAULT_STACK_SIZE), + NbBounces (THE_DEFAULT_NB_BOUNCES), + TransparentShadows (Standard_False) + { + // + } + }; + +protected: //! @name methods related to ray-tracing + + //! Updates 3D scene geometry for ray-tracing. + Standard_Boolean updateRaytraceGeometry (const RaytraceUpdateMode theMode, + const Standard_Integer theViewId, + const Handle(OpenGl_Context)& theGlContext); + + //! Updates 3D scene light sources for ray-tracing. + Standard_Boolean updateRaytraceLightSources (const OpenGl_Mat4& theInvModelView, const Handle(OpenGl_Context)& theGlContext); + + //! Updates environment map for ray-tracing. + Standard_Boolean updateRaytraceEnvironmentMap (const Handle(OpenGl_Context)& theGlContext); + + //! Checks to see if the OpenGL structure is modified. + Standard_Boolean toUpdateStructure (const OpenGl_Structure* theStructure); + + //! Adds OpenGL structure to ray-traced scene geometry. + Standard_Boolean addRaytraceStructure (const OpenGl_Structure* theStructure, + const Handle(OpenGl_Context)& theGlContext); + + //! Adds OpenGL groups to ray-traced scene geometry. + Standard_Boolean addRaytraceGroups (const OpenGl_Structure* theStructure, + const Standard_Integer theStructMat, + const Standard_ShortReal* theTransform, + const Handle(OpenGl_Context)& theGlContext); + + //! Creates ray-tracing material properties. + OpenGl_RaytraceMaterial convertMaterial (const OpenGl_AspectFace* theAspect, + const Handle(OpenGl_Context)& theGlContext); + + //! Adds OpenGL primitive array to ray-traced scene geometry. + OpenGl_TriangleSet* addRaytracePrimitiveArray (const OpenGl_PrimitiveArray* theArray, + const Standard_Integer theMatID, + const OpenGl_Mat4* theTrans); + + //! Adds vertex indices from OpenGL primitive array to ray-traced scene geometry. + Standard_Boolean addRaytraceVertexIndices (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const OpenGl_PrimitiveArray& theArray); + + //! Adds OpenGL triangle array to ray-traced scene geometry. + Standard_Boolean addRaytraceTriangleArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices); + + //! Adds OpenGL triangle fan array to ray-traced scene geometry. + Standard_Boolean addRaytraceTriangleFanArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices); + + //! Adds OpenGL triangle strip array to ray-traced scene geometry. + Standard_Boolean addRaytraceTriangleStripArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices); + + //! Adds OpenGL quadrangle array to ray-traced scene geometry. + Standard_Boolean addRaytraceQuadrangleArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices); + + //! Adds OpenGL quadrangle strip array to ray-traced scene geometry. + Standard_Boolean addRaytraceQuadrangleStripArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices); + + //! Adds OpenGL polygon array to ray-traced scene geometry. + Standard_Boolean addRaytracePolygonArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices); + + //! Uploads ray-trace data to the GPU. + Standard_Boolean uploadRaytraceData (const Handle(OpenGl_Context)& theGlContext); + + //! Generates shader prefix based on current ray-tracing options. + TCollection_AsciiString generateShaderPrefix (const Handle(OpenGl_Context)& theGlContext) const; + + //! Performs safe exit when shaders initialization fails. + Standard_Boolean safeFailBack (const TCollection_ExtendedString& theMessage, + const Handle(OpenGl_Context)& theGlContext); + + //! Loads and compiles shader object from specified source. + Handle(OpenGl_ShaderObject) initShader (const GLenum theType, + const ShaderSource& theSource, + const Handle(OpenGl_Context)& theGlContext); + + //! Initializes OpenGL/GLSL shader programs. + Standard_Boolean initRaytraceResources (const Graphic3d_CView& theCView, + const Handle(OpenGl_Context)& theGlContext); + + //! Releases OpenGL/GLSL shader programs. + void releaseRaytraceResources (const Handle(OpenGl_Context)& theGlContext); + + //! Resizes OpenGL frame buffers. + Standard_Boolean resizeRaytraceBuffers (const Standard_Integer theSizeX, + const Standard_Integer theSizeY, + const Handle(OpenGl_Context)& theGlContext); + + //! Generates viewing rays for corners of screen quad. + void updateCamera (const OpenGl_Mat4& theOrientation, + const OpenGl_Mat4& theViewMapping, + OpenGl_Vec3* theOrigins, + OpenGl_Vec3* theDirects, + OpenGl_Mat4& theUnView); + + //! Binds ray-trace textures to corresponding texture units. + void bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext); + + //! Unbinds ray-trace textures from corresponding texture unit. + void unbindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext); + + //! Sets uniform state for the given ray-tracing shader program. + Standard_Boolean setUniformState (const Graphic3d_CView& theCView, + const OpenGl_Vec3* theOrigins, + const OpenGl_Vec3* theDirects, + const OpenGl_Mat4& theUnviewMat, + const Standard_Integer theProgramId, + const Handle(OpenGl_Context)& theGlContext); + + //! Runs ray-tracing shader programs. + Standard_Boolean runRaytraceShaders (const Graphic3d_CView& theCView, + const Standard_Integer theSizeX, + const Standard_Integer theSizeY, + const OpenGl_Vec3* theOrigins, + const OpenGl_Vec3* theDirects, + const OpenGl_Mat4& theUnviewMat, + OpenGl_FrameBuffer* theOutputFBO, + const Handle(OpenGl_Context)& theGlContext); + + //! Redraws the window using OpenGL/GLSL ray-tracing. + Standard_Boolean raytrace (const Graphic3d_CView& theCView, + const Standard_Integer theSizeX, + const Standard_Integer theSizeY, + OpenGl_FrameBuffer* theOutputFBO, + const Handle(OpenGl_Context)& theGlContext); + +protected: //! @name fields related to ray-tracing + + //! Result of shaders initialization. + RaytraceInitStatus myRaytraceInitStatus; + + //! Is geometry data valid? + Standard_Boolean myIsRaytraceDataValid; + + //! Warning about missing extension GL_ARB_bindless_texture has been displayed? + Standard_Boolean myIsRaytraceWarnTextures; + + //! 3D scene geometry data for ray-tracing. + OpenGl_RaytraceGeometry myRaytraceGeometry; + + //! Compile-time ray-tracing parameters. + RaytracingParams myRaytraceParameters; + + //! Radius of bounding sphere of the scene. + Standard_ShortReal myRaytraceSceneRadius; + //! Scene epsilon to prevent self-intersections. + Standard_ShortReal myRaytraceSceneEpsilon; + + //! OpenGL/GLSL source of ray-tracing fragment shader. + ShaderSource myRaytraceShaderSource; + //! OpenGL/GLSL source of adaptive-AA fragment shader. + ShaderSource myPostFSAAShaderSource; + + //! OpenGL/GLSL ray-tracing fragment shader. + Handle(OpenGl_ShaderObject) myRaytraceShader; + //! OpenGL/GLSL adaptive-AA fragment shader. + Handle(OpenGl_ShaderObject) myPostFSAAShader; + + //! OpenGL/GLSL ray-tracing shader program. + Handle(OpenGl_ShaderProgram) myRaytraceProgram; + //! OpenGL/GLSL adaptive-AA shader program. + Handle(OpenGl_ShaderProgram) myPostFSAAProgram; + + //! Texture buffer of data records of bottom-level BVH nodes. + Handle(OpenGl_TextureBufferArb) mySceneNodeInfoTexture; + //! Texture buffer of minimum points of bottom-level BVH nodes. + Handle(OpenGl_TextureBufferArb) mySceneMinPointTexture; + //! Texture buffer of maximum points of bottom-level BVH nodes. + Handle(OpenGl_TextureBufferArb) mySceneMaxPointTexture; + //! Texture buffer of transformations of high-level BVH nodes. + Handle(OpenGl_TextureBufferArb) mySceneTransformTexture; + + //! Texture buffer of vertex coords. + Handle(OpenGl_TextureBufferArb) myGeometryVertexTexture; + //! Texture buffer of vertex normals. + Handle(OpenGl_TextureBufferArb) myGeometryNormalTexture; + //! Texture buffer of vertex UV coords. + Handle(OpenGl_TextureBufferArb) myGeometryTexCrdTexture; + //! Texture buffer of triangle indices. + Handle(OpenGl_TextureBufferArb) myGeometryTriangTexture; + + //! Texture buffer of material properties. + Handle(OpenGl_TextureBufferArb) myRaytraceMaterialTexture; + //! Texture buffer of light source properties. + Handle(OpenGl_TextureBufferArb) myRaytraceLightSrcTexture; + + //! 1st framebuffer (FBO) to perform adaptive FSAA. + Handle(OpenGl_FrameBuffer) myRaytraceFBO1; + //! 2nd framebuffer (FBO) to perform adaptive FSAA. + Handle(OpenGl_FrameBuffer) myRaytraceFBO2; + //! Framebuffer (FBO) for preliminary OpenGL output. + Handle(OpenGl_FrameBuffer) myOpenGlFBO; + + //! Vertex buffer (VBO) for drawing dummy quad. + OpenGl_VertexBuffer myRaytraceScreenQuad; + + //! Cached locations of frequently used uniform variables. + Standard_Integer myUniformLocations[2][OpenGl_RT_NbVariables]; + + //! State of OpenGL structures reflected to ray-tracing. + std::map myStructureStates; + + //! PrimitiveArray to TriangleSet map for scene partial update. + std::map myArrayToTrianglesMap; + + //! Graphical ray-tracing filter to filter out all raytracable structures. + Handle(OpenGl_RaytraceFilter) myRaytraceFilter; + + //! Marks if environment map should be updated. + Standard_Boolean myToUpdateEnvironmentMap; + + //! State of OpenGL layer list. + Standard_Size myLayersModificationStatus; + public: DEFINE_STANDARD_ALLOC diff --git a/src/OpenGl/OpenGl_View_2.cxx b/src/OpenGl/OpenGl_View_2.cxx index 2e79d4d2b8..24b374a7a8 100644 --- a/src/OpenGl/OpenGl_View_2.cxx +++ b/src/OpenGl/OpenGl_View_2.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #define EPSI 0.0001 @@ -241,7 +242,7 @@ void OpenGl_View::DrawBackground (const Handle(OpenGl_Workspace)& theWorkspace) aCtx->ProjectionState.Pop(); aCtx->ApplyProjectionMatrix(); - if (theWorkspace->UseZBuffer() && theWorkspace->ToRedrawGL()) + if (theWorkspace->UseZBuffer()) { aCtx->core11fwd->glEnable (GL_DEPTH_TEST); } @@ -340,8 +341,7 @@ void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext, // ==================================== // Render background - if (theWorkspace->ToRedrawGL() - && !theToDrawImmediate) + if (!theToDrawImmediate) { DrawBackground (theWorkspace); } @@ -456,7 +456,7 @@ void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext, { // single-pass monographic rendering // redraw scene with normal orientation and projection - RedrawScene (thePrintContext, theWorkspace, theToDrawImmediate); + RedrawScene (thePrintContext, theWorkspace, theCView, theToDrawImmediate); } else { @@ -469,7 +469,7 @@ void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext, aContext->ApplyProjectionMatrix(); // redraw left Eye - RedrawScene (thePrintContext, theWorkspace, theToDrawImmediate); + RedrawScene (thePrintContext, theWorkspace, theCView, theToDrawImmediate); // reset depth buffer of first rendering pass if (theWorkspace->UseDepthTest()) @@ -483,7 +483,7 @@ void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext, aContext->ApplyProjectionMatrix(); // redraw right Eye - RedrawScene (thePrintContext, theWorkspace, theToDrawImmediate); + RedrawScene (thePrintContext, theWorkspace, theCView, theToDrawImmediate); // switch back to monographic rendering aContext->SetDrawBufferMono(); @@ -513,8 +513,7 @@ void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext, } // Render trihedron - if (theWorkspace->ToRedrawGL() - && !theToDrawImmediate) + if (!theToDrawImmediate) { RedrawTrihedron (theWorkspace); @@ -587,6 +586,7 @@ void OpenGl_View::InvalidateBVHData (const Graphic3d_ZLayerId theLayerId) //ExecuteViewDisplay void OpenGl_View::RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, + const Graphic3d_CView& theCView, const Standard_Boolean theToDrawImmediate) { if ( myZLayers.NbStructures() <= 0 ) @@ -628,7 +628,109 @@ void OpenGl_View::RenderStructs (const Handle(OpenGl_Workspace)& theWorkspace, } } - myZLayers.Render (theWorkspace, theToDrawImmediate); + Standard_Boolean toRenderGL = theToDrawImmediate || + theCView.RenderParams.Method != Graphic3d_RM_RAYTRACING || myRaytraceInitStatus == OpenGl_RT_FAIL; + + if (!toRenderGL) + { + toRenderGL = !initRaytraceResources (theCView, aCtx) || + !updateRaytraceGeometry (OpenGl_GUM_CHECK, theWorkspace->ActiveViewId(), aCtx); + + OpenGl_FrameBuffer* anOutputFBO = NULL; + + if (theWorkspace->ResultFBO()->IsValid()) + { + anOutputFBO = theWorkspace->ResultFBO().operator->(); + } + else if (theCView.ptrFBO != NULL) + { + anOutputFBO = (OpenGl_FrameBuffer* )theCView.ptrFBO; + } + else + { + //toRenderGL = Standard_True; // failed to get valid FBO + } + + if (!toRenderGL && myIsRaytraceDataValid) + { + const Standard_Integer aSizeX = anOutputFBO != NULL ? + anOutputFBO->GetVPSizeX() : theWorkspace->Width(); + const Standard_Integer aSizeY = anOutputFBO != NULL ? + anOutputFBO->GetVPSizeY() : theWorkspace->Height(); + + if (myOpenGlFBO.IsNull()) + myOpenGlFBO = new OpenGl_FrameBuffer; + + if (myOpenGlFBO->GetVPSizeX() != aSizeX + || myOpenGlFBO->GetVPSizeY() != aSizeY) + { + myOpenGlFBO->Init (aCtx, aSizeX, aSizeY); + } + + if (myRaytraceFilter.IsNull()) + myRaytraceFilter = new OpenGl_RaytraceFilter; + + myRaytraceFilter->SetPrevRenderFilter (theWorkspace->GetRenderFilter()); + + if (anOutputFBO != NULL) + anOutputFBO->UnbindBuffer (aCtx); + + // Prepare preliminary OpenGL output + if (aCtx->arbFBOBlit != NULL) + { + // Render bottom OSD layer + myZLayers.Render (theWorkspace, theToDrawImmediate, OpenGl_LF_Bottom); + + theWorkspace->SetRenderFilter (myRaytraceFilter); + { + if (anOutputFBO != NULL) + { + anOutputFBO->BindReadBuffer (aCtx); + } + else + { + aCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, 0); + } + + myOpenGlFBO->BindDrawBuffer (aCtx); + + aCtx->arbFBOBlit->glBlitFramebuffer (0, 0, aSizeX, aSizeY, + 0, 0, aSizeX, aSizeY, + GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, + GL_NEAREST); + + // Render non-polygonal elements in default layer + myZLayers.Render (theWorkspace, theToDrawImmediate, OpenGl_LF_Default); + } + theWorkspace->SetRenderFilter (myRaytraceFilter->PrevRenderFilter()); + } + + if (anOutputFBO != NULL) + { + anOutputFBO->BindBuffer (aCtx); + } + else + { + aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, 0); + } + + // Ray-tracing polygonal primitive arrays + raytrace (theCView, aSizeX, aSizeY, anOutputFBO, aCtx); + + // Render upper (top and topmost) OpenGL layers + myZLayers.Render (theWorkspace, theToDrawImmediate, OpenGl_LF_Upper); + } + } + + // Redraw 3D scene using OpenGL in standard + // mode or in case of ray-tracing failure + if (toRenderGL) + { + myZLayers.Render (theWorkspace, theToDrawImmediate, OpenGl_LF_All); + + // Set flag that scene was redrawn by standard pipeline + theCView.WasRedrawnGL = Standard_True; + } } /*----------------------------------------------------------------------*/ @@ -971,6 +1073,7 @@ void OpenGl_View::ChangePriority (const OpenGl_Structure *theStructure, void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintContext, const Handle(OpenGl_Workspace)& theWorkspace, + const Graphic3d_CView& theCView, const Standard_Boolean theToDrawImmediate) { const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext(); @@ -1103,14 +1206,14 @@ void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintCont theWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX; theWorkspace->DisableTexture(); // Render the view - RenderStructs (theWorkspace, theToDrawImmediate); + RenderStructs (theWorkspace, theCView, theToDrawImmediate); break; case Visual3d_TOD_ENVIRONMENT: theWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX; theWorkspace->EnableTexture (myTextureEnv); // Render the view - RenderStructs (theWorkspace, theToDrawImmediate); + RenderStructs (theWorkspace, theCView, theToDrawImmediate); theWorkspace->DisableTexture(); break; @@ -1118,7 +1221,7 @@ void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintCont // First pass theWorkspace->NamedStatus &= ~OPENGL_NS_FORBIDSETTEX; // Render the view - RenderStructs (theWorkspace, theToDrawImmediate); + RenderStructs (theWorkspace, theCView, theToDrawImmediate); theWorkspace->DisableTexture(); // Second pass @@ -1151,7 +1254,7 @@ void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintCont theWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX; // Render the view - RenderStructs (theWorkspace, theToDrawImmediate); + RenderStructs (theWorkspace, theCView, theToDrawImmediate); theWorkspace->DisableTexture(); // Restore properties back diff --git a/src/OpenGl/OpenGl_View_Raytrace.cxx b/src/OpenGl/OpenGl_View_Raytrace.cxx new file mode 100644 index 0000000000..7cde775d43 --- /dev/null +++ b/src/OpenGl/OpenGl_View_Raytrace.cxx @@ -0,0 +1,2416 @@ +// Created on: 2015-02-20 +// Created by: Denis BOGOLEPOV +// Copyright (c) 2015 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. + +#include + +#include +#include +#include +#include + +#include +#include + +using namespace OpenGl_Raytrace; + +//! Use this macro to output ray-tracing debug info +// #define RAY_TRACE_PRINT_INFO + +#ifdef RAY_TRACE_PRINT_INFO + #include +#endif + +// ======================================================================= +// function : UpdateRaytraceGeometry +// purpose : Updates 3D scene geometry for ray-tracing +// ======================================================================= +Standard_Boolean OpenGl_View::updateRaytraceGeometry (const RaytraceUpdateMode theMode, + const Standard_Integer theViewId, + const Handle(OpenGl_Context)& theGlContext) +{ + // In 'check' mode (OpenGl_GUM_CHECK) the scene geometry is analyzed for + // modifications. This is light-weight procedure performed on each frame + if (theMode == OpenGl_GUM_CHECK) + { + if (myLayersModificationStatus != myZLayers.ModificationState()) + { + return updateRaytraceGeometry (OpenGl_GUM_PREPARE, theViewId, theGlContext); + } + } + else if (theMode == OpenGl_GUM_PREPARE) + { + myRaytraceGeometry.ClearMaterials(); + + myArrayToTrianglesMap.clear(); + + myIsRaytraceDataValid = Standard_False; + } + + // The set of processed structures (reflected to ray-tracing) + // This set is used to remove out-of-date records from the + // hash map of structures + std::set anElements; + + // Set to store all currently visible OpenGL primitive arrays + // applicable for ray-tracing + std::set anArrayIDs; + + const OpenGl_Layer& aLayer = myZLayers.Layer (Graphic3d_ZLayerId_Default); + + if (aLayer.NbStructures() != 0) + { + const OpenGl_ArrayOfStructure& aStructArray = aLayer.ArrayOfStructures(); + + for (Standard_Integer anIndex = 0; anIndex < aStructArray.Length(); ++anIndex) + { + for (OpenGl_SequenceOfStructure::Iterator aStructIt (aStructArray (anIndex)); aStructIt.More(); aStructIt.Next()) + { + const OpenGl_Structure* aStructure = aStructIt.Value(); + + if (theMode == OpenGl_GUM_CHECK) + { + if (toUpdateStructure (aStructure)) + { + return updateRaytraceGeometry (OpenGl_GUM_PREPARE, theViewId, theGlContext); + } + } + else if (theMode == OpenGl_GUM_PREPARE) + { + if (!aStructure->IsRaytracable() || !aStructure->IsVisible()) + { + continue; + } + else if (!aStructure->ViewAffinity.IsNull() && !aStructure->ViewAffinity->IsVisible (theViewId)) + { + continue; + } + + for (OpenGl_Structure::GroupIterator aGroupIter (aStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next()) + { + // Extract OpenGL elements from the group (primitives arrays) + for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next) + { + OpenGl_PrimitiveArray* aPrimArray = dynamic_cast (aNode->elem); + + if (aPrimArray != NULL) + { + anArrayIDs.insert (aPrimArray->GetUID()); + } + } + } + } + else if (theMode == OpenGl_GUM_REBUILD) + { + if (!aStructure->IsRaytracable()) + { + continue; + } + else if (addRaytraceStructure (aStructure, theGlContext)) + { + anElements.insert (aStructure); // structure was processed + } + } + } + } + } + + if (theMode == OpenGl_GUM_PREPARE) + { + BVH_ObjectSet::BVH_ObjectList anUnchangedObjects; + + // Filter out unchanged objects so only their transformations and materials + // will be updated (and newly added objects will be processed from scratch) + for (Standard_Integer anObjIdx = 0; anObjIdx < myRaytraceGeometry.Size(); ++anObjIdx) + { + OpenGl_TriangleSet* aTriangleSet = dynamic_cast ( + myRaytraceGeometry.Objects().ChangeValue (anObjIdx).operator->()); + + if (aTriangleSet == NULL) + { + continue; + } + + if (anArrayIDs.find (aTriangleSet->AssociatedPArrayID()) != anArrayIDs.end()) + { + anUnchangedObjects.Append (myRaytraceGeometry.Objects().Value (anObjIdx)); + + myArrayToTrianglesMap[aTriangleSet->AssociatedPArrayID()] = aTriangleSet; + } + } + + myRaytraceGeometry.Objects() = anUnchangedObjects; + + return updateRaytraceGeometry (OpenGl_GUM_REBUILD, theViewId, theGlContext); + } + else if (theMode == OpenGl_GUM_REBUILD) + { + // Actualize the hash map of structures - remove out-of-date records + std::map::iterator anIter = myStructureStates.begin(); + + while (anIter != myStructureStates.end()) + { + if (anElements.find (anIter->first) == anElements.end()) + { + myStructureStates.erase (anIter++); + } + else + { + ++anIter; + } + } + + // Actualize OpenGL layer list state + myLayersModificationStatus = myZLayers.ModificationState(); + + // Rebuild two-level acceleration structure + myRaytraceGeometry.ProcessAcceleration(); + + myRaytraceSceneRadius = 2.f /* scale factor */ * std::max ( + myRaytraceGeometry.Box().CornerMin().cwiseAbs().maxComp(), + myRaytraceGeometry.Box().CornerMax().cwiseAbs().maxComp()); + + const BVH_Vec3f aSize = myRaytraceGeometry.Box().Size(); + + myRaytraceSceneEpsilon = Max (1.0e-6f, 1.0e-4f * aSize.Modulus()); + + return uploadRaytraceData (theGlContext); + } + + return Standard_True; +} + +// ======================================================================= +// function : ToUpdateStructure +// purpose : Checks to see if the structure is modified +// ======================================================================= +Standard_Boolean OpenGl_View::toUpdateStructure (const OpenGl_Structure* theStructure) +{ + if (!theStructure->IsRaytracable()) + { + if (theStructure->ModificationState() > 0) + { + theStructure->ResetModificationState(); + + return Standard_True; // ray-trace element was removed - need to rebuild + } + + return Standard_False; // did not contain ray-trace elements + } + + std::map::iterator aStructState = myStructureStates.find (theStructure); + + if (aStructState != myStructureStates.end()) + { + return aStructState->second != theStructure->ModificationState(); + } + + return Standard_True; +} + +// ======================================================================= +// function : BuildTextureTransform +// purpose : Constructs texture transformation matrix +// ======================================================================= +void BuildTextureTransform (const Handle(Graphic3d_TextureParams)& theParams, BVH_Mat4f& theMatrix) +{ + theMatrix.InitIdentity(); + + // Apply scaling + const Graphic3d_Vec2& aScale = theParams->Scale(); + + theMatrix.ChangeValue (0, 0) *= aScale.x(); + theMatrix.ChangeValue (1, 0) *= aScale.x(); + theMatrix.ChangeValue (2, 0) *= aScale.x(); + theMatrix.ChangeValue (3, 0) *= aScale.x(); + + theMatrix.ChangeValue (0, 1) *= aScale.y(); + theMatrix.ChangeValue (1, 1) *= aScale.y(); + theMatrix.ChangeValue (2, 1) *= aScale.y(); + theMatrix.ChangeValue (3, 1) *= aScale.y(); + + // Apply translation + const Graphic3d_Vec2 aTrans = -theParams->Translation(); + + theMatrix.ChangeValue (0, 3) = theMatrix.GetValue (0, 0) * aTrans.x() + + theMatrix.GetValue (0, 1) * aTrans.y(); + + theMatrix.ChangeValue (1, 3) = theMatrix.GetValue (1, 0) * aTrans.x() + + theMatrix.GetValue (1, 1) * aTrans.y(); + + theMatrix.ChangeValue (2, 3) = theMatrix.GetValue (2, 0) * aTrans.x() + + theMatrix.GetValue (2, 1) * aTrans.y(); + + // Apply rotation + const Standard_ShortReal aSin = std::sin ( + -theParams->Rotation() * static_cast (M_PI / 180.0)); + const Standard_ShortReal aCos = std::cos ( + -theParams->Rotation() * static_cast (M_PI / 180.0)); + + BVH_Mat4f aRotationMat; + aRotationMat.SetValue (0, 0, aCos); + aRotationMat.SetValue (1, 1, aCos); + aRotationMat.SetValue (0, 1, -aSin); + aRotationMat.SetValue (1, 0, aSin); + + theMatrix = theMatrix * aRotationMat; +} + +// ======================================================================= +// function : ConvertMaterial +// purpose : Creates ray-tracing material properties +// ======================================================================= +OpenGl_RaytraceMaterial OpenGl_View::convertMaterial (const OpenGl_AspectFace* theAspect, + const Handle(OpenGl_Context)& theGlContext) +{ + OpenGl_RaytraceMaterial theMaterial; + + const OPENGL_SURF_PROP& aProperties = theAspect->IntFront(); + + theMaterial.Ambient = BVH_Vec4f ( + (aProperties.isphysic ? aProperties.ambcol.rgb[0] : aProperties.matcol.rgb[0]) * aProperties.amb, + (aProperties.isphysic ? aProperties.ambcol.rgb[1] : aProperties.matcol.rgb[1]) * aProperties.amb, + (aProperties.isphysic ? aProperties.ambcol.rgb[2] : aProperties.matcol.rgb[2]) * aProperties.amb, + 1.f); + + theMaterial.Diffuse = BVH_Vec4f ( + (aProperties.isphysic ? aProperties.difcol.rgb[0] : aProperties.matcol.rgb[0]) * aProperties.diff, + (aProperties.isphysic ? aProperties.difcol.rgb[1] : aProperties.matcol.rgb[1]) * aProperties.diff, + (aProperties.isphysic ? aProperties.difcol.rgb[2] : aProperties.matcol.rgb[2]) * aProperties.diff, + -1.f /* no texture */); + + theMaterial.Specular = BVH_Vec4f ( + (aProperties.isphysic ? aProperties.speccol.rgb[0] : 1.f) * aProperties.spec, + (aProperties.isphysic ? aProperties.speccol.rgb[1] : 1.f) * aProperties.spec, + (aProperties.isphysic ? aProperties.speccol.rgb[2] : 1.f) * aProperties.spec, + aProperties.shine); + + theMaterial.Emission = BVH_Vec4f ( + (aProperties.isphysic ? aProperties.emscol.rgb[0] : aProperties.matcol.rgb[0]) * aProperties.emsv, + (aProperties.isphysic ? aProperties.emscol.rgb[1] : aProperties.matcol.rgb[1]) * aProperties.emsv, + (aProperties.isphysic ? aProperties.emscol.rgb[2] : aProperties.matcol.rgb[2]) * aProperties.emsv, + 1.f); + + theMaterial.Transparency = BVH_Vec4f (aProperties.trans, + 1.f - aProperties.trans, + aProperties.index == 0 ? 1.f : aProperties.index, + aProperties.index == 0 ? 1.f : 1.f / aProperties.index); + + const Standard_ShortReal aMaxRefl = Max (theMaterial.Diffuse.x() + theMaterial.Specular.x(), + Max (theMaterial.Diffuse.y() + theMaterial.Specular.y(), + theMaterial.Diffuse.z() + theMaterial.Specular.z())); + + const Standard_ShortReal aReflectionScale = 0.75f / aMaxRefl; + + theMaterial.Reflection = BVH_Vec4f ( + aProperties.speccol.rgb[0] * aProperties.spec * aReflectionScale, + aProperties.speccol.rgb[1] * aProperties.spec * aReflectionScale, + aProperties.speccol.rgb[2] * aProperties.spec * aReflectionScale, + 0.f); + + if (theAspect->DoTextureMap()) + { + if (theGlContext->arbTexBindless != NULL) + { + BuildTextureTransform (theAspect->TextureParams(), theMaterial.TextureTransform); + + // write texture ID in the w-component + theMaterial.Diffuse.w() = static_cast ( + myRaytraceGeometry.AddTexture (theAspect->TextureRes (theGlContext))); + } + else if (!myIsRaytraceWarnTextures) + { + const TCollection_ExtendedString aWarnMessage = + "Warning: texturing in Ray-Trace requires GL_ARB_bindless_texture extension which is missing. " + "Please try to update graphics card driver. At the moment textures will be ignored."; + + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aWarnMessage); + + myIsRaytraceWarnTextures = Standard_True; + } + } + + return theMaterial; +} + +// ======================================================================= +// function : AddRaytraceStructure +// purpose : Adds OpenGL structure to ray-traced scene geometry +// ======================================================================= +Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure* theStructure, + const Handle(OpenGl_Context)& theGlContext) +{ + if (!theStructure->IsVisible()) + { + myStructureStates[theStructure] = theStructure->ModificationState(); + + return Standard_True; + } + + // Get structure material + Standard_Integer aStructMatID = -1; + + if (theStructure->AspectFace() != NULL) + { + aStructMatID = static_cast (myRaytraceGeometry.Materials.size()); + + OpenGl_RaytraceMaterial aStructMaterial = convertMaterial (theStructure->AspectFace(), theGlContext); + + myRaytraceGeometry.Materials.push_back (aStructMaterial); + } + + Standard_ShortReal aStructTransform[16]; + + if (theStructure->Transformation()->mat != NULL) + { + for (Standard_Integer i = 0; i < 4; ++i) + { + for (Standard_Integer j = 0; j < 4; ++j) + { + aStructTransform[j * 4 + i] = theStructure->Transformation()->mat[i][j]; + } + } + } + + Standard_Boolean aResult = addRaytraceGroups (theStructure, aStructMatID, + theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext); + + // Process all connected OpenGL structures + for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures()); anIts.More(); anIts.Next()) + { + if (anIts.Value()->IsRaytracable()) + { + aResult &= addRaytraceGroups (anIts.Value(), aStructMatID, + theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext); + } + } + + myStructureStates[theStructure] = theStructure->ModificationState(); + + return aResult; +} + +// ======================================================================= +// function : AddRaytraceGroups +// purpose : Adds OpenGL groups to ray-traced scene geometry +// ======================================================================= +Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure* theStructure, + const Standard_Integer theStructMat, + const Standard_ShortReal* theTransform, + const Handle(OpenGl_Context)& theGlContext) +{ + for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next()) + { + // Get group material + Standard_Integer aGroupMatID = -1; + if (aGroupIter.Value()->AspectFace() != NULL) + { + aGroupMatID = static_cast (myRaytraceGeometry.Materials.size()); + + OpenGl_RaytraceMaterial aGroupMaterial = convertMaterial ( + aGroupIter.Value()->AspectFace(), theGlContext); + + myRaytraceGeometry.Materials.push_back (aGroupMaterial); + } + + Standard_Integer aMatID = aGroupMatID < 0 ? theStructMat : aGroupMatID; + if (aMatID < 0) + { + aMatID = static_cast (myRaytraceGeometry.Materials.size()); + + myRaytraceGeometry.Materials.push_back (OpenGl_RaytraceMaterial()); + } + + // Add OpenGL elements from group (extract primitives arrays and aspects) + for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next) + { + OpenGl_AspectFace* anAspect = dynamic_cast (aNode->elem); + + if (anAspect != NULL) + { + aMatID = static_cast (myRaytraceGeometry.Materials.size()); + + OpenGl_RaytraceMaterial aMaterial = convertMaterial (anAspect, theGlContext); + + myRaytraceGeometry.Materials.push_back (aMaterial); + } + else + { + OpenGl_PrimitiveArray* aPrimArray = dynamic_cast (aNode->elem); + + if (aPrimArray != NULL) + { + std::map::iterator aSetIter = myArrayToTrianglesMap.find (aPrimArray->GetUID()); + + if (aSetIter != myArrayToTrianglesMap.end()) + { + OpenGl_TriangleSet* aSet = aSetIter->second; + + BVH_Transform* aTransform = new BVH_Transform(); + + if (theTransform != NULL) + { + aTransform->SetTransform (*(reinterpret_cast (theTransform))); + } + + aSet->SetProperties (aTransform); + + if (aSet->MaterialIndex() != OpenGl_TriangleSet::INVALID_MATERIAL && aSet->MaterialIndex() != aMatID) + { + aSet->SetMaterialIndex (aMatID); + } + } + else + { + NCollection_Handle > aSet = + addRaytracePrimitiveArray (aPrimArray, aMatID, 0); + + if (!aSet.IsNull()) + { + BVH_Transform* aTransform = new BVH_Transform; + + if (theTransform != NULL) + { + aTransform->SetTransform (*(reinterpret_cast (theTransform))); + } + + aSet->SetProperties (aTransform); + + myRaytraceGeometry.Objects().Append (aSet); + } + } + } + } + } + } + + return Standard_True; +} + +// ======================================================================= +// function : AddRaytracePrimitiveArray +// purpose : Adds OpenGL primitive array to ray-traced scene geometry +// ======================================================================= +OpenGl_TriangleSet* OpenGl_View::addRaytracePrimitiveArray (const OpenGl_PrimitiveArray* theArray, + const Standard_Integer theMaterial, + const OpenGl_Mat4* theTransform) +{ + const Handle(Graphic3d_BoundBuffer)& aBounds = theArray->Bounds(); + const Handle(Graphic3d_IndexBuffer)& anIndices = theArray->Indices(); + const Handle(Graphic3d_Buffer)& anAttribs = theArray->Attributes(); + + if (theArray->DrawMode() < GL_TRIANGLES + #ifndef GL_ES_VERSION_2_0 + || theArray->DrawMode() > GL_POLYGON + #else + || theArray->DrawMode() > GL_TRIANGLE_FAN + #endif + || anAttribs.IsNull()) + { + return NULL; + } + + OpenGl_Mat4 aNormalMatrix; + + if (theTransform != NULL) + { + Standard_ASSERT_RETURN (theTransform->Inverted (aNormalMatrix), + "Error: Failed to compute normal transformation matrix", NULL); + + aNormalMatrix.Transpose(); + } + + OpenGl_TriangleSet* aSet = new OpenGl_TriangleSet (theArray->GetUID()); + { + aSet->Vertices.reserve (anAttribs->NbElements); + aSet->Normals.reserve (anAttribs->NbElements); + aSet->TexCrds.reserve (anAttribs->NbElements); + + const size_t aVertFrom = aSet->Vertices.size(); + + for (Standard_Integer anAttribIter = 0; anAttribIter < anAttribs->NbAttributes; ++anAttribIter) + { + const Graphic3d_Attribute& anAttrib = anAttribs->Attribute (anAttribIter); + const size_t anOffset = anAttribs->AttributeOffset (anAttribIter); + if (anAttrib.Id == Graphic3d_TOA_POS) + { + if (anAttrib.DataType == Graphic3d_TOD_VEC3 + || anAttrib.DataType == Graphic3d_TOD_VEC4) + { + for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) + { + aSet->Vertices.push_back ( + *reinterpret_cast (anAttribs->value (aVertIter) + anOffset)); + } + } + else if (anAttrib.DataType == Graphic3d_TOD_VEC2) + { + for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) + { + const Standard_ShortReal* aCoords = + reinterpret_cast (anAttribs->value (aVertIter) + anOffset); + + aSet->Vertices.push_back (BVH_Vec3f (aCoords[0], aCoords[1], 0.0f)); + } + } + } + else if (anAttrib.Id == Graphic3d_TOA_NORM) + { + if (anAttrib.DataType == Graphic3d_TOD_VEC3 + || anAttrib.DataType == Graphic3d_TOD_VEC4) + { + for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) + { + aSet->Normals.push_back ( + *reinterpret_cast (anAttribs->value (aVertIter) + anOffset)); + } + } + } + else if (anAttrib.Id == Graphic3d_TOA_UV) + { + if (anAttrib.DataType == Graphic3d_TOD_VEC2) + { + for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) + { + aSet->TexCrds.push_back ( + *reinterpret_cast (anAttribs->value (aVertIter) + anOffset)); + } + } + } + } + + if (aSet->Normals.size() != aSet->Vertices.size()) + { + for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) + { + aSet->Normals.push_back (BVH_Vec3f()); + } + } + + if (aSet->TexCrds.size() != aSet->Vertices.size()) + { + for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) + { + aSet->TexCrds.push_back (BVH_Vec2f()); + } + } + + if (theTransform != NULL) + { + for (size_t aVertIter = aVertFrom; aVertIter < aSet->Vertices.size(); ++aVertIter) + { + BVH_Vec3f& aVertex = aSet->Vertices[aVertIter]; + + BVH_Vec4f aTransVertex = *theTransform * + BVH_Vec4f (aVertex.x(), aVertex.y(), aVertex.z(), 1.f); + + aVertex = BVH_Vec3f (aTransVertex.x(), aTransVertex.y(), aTransVertex.z()); + } + for (size_t aVertIter = aVertFrom; aVertIter < aSet->Normals.size(); ++aVertIter) + { + BVH_Vec3f& aNormal = aSet->Normals[aVertIter]; + + BVH_Vec4f aTransNormal = aNormalMatrix * + BVH_Vec4f (aNormal.x(), aNormal.y(), aNormal.z(), 0.f); + + aNormal = BVH_Vec3f (aTransNormal.x(), aTransNormal.y(), aTransNormal.z()); + } + } + + if (!aBounds.IsNull()) + { + for (Standard_Integer aBound = 0, aBoundStart = 0; aBound < aBounds->NbBounds; ++aBound) + { + const Standard_Integer aVertNum = aBounds->Bounds[aBound]; + + if (!addRaytraceVertexIndices (*aSet, theMaterial, aVertNum, aBoundStart, *theArray)) + { + delete aSet; + return NULL; + } + + aBoundStart += aVertNum; + } + } + else + { + const Standard_Integer aVertNum = !anIndices.IsNull() ? anIndices->NbElements : anAttribs->NbElements; + + if (!addRaytraceVertexIndices (*aSet, theMaterial, aVertNum, 0, *theArray)) + { + delete aSet; + return NULL; + } + } + } + + if (aSet->Size() != 0) + { + aSet->MarkDirty(); + } + + return aSet; +} + +// ======================================================================= +// function : AddRaytraceVertexIndices +// purpose : Adds vertex indices to ray-traced scene geometry +// ======================================================================= +Standard_Boolean OpenGl_View::addRaytraceVertexIndices (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const OpenGl_PrimitiveArray& theArray) +{ + switch (theArray.DrawMode()) + { + case GL_TRIANGLES: return addRaytraceTriangleArray (theSet, theMatID, theCount, theOffset, theArray.Indices()); + case GL_TRIANGLE_FAN: return addRaytraceTriangleFanArray (theSet, theMatID, theCount, theOffset, theArray.Indices()); + case GL_TRIANGLE_STRIP: return addRaytraceTriangleStripArray (theSet, theMatID, theCount, theOffset, theArray.Indices()); + #if !defined(GL_ES_VERSION_2_0) + case GL_QUAD_STRIP: return addRaytraceQuadrangleStripArray (theSet, theMatID, theCount, theOffset, theArray.Indices()); + case GL_QUADS: return addRaytraceQuadrangleArray (theSet, theMatID, theCount, theOffset, theArray.Indices()); + case GL_POLYGON: return addRaytracePolygonArray (theSet, theMatID, theCount, theOffset, theArray.Indices()); + #endif + } + + return Standard_False; +} + +// ======================================================================= +// function : AddRaytraceTriangleArray +// purpose : Adds OpenGL triangle array to ray-traced scene geometry +// ======================================================================= +Standard_Boolean OpenGl_View::addRaytraceTriangleArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices) +{ + if (theCount < 3) + { + return Standard_True; + } + + theSet.Elements.reserve (theSet.Elements.size() + theCount / 3); + + if (!theIndices.IsNull()) + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; aVert += 3) + { + theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0), + theIndices->Index (aVert + 1), + theIndices->Index (aVert + 2), + theMatID)); + } + } + else + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; aVert += 3) + { + theSet.Elements.push_back (BVH_Vec4i (aVert + 0, aVert + 1, aVert + 2, theMatID)); + } + } + + return Standard_True; +} + +// ======================================================================= +// function : AddRaytraceTriangleFanArray +// purpose : Adds OpenGL triangle fan array to ray-traced scene geometry +// ======================================================================= +Standard_Boolean OpenGl_View::addRaytraceTriangleFanArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices) +{ + if (theCount < 3) + { + return Standard_True; + } + + theSet.Elements.reserve (theSet.Elements.size() + theCount - 2); + + if (!theIndices.IsNull()) + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert) + { + theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (theOffset), + theIndices->Index (aVert + 1), + theIndices->Index (aVert + 2), + theMatID)); + } + } + else + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert) + { + theSet.Elements.push_back (BVH_Vec4i (theOffset, + aVert + 1, + aVert + 2, + theMatID)); + } + } + + return Standard_True; +} + +// ======================================================================= +// function : AddRaytraceTriangleStripArray +// purpose : Adds OpenGL triangle strip array to ray-traced scene geometry +// ======================================================================= +Standard_Boolean OpenGl_View::addRaytraceTriangleStripArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices) +{ + if (theCount < 3) + { + return Standard_True; + } + + theSet.Elements.reserve (theSet.Elements.size() + theCount - 2); + + if (!theIndices.IsNull()) + { + for (Standard_Integer aVert = theOffset, aCW = 0; aVert < theOffset + theCount - 2; ++aVert, aCW = (aCW + 1) % 2) + { + theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + aCW ? 1 : 0), + theIndices->Index (aVert + aCW ? 0 : 1), + theIndices->Index (aVert + 2), + theMatID)); + } + } + else + { + for (Standard_Integer aVert = theOffset, aCW = 0; aVert < theOffset + theCount - 2; ++aVert, aCW = (aCW + 1) % 2) + { + theSet.Elements.push_back (BVH_Vec4i (aVert + aCW ? 1 : 0, + aVert + aCW ? 0 : 1, + aVert + 2, + theMatID)); + } + } + + return Standard_True; +} + +// ======================================================================= +// function : AddRaytraceQuadrangleArray +// purpose : Adds OpenGL quad array to ray-traced scene geometry +// ======================================================================= +Standard_Boolean OpenGl_View::addRaytraceQuadrangleArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices) +{ + if (theCount < 4) + { + return Standard_True; + } + + theSet.Elements.reserve (theSet.Elements.size() + theCount / 2); + + if (!theIndices.IsNull()) + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 4) + { + theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0), + theIndices->Index (aVert + 1), + theIndices->Index (aVert + 2), + theMatID)); + theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0), + theIndices->Index (aVert + 2), + theIndices->Index (aVert + 3), + theMatID)); + } + } + else + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 4) + { + theSet.Elements.push_back (BVH_Vec4i (aVert + 0, aVert + 1, aVert + 2, + theMatID)); + theSet.Elements.push_back (BVH_Vec4i (aVert + 0, aVert + 2, aVert + 3, + theMatID)); + } + } + + return Standard_True; +} + +// ======================================================================= +// function : AddRaytraceQuadrangleStripArray +// purpose : Adds OpenGL quad strip array to ray-traced scene geometry +// ======================================================================= +Standard_Boolean OpenGl_View::addRaytraceQuadrangleStripArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices) +{ + if (theCount < 4) + { + return Standard_True; + } + + theSet.Elements.reserve (theSet.Elements.size() + 2 * theCount - 6); + + if (!theIndices.IsNull()) + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 2) + { + theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0), + theIndices->Index (aVert + 1), + theIndices->Index (aVert + 2), + theMatID)); + + theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 1), + theIndices->Index (aVert + 3), + theIndices->Index (aVert + 2), + theMatID)); + } + } + else + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 2) + { + theSet.Elements.push_back (BVH_Vec4i (aVert + 0, + aVert + 1, + aVert + 2, + theMatID)); + + theSet.Elements.push_back (BVH_Vec4i (aVert + 1, + aVert + 3, + aVert + 2, + theMatID)); + } + } + + return Standard_True; +} + +// ======================================================================= +// function : AddRaytracePolygonArray +// purpose : Adds OpenGL polygon array to ray-traced scene geometry +// ======================================================================= +Standard_Boolean OpenGl_View::addRaytracePolygonArray (OpenGl_TriangleSet& theSet, + const Standard_Integer theMatID, + const Standard_Integer theCount, + const Standard_Integer theOffset, + const Handle(Graphic3d_IndexBuffer)& theIndices) +{ + if (theCount < 3) + { + return Standard_True; + } + + theSet.Elements.reserve (theSet.Elements.size() + theCount - 2); + + if (!theIndices.IsNull()) + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert) + { + theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (theOffset), + theIndices->Index (aVert + 1), + theIndices->Index (aVert + 2), + theMatID)); + } + } + else + { + for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert) + { + theSet.Elements.push_back (BVH_Vec4i (theOffset, + aVert + 1, + aVert + 2, + theMatID)); + } + } + + return Standard_True; +} + +// ======================================================================= +// function : Source +// purpose : Returns shader source combined with prefix +// ======================================================================= +TCollection_AsciiString OpenGl_View::ShaderSource::Source() const +{ + static const TCollection_AsciiString aVersion = "#version 140"; + + if (myPrefix.IsEmpty()) + { + return aVersion + "\n" + mySource; + } + + return aVersion + "\n" + myPrefix + "\n" + mySource; +} + +// ======================================================================= +// function : Load +// purpose : Loads shader source from specified files +// ======================================================================= +void OpenGl_View::ShaderSource::Load (const TCollection_AsciiString* theFileNames, + const Standard_Integer theCount) +{ + mySource.Clear(); + + for (Standard_Integer anIndex = 0; anIndex < theCount; ++anIndex) + { + OSD_File aFile (theFileNames[anIndex]); + + Standard_ASSERT_RETURN (aFile.Exists(), + "Error: Failed to find shader source file", /* none */); + + aFile.Open (OSD_ReadOnly, OSD_Protection()); + + TCollection_AsciiString aSource; + + Standard_ASSERT_RETURN (aFile.IsOpen(), + "Error: Failed to open shader source file", /* none */); + + aFile.Read (aSource, (Standard_Integer) aFile.Size()); + + if (!aSource.IsEmpty()) + { + mySource += TCollection_AsciiString ("\n") + aSource; + } + + aFile.Close(); + } +} + +// ======================================================================= +// function : GenerateShaderPrefix +// purpose : Generates shader prefix based on current ray-tracing options +// ======================================================================= +TCollection_AsciiString OpenGl_View::generateShaderPrefix (const Handle(OpenGl_Context)& theGlContext) const +{ + TCollection_AsciiString aPrefixString = + TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myRaytraceParameters.StackSize) + "\n" + + TCollection_AsciiString ("#define NB_BOUNCES ") + TCollection_AsciiString (myRaytraceParameters.NbBounces); + + if (myRaytraceParameters.TransparentShadows) + { + aPrefixString += TCollection_AsciiString ("\n#define TRANSPARENT_SHADOWS"); + } + + // If OpenGL driver supports bindless textures, + // activate texturing in ray-tracing mode + if (theGlContext->arbTexBindless != NULL) + { + aPrefixString += TCollection_AsciiString ("\n#define USE_TEXTURES") + + TCollection_AsciiString ("\n#define MAX_TEX_NUMBER ") + TCollection_AsciiString (OpenGl_RaytraceGeometry::MAX_TEX_NUMBER); + } + + return aPrefixString; +} + +// ======================================================================= +// function : SafeFailBack +// purpose : Performs safe exit when shaders initialization fails +// ======================================================================= +Standard_Boolean OpenGl_View::safeFailBack (const TCollection_ExtendedString& theMessage, + const Handle(OpenGl_Context)& theGlContext) +{ + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, theMessage); + + myRaytraceInitStatus = OpenGl_RT_FAIL; + + releaseRaytraceResources (theGlContext); + + return Standard_False; +} + +// ======================================================================= +// function : InitShader +// purpose : Creates new shader object with specified source +// ======================================================================= +Handle(OpenGl_ShaderObject) OpenGl_View::initShader (const GLenum theType, + const ShaderSource& theSource, + const Handle(OpenGl_Context)& theGlContext) +{ + Handle(OpenGl_ShaderObject) aShader = new OpenGl_ShaderObject (theType); + + if (!aShader->Create (theGlContext)) + { + const TCollection_ExtendedString aMessage = TCollection_ExtendedString ("Error: Failed to create ") + + (theType == GL_VERTEX_SHADER ? "vertex" : "fragment") + " shader object"; + + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage); + + aShader->Release (theGlContext.operator->()); + + return Handle(OpenGl_ShaderObject)(); + } + + if (!aShader->LoadSource (theGlContext, theSource.Source())) + { + const TCollection_ExtendedString aMessage = TCollection_ExtendedString ("Error: Failed to set ") + + (theType == GL_VERTEX_SHADER ? "vertex" : "fragment") + " shader source"; + + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage); + + aShader->Release (theGlContext.operator->()); + + return Handle(OpenGl_ShaderObject)(); + } + + TCollection_AsciiString aBuildLog; + + if (!aShader->Compile (theGlContext)) + { + aShader->FetchInfoLog (theGlContext, aBuildLog); + + const TCollection_ExtendedString aMessage = TCollection_ExtendedString ("Error: Failed to compile ") + + (theType == GL_VERTEX_SHADER ? "vertex" : "fragment") + " shader object:\n" + aBuildLog; + + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage); + + aShader->Release (theGlContext.operator->()); + + return Handle(OpenGl_ShaderObject)(); + } + else if (theGlContext->caps->glslWarnings) + { + aShader->FetchInfoLog (theGlContext, aBuildLog); + + if (!aBuildLog.IsEmpty() && !aBuildLog.IsEqual ("No errors.\n")) + { + const TCollection_ExtendedString aMessage = TCollection_ExtendedString (theType == GL_VERTEX_SHADER ? + "Vertex" : "Fragment") + " shader was compiled with following warnings:\n" + aBuildLog; + + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage); + } + } + + return aShader; +} + +// ======================================================================= +// function : InitRaytraceResources +// purpose : Initializes OpenGL/GLSL shader programs +// ======================================================================= +Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theCView, const Handle(OpenGl_Context)& theGlContext) +{ + if (myRaytraceInitStatus == OpenGl_RT_FAIL) + { + return Standard_False; + } + + Standard_Boolean aToRebuildShaders = Standard_False; + + if (myRaytraceInitStatus == OpenGl_RT_INIT) + { + if (!myIsRaytraceDataValid) + return Standard_True; + + const Standard_Integer aRequiredStackSize = + myRaytraceGeometry.HighLevelTreeDepth() + myRaytraceGeometry.BottomLevelTreeDepth(); + + if (myRaytraceParameters.StackSize < aRequiredStackSize) + { + myRaytraceParameters.StackSize = Max (aRequiredStackSize, THE_DEFAULT_STACK_SIZE); + + aToRebuildShaders = Standard_True; + } + else + { + if (aRequiredStackSize < myRaytraceParameters.StackSize) + { + if (myRaytraceParameters.StackSize > THE_DEFAULT_STACK_SIZE) + { + myRaytraceParameters.StackSize = Max (aRequiredStackSize, THE_DEFAULT_STACK_SIZE); + aToRebuildShaders = Standard_True; + } + } + } + + if (theCView.RenderParams.RaytracingDepth != myRaytraceParameters.NbBounces) + { + myRaytraceParameters.NbBounces = theCView.RenderParams.RaytracingDepth; + aToRebuildShaders = Standard_True; + } + + if (theCView.RenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows) + { + myRaytraceParameters.TransparentShadows = theCView.RenderParams.IsTransparentShadowEnabled; + aToRebuildShaders = Standard_True; + } + + if (aToRebuildShaders) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Info: Rebuild shaders with stack size: " << myRaytraceParameters.StackSize << std::endl; +#endif + + // Change state to force update all uniforms + myToUpdateEnvironmentMap = Standard_True; + + TCollection_AsciiString aPrefixString = generateShaderPrefix (theGlContext); + +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "GLSL prefix string:" << std::endl << aPrefixString << std::endl; +#endif + + myRaytraceShaderSource.SetPrefix (aPrefixString); + myPostFSAAShaderSource.SetPrefix (aPrefixString); + + if (!myRaytraceShader->LoadSource (theGlContext, myRaytraceShaderSource.Source()) + || !myPostFSAAShader->LoadSource (theGlContext, myPostFSAAShaderSource.Source())) + { + return safeFailBack ("Failed to load source into ray-tracing fragment shaders", theGlContext); + } + + if (!myRaytraceShader->Compile (theGlContext) + || !myPostFSAAShader->Compile (theGlContext)) + { + return safeFailBack ("Failed to compile ray-tracing fragment shaders", theGlContext); + } + + myRaytraceProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex"); + myPostFSAAProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex"); + if (!myRaytraceProgram->Link (theGlContext) + || !myPostFSAAProgram->Link (theGlContext)) + { + return safeFailBack ("Failed to initialize vertex attributes for ray-tracing program", theGlContext); + } + } + } + + if (myRaytraceInitStatus == OpenGl_RT_NONE) + { + if (!theGlContext->IsGlGreaterEqual (3, 1)) + { + return safeFailBack ("Ray-tracing requires OpenGL 3.1 and higher", theGlContext); + } + else if (!theGlContext->arbTboRGB32) + { + return safeFailBack ("Ray-tracing requires OpenGL 4.0+ or GL_ARB_texture_buffer_object_rgb32 extension", theGlContext); + } + else if (!theGlContext->arbFBOBlit) + { + return safeFailBack ("Ray-tracing requires EXT_framebuffer_blit extension", theGlContext); + } + + myRaytraceParameters.NbBounces = theCView.RenderParams.RaytracingDepth; + + TCollection_AsciiString aFolder = Graphic3d_ShaderProgram::ShadersFolder(); + + if (aFolder.IsEmpty()) + { + return safeFailBack ("Failed to locate shaders directory", theGlContext); + } + + if (myIsRaytraceDataValid) + { + myRaytraceParameters.StackSize = Max (THE_DEFAULT_STACK_SIZE, + myRaytraceGeometry.HighLevelTreeDepth() + myRaytraceGeometry.BottomLevelTreeDepth()); + } + + TCollection_AsciiString aPrefixString = generateShaderPrefix (theGlContext); + +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "GLSL prefix string:" << std::endl << aPrefixString << std::endl; +#endif + + { + Handle(OpenGl_ShaderObject) aBasicVertShader = initShader ( + GL_VERTEX_SHADER, ShaderSource (aFolder + "/RaytraceBase.vs"), theGlContext); + + if (aBasicVertShader.IsNull()) + { + return safeFailBack ("Failed to initialize ray-trace vertex shader", theGlContext); + } + + TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs", + aFolder + "/RaytraceRender.fs" }; + + myRaytraceShaderSource.Load (aFiles, 2); + + myRaytraceShaderSource.SetPrefix (aPrefixString); + + myRaytraceShader = initShader (GL_FRAGMENT_SHADER, myRaytraceShaderSource, theGlContext); + + if (myRaytraceShader.IsNull()) + { + aBasicVertShader->Release (theGlContext.operator->()); + + return safeFailBack ("Failed to initialize ray-trace fragment shader", theGlContext); + } + + myRaytraceProgram = new OpenGl_ShaderProgram; + + if (!myRaytraceProgram->Create (theGlContext)) + { + aBasicVertShader->Release (theGlContext.operator->()); + + return safeFailBack ("Failed to create ray-trace shader program", theGlContext); + } + + if (!myRaytraceProgram->AttachShader (theGlContext, aBasicVertShader) + || !myRaytraceProgram->AttachShader (theGlContext, myRaytraceShader)) + { + aBasicVertShader->Release (theGlContext.operator->()); + + return safeFailBack ("Failed to attach ray-trace shader objects", theGlContext); + } + + myRaytraceProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex"); + + TCollection_AsciiString aLinkLog; + + if (!myRaytraceProgram->Link (theGlContext)) + { + myRaytraceProgram->FetchInfoLog (theGlContext, aLinkLog); + + return safeFailBack (TCollection_ExtendedString ( + "Failed to link ray-trace shader program:\n") + aLinkLog, theGlContext); + } + else if (theGlContext->caps->glslWarnings) + { + myRaytraceProgram->FetchInfoLog (theGlContext, aLinkLog); + + if (!aLinkLog.IsEmpty() && !aLinkLog.IsEqual ("No errors.\n")) + { + const TCollection_ExtendedString aMessage = TCollection_ExtendedString ( + "Ray-trace shader program was linked with following warnings:\n") + aLinkLog; + + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage); + } + } + } + + { + Handle(OpenGl_ShaderObject) aBasicVertShader = initShader ( + GL_VERTEX_SHADER, ShaderSource (aFolder + "/RaytraceBase.vs"), theGlContext); + + if (aBasicVertShader.IsNull()) + { + return safeFailBack ("Failed to initialize FSAA vertex shader", theGlContext); + } + + TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs", + aFolder + "/RaytraceSmooth.fs" }; + + myPostFSAAShaderSource.Load (aFiles, 2); + + myPostFSAAShaderSource.SetPrefix (aPrefixString); + + myPostFSAAShader = initShader (GL_FRAGMENT_SHADER, myPostFSAAShaderSource, theGlContext); + + if (myPostFSAAShader.IsNull()) + { + aBasicVertShader->Release (theGlContext.operator->()); + + return safeFailBack ("Failed to initialize FSAA fragment shader", theGlContext); + } + + myPostFSAAProgram = new OpenGl_ShaderProgram; + + if (!myPostFSAAProgram->Create (theGlContext)) + { + aBasicVertShader->Release (theGlContext.operator->()); + + return safeFailBack ("Failed to create FSAA shader program", theGlContext); + } + + if (!myPostFSAAProgram->AttachShader (theGlContext, aBasicVertShader) + || !myPostFSAAProgram->AttachShader (theGlContext, myPostFSAAShader)) + { + aBasicVertShader->Release (theGlContext.operator->()); + + return safeFailBack ("Failed to attach FSAA shader objects", theGlContext); + } + + myPostFSAAProgram->SetAttributeName (theGlContext, Graphic3d_TOA_POS, "occVertex"); + + TCollection_AsciiString aLinkLog; + + if (!myPostFSAAProgram->Link (theGlContext)) + { + myPostFSAAProgram->FetchInfoLog (theGlContext, aLinkLog); + + return safeFailBack (TCollection_ExtendedString ( + "Failed to link FSAA shader program:\n") + aLinkLog, theGlContext); + } + else if (theGlContext->caps->glslWarnings) + { + myPostFSAAProgram->FetchInfoLog (theGlContext, aLinkLog); + + if (!aLinkLog.IsEmpty() && !aLinkLog.IsEqual ("No errors.\n")) + { + const TCollection_ExtendedString aMessage = TCollection_ExtendedString ( + "FSAA shader program was linked with following warnings:\n") + aLinkLog; + + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, + GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage); + } + } + } + } + + if (myRaytraceInitStatus == OpenGl_RT_NONE || aToRebuildShaders) + { + for (Standard_Integer anIndex = 0; anIndex < 2; ++anIndex) + { + Handle(OpenGl_ShaderProgram)& aShaderProgram = + (anIndex == 0) ? myRaytraceProgram : myPostFSAAProgram; + + theGlContext->BindProgram (aShaderProgram); + + aShaderProgram->SetSampler (theGlContext, + "uSceneMinPointTexture", OpenGl_RT_SceneMinPointTexture); + aShaderProgram->SetSampler (theGlContext, + "uSceneMaxPointTexture", OpenGl_RT_SceneMaxPointTexture); + aShaderProgram->SetSampler (theGlContext, + "uSceneNodeInfoTexture", OpenGl_RT_SceneNodeInfoTexture); + aShaderProgram->SetSampler (theGlContext, + "uGeometryVertexTexture", OpenGl_RT_GeometryVertexTexture); + aShaderProgram->SetSampler (theGlContext, + "uGeometryNormalTexture", OpenGl_RT_GeometryNormalTexture); + aShaderProgram->SetSampler (theGlContext, + "uGeometryTexCrdTexture", OpenGl_RT_GeometryTexCrdTexture); + aShaderProgram->SetSampler (theGlContext, + "uGeometryTriangTexture", OpenGl_RT_GeometryTriangTexture); + aShaderProgram->SetSampler (theGlContext, + "uSceneTransformTexture", OpenGl_RT_SceneTransformTexture); + aShaderProgram->SetSampler (theGlContext, + "uEnvironmentMapTexture", OpenGl_RT_EnvironmentMapTexture); + aShaderProgram->SetSampler (theGlContext, + "uRaytraceMaterialTexture", OpenGl_RT_RaytraceMaterialTexture); + aShaderProgram->SetSampler (theGlContext, + "uRaytraceLightSrcTexture", OpenGl_RT_RaytraceLightSrcTexture); + + aShaderProgram->SetSampler (theGlContext, + "uOpenGlColorTexture", OpenGl_RT_OpenGlColorTexture); + aShaderProgram->SetSampler (theGlContext, + "uOpenGlDepthTexture", OpenGl_RT_OpenGlDepthTexture); + + if (anIndex == 1) + { + aShaderProgram->SetSampler (theGlContext, + "uFSAAInputTexture", OpenGl_RT_FSAAInputTexture); + } + + myUniformLocations[anIndex][OpenGl_RT_aPosition] = + aShaderProgram->GetAttributeLocation (theGlContext, "occVertex"); + + myUniformLocations[anIndex][OpenGl_RT_uOriginLB] = + aShaderProgram->GetUniformLocation (theGlContext, "uOriginLB"); + myUniformLocations[anIndex][OpenGl_RT_uOriginRB] = + aShaderProgram->GetUniformLocation (theGlContext, "uOriginRB"); + myUniformLocations[anIndex][OpenGl_RT_uOriginLT] = + aShaderProgram->GetUniformLocation (theGlContext, "uOriginLT"); + myUniformLocations[anIndex][OpenGl_RT_uOriginRT] = + aShaderProgram->GetUniformLocation (theGlContext, "uOriginRT"); + myUniformLocations[anIndex][OpenGl_RT_uDirectLB] = + aShaderProgram->GetUniformLocation (theGlContext, "uDirectLB"); + myUniformLocations[anIndex][OpenGl_RT_uDirectRB] = + aShaderProgram->GetUniformLocation (theGlContext, "uDirectRB"); + myUniformLocations[anIndex][OpenGl_RT_uDirectLT] = + aShaderProgram->GetUniformLocation (theGlContext, "uDirectLT"); + myUniformLocations[anIndex][OpenGl_RT_uDirectRT] = + aShaderProgram->GetUniformLocation (theGlContext, "uDirectRT"); + myUniformLocations[anIndex][OpenGl_RT_uUnviewMat] = + aShaderProgram->GetUniformLocation (theGlContext, "uUnviewMat"); + + myUniformLocations[anIndex][OpenGl_RT_uSceneRad] = + aShaderProgram->GetUniformLocation (theGlContext, "uSceneRadius"); + myUniformLocations[anIndex][OpenGl_RT_uSceneEps] = + aShaderProgram->GetUniformLocation (theGlContext, "uSceneEpsilon"); + myUniformLocations[anIndex][OpenGl_RT_uLightCount] = + aShaderProgram->GetUniformLocation (theGlContext, "uLightCount"); + myUniformLocations[anIndex][OpenGl_RT_uLightAmbnt] = + aShaderProgram->GetUniformLocation (theGlContext, "uGlobalAmbient"); + + myUniformLocations[anIndex][OpenGl_RT_uOffsetX] = + aShaderProgram->GetUniformLocation (theGlContext, "uOffsetX"); + myUniformLocations[anIndex][OpenGl_RT_uOffsetY] = + aShaderProgram->GetUniformLocation (theGlContext, "uOffsetY"); + myUniformLocations[anIndex][OpenGl_RT_uSamples] = + aShaderProgram->GetUniformLocation (theGlContext, "uSamples"); + myUniformLocations[anIndex][OpenGl_RT_uWinSizeX] = + aShaderProgram->GetUniformLocation (theGlContext, "uWinSizeX"); + myUniformLocations[anIndex][OpenGl_RT_uWinSizeY] = + aShaderProgram->GetUniformLocation (theGlContext, "uWinSizeY"); + + myUniformLocations[anIndex][OpenGl_RT_uTextures] = + aShaderProgram->GetUniformLocation (theGlContext, "uTextureSamplers"); + + myUniformLocations[anIndex][OpenGl_RT_uShadEnabled] = + aShaderProgram->GetUniformLocation (theGlContext, "uShadowsEnable"); + myUniformLocations[anIndex][OpenGl_RT_uReflEnabled] = + aShaderProgram->GetUniformLocation (theGlContext, "uReflectionsEnable"); + myUniformLocations[anIndex][OpenGl_RT_uEnvMapEnable] = + aShaderProgram->GetUniformLocation (theGlContext, "uEnvironmentEnable"); + } + + theGlContext->BindProgram (NULL); + } + + if (myRaytraceInitStatus != OpenGl_RT_NONE) + { + return myRaytraceInitStatus == OpenGl_RT_INIT; + } + + if (myRaytraceFBO1.IsNull()) + { + myRaytraceFBO1 = new OpenGl_FrameBuffer; + } + + if (myRaytraceFBO2.IsNull()) + { + myRaytraceFBO2 = new OpenGl_FrameBuffer; + } + + const GLfloat aVertices[] = { -1.f, -1.f, 0.f, + -1.f, 1.f, 0.f, + 1.f, 1.f, 0.f, + 1.f, 1.f, 0.f, + 1.f, -1.f, 0.f, + -1.f, -1.f, 0.f }; + + myRaytraceScreenQuad.Init (theGlContext, 3, 6, aVertices); + + myRaytraceInitStatus = OpenGl_RT_INIT; // initialized in normal way + + return Standard_True; +} + +// ======================================================================= +// function : NullifyResource +// purpose : +// ======================================================================= +inline void NullifyResource (const Handle(OpenGl_Context)& theGlContext, + Handle(OpenGl_Resource)& theResource) +{ + if (!theResource.IsNull()) + { + theResource->Release (theGlContext.operator->()); + theResource.Nullify(); + } +} + +// ======================================================================= +// function : ReleaseRaytraceResources +// purpose : Releases OpenGL/GLSL shader programs +// ======================================================================= +void OpenGl_View::releaseRaytraceResources (const Handle(OpenGl_Context)& theGlContext) +{ + NullifyResource (theGlContext, myOpenGlFBO); + NullifyResource (theGlContext, myRaytraceFBO1); + NullifyResource (theGlContext, myRaytraceFBO2); + + NullifyResource (theGlContext, myRaytraceShader); + NullifyResource (theGlContext, myPostFSAAShader); + + NullifyResource (theGlContext, myRaytraceProgram); + NullifyResource (theGlContext, myPostFSAAProgram); + + NullifyResource (theGlContext, mySceneNodeInfoTexture); + NullifyResource (theGlContext, mySceneMinPointTexture); + NullifyResource (theGlContext, mySceneMaxPointTexture); + + NullifyResource (theGlContext, myGeometryVertexTexture); + NullifyResource (theGlContext, myGeometryNormalTexture); + NullifyResource (theGlContext, myGeometryTexCrdTexture); + NullifyResource (theGlContext, myGeometryTriangTexture); + NullifyResource (theGlContext, mySceneTransformTexture); + + NullifyResource (theGlContext, myRaytraceLightSrcTexture); + NullifyResource (theGlContext, myRaytraceMaterialTexture); + + if (myRaytraceScreenQuad.IsValid()) + myRaytraceScreenQuad.Release (theGlContext.operator->()); +} + +// ======================================================================= +// function : ResizeRaytraceBuffers +// purpose : Resizes OpenGL frame buffers +// ======================================================================= +Standard_Boolean OpenGl_View::resizeRaytraceBuffers (const Standard_Integer theSizeX, + const Standard_Integer theSizeY, + const Handle(OpenGl_Context)& theGlContext) +{ + if (myRaytraceFBO1->GetVPSizeX() != theSizeX + || myRaytraceFBO1->GetVPSizeY() != theSizeY) + { + myRaytraceFBO1->Init (theGlContext, theSizeX, theSizeY); + myRaytraceFBO2->Init (theGlContext, theSizeX, theSizeY); + } + + return Standard_True; +} + +// ======================================================================= +// function : UpdateCamera +// purpose : Generates viewing rays for corners of screen quad +// ======================================================================= +void OpenGl_View::updateCamera (const OpenGl_Mat4& theOrientation, + const OpenGl_Mat4& theViewMapping, + OpenGl_Vec3* theOrigins, + OpenGl_Vec3* theDirects, + OpenGl_Mat4& theUnview) +{ + // compute inverse model-view-projection matrix + (theViewMapping * theOrientation).Inverted (theUnview); + + Standard_Integer aOriginIndex = 0; + Standard_Integer aDirectIndex = 0; + + for (Standard_Integer aY = -1; aY <= 1; aY += 2) + { + for (Standard_Integer aX = -1; aX <= 1; aX += 2) + { + OpenGl_Vec4 aOrigin (GLfloat(aX), + GLfloat(aY), + -1.0f, + 1.0f); + + aOrigin = theUnview * aOrigin; + + aOrigin.x() = aOrigin.x() / aOrigin.w(); + aOrigin.y() = aOrigin.y() / aOrigin.w(); + aOrigin.z() = aOrigin.z() / aOrigin.w(); + + OpenGl_Vec4 aDirect (GLfloat(aX), + GLfloat(aY), + 1.0f, + 1.0f); + + aDirect = theUnview * aDirect; + + aDirect.x() = aDirect.x() / aDirect.w(); + aDirect.y() = aDirect.y() / aDirect.w(); + aDirect.z() = aDirect.z() / aDirect.w(); + + aDirect = aDirect - aOrigin; + + GLdouble aInvLen = 1.0 / sqrt (aDirect.x() * aDirect.x() + + aDirect.y() * aDirect.y() + + aDirect.z() * aDirect.z()); + + theOrigins[aOriginIndex++] = OpenGl_Vec3 (static_cast (aOrigin.x()), + static_cast (aOrigin.y()), + static_cast (aOrigin.z())); + + theDirects[aDirectIndex++] = OpenGl_Vec3 (static_cast (aDirect.x() * aInvLen), + static_cast (aDirect.y() * aInvLen), + static_cast (aDirect.z() * aInvLen)); + } + } +} + +// ======================================================================= +// function : UploadRaytraceData +// purpose : Uploads ray-trace data to the GPU +// ======================================================================= +Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)& theGlContext) +{ + if (!theGlContext->IsGlGreaterEqual (3, 1)) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: OpenGL version is less than 3.1" << std::endl; +#endif + return Standard_False; + } + + ///////////////////////////////////////////////////////////////////////////// + // Prepare OpenGL textures + + if (theGlContext->arbTexBindless != NULL) + { + // If OpenGL driver supports bindless textures we need + // to get unique 64- bit handles for using on the GPU + if (!myRaytraceGeometry.UpdateTextureHandles (theGlContext)) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to get OpenGL texture handles" << std::endl; +#endif + return Standard_False; + } + } + + ///////////////////////////////////////////////////////////////////////////// + // Create OpenGL BVH buffers + + if (mySceneNodeInfoTexture.IsNull()) // create scene BVH buffers + { + mySceneNodeInfoTexture = new OpenGl_TextureBufferArb; + mySceneMinPointTexture = new OpenGl_TextureBufferArb; + mySceneMaxPointTexture = new OpenGl_TextureBufferArb; + mySceneTransformTexture = new OpenGl_TextureBufferArb; + + if (!mySceneNodeInfoTexture->Create (theGlContext) + || !mySceneMinPointTexture->Create (theGlContext) + || !mySceneMaxPointTexture->Create (theGlContext) + || !mySceneTransformTexture->Create (theGlContext)) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to create scene BVH buffers" << std::endl; +#endif + return Standard_False; + } + } + + if (myGeometryVertexTexture.IsNull()) // create geometry buffers + { + myGeometryVertexTexture = new OpenGl_TextureBufferArb; + myGeometryNormalTexture = new OpenGl_TextureBufferArb; + myGeometryTexCrdTexture = new OpenGl_TextureBufferArb; + myGeometryTriangTexture = new OpenGl_TextureBufferArb; + + if (!myGeometryVertexTexture->Create (theGlContext) + || !myGeometryNormalTexture->Create (theGlContext) + || !myGeometryTexCrdTexture->Create (theGlContext) + || !myGeometryTriangTexture->Create (theGlContext)) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to create buffers for triangulation data" << std::endl; +#endif + return Standard_False; + } + } + + if (myRaytraceMaterialTexture.IsNull()) // create material buffer + { + myRaytraceMaterialTexture = new OpenGl_TextureBufferArb; + + if (!myRaytraceMaterialTexture->Create (theGlContext)) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to create buffers for material data" << std::endl; +#endif + return Standard_False; + } + } + + ///////////////////////////////////////////////////////////////////////////// + // Write transform buffer + + BVH_Mat4f* aNodeTransforms = new BVH_Mat4f[myRaytraceGeometry.Size()]; + + bool aResult = true; + + for (Standard_Integer anElemIndex = 0; anElemIndex < myRaytraceGeometry.Size(); ++anElemIndex) + { + OpenGl_TriangleSet* aTriangleSet = dynamic_cast ( + myRaytraceGeometry.Objects().ChangeValue (anElemIndex).operator->()); + + const BVH_Transform* aTransform = + dynamic_cast* > (aTriangleSet->Properties().operator->()); + + Standard_ASSERT_RETURN (aTransform != NULL, + "OpenGl_TriangleSet does not contain transform", Standard_False); + + aNodeTransforms[anElemIndex] = aTransform->Inversed(); + } + + aResult &= mySceneTransformTexture->Init (theGlContext, 4, + myRaytraceGeometry.Size() * 4, reinterpret_cast (aNodeTransforms)); + + delete [] aNodeTransforms; + + ///////////////////////////////////////////////////////////////////////////// + // Write geometry and bottom-level BVH buffers + + Standard_Size aTotalVerticesNb = 0; + Standard_Size aTotalElementsNb = 0; + Standard_Size aTotalBVHNodesNb = 0; + + for (Standard_Integer anElemIndex = 0; anElemIndex < myRaytraceGeometry.Size(); ++anElemIndex) + { + OpenGl_TriangleSet* aTriangleSet = dynamic_cast ( + myRaytraceGeometry.Objects().ChangeValue (anElemIndex).operator->()); + + Standard_ASSERT_RETURN (aTriangleSet != NULL, + "Error: Failed to get triangulation of OpenGL element", Standard_False); + + aTotalVerticesNb += aTriangleSet->Vertices.size(); + aTotalElementsNb += aTriangleSet->Elements.size(); + + Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(), + "Error: Failed to get bottom-level BVH of OpenGL element", Standard_False); + + aTotalBVHNodesNb += aTriangleSet->BVH()->NodeInfoBuffer().size(); + } + + aTotalBVHNodesNb += myRaytraceGeometry.BVH()->NodeInfoBuffer().size(); + + if (aTotalBVHNodesNb != 0) + { + aResult &= mySceneNodeInfoTexture->Init ( + theGlContext, 4, GLsizei (aTotalBVHNodesNb), static_cast (NULL)); + aResult &= mySceneMinPointTexture->Init ( + theGlContext, 3, GLsizei (aTotalBVHNodesNb), static_cast (NULL)); + aResult &= mySceneMaxPointTexture->Init ( + theGlContext, 3, GLsizei (aTotalBVHNodesNb), static_cast (NULL)); + } + + if (!aResult) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to upload buffers for bottom-level scene BVH" << std::endl; +#endif + return Standard_False; + } + + if (aTotalElementsNb != 0) + { + aResult &= myGeometryTriangTexture->Init ( + theGlContext, 4, GLsizei (aTotalElementsNb), static_cast (NULL)); + } + + if (aTotalVerticesNb != 0) + { + aResult &= myGeometryVertexTexture->Init ( + theGlContext, 3, GLsizei (aTotalVerticesNb), static_cast (NULL)); + aResult &= myGeometryNormalTexture->Init ( + theGlContext, 3, GLsizei (aTotalVerticesNb), static_cast (NULL)); + aResult &= myGeometryTexCrdTexture->Init ( + theGlContext, 2, GLsizei (aTotalVerticesNb), static_cast (NULL)); + } + + if (!aResult) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to upload buffers for scene geometry" << std::endl; +#endif + return Standard_False; + } + + const NCollection_Handle >& aBVH = myRaytraceGeometry.BVH(); + + if (aBVH->Length() > 0) + { + aResult &= mySceneNodeInfoTexture->SubData (theGlContext, 0, aBVH->Length(), + reinterpret_cast (&aBVH->NodeInfoBuffer().front())); + aResult &= mySceneMinPointTexture->SubData (theGlContext, 0, aBVH->Length(), + reinterpret_cast (&aBVH->MinPointBuffer().front())); + aResult &= mySceneMaxPointTexture->SubData (theGlContext, 0, aBVH->Length(), + reinterpret_cast (&aBVH->MaxPointBuffer().front())); + } + + for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx) + { + if (!aBVH->IsOuter (aNodeIdx)) + continue; + + OpenGl_TriangleSet* aTriangleSet = myRaytraceGeometry.TriangleSet (aNodeIdx); + + Standard_ASSERT_RETURN (aTriangleSet != NULL, + "Error: Failed to get triangulation of OpenGL element", Standard_False); + + Standard_Integer aBVHOffset = myRaytraceGeometry.AccelerationOffset (aNodeIdx); + + Standard_ASSERT_RETURN (aBVHOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET, + "Error: Failed to get offset for bottom-level BVH", Standard_False); + + const Standard_Integer aBvhBuffersSize = aTriangleSet->BVH()->Length(); + + if (aBvhBuffersSize != 0) + { + aResult &= mySceneNodeInfoTexture->SubData (theGlContext, aBVHOffset, aBvhBuffersSize, + reinterpret_cast (&aTriangleSet->BVH()->NodeInfoBuffer().front())); + aResult &= mySceneMinPointTexture->SubData (theGlContext, aBVHOffset, aBvhBuffersSize, + reinterpret_cast (&aTriangleSet->BVH()->MinPointBuffer().front())); + aResult &= mySceneMaxPointTexture->SubData (theGlContext, aBVHOffset, aBvhBuffersSize, + reinterpret_cast (&aTriangleSet->BVH()->MaxPointBuffer().front())); + + if (!aResult) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to upload buffers for bottom-level scene BVHs" << std::endl; +#endif + return Standard_False; + } + } + + const Standard_Integer aVerticesOffset = myRaytraceGeometry.VerticesOffset (aNodeIdx); + + Standard_ASSERT_RETURN (aVerticesOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET, + "Error: Failed to get offset for triangulation vertices of OpenGL element", Standard_False); + + if (!aTriangleSet->Vertices.empty()) + { + aResult &= myGeometryNormalTexture->SubData (theGlContext, aVerticesOffset, + GLsizei (aTriangleSet->Normals.size()), reinterpret_cast (&aTriangleSet->Normals.front())); + aResult &= myGeometryTexCrdTexture->SubData (theGlContext, aVerticesOffset, + GLsizei (aTriangleSet->TexCrds.size()), reinterpret_cast (&aTriangleSet->TexCrds.front())); + aResult &= myGeometryVertexTexture->SubData (theGlContext, aVerticesOffset, + GLsizei (aTriangleSet->Vertices.size()), reinterpret_cast (&aTriangleSet->Vertices.front())); + } + + const Standard_Integer anElementsOffset = myRaytraceGeometry.ElementsOffset (aNodeIdx); + + Standard_ASSERT_RETURN (anElementsOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET, + "Error: Failed to get offset for triangulation elements of OpenGL element", Standard_False); + + if (!aTriangleSet->Elements.empty()) + { + aResult &= myGeometryTriangTexture->SubData (theGlContext, anElementsOffset, GLsizei (aTriangleSet->Elements.size()), + reinterpret_cast (&aTriangleSet->Elements.front())); + } + + if (!aResult) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to upload triangulation buffers for OpenGL element" << std::endl; +#endif + return Standard_False; + } + } + + ///////////////////////////////////////////////////////////////////////////// + // Write material buffer + + if (myRaytraceGeometry.Materials.size() != 0) + { + aResult &= myRaytraceMaterialTexture->Init (theGlContext, 4, + GLsizei (myRaytraceGeometry.Materials.size() * 11), myRaytraceGeometry.Materials.front().Packed()); + + if (!aResult) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to upload material buffer" << std::endl; +#endif + return Standard_False; + } + } + + myIsRaytraceDataValid = myRaytraceGeometry.Objects().Size() != 0; + +#ifdef RAY_TRACE_PRINT_INFO + + Standard_ShortReal aMemUsed = 0.f; + + for (Standard_Integer anElemIdx = 0; anElemIdx < myRaytraceGeometry.Size(); ++anElemIdx) + { + OpenGl_TriangleSet* aTriangleSet = dynamic_cast ( + myRaytraceGeometry.Objects().ChangeValue (anElemIdx).operator->()); + + aMemUsed += static_cast ( + aTriangleSet->Vertices.size() * sizeof (BVH_Vec3f)); + aMemUsed += static_cast ( + aTriangleSet->Normals.size() * sizeof (BVH_Vec3f)); + aMemUsed += static_cast ( + aTriangleSet->TexCrds.size() * sizeof (BVH_Vec2f)); + aMemUsed += static_cast ( + aTriangleSet->Elements.size() * sizeof (BVH_Vec4i)); + + aMemUsed += static_cast ( + aTriangleSet->BVH()->NodeInfoBuffer().size() * sizeof (BVH_Vec4i)); + aMemUsed += static_cast ( + aTriangleSet->BVH()->MinPointBuffer().size() * sizeof (BVH_Vec3f)); + aMemUsed += static_cast ( + aTriangleSet->BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec3f)); + } + + aMemUsed += static_cast ( + myRaytraceGeometry.BVH()->NodeInfoBuffer().size() * sizeof (BVH_Vec4i)); + aMemUsed += static_cast ( + myRaytraceGeometry.BVH()->MinPointBuffer().size() * sizeof (BVH_Vec3f)); + aMemUsed += static_cast ( + myRaytraceGeometry.BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec3f)); + + std::cout << "GPU Memory Used (MB): ~" << aMemUsed / 1048576 << std::endl; + +#endif + + return aResult; +} + +// ======================================================================= +// function : UpdateRaytraceLightSources +// purpose : Updates 3D scene light sources for ray-tracing +// ======================================================================= +Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& theInvModelView, const Handle(OpenGl_Context)& theGlContext) +{ + myRaytraceGeometry.Sources.clear(); + + myRaytraceGeometry.Ambient = BVH_Vec4f (0.0f, 0.0f, 0.0f, 0.0f); + + for (OpenGl_ListOfLight::Iterator anItl (LightList()); anItl.More(); anItl.Next()) + { + const OpenGl_Light& aLight = anItl.Value(); + + if (aLight.Type == Visual3d_TOLS_AMBIENT) + { + myRaytraceGeometry.Ambient += BVH_Vec4f (aLight.Color.r(), + aLight.Color.g(), + aLight.Color.b(), + 0.0f); + continue; + } + + BVH_Vec4f aDiffuse (aLight.Color.r(), + aLight.Color.g(), + aLight.Color.b(), + 1.0f); + + BVH_Vec4f aPosition (-aLight.Direction.x(), + -aLight.Direction.y(), + -aLight.Direction.z(), + 0.0f); + + if (aLight.Type != Visual3d_TOLS_DIRECTIONAL) + { + aPosition = BVH_Vec4f (aLight.Position.x(), + aLight.Position.y(), + aLight.Position.z(), + 1.0f); + } + + if (aLight.IsHeadlight) + { + aPosition = theInvModelView * aPosition; + } + + myRaytraceGeometry.Sources.push_back (OpenGl_RaytraceLight (aDiffuse, aPosition)); + } + + if (myRaytraceLightSrcTexture.IsNull()) // create light source buffer + { + myRaytraceLightSrcTexture = new OpenGl_TextureBufferArb; + + if (!myRaytraceLightSrcTexture->Create (theGlContext)) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to create light source buffer" << std::endl; +#endif + return Standard_False; + } + } + + if (myRaytraceGeometry.Sources.size() != 0) + { + const GLfloat* aDataPtr = myRaytraceGeometry.Sources.front().Packed(); + if (!myRaytraceLightSrcTexture->Init (theGlContext, 4, GLsizei (myRaytraceGeometry.Sources.size() * 2), aDataPtr)) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Error: Failed to upload light source buffer" << std::endl; +#endif + return Standard_False; + } + } + + return Standard_True; +} + +// ======================================================================= +// function : UpdateRaytraceEnvironmentMap +// purpose : Updates environment map for ray-tracing +// ======================================================================= +Standard_Boolean OpenGl_View::updateRaytraceEnvironmentMap (const Handle(OpenGl_Context)& theGlContext) +{ + Standard_Boolean aResult = Standard_True; + + if (!myToUpdateEnvironmentMap) + { + return aResult; + } + + for (Standard_Integer anIdx = 0; anIdx < 2; ++anIdx) + { + const Handle(OpenGl_ShaderProgram)& aProgram = + anIdx == 0 ? myRaytraceProgram : myPostFSAAProgram; + + if (!aProgram.IsNull()) + { + aResult &= theGlContext->BindProgram (aProgram); + + if (!myTextureEnv.IsNull() && mySurfaceDetail != Visual3d_TOD_NONE) + { + myTextureEnv->Bind (theGlContext, + GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture); + + aResult &= aProgram->SetUniform (theGlContext, + myUniformLocations[anIdx][OpenGl_RT_uEnvMapEnable], 1); + } + else + { + aResult &= aProgram->SetUniform (theGlContext, + myUniformLocations[anIdx][OpenGl_RT_uEnvMapEnable], 0); + } + } + } + + myToUpdateEnvironmentMap = Standard_False; + + theGlContext->BindProgram (NULL); + + return aResult; +} + +// ======================================================================= +// function : SetUniformState +// purpose : Sets uniform state for the given ray-tracing shader program +// ======================================================================= +Standard_Boolean OpenGl_View::setUniformState (const Graphic3d_CView& theCView, + const OpenGl_Vec3* theOrigins, + const OpenGl_Vec3* theDirects, + const OpenGl_Mat4& theUnviewMat, + const Standard_Integer theProgramId, + const Handle(OpenGl_Context)& theGlContext) +{ + Handle(OpenGl_ShaderProgram)& theProgram = + theProgramId == 0 ? myRaytraceProgram : myPostFSAAProgram; + + if (theProgram.IsNull()) + { + return Standard_False; + } + + Standard_Boolean aResult = Standard_True; + + const Standard_Integer aLightSourceBufferSize = + static_cast (myRaytraceGeometry.Sources.size()); + + // Set camera state + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uOriginLB], theOrigins[0]); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uOriginRB], theOrigins[1]); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uOriginLT], theOrigins[2]); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uOriginRT], theOrigins[3]); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uDirectLB], theDirects[0]); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uDirectRB], theDirects[1]); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uDirectLT], theDirects[2]); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uDirectRT], theDirects[3]); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uUnviewMat], theUnviewMat); + + // Set scene parameters + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uSceneRad], myRaytraceSceneRadius); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uSceneEps], myRaytraceSceneEpsilon); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uLightCount], aLightSourceBufferSize); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uLightAmbnt], myRaytraceGeometry.Ambient); + + // Set run-time rendering options + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uShadEnabled], theCView.RenderParams.IsShadowEnabled ? 1 : 0); + aResult &= theProgram->SetUniform (theGlContext, + myUniformLocations[theProgramId][OpenGl_RT_uReflEnabled], theCView.RenderParams.IsReflectionEnabled ? 1 : 0); + + // Set array of 64-bit texture handles + if (theGlContext->arbTexBindless != NULL && myRaytraceGeometry.HasTextures()) + { + aResult &= theProgram->SetUniform (theGlContext, "uTextureSamplers", static_cast ( + myRaytraceGeometry.TextureHandles().size()), &myRaytraceGeometry.TextureHandles()[0]); + } + + if (!aResult) + { +#ifdef RAY_TRACE_PRINT_INFO + std::cout << "Info: Not all uniforms were detected for program " << theProgramId << std::endl; +#endif + } + + return aResult; +} + +// ======================================================================= +// function : BindRaytraceTextures +// purpose : Binds ray-trace textures to corresponding texture units +// ======================================================================= +void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext) +{ + mySceneMinPointTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMinPointTexture); + mySceneMaxPointTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMaxPointTexture); + mySceneNodeInfoTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneNodeInfoTexture); + myGeometryVertexTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryVertexTexture); + myGeometryNormalTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryNormalTexture); + myGeometryTexCrdTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTexCrdTexture); + myGeometryTriangTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture); + mySceneTransformTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture); + myRaytraceMaterialTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture); + myRaytraceLightSrcTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture); + + if (!myOpenGlFBO.IsNull()) + { + myOpenGlFBO->ColorTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlColorTexture); + myOpenGlFBO->DepthStencilTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlDepthTexture); + } +} + +// ======================================================================= +// function : UnbindRaytraceTextures +// purpose : Unbinds ray-trace textures from corresponding texture units +// ======================================================================= +void OpenGl_View::unbindRaytraceTextures (const Handle(OpenGl_Context)& theGlContext) +{ + mySceneMinPointTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMinPointTexture); + mySceneMaxPointTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMaxPointTexture); + mySceneNodeInfoTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneNodeInfoTexture); + myGeometryVertexTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryVertexTexture); + myGeometryNormalTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryNormalTexture); + myGeometryTexCrdTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTexCrdTexture); + myGeometryTriangTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture); + mySceneTransformTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture); + myRaytraceMaterialTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture); + myRaytraceLightSrcTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture); + + if (!myOpenGlFBO.IsNull()) + { + myOpenGlFBO->ColorTexture()->Unbind (theGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlColorTexture); + myOpenGlFBO->DepthStencilTexture()->Unbind (theGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlDepthTexture); + } + + theGlContext->core15fwd->glActiveTexture (GL_TEXTURE0); +} + +// ======================================================================= +// function : RunRaytraceShaders +// purpose : Runs ray-tracing shader programs +// ======================================================================= +Standard_Boolean OpenGl_View::runRaytraceShaders (const Graphic3d_CView& theCView, + const Standard_Integer theSizeX, + const Standard_Integer theSizeY, + const OpenGl_Vec3* theOrigins, + const OpenGl_Vec3* theDirects, + const OpenGl_Mat4& theUnviewMat, + OpenGl_FrameBuffer* theOutputFBO, + const Handle(OpenGl_Context)& theGlContext) +{ + bindRaytraceTextures (theGlContext); + + if (theCView.RenderParams.IsAntialiasingEnabled) // render source image to FBO + { + myRaytraceFBO1->BindBuffer (theGlContext); + + glDisable (GL_BLEND); + } + + Standard_Boolean aResult = theGlContext->BindProgram (myRaytraceProgram); + + aResult &= setUniformState (theCView, + theOrigins, + theDirects, + theUnviewMat, + 0, // ID of RT program + theGlContext); + + myRaytraceScreenQuad.BindVertexAttrib (theGlContext, Graphic3d_TOA_POS); + { + if (aResult) + theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6); + } + myRaytraceScreenQuad.UnbindVertexAttrib (theGlContext, Graphic3d_TOA_POS); + + if (!theCView.RenderParams.IsAntialiasingEnabled || !aResult) + { + unbindRaytraceTextures (theGlContext); + + theGlContext->BindProgram (NULL); + + return aResult; + } + + myRaytraceFBO1->ColorTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_FSAAInputTexture); + + aResult &= theGlContext->BindProgram (myPostFSAAProgram); + + aResult &= setUniformState (theCView, + theOrigins, + theDirects, + theUnviewMat, + 1, // ID of FSAA program + theGlContext); + + myRaytraceScreenQuad.BindVertexAttrib (theGlContext, Graphic3d_TOA_POS); + { + // Perform multi-pass adaptive FSAA using ping-pong technique. + // We use 'FLIPTRI' sampling pattern changing for every pixel + // (3 additional samples per pixel, the 1st sample is already + // available from initial ray-traced image). + for (Standard_Integer anIt = 1; anIt < 4; ++anIt) + { + GLfloat aOffsetX = 1.f / theSizeX; + GLfloat aOffsetY = 1.f / theSizeY; + + if (anIt == 1) + { + aOffsetX *= -0.55f; + aOffsetY *= 0.55f; + } + else if (anIt == 2) + { + aOffsetX *= 0.00f; + aOffsetY *= -0.55f; + } + else if (anIt == 3) + { + aOffsetX *= 0.55f; + aOffsetY *= 0.00f; + } + + aResult &= myPostFSAAProgram->SetUniform (theGlContext, + myUniformLocations[1][OpenGl_RT_uSamples], anIt + 1); + aResult &= myPostFSAAProgram->SetUniform (theGlContext, + myUniformLocations[1][OpenGl_RT_uOffsetX], aOffsetX); + aResult &= myPostFSAAProgram->SetUniform (theGlContext, + myUniformLocations[1][OpenGl_RT_uOffsetY], aOffsetY); + + Handle(OpenGl_FrameBuffer)& aFramebuffer = anIt % 2 ? myRaytraceFBO2 : myRaytraceFBO1; + + if (anIt == 3) // disable FBO on last iteration + { + glEnable (GL_BLEND); + + if (theOutputFBO != NULL) + theOutputFBO->BindBuffer (theGlContext); + } + else + { + aFramebuffer->BindBuffer (theGlContext); + } + + theGlContext->core20fwd->glDrawArrays (GL_TRIANGLES, 0, 6); + + if (anIt != 3) // set input for the next pass + { + aFramebuffer->ColorTexture()->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_FSAAInputTexture); + } + } + } + myRaytraceScreenQuad.UnbindVertexAttrib (theGlContext, Graphic3d_TOA_POS); + + unbindRaytraceTextures (theGlContext); + + theGlContext->BindProgram (NULL); + + return aResult; +} + +// ======================================================================= +// function : Raytrace +// purpose : Redraws the window using OpenGL/GLSL ray-tracing +// ======================================================================= +Standard_Boolean OpenGl_View::raytrace (const Graphic3d_CView& theCView, + const Standard_Integer theSizeX, + const Standard_Integer theSizeY, + OpenGl_FrameBuffer* theOutputFBO, + const Handle(OpenGl_Context)& theGlContext) +{ + if (!initRaytraceResources (theCView, theGlContext)) + { + return Standard_False; + } + + if (!resizeRaytraceBuffers (theSizeX, theSizeY, theGlContext)) + { + return Standard_False; + } + + if (!updateRaytraceEnvironmentMap (theGlContext)) + { + return Standard_False; + } + + // Get model-view and projection matrices + OpenGl_Mat4 aOrientationMatrix; + OpenGl_Mat4 aViewMappingMatrix; + OpenGl_Mat4 aInverOrientMatrix; + + GetMatrices (aOrientationMatrix, + aViewMappingMatrix); + + aOrientationMatrix.Inverted (aInverOrientMatrix); + + if (!updateRaytraceLightSources (aInverOrientMatrix, theGlContext)) + { + return Standard_False; + } + + OpenGl_Vec3 aOrigins[4]; + OpenGl_Vec3 aDirects[4]; + OpenGl_Mat4 anUnviewMat; + + updateCamera (aOrientationMatrix, + aViewMappingMatrix, + aOrigins, + aDirects, + anUnviewMat); + + glEnable (GL_BLEND); + glDisable (GL_DEPTH_TEST); + glBlendFunc (GL_ONE, GL_SRC_ALPHA); + + if (theOutputFBO != NULL) + { + theOutputFBO->BindBuffer (theGlContext); + } + + // Generate ray-traced image + if (myIsRaytraceDataValid) + { + myRaytraceScreenQuad.Bind (theGlContext); + + if (!myRaytraceGeometry.AcquireTextures (theGlContext)) + { + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_ERROR_ARB, + 0, GL_DEBUG_SEVERITY_MEDIUM_ARB, "Error: Failed to acquire OpenGL image textures"); + } + + Standard_Boolean aResult = runRaytraceShaders (theCView, + theSizeX, + theSizeY, + aOrigins, + aDirects, + anUnviewMat, + theOutputFBO, + theGlContext); + + if (!aResult) + { + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_ERROR_ARB, + 0, GL_DEBUG_SEVERITY_MEDIUM_ARB, "Error: Failed to execute ray-tracing shaders"); + } + + if (!myRaytraceGeometry.ReleaseTextures (theGlContext)) + { + theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_ERROR_ARB, + 0, GL_DEBUG_SEVERITY_MEDIUM_ARB, "Error: Failed to release OpenGL image textures"); + } + + myRaytraceScreenQuad.Unbind (theGlContext); + } + + glDisable (GL_BLEND); + glEnable (GL_DEPTH_TEST); + + return Standard_True; +} \ No newline at end of file diff --git a/src/OpenGl/OpenGl_Workspace.cxx b/src/OpenGl/OpenGl_Workspace.cxx index e6088476d4..606d30846b 100644 --- a/src/OpenGl/OpenGl_Workspace.cxx +++ b/src/OpenGl/OpenGl_Workspace.cxx @@ -146,15 +146,8 @@ OpenGl_Workspace::OpenGl_Workspace (const Handle(OpenGl_GraphicDriver)& theDrive NamedStatus (0), HighlightColor (&THE_WHITE_COLOR), // - myComputeInitStatus (OpenGl_RT_NONE), - myIsRaytraceDataValid (Standard_False), - myIsRaytraceWarnTextures (Standard_False), myHasFboBlit (Standard_True), - myViewModificationStatus (0), - myLayersModificationStatus (0), // - myRaytraceFilter (new OpenGl_RaytraceFilter()), - myToRedrawGL (Standard_True), myViewId (-1), myAntiAliasingMode (3), myTransientDrawToFront (Standard_True), @@ -252,8 +245,6 @@ OpenGl_Workspace::~OpenGl_Workspace() { myFullScreenQuad.Release (myGlContext.operator->()); } - - ReleaseRaytraceResources(); } // ======================================================================= @@ -727,77 +718,25 @@ void OpenGl_Workspace::Redraw (const Graphic3d_CView& theCView, else { myResultFBO->Release (myGlContext.operator->()); + myResultFBO->ChangeViewport (0, 0); } - myToRedrawGL = Standard_True; - if (theCView.RenderParams.Method == Graphic3d_RM_RAYTRACING - && myComputeInitStatus != OpenGl_RT_FAIL) + // draw entire frame using normal OpenGL pipeline + if (myResultFBO->IsValid()) { - if (InitRaytraceResources (theCView) && UpdateRaytraceGeometry (OpenGl_GUM_CHECK) && myIsRaytraceDataValid) - { - myToRedrawGL = Standard_False; - - // Only non-raytracable structures should be rendered in OpenGL mode. - Handle(OpenGl_RenderFilter) aRenderFilter = GetRenderFilter(); - myRaytraceFilter->SetPrevRenderFilter (aRenderFilter); - SetRenderFilter (myRaytraceFilter); - - if (myOpenGlFBO.IsNull()) - { - myOpenGlFBO = new OpenGl_FrameBuffer(); - } - if (myOpenGlFBO->GetVPSizeX() != aSizeX - || myOpenGlFBO->GetVPSizeY() != aSizeY) - { - myOpenGlFBO->Init (myGlContext, aSizeX, aSizeY); - } - - // OverLayer and UnderLayer shouldn't be drawn by OpenGL. - // They will be drawn during ray-tracing. - Aspect_CLayer2d anEmptyCLayer; - anEmptyCLayer.ptrLayer = NULL; - - myOpenGlFBO->BindBuffer (myGlContext); - redraw1 (theCView, anEmptyCLayer, anEmptyCLayer); - myOpenGlFBO->UnbindBuffer (myGlContext); - - Raytrace (theCView, aSizeX, aSizeY, - theCOverLayer, theCUnderLayer, - myResultFBO->IsValid() ? myResultFBO.operator->() : aFrameBuffer); - myBackBufferRestored = Standard_True; - myIsImmediateDrawn = Standard_False; - if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aFrameBuffer)) - { - toSwap = false; - } - - SetRenderFilter (aRenderFilter); - - theCView.WasRedrawnGL = Standard_False; - } + myResultFBO->BindBuffer (myGlContext); } - - if (myToRedrawGL) + else if (aFrameBuffer != NULL) { - // draw entire frame using normal OpenGL pipeline - if (myResultFBO->IsValid()) - { - myResultFBO->BindBuffer (myGlContext); - } - else if (aFrameBuffer != NULL) - { - aFrameBuffer->BindBuffer (myGlContext); - } - - redraw1 (theCView, theCUnderLayer, theCOverLayer); - myBackBufferRestored = Standard_True; - myIsImmediateDrawn = Standard_False; - if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aFrameBuffer)) - { - toSwap = false; - } + aFrameBuffer->BindBuffer (myGlContext); + } - theCView.WasRedrawnGL = Standard_True; + redraw1 (theCView, theCUnderLayer, theCOverLayer); + myBackBufferRestored = Standard_True; + myIsImmediateDrawn = Standard_False; + if (!redrawImmediate (theCView, theCOverLayer, theCUnderLayer, aFrameBuffer)) + { + toSwap = false; } if (aFrameBuffer != NULL) @@ -885,25 +824,17 @@ void OpenGl_Workspace::redraw1 (const Graphic3d_CView& theCView, glDisable (GL_DEPTH_TEST); } - if (!ToRedrawGL()) + if (NamedStatus & OPENGL_NS_WHITEBACK) { - // set background to black - glClearColor (0.0f, 0.0f, 0.0f, 0.0f); - toClear |= GL_DEPTH_BUFFER_BIT; // + // set background to white + glClearColor (1.0f, 1.0f, 1.0f, 1.0f); + toClear |= GL_DEPTH_BUFFER_BIT; } else { - if (NamedStatus & OPENGL_NS_WHITEBACK) - { - // set background to white - glClearColor (1.0f, 1.0f, 1.0f, 1.0f); - toClear |= GL_DEPTH_BUFFER_BIT; - } - else - { - glClearColor (myBgColor.rgb[0], myBgColor.rgb[1], myBgColor.rgb[2], 0.0f); - } + glClearColor (myBgColor.rgb[0], myBgColor.rgb[1], myBgColor.rgb[2], 0.0f); } + glClear (toClear); Handle(OpenGl_Workspace) aWS (this); @@ -1211,3 +1142,21 @@ bool OpenGl_Workspace::redrawImmediate (const Graphic3d_CView& theCView, } return true; } + +IMPLEMENT_STANDARD_HANDLE (OpenGl_RaytraceFilter, OpenGl_RenderFilter) +IMPLEMENT_STANDARD_RTTIEXT(OpenGl_RaytraceFilter, OpenGl_RenderFilter) + +// ======================================================================= +// function : CanRender +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_RaytraceFilter::CanRender (const OpenGl_Element* theElement) +{ + Standard_Boolean aPrevFilterResult = Standard_True; + if (!myPrevRenderFilter.IsNull()) + { + aPrevFilterResult = myPrevRenderFilter->CanRender (theElement); + } + return aPrevFilterResult && + !OpenGl_Raytrace::IsRaytracedElement (theElement); +} diff --git a/src/OpenGl/OpenGl_Workspace.hxx b/src/OpenGl/OpenGl_Workspace.hxx index 5f74ef3971..2b1ba4541d 100644 --- a/src/OpenGl/OpenGl_Workspace.hxx +++ b/src/OpenGl/OpenGl_Workspace.hxx @@ -104,8 +104,14 @@ public: //! Default constructor. OpenGl_RaytraceFilter() {} + //! Returns the previously set filter. + const Handle(OpenGl_RenderFilter)& PrevRenderFilter() + { + return myPrevRenderFilter; + } + //! Remembers the previously set filter. - inline void SetPrevRenderFilter (const Handle(OpenGl_RenderFilter)& theFilter) + void SetPrevRenderFilter (const Handle(OpenGl_RenderFilter)& theFilter) { myPrevRenderFilter = theFilter; } @@ -259,8 +265,8 @@ public: //! @return true if clipping algorithm enabled inline Standard_Boolean IsCullingEnabled() const { return myIsCullingEnabled; } - //! Returns a flag whether to redraw the scene using OpenGL rasterization - Standard_Boolean ToRedrawGL() const { return myToRedrawGL; } + //! Returns framebuffer storing cached main presentation of the view. + const Handle(OpenGl_FrameBuffer)& ResultFBO() const { return myResultFBO; } protected: @@ -292,358 +298,7 @@ protected: void setTextureParams (Handle(OpenGl_Texture)& theTexture, const Handle(Graphic3d_TextureParams)& theParams); -protected: - - //! Result of OpenGL shaders initialization. - enum RaytraceInitStatus - { - OpenGl_RT_NONE, - OpenGl_RT_INIT, - OpenGl_RT_FAIL - }; - - //! Describes update mode (state). - enum GeomUpdateMode - { - OpenGl_GUM_CHECK, //!< check if geometry update is necessary - OpenGl_GUM_PREPARE, //!< collect unchanged objects - OpenGl_GUM_UPDATE //!< update raytracing data, rebuild changed objects - }; - - //! Defines frequently used shader variables. - enum ShaderVariableIndex - { - OpenGl_RT_aPosition, - - OpenGl_RT_uOriginLT, - OpenGl_RT_uOriginLB, - OpenGl_RT_uOriginRT, - OpenGl_RT_uOriginRB, - OpenGl_RT_uDirectLT, - OpenGl_RT_uDirectLB, - OpenGl_RT_uDirectRT, - OpenGl_RT_uDirectRB, - OpenGl_RT_uUnviewMat, - - OpenGl_RT_uSceneRad, - OpenGl_RT_uSceneEps, - OpenGl_RT_uLightAmbnt, - OpenGl_RT_uLightCount, - - OpenGl_RT_uShadEnabled, - OpenGl_RT_uReflEnabled, - OpenGl_RT_uEnvMapEnable, - - OpenGl_RT_uOffsetX, - OpenGl_RT_uOffsetY, - OpenGl_RT_uSamples, - OpenGl_RT_uWinSizeX, - OpenGl_RT_uWinSizeY, - - OpenGl_RT_uTextures, - - OpenGl_RT_NbVariables // special field - }; - - //! Defines texture samplers. - enum ShaderSamplerNames - { - OpenGl_RT_SceneNodeInfoTexture = 0, - OpenGl_RT_SceneMinPointTexture = 1, - OpenGl_RT_SceneMaxPointTexture = 2, - OpenGl_RT_SceneTransformTexture = 3, - - OpenGl_RT_GeometryVertexTexture = 4, - OpenGl_RT_GeometryNormalTexture = 5, - OpenGl_RT_GeometryTexCrdTexture = 6, - OpenGl_RT_GeometryTriangTexture = 7, - - OpenGl_RT_EnvironmentMapTexture = 8, - - OpenGl_RT_RaytraceMaterialTexture = 9, - OpenGl_RT_RaytraceLightSrcTexture = 10, - - OpenGl_RT_FSAAInputTexture = 11, - - OpenGl_RT_OpenGlColorTexture = 12, - OpenGl_RT_OpenGlDepthTexture = 13 - }; - - //! Tool class for management of shader sources. - class ShaderSource - { - public: - - //! Creates new uninitialized shader source. - ShaderSource() - { - // - } - - //! Creates new shader source from specified file. - ShaderSource (const TCollection_AsciiString& theFileName) - { - Load (&theFileName, 1); - } - - public: - - //! Returns prefix to insert before the source. - const TCollection_AsciiString& Prefix() const - { - return myPrefix; - } - - //! Sets prefix to insert before the source. - void SetPrefix (const TCollection_AsciiString& thePrefix) - { - myPrefix = thePrefix; - } - - //! Returns shader source combined with prefix. - TCollection_AsciiString Source() const; - - //! Loads shader source from specified files. - void Load (const TCollection_AsciiString* theFileNames, const Standard_Integer theCount); - - private: - - TCollection_AsciiString mySource; //!< Source string of the shader object - TCollection_AsciiString myPrefix; //!< Prefix to insert before the source - - }; - - //! Default ray-tracing depth. - static const Standard_Integer THE_DEFAULT_NB_BOUNCES = 3; - - //! Default size of traversal stack. - static const Standard_Integer THE_DEFAULT_STACK_SIZE = 24; - - //! Compile-time ray-tracing parameters. - struct RaytracingParams - { - //! Actual size of traversal stack in shader program. - Standard_Integer StackSize; - - //! Actual ray-tracing depth (number of ray bounces). - Standard_Integer NbBounces; - - //! Sets light propagation through transparent media. - Standard_Boolean TransparentShadows; - - //! Creates default compile-time ray-tracing parameters. - RaytracingParams() - : StackSize (THE_DEFAULT_STACK_SIZE), - NbBounces (THE_DEFAULT_NB_BOUNCES), - TransparentShadows (Standard_False) - { - // - } - }; - -protected: //! @name methods related to ray-tracing - - //! Updates 3D scene geometry for ray-tracing. - Standard_Boolean UpdateRaytraceGeometry (GeomUpdateMode theMode); - - //! Checks to see if the structure is modified. - Standard_Boolean CheckRaytraceStructure (const OpenGl_Structure* theStructure); - - //! Creates ray-tracing material properties. - Standard_Boolean CreateMaterial (const OpenGl_AspectFace* theAspect, OpenGl_RaytraceMaterial& theMaterial); - - //! Updates 3D scene light sources for ray-tracing. - Standard_Boolean UpdateRaytraceLightSources (const OpenGl_Mat4& theInvModelView); - - //! Updates environment map for ray-tracing. - Standard_Boolean UpdateRaytraceEnvironmentMap(); - - //! Adds OpenGL structure to ray-traced scene geometry. - Standard_Boolean AddRaytraceStructure (const OpenGl_Structure* theStructure, std::set& theElements); - - //! Adds OpenGL groups to ray-traced scene geometry. - Standard_Boolean AddRaytraceGroups (const OpenGl_Structure* theStructure, - const Standard_Integer theStructMatId, - const Standard_ShortReal* theTransform); - - //! Adds OpenGL primitive array to ray-traced scene geometry. - OpenGl_TriangleSet* AddRaytracePrimitiveArray ( - const OpenGl_PrimitiveArray* theArray, int theMatID, const OpenGl_Mat4* theTrans); - - //! Adds vertex indices from OpenGL primitive array to ray-traced scene geometry. - Standard_Boolean AddRaytraceVertexIndices (OpenGl_TriangleSet& theSet, - const OpenGl_PrimitiveArray& theArray, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID); - - //! Adds OpenGL triangle array to ray-traced scene geometry. - Standard_Boolean AddRaytraceTriangleArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID); - - //! Adds OpenGL triangle fan array to ray-traced scene geometry. - Standard_Boolean AddRaytraceTriangleFanArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID); - - //! Adds OpenGL triangle strip array to ray-traced scene geometry. - Standard_Boolean AddRaytraceTriangleStripArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID); - - //! Adds OpenGL quadrangle array to ray-traced scene geometry. - Standard_Boolean AddRaytraceQuadrangleArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID); - - //! Adds OpenGL quadrangle strip array to ray-traced scene geometry. - Standard_Boolean AddRaytraceQuadrangleStripArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID); - - //! Adds OpenGL polygon array to ray-traced scene geometry. - Standard_Boolean AddRaytracePolygonArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID); - - //! Loads and compiles shader object from specified source. - Handle(OpenGl_ShaderObject) LoadShader (const ShaderSource& theSource, GLenum theType); - - //! Performs safe exit when shaders initialization fails. - Standard_Boolean SafeFailBack (const TCollection_ExtendedString& theMessage); - - //! Generates shader prefix based on current ray-tracing options. - TCollection_AsciiString GenerateShaderPrefix(); - - //! Initializes OpenGL/GLSL shader programs. - Standard_Boolean InitRaytraceResources (const Graphic3d_CView& theCView); - - //! Releases OpenGL/GLSL shader programs. - void ReleaseRaytraceResources(); - - //! Uploads ray-trace data to the GPU. - Standard_Boolean UploadRaytraceData(); - - //! Resizes OpenGL frame buffers. - Standard_Boolean ResizeRaytraceBuffers (const Standard_Integer theSizeX, - const Standard_Integer theSizeY); - - //! Generates viewing rays for corners of screen quad. - void UpdateCamera (const OpenGl_Mat4& theOrientation, - const OpenGl_Mat4& theViewMapping, - OpenGl_Vec3 theOrigins[4], - OpenGl_Vec3 theDirects[4], - OpenGl_Mat4& theInvModelProj); - - //! Sets uniform state for the given ray-tracing shader program. - Standard_Boolean SetUniformState (const Graphic3d_CView& theCView, - const Standard_Integer theSizeX, - const Standard_Integer theSizeY, - const OpenGl_Vec3* theOrigins, - const OpenGl_Vec3* theDirects, - const OpenGl_Mat4& theUnviewMat, - const Standard_Integer theProgramIndex, - Handle(OpenGl_ShaderProgram)& theRaytraceProgram); - - //! Runs ray-tracing shader programs. - Standard_Boolean RunRaytraceShaders (const Graphic3d_CView& theCView, - const Standard_Integer theSizeX, - const Standard_Integer theSizeY, - const OpenGl_Vec3 theOrigins[4], - const OpenGl_Vec3 theDirects[4], - const OpenGl_Mat4& theUnviewMat, - OpenGl_FrameBuffer* theFrameBuffer); - - //! Redraws the window using OpenGL/GLSL ray-tracing. - Standard_Boolean Raytrace (const Graphic3d_CView& theCView, - const Standard_Integer theSizeX, - const Standard_Integer theSizeY, - const Aspect_CLayer2d& theCOverLayer, - const Aspect_CLayer2d& theCUnderLayer, - OpenGl_FrameBuffer* theFrameBuffer); - -protected: //! @name fields related to ray-tracing - - //! Result of shaders initialization. - RaytraceInitStatus myComputeInitStatus; - - //! Is geometry data valid? - Standard_Boolean myIsRaytraceDataValid; - - //! Warning about missing extension GL_ARB_bindless_texture has been displayed? - Standard_Boolean myIsRaytraceWarnTextures; - - //! 3D scene geometry data for ray-tracing. - OpenGl_RaytraceGeometry myRaytraceGeometry; - - //! Radius of bounding sphere of the scene. - Standard_ShortReal myRaytraceSceneRadius; - //! Scene epsilon to prevent self-intersections. - Standard_ShortReal myRaytraceSceneEpsilon; - - //! Compile-time ray-tracing parameters. - RaytracingParams myRaytraceParameters; - - //! OpenGL/GLSL source of ray-tracing fragment shader. - ShaderSource myRaytraceShaderSource; - //! OpenGL/GLSL source of adaptive-AA fragment shader. - ShaderSource myPostFSAAShaderSource; - - //! OpenGL/GLSL ray-tracing fragment shader. - Handle(OpenGl_ShaderObject) myRaytraceShader; - //! OpenGL/GLSL adaptive-AA fragment shader. - Handle(OpenGl_ShaderObject) myPostFSAAShader; - - //! OpenGL/GLSL ray-tracing shader program. - Handle(OpenGl_ShaderProgram) myRaytraceProgram; - //! OpenGL/GLSL adaptive-AA shader program. - Handle(OpenGl_ShaderProgram) myPostFSAAProgram; - - //! Texture buffer of data records of bottom-level BVH nodes. - Handle(OpenGl_TextureBufferArb) mySceneNodeInfoTexture; - //! Texture buffer of minimum points of bottom-level BVH nodes. - Handle(OpenGl_TextureBufferArb) mySceneMinPointTexture; - //! Texture buffer of maximum points of bottom-level BVH nodes. - Handle(OpenGl_TextureBufferArb) mySceneMaxPointTexture; - //! Texture buffer of transformations of high-level BVH nodes. - Handle(OpenGl_TextureBufferArb) mySceneTransformTexture; - - //! Texture buffer of vertex coords. - Handle(OpenGl_TextureBufferArb) myGeometryVertexTexture; - //! Texture buffer of vertex normals. - Handle(OpenGl_TextureBufferArb) myGeometryNormalTexture; - //! Texture buffer of vertex UV coords. - Handle(OpenGl_TextureBufferArb) myGeometryTexCrdTexture; - //! Texture buffer of triangle indices. - Handle(OpenGl_TextureBufferArb) myGeometryTriangTexture; - - //! Texture buffer of material properties. - Handle(OpenGl_TextureBufferArb) myRaytraceMaterialTexture; - //! Texture buffer of light source properties. - Handle(OpenGl_TextureBufferArb) myRaytraceLightSrcTexture; - - //! Vertex buffer (VBO) for drawing dummy quad. - OpenGl_VertexBuffer myRaytraceScreenQuad; - - //! Framebuffer (FBO) to perform adaptive FSAA. - Handle(OpenGl_FrameBuffer) myRaytraceFBO1; - //! Framebuffer (FBO) to perform adaptive FSAA. - Handle(OpenGl_FrameBuffer) myRaytraceFBO2; - //! Framebuffer (FBO) for pre-raytrace rendering by OpenGL. - Handle(OpenGl_FrameBuffer) myOpenGlFBO; +protected: //! @name protected fields //! Framebuffer stores cached main presentation of the view (without presentation of immediate layers). Handle(OpenGl_FrameBuffer) myResultFBO; @@ -653,28 +308,6 @@ protected: //! @name fields related to ray-tracing //! Vertices for full-screen quad rendering. OpenGl_VertexBuffer myFullScreenQuad; - //! State of OpenGL view. - Standard_Size myViewModificationStatus; - //! State of OpenGL layer list. - Standard_Size myLayersModificationStatus; - - //! State of OpenGL structures reflected to ray-tracing. - std::map myStructureStates; - - //! PrimitiveArray to TriangleSet map for scene partial update. - std::map myArrayToTrianglesMap; - - //! Cached locations of frequently used uniform variables. - Standard_Integer myUniformLocations[2][OpenGl_RT_NbVariables]; - - //! Graphical ray-tracing filter to filter out all raytracable structures. - Handle(OpenGl_RaytraceFilter) myRaytraceFilter; - - //! Redraw the scene using OpenGL rasterization or ray-tracing? - Standard_Boolean myToRedrawGL; - -protected: //! @name protected fields - Handle(OpenGl_PrinterContext) myPrintContext; Handle(OpenGl_View) myView; Handle(OpenGl_LineAttributes) myLineAttribs; diff --git a/src/OpenGl/OpenGl_Workspace_Raytrace.cxx b/src/OpenGl/OpenGl_Workspace_Raytrace.cxx deleted file mode 100644 index 71de4833a1..0000000000 --- a/src/OpenGl/OpenGl_Workspace_Raytrace.cxx +++ /dev/null @@ -1,2465 +0,0 @@ -// Created on: 2013-08-27 -// Created by: Denis BOGOLEPOV -// Copyright (c) 2013 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. - -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace OpenGl_Raytrace; - -//! Use this macro to output ray-tracing debug info -// #define RAY_TRACE_PRINT_INFO - -#ifdef RAY_TRACE_PRINT_INFO - #include -#endif - -// ======================================================================= -// function : UpdateRaytraceGeometry -// purpose : Updates 3D scene geometry for ray tracing -// ======================================================================= -Standard_Boolean OpenGl_Workspace::UpdateRaytraceGeometry (GeomUpdateMode theMode) -{ - if (myView.IsNull()) - return Standard_False; - - // Note: In 'check' mode (OpenGl_GUM_CHECK) the scene geometry is analyzed for modifications - // This is light-weight procedure performed for each frame - - if (theMode == OpenGl_GUM_CHECK) - { - if (myLayersModificationStatus != myView->LayerList().ModificationState()) - { - return UpdateRaytraceGeometry (OpenGl_GUM_PREPARE); - } - } - else if (theMode == OpenGl_GUM_PREPARE) - { - myRaytraceGeometry.ClearMaterials(); - myArrayToTrianglesMap.clear(); - - myIsRaytraceDataValid = Standard_False; - } - - // The set of processed structures (reflected to ray-tracing) - // This set is used to remove out-of-date records from the - // hash map of structures - std::set anElements; - - // Set of all currently visible and "raytracable" primitive arrays. - std::set anArrayIDs; - - const OpenGl_LayerList& aList = myView->LayerList(); - - for (OpenGl_SequenceOfLayers::Iterator anLayerIt (aList.Layers()); anLayerIt.More(); anLayerIt.Next()) - { - const OpenGl_Layer& aLayer = anLayerIt.Value(); - if (aLayer.NbStructures() == 0) - continue; - - const OpenGl_ArrayOfStructure& aStructArray = aLayer.ArrayOfStructures(); - for (Standard_Integer anIndex = 0; anIndex < aStructArray.Length(); ++anIndex) - { - for (OpenGl_SequenceOfStructure::Iterator aStructIt (aStructArray (anIndex)); aStructIt.More(); aStructIt.Next()) - { - const OpenGl_Structure* aStructure = aStructIt.Value(); - - if (theMode == OpenGl_GUM_CHECK) - { - if (CheckRaytraceStructure (aStructure)) - { - return UpdateRaytraceGeometry (OpenGl_GUM_PREPARE); - } - } - else if (theMode == OpenGl_GUM_PREPARE) - { - if (!aStructure->IsRaytracable() - || !aStructure->IsVisible()) - { - continue; - } - else if (!aStructure->ViewAffinity.IsNull() - && !aStructure->ViewAffinity->IsVisible (myViewId)) - { - continue; - } - - for (OpenGl_Structure::GroupIterator aGroupIter (aStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next()) - { - // OpenGL elements from group (extract primitives arrays) - for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next) - { - OpenGl_PrimitiveArray* aPrimArray = dynamic_cast (aNode->elem); - - if (aPrimArray != NULL) - { - // Collect all primitive arrays in scene. - anArrayIDs.insert (aPrimArray->GetUID()); - } - } - } - } - else if (theMode == OpenGl_GUM_UPDATE) - { - if (!aStructure->IsRaytracable()) - continue; - - AddRaytraceStructure (aStructure, anElements); - } - } - } - } - - if (theMode == OpenGl_GUM_PREPARE) - { - BVH_ObjectSet::BVH_ObjectList anUnchangedObjects; - - // Leave only unchanged objects in myRaytraceGeometry so only their transforms and materials will be updated - // Objects which not in myArrayToTrianglesMap will be built from scratch. - for (Standard_Integer anObjectIdx = 0; anObjectIdx < myRaytraceGeometry.Objects().Size(); ++anObjectIdx) - { - OpenGl_TriangleSet* aTriangleSet = dynamic_cast ( - myRaytraceGeometry.Objects().ChangeValue (anObjectIdx).operator->()); - - // If primitive array of object not in "anArrays" set then it was hided or deleted. - // If primitive array present in "anArrays" set but we don't have associated object yet, then - // the object is new and still has to be built. - if ((aTriangleSet != NULL) && ((anArrayIDs.find (aTriangleSet->AssociatedPArrayID())) != anArrayIDs.end())) - { - anUnchangedObjects.Append (myRaytraceGeometry.Objects().Value (anObjectIdx)); - - myArrayToTrianglesMap[aTriangleSet->AssociatedPArrayID()] = aTriangleSet; - } - } - - myRaytraceGeometry.Objects() = anUnchangedObjects; - - return UpdateRaytraceGeometry (OpenGl_GUM_UPDATE); - } - - if (theMode == OpenGl_GUM_UPDATE) - { - // Actualize the hash map of structures -- remove out-of-date records - std::map::iterator anIter = myStructureStates.begin(); - - while (anIter != myStructureStates.end()) - { - if (anElements.find (anIter->first) == anElements.end()) - { - myStructureStates.erase (anIter++); - } - else - { - ++anIter; - } - } - - // Actualize OpenGL layer list state - myLayersModificationStatus = myView->LayerList().ModificationState(); - - // Rebuild bottom-level and high-level BVHs - myRaytraceGeometry.ProcessAcceleration(); - - const Standard_ShortReal aMinRadius = Max (fabs (myRaytraceGeometry.Box().CornerMin().x()), Max ( - fabs (myRaytraceGeometry.Box().CornerMin().y()), fabs (myRaytraceGeometry.Box().CornerMin().z()))); - const Standard_ShortReal aMaxRadius = Max (fabs (myRaytraceGeometry.Box().CornerMax().x()), Max ( - fabs (myRaytraceGeometry.Box().CornerMax().y()), fabs (myRaytraceGeometry.Box().CornerMax().z()))); - - myRaytraceSceneRadius = 2.f /* scale factor */ * Max (aMinRadius, aMaxRadius); - - const BVH_Vec3f aSize = myRaytraceGeometry.Box().Size(); - - myRaytraceSceneEpsilon = Max (1e-6f, 1e-4f * sqrtf ( - aSize.x() * aSize.x() + aSize.y() * aSize.y() + aSize.z() * aSize.z())); - - return UploadRaytraceData(); - } - - return Standard_True; -} - -// ======================================================================= -// function : CheckRaytraceStructure -// purpose : Checks to see if the structure is modified -// ======================================================================= -Standard_Boolean OpenGl_Workspace::CheckRaytraceStructure (const OpenGl_Structure* theStructure) -{ - if (!theStructure->IsRaytracable()) - { - // Checks to see if all ray-tracable elements were - // removed from the structure - if (theStructure->ModificationState() > 0) - { - theStructure->ResetModificationState(); - return Standard_True; - } - - return Standard_False; - } - - std::map::iterator aStructState = myStructureStates.find (theStructure); - - if (aStructState != myStructureStates.end()) - return aStructState->second != theStructure->ModificationState(); - - return Standard_True; -} - -// ======================================================================= -// function : BuildTexTransform -// purpose : Constructs texture transformation matrix -// ======================================================================= -void BuildTexTransform (const Handle(Graphic3d_TextureParams)& theParams, BVH_Mat4f& theMatrix) -{ - theMatrix.InitIdentity(); - - // Apply scaling - const Graphic3d_Vec2& aScale = theParams->Scale(); - - theMatrix.ChangeValue (0, 0) *= aScale.x(); - theMatrix.ChangeValue (1, 0) *= aScale.x(); - theMatrix.ChangeValue (2, 0) *= aScale.x(); - theMatrix.ChangeValue (3, 0) *= aScale.x(); - - theMatrix.ChangeValue (0, 1) *= aScale.y(); - theMatrix.ChangeValue (1, 1) *= aScale.y(); - theMatrix.ChangeValue (2, 1) *= aScale.y(); - theMatrix.ChangeValue (3, 1) *= aScale.y(); - - // Apply translation - const Graphic3d_Vec2 aTrans = -theParams->Translation(); - - theMatrix.ChangeValue (0, 3) = theMatrix.GetValue (0, 0) * aTrans.x() + - theMatrix.GetValue (0, 1) * aTrans.y(); - - theMatrix.ChangeValue (1, 3) = theMatrix.GetValue (1, 0) * aTrans.x() + - theMatrix.GetValue (1, 1) * aTrans.y(); - - theMatrix.ChangeValue (2, 3) = theMatrix.GetValue (2, 0) * aTrans.x() + - theMatrix.GetValue (2, 1) * aTrans.y(); - - // Apply rotation - const Standard_ShortReal aSin = std::sin ( - -theParams->Rotation() * static_cast (M_PI / 180.0)); - const Standard_ShortReal aCos = std::cos ( - -theParams->Rotation() * static_cast (M_PI / 180.0)); - - BVH_Mat4f aRotationMat; - aRotationMat.SetValue (0, 0, aCos); - aRotationMat.SetValue (1, 1, aCos); - aRotationMat.SetValue (0, 1, -aSin); - aRotationMat.SetValue (1, 0, aSin); - - theMatrix = theMatrix * aRotationMat; -} - -// ======================================================================= -// function : CreateMaterial -// purpose : Creates ray-tracing material properties -// ======================================================================= -Standard_Boolean OpenGl_Workspace::CreateMaterial (const OpenGl_AspectFace* theAspect, OpenGl_RaytraceMaterial& theMaterial) -{ - const OPENGL_SURF_PROP& aProperties = theAspect->IntFront(); - - const Standard_ShortReal* aSrcAmbient = - aProperties.isphysic ? aProperties.ambcol.rgb : aProperties.matcol.rgb; - - theMaterial.Ambient = BVH_Vec4f (aSrcAmbient[0] * aProperties.amb, - aSrcAmbient[1] * aProperties.amb, - aSrcAmbient[2] * aProperties.amb, - 1.f); - - const Standard_ShortReal* aSrcDiffuse = - aProperties.isphysic ? aProperties.difcol.rgb : aProperties.matcol.rgb; - - theMaterial.Diffuse = BVH_Vec4f (aSrcDiffuse[0] * aProperties.diff, - aSrcDiffuse[1] * aProperties.diff, - aSrcDiffuse[2] * aProperties.diff, - -1.f /* no texture */); - - theMaterial.Specular = BVH_Vec4f ( - (aProperties.isphysic ? aProperties.speccol.rgb[0] : 1.f) * aProperties.spec, - (aProperties.isphysic ? aProperties.speccol.rgb[1] : 1.f) * aProperties.spec, - (aProperties.isphysic ? aProperties.speccol.rgb[2] : 1.f) * aProperties.spec, - aProperties.shine); - - const Standard_ShortReal* aSrcEmission = - aProperties.isphysic ? aProperties.emscol.rgb : aProperties.matcol.rgb; - - theMaterial.Emission = BVH_Vec4f (aSrcEmission[0] * aProperties.emsv, - aSrcEmission[1] * aProperties.emsv, - aSrcEmission[2] * aProperties.emsv, - 1.f); - - // Note: Here we use sub-linear transparency function - // to produce realistic-looking transparency effect - theMaterial.Transparency = BVH_Vec4f (powf (aProperties.trans, 0.75f), - 1.f - aProperties.trans, - aProperties.index == 0 ? 1.f : aProperties.index, - aProperties.index == 0 ? 1.f : 1.f / aProperties.index); - - const Standard_ShortReal aMaxRefl = Max (theMaterial.Diffuse.x() + theMaterial.Specular.x(), - Max (theMaterial.Diffuse.y() + theMaterial.Specular.y(), - theMaterial.Diffuse.z() + theMaterial.Specular.z())); - - const Standard_ShortReal aReflectionScale = 0.75f / aMaxRefl; - - theMaterial.Reflection = BVH_Vec4f ( - aProperties.speccol.rgb[0] * aProperties.spec * aReflectionScale, - aProperties.speccol.rgb[1] * aProperties.spec * aReflectionScale, - aProperties.speccol.rgb[2] * aProperties.spec * aReflectionScale, - 0.f); - - if (theAspect->DoTextureMap()) - { - if (myGlContext->arbTexBindless != NULL) - { - BuildTexTransform (theAspect->TextureParams(), theMaterial.TextureTransform); - theMaterial.Diffuse.w() = static_cast ( - myRaytraceGeometry.AddTexture (theAspect->TextureRes (myGlContext))); - } - else if (!myIsRaytraceWarnTextures) - { - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, - "Warning: texturing in Ray-Trace requires GL_ARB_bindless_texture extension which is missing. " - "Textures will be ignored."); - myIsRaytraceWarnTextures = Standard_True; - } - } - - return Standard_True; -} - -// ======================================================================= -// function : AddRaytraceStructure -// purpose : Adds OpenGL structure to ray-traced scene geometry -// ======================================================================= -Standard_Boolean OpenGl_Workspace::AddRaytraceStructure (const OpenGl_Structure* theStructure, std::set& theElements) -{ - theElements.insert (theStructure); - - if (!theStructure->IsVisible()) - { - myStructureStates[theStructure] = theStructure->ModificationState(); - return Standard_True; - } - - // Get structure material - Standard_Integer aStructMatID = -1; - - if (theStructure->AspectFace() != NULL) - { - aStructMatID = static_cast (myRaytraceGeometry.Materials.size()); - - OpenGl_RaytraceMaterial aStructMaterial; - CreateMaterial (theStructure->AspectFace(), aStructMaterial); - - myRaytraceGeometry.Materials.push_back (aStructMaterial); - } - - Standard_ShortReal aStructTransformArr[16]; - Standard_ShortReal* aStructTransform = NULL; - if (theStructure->Transformation()->mat != NULL) - { - aStructTransform = aStructTransformArr; - for (Standard_Integer i = 0; i < 4; ++i) - { - for (Standard_Integer j = 0; j < 4; ++j) - { - aStructTransform[j * 4 + i] = theStructure->Transformation()->mat[i][j]; - } - } - } - - AddRaytraceGroups (theStructure, aStructMatID, aStructTransform); - - // Process all connected OpenGL structures - for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures()); anIts.More(); anIts.Next()) - { - if (anIts.Value()->IsRaytracable()) - AddRaytraceGroups (anIts.Value(), aStructMatID, aStructTransform); - } - - myStructureStates[theStructure] = theStructure->ModificationState(); - return Standard_True; -} - -// ======================================================================= -// function : AddRaytraceGroups -// purpose : Adds OpenGL groups to ray-traced scene geometry -// ======================================================================= -Standard_Boolean OpenGl_Workspace::AddRaytraceGroups (const OpenGl_Structure* theStructure, - const Standard_Integer theStructMatId, - const Standard_ShortReal* theTransform) -{ - for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next()) - { - // Get group material - Standard_Integer aGroupMatID = -1; - if (aGroupIter.Value()->AspectFace() != NULL) - { - aGroupMatID = static_cast (myRaytraceGeometry.Materials.size()); - - OpenGl_RaytraceMaterial aGroupMaterial; - CreateMaterial (aGroupIter.Value()->AspectFace(), aGroupMaterial); - - myRaytraceGeometry.Materials.push_back (aGroupMaterial); - } - - Standard_Integer aMatID = aGroupMatID < 0 ? theStructMatId : aGroupMatID; - - if (aMatID < 0) - { - aMatID = static_cast (myRaytraceGeometry.Materials.size()); - - myRaytraceGeometry.Materials.push_back (OpenGl_RaytraceMaterial()); - } - - // Add OpenGL elements from group (extract primitives arrays and aspects) - for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next) - { - OpenGl_AspectFace* anAspect = dynamic_cast (aNode->elem); - if (anAspect != NULL) - { - aMatID = static_cast (myRaytraceGeometry.Materials.size()); - - OpenGl_RaytraceMaterial aMaterial; - CreateMaterial (anAspect, aMaterial); - - myRaytraceGeometry.Materials.push_back (aMaterial); - } - else - { - OpenGl_PrimitiveArray* aPrimArray = dynamic_cast (aNode->elem); - - if (aPrimArray != NULL) - { - std::map::iterator aSetIter = myArrayToTrianglesMap.find (aPrimArray->GetUID()); - - if (aSetIter != myArrayToTrianglesMap.end()) - { - OpenGl_TriangleSet* aSet = aSetIter->second; - - BVH_Transform* aTransform = new BVH_Transform(); - - if (theTransform != NULL) - { - aTransform->SetTransform (*(reinterpret_cast (theTransform))); - } - - aSet->SetProperties (aTransform); - - if (aSet->MaterialIndex() != OpenGl_TriangleSet::INVALID_MATERIAL && aSet->MaterialIndex() != aMatID) - { - aSet->SetMaterialIndex (aMatID); - } - } - else - { - NCollection_Handle > aSet = - AddRaytracePrimitiveArray (aPrimArray, aMatID, 0); - - if (!aSet.IsNull()) - { - BVH_Transform* aTransform = new BVH_Transform; - - if (theTransform != NULL) - { - aTransform->SetTransform (*(reinterpret_cast (theTransform))); - } - - aSet->SetProperties (aTransform); - - myRaytraceGeometry.Objects().Append (aSet); - } - } - } - } - } - } - - return Standard_True; -} - -// ======================================================================= -// function : AddRaytracePrimitiveArray -// purpose : Adds OpenGL primitive array to ray-traced scene geometry -// ======================================================================= -OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (const OpenGl_PrimitiveArray* theArray, - Standard_Integer theMatID, - const OpenGl_Mat4* theTransform) -{ - const Handle(Graphic3d_IndexBuffer)& anIndices = theArray->Indices(); - const Handle(Graphic3d_Buffer)& anAttribs = theArray->Attributes(); - const Handle(Graphic3d_BoundBuffer)& aBounds = theArray->Bounds(); - if (theArray->DrawMode() < GL_TRIANGLES - #if !defined(GL_ES_VERSION_2_0) - || theArray->DrawMode() > GL_POLYGON - #else - || theArray->DrawMode() > GL_TRIANGLE_FAN - #endif - || anAttribs.IsNull()) - { - return NULL; - } - -#ifdef RAY_TRACE_PRINT_INFO - switch (theArray->DrawMode()) - { - case GL_TRIANGLES: std::cout << "\tAdding GL_TRIANGLES\n"; break; - case GL_TRIANGLE_FAN: std::cout << "\tAdding GL_TRIANGLE_FAN\n"; break; - case GL_TRIANGLE_STRIP: std::cout << "\tAdding GL_TRIANGLE_STRIP\n"; break; - #if !defined(GL_ES_VERSION_2_0) - case GL_QUADS: std::cout << "\tAdding GL_QUADS\n"; break; - case GL_QUAD_STRIP: std::cout << "\tAdding GL_QUAD_STRIP\n"; break; - case GL_POLYGON: std::cout << "\tAdding GL_POLYGON\n"; break; - #endif - } -#endif - - OpenGl_Mat4 aNormalMatrix; - - if (theTransform != NULL) - { - Standard_ASSERT_RETURN (theTransform->Inverted (aNormalMatrix), - "Error: Failed to compute normal transformation matrix", NULL); - - aNormalMatrix.Transpose(); - } - - OpenGl_TriangleSet* aSet = new OpenGl_TriangleSet (theArray->GetUID()); - { - aSet->Vertices.reserve (anAttribs->NbElements); - aSet->Normals .reserve (anAttribs->NbElements); - aSet->TexCrds .reserve (anAttribs->NbElements); - - const size_t aVertFrom = aSet->Vertices.size(); - for (Standard_Integer anAttribIter = 0; anAttribIter < anAttribs->NbAttributes; ++anAttribIter) - { - const Graphic3d_Attribute& anAttrib = anAttribs->Attribute (anAttribIter); - const size_t anOffset = anAttribs->AttributeOffset (anAttribIter); - if (anAttrib.Id == Graphic3d_TOA_POS) - { - if (anAttrib.DataType == Graphic3d_TOD_VEC3 - || anAttrib.DataType == Graphic3d_TOD_VEC4) - { - for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) - { - aSet->Vertices.push_back ( - *reinterpret_cast(anAttribs->value (aVertIter) + anOffset)); - } - } - else if (anAttrib.DataType == Graphic3d_TOD_VEC2) - { - for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) - { - const Graphic3d_Vec2& aVert = *reinterpret_cast(anAttribs->value (aVertIter) + anOffset); - aSet->Vertices.push_back (BVH_Vec3f (aVert.x(), aVert.y(), 0.0f)); - } - } - } - else if (anAttrib.Id == Graphic3d_TOA_NORM) - { - if (anAttrib.DataType == Graphic3d_TOD_VEC3 - || anAttrib.DataType == Graphic3d_TOD_VEC4) - { - for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) - { - aSet->Normals.push_back ( - *reinterpret_cast(anAttribs->value (aVertIter) + anOffset)); - } - } - } - else if (anAttrib.Id == Graphic3d_TOA_UV) - { - if (anAttrib.DataType == Graphic3d_TOD_VEC2) - { - for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) - { - aSet->TexCrds.push_back ( - *reinterpret_cast(anAttribs->value (aVertIter) + anOffset)); - } - } - } - } - - if (aSet->Normals.size() != aSet->Vertices.size()) - { - for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) - { - aSet->Normals.push_back (BVH_Vec3f()); - } - } - - if (aSet->TexCrds.size() != aSet->Vertices.size()) - { - for (Standard_Integer aVertIter = 0; aVertIter < anAttribs->NbElements; ++aVertIter) - { - aSet->TexCrds.push_back (BVH_Vec2f()); - } - } - - if (theTransform != NULL) - { - for (size_t aVertIter = aVertFrom; aVertIter < aSet->Vertices.size(); ++aVertIter) - { - BVH_Vec3f& aVertex = aSet->Vertices[aVertIter]; - - BVH_Vec4f aTransVertex = - *theTransform * BVH_Vec4f (aVertex.x(), aVertex.y(), aVertex.z(), 1.f); - - aVertex = BVH_Vec3f (aTransVertex.x(), aTransVertex.y(), aTransVertex.z()); - } - for (size_t aVertIter = aVertFrom; aVertIter < aSet->Normals.size(); ++aVertIter) - { - BVH_Vec3f& aNormal = aSet->Normals[aVertIter]; - - BVH_Vec4f aTransNormal = - aNormalMatrix * BVH_Vec4f (aNormal.x(), aNormal.y(), aNormal.z(), 0.f); - - aNormal = BVH_Vec3f (aTransNormal.x(), aTransNormal.y(), aTransNormal.z()); - } - } - - if (!aBounds.IsNull()) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "\tNumber of bounds = " << aBounds->NbBounds << std::endl; -#endif - - Standard_Integer aBoundStart = 0; - for (Standard_Integer aBound = 0; aBound < aBounds->NbBounds; ++aBound) - { - const Standard_Integer aVertNum = aBounds->Bounds[aBound]; - -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "\tAdding indices from bound " << aBound << ": " << - aBoundStart << " .. " << aVertNum << std::endl; -#endif - - if (!AddRaytraceVertexIndices (*aSet, *theArray, aBoundStart, aVertNum, theMatID)) - { - delete aSet; - return NULL; - } - - aBoundStart += aVertNum; - } - } - else - { - const Standard_Integer aVertNum = !anIndices.IsNull() ? anIndices->NbElements : anAttribs->NbElements; - - #ifdef RAY_TRACE_PRINT_INFO - std::cout << "\tAdding indices from array: " << aVertNum << std::endl; - #endif - - if (!AddRaytraceVertexIndices (*aSet, *theArray, 0, aVertNum, theMatID)) - { - delete aSet; - return NULL; - } - } - } - - if (aSet->Size() != 0) - aSet->MarkDirty(); - - return aSet; -} - -// ======================================================================= -// function : AddRaytraceVertexIndices -// purpose : Adds vertex indices to ray-traced scene geometry -// ======================================================================= -Standard_Boolean OpenGl_Workspace::AddRaytraceVertexIndices (OpenGl_TriangleSet& theSet, - const OpenGl_PrimitiveArray& theArray, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID) -{ - switch (theArray.DrawMode()) - { - case GL_TRIANGLES: return AddRaytraceTriangleArray (theSet, theArray.Indices(), theOffset, theCount, theMatID); - case GL_TRIANGLE_FAN: return AddRaytraceTriangleFanArray (theSet, theArray.Indices(), theOffset, theCount, theMatID); - case GL_TRIANGLE_STRIP: return AddRaytraceTriangleStripArray (theSet, theArray.Indices(), theOffset, theCount, theMatID); - #if !defined(GL_ES_VERSION_2_0) - case GL_QUADS: return AddRaytraceQuadrangleArray (theSet, theArray.Indices(), theOffset, theCount, theMatID); - case GL_QUAD_STRIP: return AddRaytraceQuadrangleStripArray (theSet, theArray.Indices(), theOffset, theCount, theMatID); - case GL_POLYGON: return AddRaytracePolygonArray (theSet, theArray.Indices(), theOffset, theCount, theMatID); - #endif - } - return Standard_False; -} - -// ======================================================================= -// function : AddRaytraceTriangleArray -// purpose : Adds OpenGL triangle array to ray-traced scene geometry -// ======================================================================= -Standard_Boolean OpenGl_Workspace::AddRaytraceTriangleArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID) -{ - if (theCount < 3) - return Standard_True; - - theSet.Elements.reserve (theSet.Elements.size() + theCount / 3); - - if (!theIndices.IsNull()) - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; aVert += 3) - { - theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0), - theIndices->Index (aVert + 1), - theIndices->Index (aVert + 2), - theMatID)); - } - } - else - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; aVert += 3) - { - theSet.Elements.push_back (BVH_Vec4i (aVert + 0, aVert + 1, aVert + 2, - theMatID)); - } - } - - return Standard_True; -} - -// ======================================================================= -// function : AddRaytraceTriangleFanArray -// purpose : Adds OpenGL triangle fan array to ray-traced scene geometry -// ======================================================================= -Standard_Boolean OpenGl_Workspace::AddRaytraceTriangleFanArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID) -{ - if (theCount < 3) - return Standard_True; - - theSet.Elements.reserve (theSet.Elements.size() + theCount - 2); - - if (!theIndices.IsNull()) - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert) - { - theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (theOffset), - theIndices->Index (aVert + 1), - theIndices->Index (aVert + 2), - theMatID)); - } - } - else - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert) - { - theSet.Elements.push_back (BVH_Vec4i (theOffset, - aVert + 1, - aVert + 2, - theMatID)); - } - } - - return Standard_True; -} - -// ======================================================================= -// function : AddRaytraceTriangleStripArray -// purpose : Adds OpenGL triangle strip array to ray-traced scene geometry -// ======================================================================= -Standard_Boolean OpenGl_Workspace::AddRaytraceTriangleStripArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID) -{ - if (theCount < 3) - return Standard_True; - - theSet.Elements.reserve (theSet.Elements.size() + theCount - 2); - - if (!theIndices.IsNull()) - { - for (Standard_Integer aVert = theOffset, aCW = 0; aVert < theOffset + theCount - 2; ++aVert, aCW = (aCW + 1) % 2) - { - theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + aCW ? 1 : 0), - theIndices->Index (aVert + aCW ? 0 : 1), - theIndices->Index (aVert + 2), - theMatID)); - } - } - else - { - for (Standard_Integer aVert = theOffset, aCW = 0; aVert < theOffset + theCount - 2; ++aVert, aCW = (aCW + 1) % 2) - { - theSet.Elements.push_back (BVH_Vec4i (aVert + aCW ? 1 : 0, - aVert + aCW ? 0 : 1, - aVert + 2, - theMatID)); - } - } - - return Standard_True; -} - -// ======================================================================= -// function : AddRaytraceQuadrangleArray -// purpose : Adds OpenGL quad array to ray-traced scene geometry -// ======================================================================= -Standard_Boolean OpenGl_Workspace::AddRaytraceQuadrangleArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID) -{ - if (theCount < 4) - return Standard_True; - - theSet.Elements.reserve (theSet.Elements.size() + theCount / 2); - - if (!theIndices.IsNull()) - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 4) - { - theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0), - theIndices->Index (aVert + 1), - theIndices->Index (aVert + 2), - theMatID)); - theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0), - theIndices->Index (aVert + 2), - theIndices->Index (aVert + 3), - theMatID)); - } - } - else - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 4) - { - theSet.Elements.push_back (BVH_Vec4i (aVert + 0, aVert + 1, aVert + 2, - theMatID)); - theSet.Elements.push_back (BVH_Vec4i (aVert + 0, aVert + 2, aVert + 3, - theMatID)); - } - } - - return Standard_True; -} - -// ======================================================================= -// function : AddRaytraceQuadrangleStripArray -// purpose : Adds OpenGL quad strip array to ray-traced scene geometry -// ======================================================================= -Standard_Boolean OpenGl_Workspace::AddRaytraceQuadrangleStripArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID) -{ - if (theCount < 4) - return Standard_True; - - theSet.Elements.reserve (theSet.Elements.size() + 2 * theCount - 6); - - if (!theIndices.IsNull()) - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 2) - { - theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 0), - theIndices->Index (aVert + 1), - theIndices->Index (aVert + 2), - theMatID)); - - theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (aVert + 1), - theIndices->Index (aVert + 3), - theIndices->Index (aVert + 2), - theMatID)); - } - } - else - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 2) - { - theSet.Elements.push_back (BVH_Vec4i (aVert + 0, - aVert + 1, - aVert + 2, - theMatID)); - - theSet.Elements.push_back (BVH_Vec4i (aVert + 1, - aVert + 3, - aVert + 2, - theMatID)); - } - } - - return Standard_True; -} - -// ======================================================================= -// function : AddRaytracePolygonArray -// purpose : Adds OpenGL polygon array to ray-traced scene geometry -// ======================================================================= -Standard_Boolean OpenGl_Workspace::AddRaytracePolygonArray (OpenGl_TriangleSet& theSet, - const Handle(Graphic3d_IndexBuffer)& theIndices, - Standard_Integer theOffset, - Standard_Integer theCount, - Standard_Integer theMatID) -{ - if (theCount < 3) - return Standard_True; - - theSet.Elements.reserve (theSet.Elements.size() + theCount - 2); - - if (!theIndices.IsNull()) - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert) - { - theSet.Elements.push_back (BVH_Vec4i (theIndices->Index (theOffset), - theIndices->Index (aVert + 1), - theIndices->Index (aVert + 2), - theMatID)); - } - } - else - { - for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert) - { - theSet.Elements.push_back (BVH_Vec4i (theOffset, - aVert + 1, - aVert + 2, - theMatID)); - } - } - - return Standard_True; -} - -// ======================================================================= -// function : UpdateRaytraceLightSources -// purpose : Updates 3D scene light sources for ray-tracing -// ======================================================================= -Standard_Boolean OpenGl_Workspace::UpdateRaytraceLightSources (const OpenGl_Mat4& theInvModelView) -{ - myRaytraceGeometry.Sources.clear(); - - myRaytraceGeometry.Ambient = BVH_Vec4f (0.0f, 0.0f, 0.0f, 0.0f); - - for (OpenGl_ListOfLight::Iterator anItl (myView->LightList()); anItl.More(); anItl.Next()) - { - const OpenGl_Light& aLight = anItl.Value(); - - if (aLight.Type == Visual3d_TOLS_AMBIENT) - { - myRaytraceGeometry.Ambient += BVH_Vec4f (aLight.Color.r(), - aLight.Color.g(), - aLight.Color.b(), - 0.0f); - continue; - } - - BVH_Vec4f aDiffuse (aLight.Color.r(), - aLight.Color.g(), - aLight.Color.b(), - 1.0f); - - BVH_Vec4f aPosition (-aLight.Direction.x(), - -aLight.Direction.y(), - -aLight.Direction.z(), - 0.0f); - - if (aLight.Type != Visual3d_TOLS_DIRECTIONAL) - { - aPosition = BVH_Vec4f (aLight.Position.x(), - aLight.Position.y(), - aLight.Position.z(), - 1.0f); - } - - if (aLight.IsHeadlight) - { - aPosition = theInvModelView * aPosition; - } - - myRaytraceGeometry.Sources.push_back (OpenGl_RaytraceLight (aDiffuse, aPosition)); - } - - if (myRaytraceLightSrcTexture.IsNull()) // create light source buffer - { - myRaytraceLightSrcTexture = new OpenGl_TextureBufferArb; - - if (!myRaytraceLightSrcTexture->Create (myGlContext)) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to create light source buffer" << std::endl; -#endif - return Standard_False; - } - } - - if (myRaytraceGeometry.Sources.size() != 0) - { - const GLfloat* aDataPtr = myRaytraceGeometry.Sources.front().Packed(); - if (!myRaytraceLightSrcTexture->Init (myGlContext, 4, GLsizei (myRaytraceGeometry.Sources.size() * 2), aDataPtr)) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to upload light source buffer" << std::endl; -#endif - return Standard_False; - } - } - - return Standard_True; -} - -// ======================================================================= -// function : UpdateRaytraceEnvironmentMap -// purpose : Updates environment map for ray-tracing -// ======================================================================= -Standard_Boolean OpenGl_Workspace::UpdateRaytraceEnvironmentMap() -{ - if (myView.IsNull()) - return Standard_False; - - if (myViewModificationStatus == myView->ModificationState()) - return Standard_True; - - for (Standard_Integer anIdx = 0; anIdx < 2; ++anIdx) - { - const Handle(OpenGl_ShaderProgram)& aProgram = - anIdx == 0 ? myRaytraceProgram : myPostFSAAProgram; - - if (!aProgram.IsNull()) - { - myGlContext->BindProgram (aProgram); - - if (!myView->TextureEnv().IsNull() && myView->SurfaceDetail() != Visual3d_TOD_NONE) - { - myView->TextureEnv()->Bind ( - myGlContext, GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture); - - aProgram->SetUniform (myGlContext, - myUniformLocations[anIdx][OpenGl_RT_uEnvMapEnable], 1); - } - else - { - aProgram->SetUniform (myGlContext, - myUniformLocations[anIdx][OpenGl_RT_uEnvMapEnable], 0); - } - } - } - - myGlContext->BindProgram (NULL); - myViewModificationStatus = myView->ModificationState(); - return Standard_True; -} - -// ======================================================================= -// function : Source -// purpose : Returns shader source combined with prefix -// ======================================================================= -TCollection_AsciiString OpenGl_Workspace::ShaderSource::Source() const -{ - static const TCollection_AsciiString aVersion = "#version 140"; - - if (myPrefix.IsEmpty()) - { - return aVersion + "\n" + mySource; - } - - return aVersion + "\n" + myPrefix + "\n" + mySource; -} - -// ======================================================================= -// function : Load -// purpose : Loads shader source from specified files -// ======================================================================= -void OpenGl_Workspace::ShaderSource::Load ( - const TCollection_AsciiString* theFileNames, const Standard_Integer theCount) -{ - mySource.Clear(); - - for (Standard_Integer anIndex = 0; anIndex < theCount; ++anIndex) - { - OSD_File aFile (theFileNames[anIndex]); - - Standard_ASSERT_RETURN (aFile.Exists(), - "Error: Failed to find shader source file", /* none */); - - aFile.Open (OSD_ReadOnly, OSD_Protection()); - - TCollection_AsciiString aSource; - - Standard_ASSERT_RETURN (aFile.IsOpen(), - "Error: Failed to open shader source file", /* none */); - - aFile.Read (aSource, (Standard_Integer) aFile.Size()); - - if (!aSource.IsEmpty()) - { - mySource += TCollection_AsciiString ("\n") + aSource; - } - - aFile.Close(); - } -} - -// ======================================================================= -// function : LoadShader -// purpose : Creates new shader object with specified source -// ======================================================================= -Handle(OpenGl_ShaderObject) OpenGl_Workspace::LoadShader (const ShaderSource& theSource, GLenum theType) -{ - Handle(OpenGl_ShaderObject) aShader = new OpenGl_ShaderObject (theType); - - if (!aShader->Create (myGlContext)) - { - const TCollection_ExtendedString aMessage = TCollection_ExtendedString ("Error: Failed to create ") + - (theType == GL_VERTEX_SHADER ? "vertex" : "fragment") + " shader object"; - - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage); - - aShader->Release (myGlContext.operator->()); - - return Handle(OpenGl_ShaderObject)(); - } - - if (!aShader->LoadSource (myGlContext, theSource.Source())) - { - const TCollection_ExtendedString aMessage = TCollection_ExtendedString ("Error: Failed to set ") + - (theType == GL_VERTEX_SHADER ? "vertex" : "fragment") + " shader source"; - - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage); - - aShader->Release (myGlContext.operator->()); - - return Handle(OpenGl_ShaderObject)(); - } - - TCollection_AsciiString aBuildLog; - - if (!aShader->Compile (myGlContext)) - { - aShader->FetchInfoLog (myGlContext, aBuildLog); - - const TCollection_ExtendedString aMessage = TCollection_ExtendedString ("Error: Failed to compile ") + - (theType == GL_VERTEX_SHADER ? "vertex" : "fragment") + " shader object:\n" + aBuildLog; - - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage); - - aShader->Release (myGlContext.operator->()); - - return Handle(OpenGl_ShaderObject)(); - } - else if (myGlContext->caps->glslWarnings) - { - aShader->FetchInfoLog (myGlContext, aBuildLog); - - if (!aBuildLog.IsEmpty() && !aBuildLog.IsEqual ("No errors.\n")) - { - const TCollection_ExtendedString aMessage = TCollection_ExtendedString (theType == GL_VERTEX_SHADER ? - "Vertex" : "Fragment") + " shader was compiled with following warnings:\n" + aBuildLog; - - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage); - } - } - - return aShader; -} - -// ======================================================================= -// function : SafeFailBack -// purpose : Performs safe exit when shaders initialization fails -// ======================================================================= -Standard_Boolean OpenGl_Workspace::SafeFailBack (const TCollection_ExtendedString& theMessage) -{ - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, theMessage); - - myComputeInitStatus = OpenGl_RT_FAIL; - - ReleaseRaytraceResources(); - - return Standard_False; -} - -// ======================================================================= -// function : GenerateShaderPrefix -// purpose : Generates shader prefix based on current ray-tracing options -// ======================================================================= -TCollection_AsciiString OpenGl_Workspace::GenerateShaderPrefix() -{ - TCollection_AsciiString aPrefixString = - TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myRaytraceParameters.StackSize) + "\n" + - TCollection_AsciiString ("#define NB_BOUNCES ") + TCollection_AsciiString (myRaytraceParameters.NbBounces); - - if (myRaytraceParameters.TransparentShadows) - { - aPrefixString += TCollection_AsciiString ("\n#define TRANSPARENT_SHADOWS"); - } - - // If OpenGL driver supports bindless textures - // activate texturing in ray-tracing mode - if (myGlContext->arbTexBindless != NULL) - { - aPrefixString += TCollection_AsciiString ("\n#define USE_TEXTURES") + - TCollection_AsciiString ("\n#define MAX_TEX_NUMBER ") + TCollection_AsciiString (OpenGl_RaytraceGeometry::MAX_TEX_NUMBER); - } - - return aPrefixString; -} - -// ======================================================================= -// function : InitRaytraceResources -// purpose : Initializes OpenGL/GLSL shader programs -// ======================================================================= -Standard_Boolean OpenGl_Workspace::InitRaytraceResources (const Graphic3d_CView& theCView) -{ - if (myComputeInitStatus == OpenGl_RT_FAIL) - { - return Standard_False; - } - - Standard_Boolean aToRebuildShaders = Standard_False; - - if (myComputeInitStatus == OpenGl_RT_INIT) - { - if (!myIsRaytraceDataValid) - return Standard_True; - - const Standard_Integer aRequiredStackSize = - myRaytraceGeometry.HighLevelTreeDepth() + myRaytraceGeometry.BottomLevelTreeDepth(); - - if (myRaytraceParameters.StackSize < aRequiredStackSize) - { - myRaytraceParameters.StackSize = Max (aRequiredStackSize, THE_DEFAULT_STACK_SIZE); - - aToRebuildShaders = Standard_True; - } - else - { - if (aRequiredStackSize < myRaytraceParameters.StackSize) - { - if (myRaytraceParameters.StackSize > THE_DEFAULT_STACK_SIZE) - { - myRaytraceParameters.StackSize = Max (aRequiredStackSize, THE_DEFAULT_STACK_SIZE); - aToRebuildShaders = Standard_True; - } - } - } - - if (theCView.RenderParams.RaytracingDepth != myRaytraceParameters.NbBounces) - { - myRaytraceParameters.NbBounces = theCView.RenderParams.RaytracingDepth; - aToRebuildShaders = Standard_True; - } - - if (theCView.RenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows) - { - myRaytraceParameters.TransparentShadows = theCView.RenderParams.IsTransparentShadowEnabled; - aToRebuildShaders = Standard_True; - } - - if (aToRebuildShaders) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Info: Rebuild shaders with stack size: " << myRaytraceParameters.StackSize << std::endl; -#endif - - // Change state to force update all uniforms - ++myViewModificationStatus; - - TCollection_AsciiString aPrefixString = GenerateShaderPrefix(); - -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "GLSL prefix string:" << std::endl << aPrefixString << std::endl; -#endif - - myRaytraceShaderSource.SetPrefix (aPrefixString); - myPostFSAAShaderSource.SetPrefix (aPrefixString); - - if (!myRaytraceShader->LoadSource (myGlContext, myRaytraceShaderSource.Source()) - || !myPostFSAAShader->LoadSource (myGlContext, myPostFSAAShaderSource.Source())) - { - return SafeFailBack ("Failed to load source into ray-tracing fragment shaders"); - } - - if (!myRaytraceShader->Compile (myGlContext) - || !myPostFSAAShader->Compile (myGlContext)) - { - return SafeFailBack ("Failed to compile ray-tracing fragment shaders"); - } - - myRaytraceProgram->SetAttributeName (myGlContext, Graphic3d_TOA_POS, "occVertex"); - myPostFSAAProgram->SetAttributeName (myGlContext, Graphic3d_TOA_POS, "occVertex"); - if (!myRaytraceProgram->Link (myGlContext) - || !myPostFSAAProgram->Link (myGlContext)) - { - return SafeFailBack ("Failed to initialize vertex attributes for ray-tracing program"); - } - } - } - - if (myComputeInitStatus == OpenGl_RT_NONE) - { - if (!myGlContext->IsGlGreaterEqual (3, 1)) - { - return SafeFailBack ("Ray-tracing requires OpenGL 3.1 and higher"); - } - else if (!myGlContext->arbTboRGB32) - { - return SafeFailBack ("Ray-tracing requires OpenGL 4.0+ or GL_ARB_texture_buffer_object_rgb32 extension"); - } - - myRaytraceParameters.NbBounces = theCView.RenderParams.RaytracingDepth; - - TCollection_AsciiString aFolder = Graphic3d_ShaderProgram::ShadersFolder(); - - if (aFolder.IsEmpty()) - { - return SafeFailBack ("Failed to locate shaders directory"); - } - - if (myIsRaytraceDataValid) - { - myRaytraceParameters.StackSize = Max (THE_DEFAULT_STACK_SIZE, - myRaytraceGeometry.HighLevelTreeDepth() + myRaytraceGeometry.BottomLevelTreeDepth()); - } - - TCollection_AsciiString aPrefixString = GenerateShaderPrefix(); - -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "GLSL prefix string:" << std::endl << aPrefixString << std::endl; -#endif - - { - Handle(OpenGl_ShaderObject) aBasicVertShader = LoadShader ( - ShaderSource (aFolder + "/RaytraceBase.vs"), GL_VERTEX_SHADER); - - if (aBasicVertShader.IsNull()) - { - return SafeFailBack ("Failed to initialize ray-trace vertex shader"); - } - - TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs", - aFolder + "/RaytraceRender.fs" }; - - myRaytraceShaderSource.Load (aFiles, 2); - - myRaytraceShaderSource.SetPrefix (aPrefixString); - - myRaytraceShader = LoadShader (myRaytraceShaderSource, GL_FRAGMENT_SHADER); - - if (myRaytraceShader.IsNull()) - { - aBasicVertShader->Release (myGlContext.operator->()); - - return SafeFailBack ("Failed to initialize ray-trace fragment shader"); - } - - myRaytraceProgram = new OpenGl_ShaderProgram; - - if (!myRaytraceProgram->Create (myGlContext)) - { - aBasicVertShader->Release (myGlContext.operator->()); - - return SafeFailBack ("Failed to create ray-trace shader program"); - } - - if (!myRaytraceProgram->AttachShader (myGlContext, aBasicVertShader) - || !myRaytraceProgram->AttachShader (myGlContext, myRaytraceShader)) - { - aBasicVertShader->Release (myGlContext.operator->()); - - return SafeFailBack ("Failed to attach ray-trace shader objects"); - } - - myRaytraceProgram->SetAttributeName (myGlContext, Graphic3d_TOA_POS, "occVertex"); - - TCollection_AsciiString aLinkLog; - - if (!myRaytraceProgram->Link (myGlContext)) - { - myRaytraceProgram->FetchInfoLog (myGlContext, aLinkLog); - - return SafeFailBack (TCollection_ExtendedString ( - "Failed to link ray-trace shader program:\n") + aLinkLog); - } - else if (myGlContext->caps->glslWarnings) - { - myRaytraceProgram->FetchInfoLog (myGlContext, aLinkLog); - - if (!aLinkLog.IsEmpty() && !aLinkLog.IsEqual ("No errors.\n")) - { - const TCollection_ExtendedString aMessage = TCollection_ExtendedString ( - "Ray-trace shader program was linked with following warnings:\n") + aLinkLog; - - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage); - } - } - } - - { - Handle(OpenGl_ShaderObject) aBasicVertShader = LoadShader ( - ShaderSource (aFolder + "/RaytraceBase.vs"), GL_VERTEX_SHADER); - - if (aBasicVertShader.IsNull()) - { - return SafeFailBack ("Failed to initialize FSAA vertex shader"); - } - - TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs", - aFolder + "/RaytraceSmooth.fs" }; - - myPostFSAAShaderSource.Load (aFiles, 2); - - myPostFSAAShaderSource.SetPrefix (aPrefixString); - - myPostFSAAShader = LoadShader (myPostFSAAShaderSource, GL_FRAGMENT_SHADER); - - if (myPostFSAAShader.IsNull()) - { - aBasicVertShader->Release (myGlContext.operator->()); - - return SafeFailBack ("Failed to initialize FSAA fragment shader"); - } - - myPostFSAAProgram = new OpenGl_ShaderProgram; - - if (!myPostFSAAProgram->Create (myGlContext)) - { - aBasicVertShader->Release (myGlContext.operator->()); - - return SafeFailBack ("Failed to create FSAA shader program"); - } - - if (!myPostFSAAProgram->AttachShader (myGlContext, aBasicVertShader) - || !myPostFSAAProgram->AttachShader (myGlContext, myPostFSAAShader)) - { - aBasicVertShader->Release (myGlContext.operator->()); - - return SafeFailBack ("Failed to attach FSAA shader objects"); - } - - myPostFSAAProgram->SetAttributeName (myGlContext, Graphic3d_TOA_POS, "occVertex"); - - TCollection_AsciiString aLinkLog; - - if (!myPostFSAAProgram->Link (myGlContext)) - { - myPostFSAAProgram->FetchInfoLog (myGlContext, aLinkLog); - - return SafeFailBack (TCollection_ExtendedString ( - "Failed to link FSAA shader program:\n") + aLinkLog); - } - else if (myGlContext->caps->glslWarnings) - { - myPostFSAAProgram->FetchInfoLog (myGlContext, aLinkLog); - - if (!aLinkLog.IsEmpty() && !aLinkLog.IsEqual ("No errors.\n")) - { - const TCollection_ExtendedString aMessage = TCollection_ExtendedString ( - "FSAA shader program was linked with following warnings:\n") + aLinkLog; - - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_PORTABILITY_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, aMessage); - } - } - } - } - - if (myComputeInitStatus == OpenGl_RT_NONE || aToRebuildShaders) - { - for (Standard_Integer anIndex = 0; anIndex < 2; ++anIndex) - { - Handle(OpenGl_ShaderProgram)& aShaderProgram = - (anIndex == 0) ? myRaytraceProgram : myPostFSAAProgram; - - myGlContext->BindProgram (aShaderProgram); - - aShaderProgram->SetSampler (myGlContext, - "uSceneMinPointTexture", OpenGl_RT_SceneMinPointTexture); - aShaderProgram->SetSampler (myGlContext, - "uSceneMaxPointTexture", OpenGl_RT_SceneMaxPointTexture); - aShaderProgram->SetSampler (myGlContext, - "uSceneNodeInfoTexture", OpenGl_RT_SceneNodeInfoTexture); - aShaderProgram->SetSampler (myGlContext, - "uGeometryVertexTexture", OpenGl_RT_GeometryVertexTexture); - aShaderProgram->SetSampler (myGlContext, - "uGeometryNormalTexture", OpenGl_RT_GeometryNormalTexture); - aShaderProgram->SetSampler (myGlContext, - "uGeometryTexCrdTexture", OpenGl_RT_GeometryTexCrdTexture); - aShaderProgram->SetSampler (myGlContext, - "uGeometryTriangTexture", OpenGl_RT_GeometryTriangTexture); - aShaderProgram->SetSampler (myGlContext, - "uSceneTransformTexture", OpenGl_RT_SceneTransformTexture); - aShaderProgram->SetSampler (myGlContext, - "uEnvironmentMapTexture", OpenGl_RT_EnvironmentMapTexture); - aShaderProgram->SetSampler (myGlContext, - "uRaytraceMaterialTexture", OpenGl_RT_RaytraceMaterialTexture); - aShaderProgram->SetSampler (myGlContext, - "uRaytraceLightSrcTexture", OpenGl_RT_RaytraceLightSrcTexture); - - aShaderProgram->SetSampler (myGlContext, - "uOpenGlColorTexture", OpenGl_RT_OpenGlColorTexture); - aShaderProgram->SetSampler (myGlContext, - "uOpenGlDepthTexture", OpenGl_RT_OpenGlDepthTexture); - - if (anIndex == 1) - { - aShaderProgram->SetSampler (myGlContext, - "uFSAAInputTexture", OpenGl_RT_FSAAInputTexture); - } - - myUniformLocations[anIndex][OpenGl_RT_aPosition] = - aShaderProgram->GetAttributeLocation (myGlContext, "occVertex"); - - myUniformLocations[anIndex][OpenGl_RT_uOriginLB] = - aShaderProgram->GetUniformLocation (myGlContext, "uOriginLB"); - myUniformLocations[anIndex][OpenGl_RT_uOriginRB] = - aShaderProgram->GetUniformLocation (myGlContext, "uOriginRB"); - myUniformLocations[anIndex][OpenGl_RT_uOriginLT] = - aShaderProgram->GetUniformLocation (myGlContext, "uOriginLT"); - myUniformLocations[anIndex][OpenGl_RT_uOriginRT] = - aShaderProgram->GetUniformLocation (myGlContext, "uOriginRT"); - myUniformLocations[anIndex][OpenGl_RT_uDirectLB] = - aShaderProgram->GetUniformLocation (myGlContext, "uDirectLB"); - myUniformLocations[anIndex][OpenGl_RT_uDirectRB] = - aShaderProgram->GetUniformLocation (myGlContext, "uDirectRB"); - myUniformLocations[anIndex][OpenGl_RT_uDirectLT] = - aShaderProgram->GetUniformLocation (myGlContext, "uDirectLT"); - myUniformLocations[anIndex][OpenGl_RT_uDirectRT] = - aShaderProgram->GetUniformLocation (myGlContext, "uDirectRT"); - myUniformLocations[anIndex][OpenGl_RT_uUnviewMat] = - aShaderProgram->GetUniformLocation (myGlContext, "uUnviewMat"); - - myUniformLocations[anIndex][OpenGl_RT_uSceneRad] = - aShaderProgram->GetUniformLocation (myGlContext, "uSceneRadius"); - myUniformLocations[anIndex][OpenGl_RT_uSceneEps] = - aShaderProgram->GetUniformLocation (myGlContext, "uSceneEpsilon"); - myUniformLocations[anIndex][OpenGl_RT_uLightCount] = - aShaderProgram->GetUniformLocation (myGlContext, "uLightCount"); - myUniformLocations[anIndex][OpenGl_RT_uLightAmbnt] = - aShaderProgram->GetUniformLocation (myGlContext, "uGlobalAmbient"); - - myUniformLocations[anIndex][OpenGl_RT_uOffsetX] = - aShaderProgram->GetUniformLocation (myGlContext, "uOffsetX"); - myUniformLocations[anIndex][OpenGl_RT_uOffsetY] = - aShaderProgram->GetUniformLocation (myGlContext, "uOffsetY"); - myUniformLocations[anIndex][OpenGl_RT_uSamples] = - aShaderProgram->GetUniformLocation (myGlContext, "uSamples"); - myUniformLocations[anIndex][OpenGl_RT_uWinSizeX] = - aShaderProgram->GetUniformLocation (myGlContext, "uWinSizeX"); - myUniformLocations[anIndex][OpenGl_RT_uWinSizeY] = - aShaderProgram->GetUniformLocation (myGlContext, "uWinSizeY"); - - myUniformLocations[anIndex][OpenGl_RT_uTextures] = - aShaderProgram->GetUniformLocation (myGlContext, "uTextureSamplers"); - - myUniformLocations[anIndex][OpenGl_RT_uShadEnabled] = - aShaderProgram->GetUniformLocation (myGlContext, "uShadowsEnable"); - myUniformLocations[anIndex][OpenGl_RT_uReflEnabled] = - aShaderProgram->GetUniformLocation (myGlContext, "uReflectionsEnable"); - myUniformLocations[anIndex][OpenGl_RT_uEnvMapEnable] = - aShaderProgram->GetUniformLocation (myGlContext, "uEnvironmentEnable"); - } - - myGlContext->BindProgram (NULL); - } - - if (myComputeInitStatus != OpenGl_RT_NONE) - { - return myComputeInitStatus == OpenGl_RT_INIT; - } - - if (myRaytraceFBO1.IsNull()) - { - myRaytraceFBO1 = new OpenGl_FrameBuffer; - } - - if (myRaytraceFBO2.IsNull()) - { - myRaytraceFBO2 = new OpenGl_FrameBuffer; - } - - const GLfloat aVertices[] = { -1.f, -1.f, 0.f, - -1.f, 1.f, 0.f, - 1.f, 1.f, 0.f, - 1.f, 1.f, 0.f, - 1.f, -1.f, 0.f, - -1.f, -1.f, 0.f }; - - myRaytraceScreenQuad.Init (myGlContext, 3, 6, aVertices); - - myComputeInitStatus = OpenGl_RT_INIT; // initialized in normal way - - return Standard_True; -} - -// ======================================================================= -// function : NullifyResource -// purpose : -// ======================================================================= -inline void NullifyResource (const Handle(OpenGl_Context)& theContext, - Handle(OpenGl_Resource)& theResource) -{ - if (!theResource.IsNull()) - { - theResource->Release (theContext.operator->()); - theResource.Nullify(); - } -} - -// ======================================================================= -// function : ReleaseRaytraceResources -// purpose : Releases OpenGL/GLSL shader programs -// ======================================================================= -void OpenGl_Workspace::ReleaseRaytraceResources() -{ - NullifyResource (myGlContext, myOpenGlFBO); - NullifyResource (myGlContext, myRaytraceFBO1); - NullifyResource (myGlContext, myRaytraceFBO2); - - NullifyResource (myGlContext, myRaytraceShader); - NullifyResource (myGlContext, myPostFSAAShader); - - NullifyResource (myGlContext, myRaytraceProgram); - NullifyResource (myGlContext, myPostFSAAProgram); - - NullifyResource (myGlContext, mySceneNodeInfoTexture); - NullifyResource (myGlContext, mySceneMinPointTexture); - NullifyResource (myGlContext, mySceneMaxPointTexture); - - NullifyResource (myGlContext, myGeometryVertexTexture); - NullifyResource (myGlContext, myGeometryNormalTexture); - NullifyResource (myGlContext, myGeometryTexCrdTexture); - NullifyResource (myGlContext, myGeometryTriangTexture); - NullifyResource (myGlContext, mySceneTransformTexture); - - NullifyResource (myGlContext, myRaytraceLightSrcTexture); - NullifyResource (myGlContext, myRaytraceMaterialTexture); - - if (myRaytraceScreenQuad.IsValid()) - myRaytraceScreenQuad.Release (myGlContext.operator->()); -} - -// ======================================================================= -// function : UploadRaytraceData -// purpose : Uploads ray-trace data to the GPU -// ======================================================================= -Standard_Boolean OpenGl_Workspace::UploadRaytraceData() -{ - if (!myGlContext->IsGlGreaterEqual (3, 1)) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: OpenGL version is less than 3.1" << std::endl; -#endif - return Standard_False; - } - - ///////////////////////////////////////////////////////////////////////////// - // Prepare OpenGL textures - - if (myGlContext->arbTexBindless != NULL) - { - // If OpenGL driver supports bindless textures we need - // to get unique 64- bit handles for using on the GPU - if (!myRaytraceGeometry.UpdateTextureHandles (myGlContext)) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to get OpenGL texture handles" << std::endl; -#endif - return Standard_False; - } - } - - ///////////////////////////////////////////////////////////////////////////// - // Create OpenGL BVH buffers - - if (mySceneNodeInfoTexture.IsNull()) // create scene BVH buffers - { - mySceneNodeInfoTexture = new OpenGl_TextureBufferArb; - mySceneMinPointTexture = new OpenGl_TextureBufferArb; - mySceneMaxPointTexture = new OpenGl_TextureBufferArb; - mySceneTransformTexture = new OpenGl_TextureBufferArb; - - if (!mySceneNodeInfoTexture->Create (myGlContext) - || !mySceneMinPointTexture->Create (myGlContext) - || !mySceneMaxPointTexture->Create (myGlContext) - || !mySceneTransformTexture->Create (myGlContext)) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to create scene BVH buffers" << std::endl; -#endif - return Standard_False; - } - } - - if (myGeometryVertexTexture.IsNull()) // create geometry buffers - { - myGeometryVertexTexture = new OpenGl_TextureBufferArb; - myGeometryNormalTexture = new OpenGl_TextureBufferArb; - myGeometryTexCrdTexture = new OpenGl_TextureBufferArb; - myGeometryTriangTexture = new OpenGl_TextureBufferArb; - - if (!myGeometryVertexTexture->Create (myGlContext) - || !myGeometryNormalTexture->Create (myGlContext) - || !myGeometryTexCrdTexture->Create (myGlContext) - || !myGeometryTriangTexture->Create (myGlContext)) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to create buffers for triangulation data" << std::endl; -#endif - return Standard_False; - } - } - - if (myRaytraceMaterialTexture.IsNull()) // create material buffer - { - myRaytraceMaterialTexture = new OpenGl_TextureBufferArb; - - if (!myRaytraceMaterialTexture->Create (myGlContext)) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to create buffers for material data" << std::endl; -#endif - return Standard_False; - } - } - - ///////////////////////////////////////////////////////////////////////////// - // Write transform buffer - - BVH_Mat4f* aNodeTransforms = new BVH_Mat4f[myRaytraceGeometry.Size()]; - - bool aResult = true; - - for (Standard_Integer anElemIndex = 0; anElemIndex < myRaytraceGeometry.Size(); ++anElemIndex) - { - OpenGl_TriangleSet* aTriangleSet = dynamic_cast ( - myRaytraceGeometry.Objects().ChangeValue (anElemIndex).operator->()); - - const BVH_Transform* aTransform = - dynamic_cast* > (aTriangleSet->Properties().operator->()); - - Standard_ASSERT_RETURN (aTransform != NULL, - "OpenGl_TriangleSet does not contain transform", Standard_False); - - aNodeTransforms[anElemIndex] = aTransform->Inversed(); - } - - aResult &= mySceneTransformTexture->Init (myGlContext, 4, - myRaytraceGeometry.Size() * 4, reinterpret_cast (aNodeTransforms)); - - delete [] aNodeTransforms; - - ///////////////////////////////////////////////////////////////////////////// - // Write geometry and bottom-level BVH buffers - - Standard_Size aTotalVerticesNb = 0; - Standard_Size aTotalElementsNb = 0; - Standard_Size aTotalBVHNodesNb = 0; - - for (Standard_Integer anElemIndex = 0; anElemIndex < myRaytraceGeometry.Size(); ++anElemIndex) - { - OpenGl_TriangleSet* aTriangleSet = dynamic_cast ( - myRaytraceGeometry.Objects().ChangeValue (anElemIndex).operator->()); - - Standard_ASSERT_RETURN (aTriangleSet != NULL, - "Error: Failed to get triangulation of OpenGL element", Standard_False); - - aTotalVerticesNb += aTriangleSet->Vertices.size(); - aTotalElementsNb += aTriangleSet->Elements.size(); - - Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(), - "Error: Failed to get bottom-level BVH of OpenGL element", Standard_False); - - aTotalBVHNodesNb += aTriangleSet->BVH()->NodeInfoBuffer().size(); - } - - aTotalBVHNodesNb += myRaytraceGeometry.BVH()->NodeInfoBuffer().size(); - - if (aTotalBVHNodesNb != 0) - { - aResult &= mySceneNodeInfoTexture->Init ( - myGlContext, 4, GLsizei (aTotalBVHNodesNb), static_cast (NULL)); - aResult &= mySceneMinPointTexture->Init ( - myGlContext, 3, GLsizei (aTotalBVHNodesNb), static_cast (NULL)); - aResult &= mySceneMaxPointTexture->Init ( - myGlContext, 3, GLsizei (aTotalBVHNodesNb), static_cast (NULL)); - } - - if (!aResult) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to upload buffers for bottom-level scene BVH" << std::endl; -#endif - return Standard_False; - } - - if (aTotalElementsNb != 0) - { - aResult &= myGeometryTriangTexture->Init ( - myGlContext, 4, GLsizei (aTotalElementsNb), static_cast (NULL)); - } - - if (aTotalVerticesNb != 0) - { - aResult &= myGeometryVertexTexture->Init ( - myGlContext, 3, GLsizei (aTotalVerticesNb), static_cast (NULL)); - aResult &= myGeometryNormalTexture->Init ( - myGlContext, 3, GLsizei (aTotalVerticesNb), static_cast (NULL)); - aResult &= myGeometryTexCrdTexture->Init ( - myGlContext, 2, GLsizei (aTotalVerticesNb), static_cast (NULL)); - } - - if (!aResult) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to upload buffers for scene geometry" << std::endl; -#endif - return Standard_False; - } - - const NCollection_Handle >& aBVH = myRaytraceGeometry.BVH(); - const Standard_Integer aBvhLength = aBVH->Length(); - if (aBvhLength > 0) - { - aResult &= mySceneNodeInfoTexture->SubData (myGlContext, 0, aBVH->Length(), - reinterpret_cast (&aBVH->NodeInfoBuffer().front())); - aResult &= mySceneMinPointTexture->SubData (myGlContext, 0, aBVH->Length(), - reinterpret_cast (&aBVH->MinPointBuffer().front())); - aResult &= mySceneMaxPointTexture->SubData (myGlContext, 0, aBVH->Length(), - reinterpret_cast (&aBVH->MaxPointBuffer().front())); - } - - for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx) - { - if (!aBVH->IsOuter (aNodeIdx)) - continue; - - OpenGl_TriangleSet* aTriangleSet = myRaytraceGeometry.TriangleSet (aNodeIdx); - - Standard_ASSERT_RETURN (aTriangleSet != NULL, - "Error: Failed to get triangulation of OpenGL element", Standard_False); - - Standard_Integer aBVHOffset = myRaytraceGeometry.AccelerationOffset (aNodeIdx); - - Standard_ASSERT_RETURN (aBVHOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET, - "Error: Failed to get offset for bottom-level BVH", Standard_False); - - const Standard_Integer aBvhBuffersSize = aTriangleSet->BVH()->Length(); - - if (aBvhBuffersSize != 0) - { - aResult &= mySceneNodeInfoTexture->SubData (myGlContext, aBVHOffset, aBvhBuffersSize, - reinterpret_cast (&aTriangleSet->BVH()->NodeInfoBuffer().front())); - aResult &= mySceneMinPointTexture->SubData (myGlContext, aBVHOffset, aBvhBuffersSize, - reinterpret_cast (&aTriangleSet->BVH()->MinPointBuffer().front())); - aResult &= mySceneMaxPointTexture->SubData (myGlContext, aBVHOffset, aBvhBuffersSize, - reinterpret_cast (&aTriangleSet->BVH()->MaxPointBuffer().front())); - if (!aResult) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to upload buffers for bottom-level scene BVHs" << std::endl; -#endif - return Standard_False; - } - } - - const Standard_Integer aVerticesOffset = myRaytraceGeometry.VerticesOffset (aNodeIdx); - - Standard_ASSERT_RETURN (aVerticesOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET, - "Error: Failed to get offset for triangulation vertices of OpenGL element", Standard_False); - - if (!aTriangleSet->Vertices.empty()) - { - aResult &= myGeometryNormalTexture->SubData (myGlContext, aVerticesOffset, GLsizei (aTriangleSet->Normals.size()), - reinterpret_cast (&aTriangleSet->Normals.front())); - aResult &= myGeometryTexCrdTexture->SubData (myGlContext, aVerticesOffset, GLsizei (aTriangleSet->TexCrds.size()), - reinterpret_cast (&aTriangleSet->TexCrds.front())); - aResult &= myGeometryVertexTexture->SubData (myGlContext, aVerticesOffset, GLsizei (aTriangleSet->Vertices.size()), - reinterpret_cast (&aTriangleSet->Vertices.front())); - } - - const Standard_Integer anElementsOffset = myRaytraceGeometry.ElementsOffset (aNodeIdx); - - Standard_ASSERT_RETURN (anElementsOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET, - "Error: Failed to get offset for triangulation elements of OpenGL element", Standard_False); - - if (!aTriangleSet->Elements.empty()) - { - aResult &= myGeometryTriangTexture->SubData (myGlContext, anElementsOffset, GLsizei (aTriangleSet->Elements.size()), - reinterpret_cast (&aTriangleSet->Elements.front())); - } - - if (!aResult) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to upload triangulation buffers for OpenGL element" << std::endl; -#endif - return Standard_False; - } - } - - ///////////////////////////////////////////////////////////////////////////// - // Write material buffer - - if (myRaytraceGeometry.Materials.size() != 0) - { - aResult &= myRaytraceMaterialTexture->Init (myGlContext, 4, - GLsizei (myRaytraceGeometry.Materials.size() * 11), myRaytraceGeometry.Materials.front().Packed()); - - if (!aResult) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Error: Failed to upload material buffer" << std::endl; -#endif - return Standard_False; - } - } - - myIsRaytraceDataValid = myRaytraceGeometry.Objects().Size() != 0; - -#ifdef RAY_TRACE_PRINT_INFO - - Standard_ShortReal aMemUsed = 0.f; - - for (Standard_Integer anElemIdx = 0; anElemIdx < myRaytraceGeometry.Size(); ++anElemIdx) - { - OpenGl_TriangleSet* aTriangleSet = dynamic_cast ( - myRaytraceGeometry.Objects().ChangeValue (anElemIdx).operator->()); - - aMemUsed += static_cast ( - aTriangleSet->Vertices.size() * sizeof (BVH_Vec3f)); - aMemUsed += static_cast ( - aTriangleSet->Normals.size() * sizeof (BVH_Vec3f)); - aMemUsed += static_cast ( - aTriangleSet->TexCrds.size() * sizeof (BVH_Vec2f)); - aMemUsed += static_cast ( - aTriangleSet->Elements.size() * sizeof (BVH_Vec4i)); - - aMemUsed += static_cast ( - aTriangleSet->BVH()->NodeInfoBuffer().size() * sizeof (BVH_Vec4i)); - aMemUsed += static_cast ( - aTriangleSet->BVH()->MinPointBuffer().size() * sizeof (BVH_Vec3f)); - aMemUsed += static_cast ( - aTriangleSet->BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec3f)); - } - - aMemUsed += static_cast ( - myRaytraceGeometry.BVH()->NodeInfoBuffer().size() * sizeof (BVH_Vec4i)); - aMemUsed += static_cast ( - myRaytraceGeometry.BVH()->MinPointBuffer().size() * sizeof (BVH_Vec3f)); - aMemUsed += static_cast ( - myRaytraceGeometry.BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec3f)); - - std::cout << "GPU Memory Used (MB): ~" << aMemUsed / 1048576 << std::endl; - -#endif - - return aResult; -} - -// ======================================================================= -// function : ResizeRaytraceBuffers -// purpose : Resizes OpenGL frame buffers -// ======================================================================= -Standard_Boolean OpenGl_Workspace::ResizeRaytraceBuffers (const Standard_Integer theSizeX, - const Standard_Integer theSizeY) -{ - if (myRaytraceFBO1->GetVPSizeX() != theSizeX - || myRaytraceFBO1->GetVPSizeY() != theSizeY) - { - myRaytraceFBO1->Init (myGlContext, theSizeX, theSizeY); - myRaytraceFBO2->Init (myGlContext, theSizeX, theSizeY); - } - - return Standard_True; -} - -// ======================================================================= -// function : UpdateCamera -// purpose : Generates viewing rays for corners of screen quad -// ======================================================================= -void OpenGl_Workspace::UpdateCamera (const OpenGl_Mat4& theOrientation, - const OpenGl_Mat4& theViewMapping, - OpenGl_Vec3 theOrigins[4], - OpenGl_Vec3 theDirects[4], - OpenGl_Mat4& theInvModelProj) -{ - // compute inverse model-view-projection matrix - (theViewMapping * theOrientation).Inverted (theInvModelProj); - - Standard_Integer aOriginIndex = 0; - Standard_Integer aDirectIndex = 0; - - for (Standard_Integer aY = -1; aY <= 1; aY += 2) - { - for (Standard_Integer aX = -1; aX <= 1; aX += 2) - { - OpenGl_Vec4 aOrigin (GLfloat(aX), - GLfloat(aY), - -1.0f, - 1.0f); - - aOrigin = theInvModelProj * aOrigin; - - aOrigin.x() = aOrigin.x() / aOrigin.w(); - aOrigin.y() = aOrigin.y() / aOrigin.w(); - aOrigin.z() = aOrigin.z() / aOrigin.w(); - - OpenGl_Vec4 aDirect (GLfloat(aX), - GLfloat(aY), - 1.0f, - 1.0f); - - aDirect = theInvModelProj * aDirect; - - aDirect.x() = aDirect.x() / aDirect.w(); - aDirect.y() = aDirect.y() / aDirect.w(); - aDirect.z() = aDirect.z() / aDirect.w(); - - aDirect = aDirect - aOrigin; - - GLdouble aInvLen = 1.0 / sqrt (aDirect.x() * aDirect.x() + - aDirect.y() * aDirect.y() + - aDirect.z() * aDirect.z()); - - theOrigins[aOriginIndex++] = OpenGl_Vec3 (static_cast (aOrigin.x()), - static_cast (aOrigin.y()), - static_cast (aOrigin.z())); - - theDirects[aDirectIndex++] = OpenGl_Vec3 (static_cast (aDirect.x() * aInvLen), - static_cast (aDirect.y() * aInvLen), - static_cast (aDirect.z() * aInvLen)); - } - } -} - -// ======================================================================= -// function : SetUniformState -// purpose : Sets uniform state for the given ray-tracing shader program -// ======================================================================= -Standard_Boolean OpenGl_Workspace::SetUniformState (const Graphic3d_CView& theCView, - const Standard_Integer theSizeX, - const Standard_Integer theSizeY, - const OpenGl_Vec3* theOrigins, - const OpenGl_Vec3* theDirects, - const OpenGl_Mat4& theUnviewMat, - const Standard_Integer theProgramIndex, - Handle(OpenGl_ShaderProgram)& theRaytraceProgram) -{ - if (theRaytraceProgram.IsNull()) - { - return Standard_False; - } - - Standard_Integer aLightSourceBufferSize = - static_cast (myRaytraceGeometry.Sources.size()); - - Standard_Boolean aResult = Standard_True; - - // Set camera state - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uOriginLB], theOrigins[0]); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uOriginRB], theOrigins[1]); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uOriginLT], theOrigins[2]); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uOriginRT], theOrigins[3]); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uDirectLB], theDirects[0]); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uDirectRB], theDirects[1]); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uDirectLT], theDirects[2]); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uDirectRT], theDirects[3]); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uUnviewMat], theUnviewMat); - - // Set window size - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uWinSizeX], theSizeX); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uWinSizeY], theSizeY); - - // Set scene parameters - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uSceneRad], myRaytraceSceneRadius); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uSceneEps], myRaytraceSceneEpsilon); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uLightCount], aLightSourceBufferSize); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uLightAmbnt], myRaytraceGeometry.Ambient); - - // Set rendering options - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uShadEnabled], theCView.RenderParams.IsShadowEnabled ? 1 : 0); - aResult &= theRaytraceProgram->SetUniform (myGlContext, - myUniformLocations[theProgramIndex][OpenGl_RT_uReflEnabled], theCView.RenderParams.IsReflectionEnabled ? 1 : 0); - - // Set array of 64-bit texture handles - if (myGlContext->arbTexBindless != NULL && myRaytraceGeometry.HasTextures()) - { - aResult &= theRaytraceProgram->SetUniform (myGlContext, "uTextureSamplers", - static_cast (myRaytraceGeometry.TextureHandles().size()), &myRaytraceGeometry.TextureHandles()[0]); - } - - if (!aResult) - { -#ifdef RAY_TRACE_PRINT_INFO - std::cout << "Info: Not all uniforms were detected (for program " << theProgramIndex << ")" << std::endl; -#endif - } - - return aResult; -} - -// ======================================================================= -// function : RunRaytraceShaders -// purpose : Runs ray-tracing shader programs -// ======================================================================= -Standard_Boolean OpenGl_Workspace::RunRaytraceShaders (const Graphic3d_CView& theCView, - const Standard_Integer theSizeX, - const Standard_Integer theSizeY, - const OpenGl_Vec3 theOrigins[4], - const OpenGl_Vec3 theDirects[4], - const OpenGl_Mat4& theUnviewMat, - OpenGl_FrameBuffer* theFrameBuffer) -{ - mySceneMinPointTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMinPointTexture); - mySceneMaxPointTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMaxPointTexture); - mySceneNodeInfoTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneNodeInfoTexture); - myGeometryVertexTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryVertexTexture); - myGeometryNormalTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryNormalTexture); - myGeometryTexCrdTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTexCrdTexture); - myGeometryTriangTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture); - mySceneTransformTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture); - myRaytraceMaterialTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture); - myRaytraceLightSrcTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture); - - myOpenGlFBO->ColorTexture()->Bind (myGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlColorTexture); - myOpenGlFBO->DepthStencilTexture()->Bind (myGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlDepthTexture); - - if (theCView.RenderParams.IsAntialiasingEnabled) // render source image to FBO - { - myRaytraceFBO1->BindBuffer (myGlContext); - - glDisable (GL_BLEND); - } - - myGlContext->BindProgram (myRaytraceProgram); - - SetUniformState (theCView, - theSizeX, - theSizeY, - theOrigins, - theDirects, - theUnviewMat, - 0, // ID of RT program - myRaytraceProgram); - - myGlContext->core20fwd->glEnableVertexAttribArray (Graphic3d_TOA_POS); - { - myGlContext->core20fwd->glVertexAttribPointer (Graphic3d_TOA_POS, 3, GL_FLOAT, GL_FALSE, 0, NULL); - myGlContext->core15fwd->glDrawArrays (GL_TRIANGLES, 0, 6); - } - myGlContext->core20fwd->glDisableVertexAttribArray (Graphic3d_TOA_POS); - - if (!theCView.RenderParams.IsAntialiasingEnabled) - { - myGlContext->BindProgram (NULL); - - myOpenGlFBO->ColorTexture()->Unbind (myGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlColorTexture); - myOpenGlFBO->DepthStencilTexture()->Unbind (myGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlDepthTexture); - mySceneMinPointTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMinPointTexture); - mySceneMaxPointTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMaxPointTexture); - mySceneNodeInfoTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneNodeInfoTexture); - myGeometryVertexTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryVertexTexture); - myGeometryNormalTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryNormalTexture); - myGeometryTexCrdTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTexCrdTexture); - myGeometryTriangTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture); - mySceneTransformTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture); - myRaytraceMaterialTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture); - myRaytraceLightSrcTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture); - - myGlContext->core15fwd->glActiveTexture (GL_TEXTURE0); - - return Standard_True; - } - - myRaytraceFBO1->ColorTexture()->Bind (myGlContext, GL_TEXTURE0 + OpenGl_RT_FSAAInputTexture); - - myGlContext->BindProgram (myPostFSAAProgram); - - SetUniformState (theCView, - theSizeX, - theSizeY, - theOrigins, - theDirects, - theUnviewMat, - 1, // ID of FSAA program - myPostFSAAProgram); - - myGlContext->core20fwd->glEnableVertexAttribArray (Graphic3d_TOA_POS); - myGlContext->core20fwd->glVertexAttribPointer (Graphic3d_TOA_POS, 3, GL_FLOAT, GL_FALSE, 0, NULL); - - // Perform multi-pass adaptive FSAA using ping-pong technique. - // We use 'FLIPTRI' sampling pattern changing for every pixel - // (3 additional samples per pixel, the 1st sample is already - // available from initial ray-traced image). - for (Standard_Integer anIt = 1; anIt < 4; ++anIt) - { - GLfloat aOffsetX = 1.f / theSizeX; - GLfloat aOffsetY = 1.f / theSizeY; - - if (anIt == 1) - { - aOffsetX *= -0.55f; - aOffsetY *= 0.55f; - } - else if (anIt == 2) - { - aOffsetX *= 0.00f; - aOffsetY *= -0.55f; - } - else if (anIt == 3) - { - aOffsetX *= 0.55f; - aOffsetY *= 0.00f; - } - - myPostFSAAProgram->SetUniform (myGlContext, - myUniformLocations[1][OpenGl_RT_uSamples], anIt + 1); - myPostFSAAProgram->SetUniform (myGlContext, - myUniformLocations[1][OpenGl_RT_uOffsetX], aOffsetX); - myPostFSAAProgram->SetUniform (myGlContext, - myUniformLocations[1][OpenGl_RT_uOffsetY], aOffsetY); - - Handle(OpenGl_FrameBuffer)& aFramebuffer = anIt % 2 ? myRaytraceFBO2 : myRaytraceFBO1; - - if (anIt == 3) // disable FBO on last iteration - { - glEnable (GL_BLEND); - - if (theFrameBuffer != NULL) - theFrameBuffer->BindBuffer (myGlContext); - } - else - { - aFramebuffer->BindBuffer (myGlContext); - } - - myGlContext->core15fwd->glDrawArrays (GL_TRIANGLES, 0, 6); - - if (anIt != 3) // set input for the next pass - { - aFramebuffer->ColorTexture()->Bind (myGlContext, GL_TEXTURE0 + OpenGl_RT_FSAAInputTexture); - aFramebuffer->UnbindBuffer (myGlContext); - } - } - - myGlContext->core20fwd->glDisableVertexAttribArray (Graphic3d_TOA_POS); - - myGlContext->BindProgram (NULL); - myRaytraceFBO1->ColorTexture()->Unbind (myGlContext, GL_TEXTURE0 + OpenGl_RT_FSAAInputTexture); - myOpenGlFBO->ColorTexture()->Unbind (myGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlColorTexture); - myOpenGlFBO->DepthStencilTexture()->Unbind (myGlContext, GL_TEXTURE0 + OpenGl_RT_OpenGlDepthTexture); - mySceneMinPointTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMinPointTexture); - mySceneMaxPointTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMaxPointTexture); - mySceneNodeInfoTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneNodeInfoTexture); - myGeometryVertexTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryVertexTexture); - myGeometryNormalTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryNormalTexture); - myGeometryTexCrdTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTexCrdTexture); - myGeometryTriangTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture); - mySceneTransformTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture); - myRaytraceMaterialTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture); - myRaytraceLightSrcTexture->UnbindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture); - - myGlContext->core15fwd->glActiveTexture (GL_TEXTURE0); - - return Standard_True; -} - -// ======================================================================= -// function : Raytrace -// purpose : Redraws the window using OpenGL/GLSL ray-tracing -// ======================================================================= -Standard_Boolean OpenGl_Workspace::Raytrace (const Graphic3d_CView& theCView, - const Standard_Integer theSizeX, - const Standard_Integer theSizeY, - const Aspect_CLayer2d& theCOverLayer, - const Aspect_CLayer2d& theCUnderLayer, - OpenGl_FrameBuffer* theFrameBuffer) -{ - if (!ResizeRaytraceBuffers (theSizeX, theSizeY)) - return Standard_False; - - if (!UpdateRaytraceEnvironmentMap()) - return Standard_False; - - // Get model-view and projection matrices - OpenGl_Mat4 aOrientationMatrix; - OpenGl_Mat4 aViewMappingMatrix; - - myView->GetMatrices (aOrientationMatrix, - aViewMappingMatrix); - - OpenGl_Mat4 aInvOrientationMatrix; - aOrientationMatrix.Inverted (aInvOrientationMatrix); - - if (!UpdateRaytraceLightSources (aInvOrientationMatrix)) - return Standard_False; - - OpenGl_Vec3 aOrigins[4]; - OpenGl_Vec3 aDirects[4]; - OpenGl_Mat4 anUnviewMat; - - UpdateCamera (aOrientationMatrix, - aViewMappingMatrix, - aOrigins, - aDirects, - anUnviewMat); - - Standard_Boolean wasBlendingEnabled = glIsEnabled (GL_BLEND); - Standard_Boolean wasDepthTestEnabled = glIsEnabled (GL_DEPTH_TEST); - - glDisable (GL_DEPTH_TEST); - - if (theFrameBuffer != NULL) - { - theFrameBuffer->BindBuffer (myGlContext); - } - - if (NamedStatus & OPENGL_NS_WHITEBACK) - { - glClearColor (1.0f, 1.0f, 1.0f, 1.0f); - } - else - { - glClearColor (myBgColor.rgb[0], - myBgColor.rgb[1], - myBgColor.rgb[2], - 1.0f); - } - - glClear (GL_COLOR_BUFFER_BIT); - - myView->DrawBackground (this); - - myView->RedrawLayer2d (myPrintContext, this, theCView, theCUnderLayer); - - myGlContext->WorldViewState.Push(); - myGlContext->ProjectionState.Push(); - - myGlContext->WorldViewState.SetIdentity(); - myGlContext->ProjectionState.SetIdentity(); - - myGlContext->ApplyProjectionMatrix(); - myGlContext->ApplyWorldViewMatrix(); - - glEnable (GL_BLEND); - glBlendFunc (GL_ONE, GL_SRC_ALPHA); - - // Generate ray-traced image - if (myIsRaytraceDataValid) - { - myRaytraceScreenQuad.Bind (myGlContext); - - if (!myRaytraceGeometry.AcquireTextures (myGlContext)) - { - const TCollection_ExtendedString aMessage = "Error: Failed to acquire OpenGL image textures"; - - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_MEDIUM_ARB, aMessage); - } - - RunRaytraceShaders (theCView, - theSizeX, - theSizeY, - aOrigins, - aDirects, - anUnviewMat, - theFrameBuffer); - - if (!myRaytraceGeometry.ReleaseTextures (myGlContext)) - { - const TCollection_ExtendedString aMessage = "Error: Failed to release OpenGL image textures"; - - myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB, - GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_MEDIUM_ARB, aMessage); - } - - myRaytraceScreenQuad.Unbind (myGlContext); - } - - if (!wasBlendingEnabled) - glDisable (GL_BLEND); - - if (wasDepthTestEnabled) - glEnable (GL_DEPTH_TEST); - - myGlContext->WorldViewState.Pop(); - myGlContext->ProjectionState.Pop(); - - myGlContext->ApplyProjectionMatrix(); - - // Redraw trihedron - myView->RedrawTrihedron (this); - - // Redraw overlay - const int aMode = 0; - DisplayCallback (theCView, (aMode | OCC_PRE_OVERLAY)); - myView->RedrawLayer2d (myPrintContext, this, theCView, theCOverLayer); - DisplayCallback (theCView, aMode); - return Standard_True; -} - -IMPLEMENT_STANDARD_HANDLE(OpenGl_RaytraceFilter, OpenGl_RenderFilter) -IMPLEMENT_STANDARD_RTTIEXT(OpenGl_RaytraceFilter, OpenGl_RenderFilter) - -// ======================================================================= -// function : CanRender -// purpose : -// ======================================================================= -Standard_Boolean OpenGl_RaytraceFilter::CanRender (const OpenGl_Element* theElement) -{ - Standard_Boolean aPrevFilterResult = Standard_True; - if (!myPrevRenderFilter.IsNull()) - { - aPrevFilterResult = myPrevRenderFilter->CanRender(theElement); - } - return aPrevFilterResult && - !OpenGl_Raytrace::IsRaytracedElement (theElement); -}