Introduced V3d_View::SkydomeAspect() property for generating skydome cubemap environment.
Skydome features: day/night cycle, 2 types of clouds, atmosphere, water surface, stars, fog.
--- /dev/null
+// Created on: 2021-10-14
+// Created by: Artem CHESNOKOV
+// Copyright (c) 2021 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 <Aspect_SkydomeBackground.hxx>
+
+#include <Standard_RangeError.hxx>
+
+// =======================================================================
+// function : Constructor
+// purpose :
+// =======================================================================
+Aspect_SkydomeBackground::Aspect_SkydomeBackground()
+: mySunDirection (0.0f, 1.0f, 0.0f),
+ myCloudiness (0.2f),
+ myTime (0.0f),
+ myFogginess (0.0f),
+ mySize (512)
+{
+ //
+}
+
+// =======================================================================
+// function : Constructor
+// purpose :
+// =======================================================================
+Aspect_SkydomeBackground::Aspect_SkydomeBackground (const gp_Dir& theSunDirection, Standard_ShortReal theCloudiness,
+ Standard_ShortReal theTime, Standard_ShortReal theFogginess, Standard_Integer theSize)
+ : mySunDirection (theSunDirection), myCloudiness (theCloudiness), myTime (theTime), myFogginess (theFogginess), mySize (theSize)
+{
+ Standard_RangeError_Raise_if (theFogginess < 0, "Aspect_SkydomeBackground::Aspect_SkydomeBackground() theFoggines must be >= 0");
+ Standard_RangeError_Raise_if (theCloudiness < 0, "Aspect_SkydomeBackground::Aspect_SkydomeBackground() theCloudiness must be >= 0");
+ Standard_RangeError_Raise_if (theSize <= 0, "Aspect_SkydomeBackground::Aspect_SkydomeBackground() theSize must be > 0");
+}
+
+// =======================================================================
+// function : ~Aspect_SkydomeBackground
+// purpose :
+// =======================================================================
+Aspect_SkydomeBackground::~Aspect_SkydomeBackground()
+{
+ //
+}
+
+// =======================================================================
+// function : SetCloudiness
+// purpose :
+// =======================================================================
+void Aspect_SkydomeBackground::SetCloudiness (Standard_ShortReal theCloudiness)
+{
+ Standard_RangeError_Raise_if (theCloudiness < 0, "Aspect_SkydomeBackground::SetCloudiness() theCloudiness must be >= 0");
+ myCloudiness = theCloudiness;
+}
+
+// =======================================================================
+// function : SetFogginess
+// purpose :
+// =======================================================================
+void Aspect_SkydomeBackground::SetFogginess (Standard_ShortReal theFogginess)
+{
+ Standard_RangeError_Raise_if (theFogginess < 0, "Aspect_SkydomeBackground::SetFogginess() theFoggines must be >= 0");
+ myFogginess = theFogginess;
+}
+
+// =======================================================================
+// function : SetSize
+// purpose :
+// =======================================================================
+void Aspect_SkydomeBackground::SetSize (Standard_Integer theSize)
+{
+ Standard_RangeError_Raise_if (theSize <= 0, "Aspect_SkydomeBackground::SetSize() theSize must be > 0");
+ mySize = theSize;
+}
+
+// =======================================================================
+// function : DumpJson
+// purpose :
+// =======================================================================
+void Aspect_SkydomeBackground::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
+{
+ OCCT_DUMP_CLASS_BEGIN (theOStream, Aspect_GradientBackground)
+
+ OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &mySunDirection)
+ OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTime)
+ OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myFogginess)
+ OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myCloudiness)
+ OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, mySize)
+}
--- /dev/null
+// Created on: 2021-10-14
+// Created by: Artem CHESNOKOV
+// Copyright (c) 2021 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 _Aspect_SkydomeBackground_Header
+#define _Aspect_SkydomeBackground_Header
+
+#include <gp_Dir.hxx>
+#include <Graphic3d_Vec3.hxx>
+#include <Standard.hxx>
+#include <Standard_DefineAlloc.hxx>
+#include <Standard_Handle.hxx>
+
+//! This class allows the definition of a window skydome background.
+class Aspect_SkydomeBackground
+{
+public:
+
+ DEFINE_STANDARD_ALLOC
+
+ //! Creates a window skydome background.
+ //! By default skydome is initialized with sun at its zenith (0.0, 1.0, 0.0),
+ //! average clody (0.2), zero time parameter, zero fogginess, 512x512 texture size.
+ Standard_EXPORT Aspect_SkydomeBackground();
+
+ //! Creates a window skydome background with given parameters.
+ //! @param[in] theSunDirection direction to the sun (moon). Sun direction with negative Y component
+ //! represents moon with (-X, -Y, -Z) direction.
+ //! @param[in] theCloudiness cloud intensity, 0.0 means no clouds at all and 1.0 - high clody.
+ //! @param[in] theTime time parameter of simulation. Might be tweaked to slightly change appearance.
+ //! @param[in] theFogginess fog intensity, 0.0 means no fog and 1.0 - high fogginess
+ //! @param[in] theSize size of cubemap side in pixels.
+ Standard_EXPORT Aspect_SkydomeBackground (const gp_Dir& theSunDirection,
+ Standard_ShortReal theCloudiness,
+ Standard_ShortReal theTime,
+ Standard_ShortReal theFogginess,
+ Standard_Integer theSize);
+
+ //! Destructor.
+ Standard_EXPORT ~Aspect_SkydomeBackground();
+
+ //! Get sun direction. By default this value is (0, 1, 0)
+ //! Sun direction with negative Y component represents moon with (-X, -Y, -Z) direction.
+ const gp_Dir& SunDirection() const { return mySunDirection; }
+
+ //! Get cloud intensity. By default this value is 0.2
+ //! 0.0 means no clouds at all and 1.0 - high clody.
+ Standard_ShortReal Cloudiness() const { return myCloudiness; }
+
+ //! Get time of cloud simulation. By default this value is 0.0
+ //! This value might be tweaked to slightly change appearance of clouds.
+ Standard_ShortReal TimeParameter() const { return myTime; }
+
+ //! Get fog intensity. By default this value is 0.0
+ //! 0.0 means no fog and 1.0 - high fogginess
+ Standard_ShortReal Fogginess() const { return myFogginess; }
+
+ //! Get size of cubemap. By default this value is 512
+ Standard_Integer Size() const { return mySize; }
+
+ //! Set sun direction. By default this value is (0, 1, 0)
+ //! Sun direction with negative Y component represents moon with (-X, -Y, -Z) direction.
+ void SetSunDirection (const gp_Dir& theSunDirection) { mySunDirection = theSunDirection; }
+
+ //! Set cloud intensity. By default this value is 0.2
+ //! 0.0 means no clouds at all and 1.0 - high clody.
+ Standard_EXPORT void SetCloudiness (Standard_ShortReal theCloudiness);
+
+ //! Set time of cloud simulation. By default this value is 0.0
+ //! This value might be tweaked to slightly change appearance of clouds.
+ void SetTimeParameter (Standard_ShortReal theTime) { myTime = theTime; }
+
+ //! Set fog intensity. By default this value is 0.0
+ //! 0.0 means no fog and 1.0 - high fogginess
+ Standard_EXPORT void SetFogginess (Standard_ShortReal theFogginess);
+
+ //! Set size of cubemap. By default this value is 512
+ Standard_EXPORT void SetSize (Standard_Integer theSize);
+
+ //! Dumps the content of me into the stream
+ Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
+
+private:
+
+ gp_Dir mySunDirection; //!< Sun (moon) light direction.
+ Standard_ShortReal myCloudiness; //!< Cloud intensity.
+ Standard_ShortReal myTime; //!< Simulation time parameter.
+ Standard_ShortReal myFogginess; //!< Fog intensity
+ Standard_Integer mySize; //!< Size of cubemap in pixels
+
+};
+
+#endif // _Aspect_SkydomeBackground_Header
Aspect_RenderingContext.hxx
Aspect_SequenceOfColor.hxx
Aspect_ScrollDelta.hxx
+Aspect_SkydomeBackground.cxx
+Aspect_SkydomeBackground.hxx
Aspect_Touch.hxx
Aspect_TouchMap.hxx
Aspect_TrackedDevicePose.hxx
#include <Graphic3d_CView.hxx>
#include <Aspect_OpenVRSession.hxx>
+#include <Graphic3d_CubeMapPacked.hxx>
#include <Graphic3d_Layer.hxx>
#include <Graphic3d_MapIteratorOfMapOfStructure.hxx>
#include <Graphic3d_StructureManager.hxx>
Graphic3d_CView::Graphic3d_CView (const Handle(Graphic3d_StructureManager)& theMgr)
: myBgColor (Quantity_NOC_BLACK),
myBackgroundType (Graphic3d_TOB_NONE),
+ myToUpdateSkydome (Standard_False),
myStructureManager (theMgr),
myCamera (new Graphic3d_Camera()),
myHiddenObjects (new Graphic3d_NMapOfTransient()),
}
}
+// =======================================================================
+// function : SetBackgroundSkydome
+// purpose :
+// =======================================================================
+void Graphic3d_CView::SetBackgroundSkydome (const Aspect_SkydomeBackground& theAspect,
+ Standard_Boolean theToUpdatePBREnv)
+{
+ myToUpdateSkydome = true;
+ mySkydomeAspect = theAspect;
+ myCubeMapBackground = new Graphic3d_CubeMapPacked ("");
+ SetBackgroundType (Graphic3d_TOB_CUBEMAP);
+ if (theToUpdatePBREnv
+ && !myCubeMapIBL.IsNull())
+ {
+ SetImageBasedLighting (false);
+ SetImageBasedLighting (true);
+ }
+}
+
// =======================================================================
// function : Activate
// purpose :
#include <Aspect_Handle.hxx>
#include <Aspect_RenderingContext.hxx>
+#include <Aspect_SkydomeBackground.hxx>
#include <Aspect_Window.hxx>
#include <Graphic3d_BufferType.hxx>
#include <Graphic3d_Camera.hxx>
//! Sets background type.
void SetBackgroundType (Graphic3d_TypeOfBackground theType) { myBackgroundType = theType; }
+ //! Returns skydome aspect;
+ const Aspect_SkydomeBackground& BackgroundSkydome() const { return mySkydomeAspect; }
+
+ //! Sets skydome aspect
+ Standard_EXPORT void SetBackgroundSkydome (const Aspect_SkydomeBackground& theAspect,
+ Standard_Boolean theToUpdatePBREnv = Standard_True);
+
//! Enables or disables IBL (Image Based Lighting) from background cubemap.
//! Has no effect if PBR is not used.
//! @param[in] theToEnableIBL enable or disable IBL from background cubemap
Handle(Graphic3d_CubeMap) myCubeMapIBL; //!< Cubemap used for environment lighting
Handle(Graphic3d_TextureEnv) myTextureEnvData;
Graphic3d_TypeOfBackground myBackgroundType; //!< Current type of background
+ Aspect_SkydomeBackground mySkydomeAspect;
+ Standard_Boolean myToUpdateSkydome;
Handle(Graphic3d_StructureManager) myStructureManager;
Handle(Graphic3d_Camera) myCamera;
#include "../Shaders/Shaders_PhongPointLight_glsl.pxx"
#include "../Shaders/Shaders_PhongSpotLight_glsl.pxx"
#include "../Shaders/Shaders_PointLightAttenuation_glsl.pxx"
+#include "../Shaders/Shaders_SkydomBackground_fs.pxx"
#include "../Shaders/Shaders_TangentSpaceNormal_glsl.pxx"
IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ShaderManager, Standard_Transient)
return aProgSrc;
}
+// =======================================================================
+// function : getBgSkydomeProgram
+// purpose :
+// =======================================================================
+Handle(Graphic3d_ShaderProgram) Graphic3d_ShaderManager::getBgSkydomeProgram() const
+{
+ Handle(Graphic3d_ShaderProgram) aProgSrc = new Graphic3d_ShaderProgram();
+
+ Graphic3d_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
+ aStageInOuts.Append (Graphic3d_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
+
+ TCollection_AsciiString aSrcVert = TCollection_AsciiString()
+ + EOL"void main()"
+ EOL"{"
+ EOL" gl_Position = vec4 (occVertex.xy, 0.0, 1.0);"
+ EOL" TexCoord = 0.5 * gl_Position.xy + vec2 (0.5);"
+ EOL"}";
+
+ TCollection_AsciiString aSrcFrag = Shaders_SkydomBackground_fs;
+
+ if (myGapi == Aspect_GraphicsLibrary_OpenGL)
+ {
+ aProgSrc->SetHeader ("#version 130");
+ }
+ else if (myGapi == Aspect_GraphicsLibrary_OpenGLES)
+ {
+ if (IsGapiGreaterEqual (3, 0))
+ {
+ aProgSrc->SetHeader ("#version 300 es");
+ }
+ }
+ aProgSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX, aUniforms, aStageInOuts));
+ aProgSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aSrcFrag, Graphic3d_TOS_FRAGMENT, aUniforms, aStageInOuts));
+
+ return aProgSrc;
+}
+
// =======================================================================
// function : getColoredQuadProgram
// purpose :
//! Generates shader program to render environment cubemap as background.
Standard_EXPORT Handle(Graphic3d_ShaderProgram) getBgCubeMapProgram() const;
+ //! Generates shader program to render skydome background.
+ Standard_EXPORT Handle(Graphic3d_ShaderProgram) getBgSkydomeProgram() const;
+
//! Generates shader program to render correctly colored quad.
Standard_EXPORT Handle(Graphic3d_ShaderProgram) getColoredQuadProgram() const;
return myBgCubeMapProgram;
}
+// =======================================================================
+// function : GetBgSkydomeProgram
+// purpose :
+// =======================================================================
+const Handle(Graphic3d_ShaderProgram)& OpenGl_ShaderManager::GetBgSkydomeProgram ()
+{
+ if (myBgSkydomeProgram.IsNull())
+ {
+ myBgSkydomeProgram = getBgSkydomeProgram();
+ }
+ return myBgSkydomeProgram;
+}
+
// =======================================================================
// function : GetColoredQuadProgram
// purpose :
//! Generates shader program to render environment cubemap as background.
Standard_EXPORT const Handle(Graphic3d_ShaderProgram)& GetBgCubeMapProgram();
+ //! Generates shader program to render skydome background.
+ Standard_EXPORT const Handle(Graphic3d_ShaderProgram)& GetBgSkydomeProgram();
+
//! Generates shader program to render correctly colored quad.
Standard_EXPORT const Handle(Graphic3d_ShaderProgram)& GetColoredQuadProgram();
Handle(OpenGl_ShaderProgram) myPBREnvBakingProgram[3]; //!< programs for IBL maps generation used in PBR pipeline (0 for Diffuse; 1 for Specular; 2 for fallback)
Handle(Graphic3d_ShaderProgram) myBgCubeMapProgram; //!< program for background cubemap rendering
+ Handle(Graphic3d_ShaderProgram) myBgSkydomeProgram; //!< program for background cubemap rendering
Handle(Graphic3d_ShaderProgram) myColoredQuadProgram; //!< program for correct quad rendering
Handle(OpenGl_ShaderProgram) myStereoPrograms[Graphic3d_StereoMode_NB]; //!< standard stereo programs
if (myBackgroundType == Graphic3d_TOB_CUBEMAP)
{
- myCubeMapParams->Aspect()->ShaderProgram()->PushVariableInt ("uZCoeff", myCubeMapBackground->ZIsInverted() ? -1 : 1);
- myCubeMapParams->Aspect()->ShaderProgram()->PushVariableInt ("uYCoeff", myCubeMapBackground->IsTopDown() ? 1 : -1);
- const OpenGl_Aspects* anOldAspectFace = theWorkspace->SetAspects (myCubeMapParams);
+ updateSkydomeBg (aCtx);
+ if (!myCubeMapParams->Aspect()->ShaderProgram().IsNull())
+ {
+ myCubeMapParams->Aspect()->ShaderProgram()->PushVariableInt ("uZCoeff", myCubeMapBackground->ZIsInverted() ? -1 : 1);
+ myCubeMapParams->Aspect()->ShaderProgram()->PushVariableInt ("uYCoeff", myCubeMapBackground->IsTopDown() ? 1 : -1);
+ const OpenGl_Aspects* anOldAspectFace = theWorkspace->SetAspects (myCubeMapParams);
- myBackgrounds[Graphic3d_TOB_CUBEMAP]->Render (theWorkspace, theProjection);
+ myBackgrounds[Graphic3d_TOB_CUBEMAP]->Render (theWorkspace, theProjection);
- theWorkspace->SetAspects (anOldAspectFace);
+ theWorkspace->SetAspects (anOldAspectFace);
+ }
}
else if (myBackgroundType == Graphic3d_TOB_GRADIENT
|| myBackgroundType == Graphic3d_TOB_TEXTURE)
return Standard_False;
}
+// =======================================================================
+// function : updateSkydomeBg
+// purpose :
+// =======================================================================
+void OpenGl_View::updateSkydomeBg (const Handle(OpenGl_Context)& theCtx)
+{
+ if (!myToUpdateSkydome)
+ {
+ return;
+ }
+
+ myToUpdateSkydome = false;
+
+ // Set custom shader
+ Handle(OpenGl_ShaderProgram) aProg;
+ Handle(Graphic3d_ShaderProgram) aProxy = theCtx->ShaderManager()->GetBgSkydomeProgram();
+ TCollection_AsciiString anUnused;
+ theCtx->ShaderManager()->Create (aProxy, anUnused, aProg);
+ Handle(OpenGl_ShaderProgram) aPrevProgram = theCtx->ActiveProgram();
+ theCtx->BindProgram (aProg);
+
+ // Setup uniforms
+ aProg->SetUniform (theCtx, "uSunDir", OpenGl_Vec3((float )mySkydomeAspect.SunDirection().X(),
+ (float )mySkydomeAspect.SunDirection().Y(),
+ (float )mySkydomeAspect.SunDirection().Z()));
+ aProg->SetUniform (theCtx, "uCloudy", mySkydomeAspect.Cloudiness());
+ aProg->SetUniform (theCtx, "uTime", mySkydomeAspect.TimeParameter());
+ aProg->SetUniform (theCtx, "uFog", mySkydomeAspect.Fogginess());
+
+ // Create and prepare framebuffer
+ GLint aPrevFBO = 0;
+ theCtx->core11fwd->glGetIntegerv (GL_FRAMEBUFFER_BINDING, &aPrevFBO);
+ GLuint anFBO = 0;
+ theCtx->arbFBO->glGenFramebuffers (1, &anFBO);
+ theCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, anFBO);
+
+ const Standard_Integer anOldViewport[4] = {theCtx->Viewport()[0], theCtx->Viewport()[1], theCtx->Viewport()[2], theCtx->Viewport()[3]};
+ const Standard_Integer aViewport[4] = {0, 0, mySkydomeAspect.Size(), mySkydomeAspect.Size()};
+ theCtx->ResizeViewport (aViewport);
+
+ // Fullscreen triangle
+ Handle(OpenGl_VertexBuffer) aVBO = new OpenGl_VertexBuffer();
+ const float aTriangle[] = {-1.0, -1.0, 3.0, -1.0, -1.0, 3.0};
+ aVBO->Init (theCtx, 2, 3, aTriangle);
+ aVBO->BindAttribute (theCtx, Graphic3d_TypeOfAttribute::Graphic3d_TOA_POS);
+ aVBO->Bind (theCtx);
+
+ if (mySkydomeTexture.IsNull())
+ {
+ mySkydomeTexture = new OpenGl_Texture();
+ mySkydomeTexture->Sampler()->Parameters()->SetFilter (Graphic3d_TOTF_BILINEAR);
+ }
+ if (mySkydomeTexture->SizeX() != mySkydomeAspect.Size())
+ {
+ mySkydomeTexture->Release (theCtx.get());
+ mySkydomeTexture->InitCubeMap (theCtx, NULL, mySkydomeAspect.Size(),
+ Image_Format_RGB, false, false);
+ }
+
+ // init aspects if needed
+ if (myCubeMapParams->TextureSet (theCtx).IsNull())
+ {
+ myCubeMapParams->Aspect()->SetInteriorStyle (Aspect_IS_SOLID);
+ myCubeMapParams->Aspect()->SetFaceCulling (Graphic3d_TypeOfBackfacingModel_DoubleSided);
+ myCubeMapParams->Aspect()->SetShadingModel (Graphic3d_TypeOfShadingModel_Unlit);
+ myCubeMapParams->Aspect()->SetShaderProgram (theCtx->ShaderManager()->GetBgCubeMapProgram());
+ Handle(Graphic3d_TextureSet) aTextureSet = new Graphic3d_TextureSet (1);
+ myCubeMapParams->Aspect()->SetTextureSet (aTextureSet);
+ myCubeMapParams->Aspect()->SetTextureMapOn (true);
+ myCubeMapParams->SynchronizeAspects();
+ }
+
+ myCubeMapParams->Aspect()->ShaderProgram()->PushVariableInt ("uZCoeff", 1);
+ myCubeMapParams->Aspect()->ShaderProgram()->PushVariableInt ("uYCoeff", 1);
+
+ for (Standard_Integer aSideIter = 0; aSideIter < 6; aSideIter++)
+ {
+ aProg->SetUniform (theCtx, "uSide", aSideIter);
+ theCtx->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + aSideIter,
+ mySkydomeTexture->TextureId(), 0);
+ theCtx->core15->glDrawArrays (GL_TRIANGLES, 0, 3);
+ }
+ theCtx->arbFBO->glDeleteFramebuffers (1, &anFBO);
+ aVBO->Release (theCtx.get());
+
+ myCubeMapParams->TextureSet (theCtx)->ChangeFirst() = mySkydomeTexture;
+ theCtx->BindProgram (aPrevProgram);
+ theCtx->ResizeViewport (anOldViewport);
+ theCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, aPrevFBO);
+}
+
// =======================================================================
// function : checkPBRAvailability
// purpose :
// =======================================================================
void OpenGl_View::updatePBREnvironment (const Handle(OpenGl_Context)& theCtx)
{
+ if (myBackgroundType == Graphic3d_TOB_CUBEMAP
+ && myToUpdateSkydome)
+ {
+ updateSkydomeBg (theCtx);
+ }
+
if (myPBREnvState != OpenGl_PBREnvState_CREATED
|| !myPBREnvRequest)
{
OpenGl_FrameBuffer* theOitAccumFbo,
const Standard_Boolean theToDrawImmediate);
- //! Draw background (gradient / image)
+ //! Draw background (gradient / image / cubemap)
Standard_EXPORT virtual void drawBackground (const Handle(OpenGl_Workspace)& theWorkspace,
Graphic3d_Camera::Projection theProjection);
OpenGl_Aspects* myColoredQuadParams; //!< Stores parameters for gradient (corner mode) background
OpenGl_BackgroundArray* myBackgrounds[Graphic3d_TypeOfBackground_NB]; //!< Array of primitive arrays of different background types
Handle(OpenGl_TextureSet) myTextureEnv;
+ Handle(OpenGl_Texture) mySkydomeTexture;
+
+protected: //! @name methods related to skydome background
+
+ //! Generates skydome cubemap.
+ Standard_EXPORT void updateSkydomeBg (const Handle(OpenGl_Context)& theCtx);
protected: //! @name methods related to PBR
srcinc:::RaytraceBase.vs
srcinc:::RaytraceSmooth.fs
srcinc:::TangentSpaceNormal.glsl
+srcinc:::SkydomBackground.fs
Shaders_Declarations_glsl.pxx
Shaders_DeclarationsImpl_glsl.pxx
Shaders_DirectionalLightShadow_glsl.pxx
Shaders_RaytraceBase_vs.pxx
Shaders_RaytraceSmooth_fs.pxx
Shaders_TangentSpaceNormal_glsl.pxx
+Shaders_SkydomBackground_fs.pxx
--- /dev/null
+// This file has been automatically generated from resource file src/Shaders/SkydomBackground.fs
+
+static const char Shaders_SkydomBackground_fs[] =
+ "// Constants\n"
+ "const float M_PI = 3.1415926535;\n"
+ "const float THE_EARTH_RADIUS = 6360e3;\n"
+ "const vec3 THE_EARTH_CENTER = vec3 (0.0, -THE_EARTH_RADIUS, 0.0);\n"
+ "const float THE_ATMO_RADIUS = 6380e3; // atmosphere radius (6420e3?)\n"
+ "const float THE_G = 0.76; // anisotropy of the medium (papers use 0.76)\n"
+ "const float THE_G2 = THE_G * THE_G;\n"
+ "const float THE_HR = 8000.0; // Thickness of the atmosphere\n"
+ "const float THE_HM = 1000.0; // Same as above but for Mie\n"
+ "const vec3 THE_BETA_R = vec3 (5.8e-6, 13.5e-6, 33.1e-6); // Reyleigh scattering normal earth\n"
+ "const vec3 THE_BETA_M = vec3 (21e-6); // Normal Mie scattering\n"
+ "\n"
+ "// Parameters\n"
+ "const float THE_SunAttenuation = 1.0; // sun intensity\n"
+ "const float THE_EyeHeight = 100.0; // viewer height\n"
+ "const float THE_HorizonWidth = 0.002;\n"
+ "const int THE_NbSamples = 8;\n"
+ "const int THE_NbSamplesLight = 8; // integral sampling rate (might highly hit performance)\n"
+ "const float THE_SunPower = 5.0;\n"
+ "const float THE_StarTreshold = 0.98;\n"
+ "\n"
+ "// Uniforms\n"
+ "uniform vec3 uSunDir;\n"
+ "uniform float uTime;\n"
+ "uniform float uCloudy;\n"
+ "uniform float uFog;\n"
+ "\n"
+ "float hash13 (in vec3 p3)\n"
+ "{\n"
+ " p3 = fract (p3 * 0.1031);\n"
+ " p3 += dot (p3, p3.zyx + 31.32);\n"
+ " return fract ((p3.x + p3.y) * p3.z);\n"
+ "}\n"
+ "\n"
+ "float hash12 (in vec2 p)\n"
+ "{\n"
+ " vec3 p3 = fract (vec3(p.xyx) * .1031);\n"
+ " p3 += dot (p3, p3.yzx + 33.33);\n"
+ " return fract ((p3.x + p3.y) * p3.z);\n"
+ "}\n"
+ "\n"
+ "float smoothStarField (in vec2 theSamplePos)\n"
+ "{\n"
+ " vec2 aFract = fract (theSamplePos);\n"
+ " vec2 aFloorSample = floor (theSamplePos);\n"
+ " float v1 = hash12 (aFloorSample);\n"
+ " float v2 = hash12 (aFloorSample + vec2( 0.0, 1.0 ));\n"
+ " float v3 = hash12 (aFloorSample + vec2( 1.0, 0.0 ));\n"
+ " float v4 = hash12 (aFloorSample + vec2( 1.0, 1.0 ));\n"
+ "\n"
+ " vec2 u = aFract * aFract * (3.0 - 2.0 * aFract);\n"
+ "\n"
+ " return mix(v1, v2, u.x) +\n"
+ " (v3 - v1) * u.y * (1.0 - u.x) +\n"
+ " (v4 - v2) * u.x * u.y;\n"
+ "}\n"
+ "\n"
+ "float noisyStarField (in vec2 theSamplePos)\n"
+ "{\n"
+ " float aStarVal = smoothStarField (theSamplePos);\n"
+ " if (aStarVal >= THE_StarTreshold)\n"
+ " {\n"
+ " aStarVal = pow ((aStarVal - THE_StarTreshold) / (1.0 - THE_StarTreshold), 6.0);\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " aStarVal = 0.0;\n"
+ " }\n"
+ " return aStarVal;\n"
+ "}\n"
+ "\n"
+ "float smoothNoise (in vec3 theCoord)\n"
+ "{\n"
+ " vec3 anInt = floor (theCoord);\n"
+ " vec3 anFract = fract (theCoord);\n"
+ " anFract = anFract * anFract * (3.0 - (2.0 * anFract));\n"
+ " return mix(mix(mix(hash13(anInt ),\n"
+ " hash13(anInt + vec3(1.0, 0.0, 0.0)), anFract.x),\n"
+ " mix(hash13(anInt + vec3(0.0, 1.0, 0.0)),\n"
+ " hash13(anInt + vec3(1.0, 1.0, 0.0)), anFract.x), anFract.y),\n"
+ " mix(mix(hash13(anInt + vec3(0.0, 0.0, 1.0)),\n"
+ " hash13(anInt + vec3(1.0, 0.0, 1.0)), anFract.x),\n"
+ " mix(hash13(anInt + vec3(0.0, 1.0, 1.0)),\n"
+ " hash13(anInt + vec3(1.0, 1.0, 1.0)), anFract.x), anFract.y), anFract.z);\n"
+ "}\n"
+ "\n"
+ "float fnoise (in vec3 theCoord, in float theTime)\n"
+ "{\n"
+ " theCoord *= .25;\n"
+ " float aNoise;\n"
+ "\n"
+ " aNoise = 0.5000 * smoothNoise (theCoord);\n"
+ " theCoord = theCoord * 3.02; theCoord.y -= theTime * 0.2;\n"
+ " aNoise += 0.2500 * smoothNoise (theCoord);\n"
+ " theCoord = theCoord * 3.03; theCoord.y += theTime * 0.06;\n"
+ " aNoise += 0.1250 * smoothNoise (theCoord);\n"
+ " theCoord = theCoord * 3.01;\n"
+ " aNoise += 0.0625 * smoothNoise (theCoord);\n"
+ " theCoord = theCoord * 3.03;\n"
+ " aNoise += 0.03125 * smoothNoise (theCoord);\n"
+ " theCoord = theCoord * 3.02;\n"
+ " aNoise += 0.015625 * smoothNoise (theCoord);\n"
+ " return aNoise;\n"
+ "}\n"
+ "\n"
+ "float clouds (in vec3 theTs, in float theTime)\n"
+ "{\n"
+ " float aCloud = fnoise (theTs * 2e-4, theTime) + uCloudy * 0.1;\n"
+ " aCloud = smoothstep (0.44, 0.64, aCloud);\n"
+ " aCloud *= 70.0;\n"
+ " return aCloud + uFog;\n"
+ "}\n"
+ "\n"
+ "void densities (in vec3 thePos, out float theRayleigh, out float theMie, in float theTime)\n"
+ "{\n"
+ " float aHeight = length (thePos - THE_EARTH_CENTER) - THE_EARTH_RADIUS;\n"
+ " theRayleigh = exp (-aHeight / THE_HR);\n"
+ "\n"
+ " float aCloud = 0.0;\n"
+ " if (aHeight > 5000.0 && aHeight < 8000.0)\n"
+ " {\n"
+ " aCloud = clouds (thePos + vec3 (0.0, 0.,-theTime*3e3), theTime);\n"
+ " aCloud *= sin (M_PI*(aHeight - 5e3) / 5e3) * uCloudy;\n"
+ " }\n"
+ "\n"
+ " float aCloud2 = 0.0;\n"
+ " if (aHeight > 12e3 && aHeight < 15.5e3)\n"
+ " {\n"
+ " aCloud2 = fnoise (thePos * 3e-4, theTime) * clouds (thePos * 32.0, theTime);\n"
+ " aCloud2 *= sin (M_PI * (aHeight - 12e3) / 12e3) * 0.05;\n"
+ " aCloud2 = clamp (aCloud2, 0.0, 1.0);\n"
+ " }\n"
+ "\n"
+ " theMie = exp (-aHeight / THE_HM) + aCloud + uFog;\n"
+ " theMie += aCloud2;\n"
+ "}\n"
+ "\n"
+ "// ray with sphere intersection problem is reduced to solving the equation\n"
+ "// (P - C)^2 = r^2 <--- sphere equation\n"
+ "// where P is P(t) = A + t*B <--- point on ray\n"
+ "// t^2*dot(B, B) + t*2*dot(B, A-C) + dot(A-C, A-C) - r^2 = 0\n"
+ "// [ A ] [ B ] [ C ]\n"
+ "// We just need to solve the above quadratic equation\n"
+ "float raySphereIntersect (in vec3 theOrig, in vec3 theDir, in float theRadius)\n"
+ "{\n"
+ " theOrig = theOrig - THE_EARTH_CENTER;\n"
+ " // A coefficient will be always 1 (theDir is normalized)\n"
+ " float B = dot (theOrig, theDir);\n"
+ " float C = dot (theOrig, theOrig) - theRadius * theRadius;\n"
+ " // optimized version of classic (-b +- sqrt(b^2 - 4ac)) / 2a\n"
+ " float aDet2 = B * B - C;\n"
+ " if (aDet2 < 0.0) { return -1.0; }\n"
+ " float aDet = sqrt (aDet2);\n"
+ " float aT1 = -B - aDet;\n"
+ " float aT2 = -B + aDet;\n"
+ " return aT1 >= 0.0 ? aT1 : aT2;\n"
+ "}\n"
+ "\n"
+ "void scatter (in vec3 theEye, in vec3 theRay, in vec3 theSun,\n"
+ " out vec3 theCol, out float theScat, in float theTime)\n"
+ "{\n"
+ " float aRayLen = raySphereIntersect (theEye, theRay, THE_ATMO_RADIUS);\n"
+ " float aMu = dot (theRay, theSun);\n"
+ " float aMu2 = 1.0 + aMu*aMu;\n"
+ " // The Raleigh phase function looks like this:\n"
+ " float aPhaseR = 3.0/(16.0 * M_PI) * aMu2;\n"
+ " // And the Mie phase function equation is:\n"
+ " float aPhaseM = (3.0 / (8.0 * M_PI) * (1.0 - THE_G2) * aMu2)\n"
+ " / ((2.0 + THE_G2) * pow (1.0 + THE_G2 - 2.0 * THE_G * aMu, 1.5));\n"
+ "\n"
+ " float anOpticalDepthR = 0.0;\n"
+ " float anOpticalDepthM = 0.0;\n"
+ " vec3 aSumR = vec3 (0.0);\n"
+ " vec3 aSumM = vec3 (0.0); // Mie and Rayleigh contribution\n"
+ "\n"
+ " float dl = aRayLen / float (THE_NbSamples);\n"
+ " for (int i = 0; i < THE_NbSamples; ++i)\n"
+ " {\n"
+ " float l = float(i) * dl;\n"
+ " vec3 aSamplePos = theEye + theRay * l;\n"
+ "\n"
+ " float dR, dM;\n"
+ " densities (aSamplePos, dR, dM, theTime);\n"
+ " dR *= dl;\n"
+ " dM *= dl;\n"
+ " anOpticalDepthR += dR;\n"
+ " anOpticalDepthM += dM;\n"
+ "\n"
+ " float aSegmentLengthLight = raySphereIntersect (aSamplePos, theSun, THE_ATMO_RADIUS);\n"
+ " if (aSegmentLengthLight > 0.0)\n"
+ " {\n"
+ " float dls = aSegmentLengthLight / float (THE_NbSamplesLight);\n"
+ " float anOpticalDepthRs = 0.0;\n"
+ " float anOpticalDepthMs = 0.0;\n"
+ " for (int j = 0; j < THE_NbSamplesLight; ++j)\n"
+ " {\n"
+ " float ls = float (j) * dls;\n"
+ " vec3 aSamplePosS = aSamplePos + theSun * ls;\n"
+ " float dRs, dMs;\n"
+ " densities (aSamplePosS, dRs, dMs, theTime);\n"
+ " anOpticalDepthRs += dRs * dls;\n"
+ " anOpticalDepthMs += dMs * dls;\n"
+ " }\n"
+ "\n"
+ " vec3 anAttenuation = exp (-(THE_BETA_R * (anOpticalDepthR + anOpticalDepthRs)\n"
+ " + THE_BETA_M * (anOpticalDepthM + anOpticalDepthMs)));\n"
+ " aSumR += anAttenuation * dR;\n"
+ " aSumM += anAttenuation * dM;\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " theCol = THE_SunPower * (aSumR * THE_BETA_R * aPhaseR + aSumM * THE_BETA_M * aPhaseM);\n"
+ " theScat = 1.0 - clamp (anOpticalDepthM*1e-5, 0.0, 1.0);\n"
+ "}\n"
+ "\n"
+ "// This is where all the magic happens. We first raymarch along the primary ray\n"
+ "// (from the camera origin to the point where the ray exits the atmosphere).\n"
+ "// For each sample along the primary ray,\n"
+ "// we then \"cast\" a light ray and raymarch along that ray as well.\n"
+ "// We basically shoot a ray in the direction of the sun.\n"
+ "vec4 computeIncidentLight (in vec3 theRayDirection, in vec2 theUv, in float theTime)\n"
+ "{\n"
+ " float aSunAttenuation = THE_SunAttenuation;\n"
+ " vec3 aSunDir = uSunDir;\n"
+ " // conversion to moon\n"
+ " float aStarAttenuation = 0.0;\n"
+ " if (aSunDir.y < 0.0)\n"
+ " {\n"
+ " aSunDir *= -1.0;\n"
+ " aSunAttenuation = aSunAttenuation * 0.1;\n"
+ " aStarAttenuation = sqrt (aSunDir.y);\n"
+ " }\n"
+ "\n"
+ " vec3 anEyePosition = vec3(0.0, THE_EyeHeight, 0.0);\n"
+ "\n"
+ " // draw a water surface horizontally symmetrically to the sky\n"
+ " if (theRayDirection.y <= -THE_HorizonWidth / 2.0)\n"
+ " {\n"
+ " theRayDirection.y = -THE_HorizonWidth - theRayDirection.y;\n"
+ " }\n"
+ "\n"
+ " float aScattering = 0.0;\n"
+ " vec3 aColor = vec3 (0.0);\n"
+ "\n"
+ " scatter (anEyePosition, theRayDirection, aSunDir, aColor, aScattering, theTime);\n"
+ " aColor *= aSunAttenuation;\n"
+ " float aStarIntensity = noisyStarField (theUv * 2048.0);\n"
+ " vec3 aStarColor = vec3 (aScattering * aStarIntensity * aStarAttenuation);\n"
+ " aColor += aStarColor;\n"
+ "\n"
+ " return vec4 (1.18 * pow (aColor, vec3(0.7)), 1.0);\n"
+ "}\n"
+ "\n"
+ "uniform int uSide;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " vec2 anUv = vec2 (2.0 * TexCoord.x - 1.0,\n"
+ " 2.0 * TexCoord.y - 1.0);\n"
+ " vec3 aPlanes[6];\n"
+ " aPlanes[0] = vec3 (+1.0, 0.0, 0.0);\n"
+ " aPlanes[1] = vec3 (-1.0, 0.0, 0.0);\n"
+ " aPlanes[2] = vec3 ( 0.0,+1.0, 0.0);\n"
+ " aPlanes[3] = vec3 ( 0.0,-1.0, 0.0);\n"
+ " aPlanes[4] = vec3 ( 0.0, 0.0,+1.0);\n"
+ " aPlanes[5] = vec3 ( 0.0, 0.0,-1.0);\n"
+ " vec3 aRayDirection;\n"
+ " if (uSide == 0)\n"
+ " {\n"
+ " // Positive X side\n"
+ " aRayDirection = aPlanes[0] + vec3 (0.0, +anUv.y, -anUv.x);\n"
+ " }\n"
+ " else if (uSide == 1)\n"
+ " {\n"
+ " // Negative X side\n"
+ " aRayDirection = aPlanes[1] + vec3 (0.0, +anUv.y, +anUv.x);\n"
+ " }\n"
+ " else if (uSide == 2)\n"
+ " {\n"
+ " // Positive Y side\n"
+ " aRayDirection = aPlanes[2] + vec3 (+anUv.x, 0.0, +anUv.y);\n"
+ " }\n"
+ " else if (uSide == 3)\n"
+ " {\n"
+ " // Negative Y side\n"
+ " aRayDirection = aPlanes[3] + vec3 (+anUv.x, 0.0, -anUv.y);\n"
+ " }\n"
+ " else if (uSide == 4)\n"
+ " {\n"
+ " // Positive Z side\n"
+ " aRayDirection = aPlanes[4] + vec3 (+anUv.x, +anUv.y, 0.0);\n"
+ " }\n"
+ " else if (uSide == 5)\n"
+ " {\n"
+ " // Negative Z side\n"
+ " aRayDirection = aPlanes[5] + vec3 (-anUv.x, +anUv.y, 0.0);\n"
+ " }\n"
+ "\n"
+ " occFragColor = computeIncidentLight (normalize (aRayDirection), anUv, uTime);\n"
+ "}\n";
--- /dev/null
+// Constants
+const float M_PI = 3.1415926535;
+const float THE_EARTH_RADIUS = 6360e3;
+const vec3 THE_EARTH_CENTER = vec3 (0.0, -THE_EARTH_RADIUS, 0.0);
+const float THE_ATMO_RADIUS = 6380e3; // atmosphere radius (6420e3?)
+const float THE_G = 0.76; // anisotropy of the medium (papers use 0.76)
+const float THE_G2 = THE_G * THE_G;
+const float THE_HR = 8000.0; // Thickness of the atmosphere
+const float THE_HM = 1000.0; // Same as above but for Mie
+const vec3 THE_BETA_R = vec3 (5.8e-6, 13.5e-6, 33.1e-6); // Reyleigh scattering normal earth
+const vec3 THE_BETA_M = vec3 (21e-6); // Normal Mie scattering
+
+// Parameters
+const float THE_SunAttenuation = 1.0; // sun intensity
+const float THE_EyeHeight = 100.0; // viewer height
+const float THE_HorizonWidth = 0.002;
+const int THE_NbSamples = 8;
+const int THE_NbSamplesLight = 8; // integral sampling rate (might highly hit performance)
+const float THE_SunPower = 5.0;
+const float THE_StarTreshold = 0.98;
+
+// Uniforms
+uniform vec3 uSunDir;
+uniform float uTime;
+uniform float uCloudy;
+uniform float uFog;
+
+float hash13 (in vec3 p3)
+{
+ p3 = fract (p3 * 0.1031);
+ p3 += dot (p3, p3.zyx + 31.32);
+ return fract ((p3.x + p3.y) * p3.z);
+}
+
+float hash12 (in vec2 p)
+{
+ vec3 p3 = fract (vec3(p.xyx) * .1031);
+ p3 += dot (p3, p3.yzx + 33.33);
+ return fract ((p3.x + p3.y) * p3.z);
+}
+
+float smoothStarField (in vec2 theSamplePos)
+{
+ vec2 aFract = fract (theSamplePos);
+ vec2 aFloorSample = floor (theSamplePos);
+ float v1 = hash12 (aFloorSample);
+ float v2 = hash12 (aFloorSample + vec2( 0.0, 1.0 ));
+ float v3 = hash12 (aFloorSample + vec2( 1.0, 0.0 ));
+ float v4 = hash12 (aFloorSample + vec2( 1.0, 1.0 ));
+
+ vec2 u = aFract * aFract * (3.0 - 2.0 * aFract);
+
+ return mix(v1, v2, u.x) +
+ (v3 - v1) * u.y * (1.0 - u.x) +
+ (v4 - v2) * u.x * u.y;
+}
+
+float noisyStarField (in vec2 theSamplePos)
+{
+ float aStarVal = smoothStarField (theSamplePos);
+ if (aStarVal >= THE_StarTreshold)
+ {
+ aStarVal = pow ((aStarVal - THE_StarTreshold) / (1.0 - THE_StarTreshold), 6.0);
+ }
+ else
+ {
+ aStarVal = 0.0;
+ }
+ return aStarVal;
+}
+
+float smoothNoise (in vec3 theCoord)
+{
+ vec3 anInt = floor (theCoord);
+ vec3 anFract = fract (theCoord);
+ anFract = anFract * anFract * (3.0 - (2.0 * anFract));
+ return mix(mix(mix(hash13(anInt ),
+ hash13(anInt + vec3(1.0, 0.0, 0.0)), anFract.x),
+ mix(hash13(anInt + vec3(0.0, 1.0, 0.0)),
+ hash13(anInt + vec3(1.0, 1.0, 0.0)), anFract.x), anFract.y),
+ mix(mix(hash13(anInt + vec3(0.0, 0.0, 1.0)),
+ hash13(anInt + vec3(1.0, 0.0, 1.0)), anFract.x),
+ mix(hash13(anInt + vec3(0.0, 1.0, 1.0)),
+ hash13(anInt + vec3(1.0, 1.0, 1.0)), anFract.x), anFract.y), anFract.z);
+}
+
+float fnoise (in vec3 theCoord, in float theTime)
+{
+ theCoord *= .25;
+ float aNoise;
+
+ aNoise = 0.5000 * smoothNoise (theCoord);
+ theCoord = theCoord * 3.02; theCoord.y -= theTime * 0.2;
+ aNoise += 0.2500 * smoothNoise (theCoord);
+ theCoord = theCoord * 3.03; theCoord.y += theTime * 0.06;
+ aNoise += 0.1250 * smoothNoise (theCoord);
+ theCoord = theCoord * 3.01;
+ aNoise += 0.0625 * smoothNoise (theCoord);
+ theCoord = theCoord * 3.03;
+ aNoise += 0.03125 * smoothNoise (theCoord);
+ theCoord = theCoord * 3.02;
+ aNoise += 0.015625 * smoothNoise (theCoord);
+ return aNoise;
+}
+
+float clouds (in vec3 theTs, in float theTime)
+{
+ float aCloud = fnoise (theTs * 2e-4, theTime) + uCloudy * 0.1;
+ aCloud = smoothstep (0.44, 0.64, aCloud);
+ aCloud *= 70.0;
+ return aCloud + uFog;
+}
+
+void densities (in vec3 thePos, out float theRayleigh, out float theMie, in float theTime)
+{
+ float aHeight = length (thePos - THE_EARTH_CENTER) - THE_EARTH_RADIUS;
+ theRayleigh = exp (-aHeight / THE_HR);
+
+ float aCloud = 0.0;
+ if (aHeight > 5000.0 && aHeight < 8000.0)
+ {
+ aCloud = clouds (thePos + vec3 (0.0, 0.,-theTime*3e3), theTime);
+ aCloud *= sin (M_PI*(aHeight - 5e3) / 5e3) * uCloudy;
+ }
+
+ float aCloud2 = 0.0;
+ if (aHeight > 12e3 && aHeight < 15.5e3)
+ {
+ aCloud2 = fnoise (thePos * 3e-4, theTime) * clouds (thePos * 32.0, theTime);
+ aCloud2 *= sin (M_PI * (aHeight - 12e3) / 12e3) * 0.05;
+ aCloud2 = clamp (aCloud2, 0.0, 1.0);
+ }
+
+ theMie = exp (-aHeight / THE_HM) + aCloud + uFog;
+ theMie += aCloud2;
+}
+
+// ray with sphere intersection problem is reduced to solving the equation
+// (P - C)^2 = r^2 <--- sphere equation
+// where P is P(t) = A + t*B <--- point on ray
+// t^2*dot(B, B) + t*2*dot(B, A-C) + dot(A-C, A-C) - r^2 = 0
+// [ A ] [ B ] [ C ]
+// We just need to solve the above quadratic equation
+float raySphereIntersect (in vec3 theOrig, in vec3 theDir, in float theRadius)
+{
+ theOrig = theOrig - THE_EARTH_CENTER;
+ // A coefficient will be always 1 (theDir is normalized)
+ float B = dot (theOrig, theDir);
+ float C = dot (theOrig, theOrig) - theRadius * theRadius;
+ // optimized version of classic (-b +- sqrt(b^2 - 4ac)) / 2a
+ float aDet2 = B * B - C;
+ if (aDet2 < 0.0) { return -1.0; }
+ float aDet = sqrt (aDet2);
+ float aT1 = -B - aDet;
+ float aT2 = -B + aDet;
+ return aT1 >= 0.0 ? aT1 : aT2;
+}
+
+void scatter (in vec3 theEye, in vec3 theRay, in vec3 theSun,
+ out vec3 theCol, out float theScat, in float theTime)
+{
+ float aRayLen = raySphereIntersect (theEye, theRay, THE_ATMO_RADIUS);
+ float aMu = dot (theRay, theSun);
+ float aMu2 = 1.0 + aMu*aMu;
+ // The Raleigh phase function looks like this:
+ float aPhaseR = 3.0/(16.0 * M_PI) * aMu2;
+ // And the Mie phase function equation is:
+ float aPhaseM = (3.0 / (8.0 * M_PI) * (1.0 - THE_G2) * aMu2)
+ / ((2.0 + THE_G2) * pow (1.0 + THE_G2 - 2.0 * THE_G * aMu, 1.5));
+
+ float anOpticalDepthR = 0.0;
+ float anOpticalDepthM = 0.0;
+ vec3 aSumR = vec3 (0.0);
+ vec3 aSumM = vec3 (0.0); // Mie and Rayleigh contribution
+
+ float dl = aRayLen / float (THE_NbSamples);
+ for (int i = 0; i < THE_NbSamples; ++i)
+ {
+ float l = float(i) * dl;
+ vec3 aSamplePos = theEye + theRay * l;
+
+ float dR, dM;
+ densities (aSamplePos, dR, dM, theTime);
+ dR *= dl;
+ dM *= dl;
+ anOpticalDepthR += dR;
+ anOpticalDepthM += dM;
+
+ float aSegmentLengthLight = raySphereIntersect (aSamplePos, theSun, THE_ATMO_RADIUS);
+ if (aSegmentLengthLight > 0.0)
+ {
+ float dls = aSegmentLengthLight / float (THE_NbSamplesLight);
+ float anOpticalDepthRs = 0.0;
+ float anOpticalDepthMs = 0.0;
+ for (int j = 0; j < THE_NbSamplesLight; ++j)
+ {
+ float ls = float (j) * dls;
+ vec3 aSamplePosS = aSamplePos + theSun * ls;
+ float dRs, dMs;
+ densities (aSamplePosS, dRs, dMs, theTime);
+ anOpticalDepthRs += dRs * dls;
+ anOpticalDepthMs += dMs * dls;
+ }
+
+ vec3 anAttenuation = exp (-(THE_BETA_R * (anOpticalDepthR + anOpticalDepthRs)
+ + THE_BETA_M * (anOpticalDepthM + anOpticalDepthMs)));
+ aSumR += anAttenuation * dR;
+ aSumM += anAttenuation * dM;
+ }
+ }
+
+ theCol = THE_SunPower * (aSumR * THE_BETA_R * aPhaseR + aSumM * THE_BETA_M * aPhaseM);
+ theScat = 1.0 - clamp (anOpticalDepthM*1e-5, 0.0, 1.0);
+}
+
+// This is where all the magic happens. We first raymarch along the primary ray
+// (from the camera origin to the point where the ray exits the atmosphere).
+// For each sample along the primary ray,
+// we then "cast" a light ray and raymarch along that ray as well.
+// We basically shoot a ray in the direction of the sun.
+vec4 computeIncidentLight (in vec3 theRayDirection, in vec2 theUv, in float theTime)
+{
+ float aSunAttenuation = THE_SunAttenuation;
+ vec3 aSunDir = uSunDir;
+ // conversion to moon
+ float aStarAttenuation = 0.0;
+ if (aSunDir.y < 0.0)
+ {
+ aSunDir *= -1.0;
+ aSunAttenuation = aSunAttenuation * 0.1;
+ aStarAttenuation = sqrt (aSunDir.y);
+ }
+
+ vec3 anEyePosition = vec3(0.0, THE_EyeHeight, 0.0);
+
+ // draw a water surface horizontally symmetrically to the sky
+ if (theRayDirection.y <= -THE_HorizonWidth / 2.0)
+ {
+ theRayDirection.y = -THE_HorizonWidth - theRayDirection.y;
+ }
+
+ float aScattering = 0.0;
+ vec3 aColor = vec3 (0.0);
+
+ scatter (anEyePosition, theRayDirection, aSunDir, aColor, aScattering, theTime);
+ aColor *= aSunAttenuation;
+ float aStarIntensity = noisyStarField (theUv * 2048.0);
+ vec3 aStarColor = vec3 (aScattering * aStarIntensity * aStarAttenuation);
+ aColor += aStarColor;
+
+ return vec4 (1.18 * pow (aColor, vec3(0.7)), 1.0);
+}
+
+uniform int uSide;
+
+void main()
+{
+ vec2 anUv = vec2 (2.0 * TexCoord.x - 1.0,
+ 2.0 * TexCoord.y - 1.0);
+ vec3 aPlanes[6];
+ aPlanes[0] = vec3 (+1.0, 0.0, 0.0);
+ aPlanes[1] = vec3 (-1.0, 0.0, 0.0);
+ aPlanes[2] = vec3 ( 0.0,+1.0, 0.0);
+ aPlanes[3] = vec3 ( 0.0,-1.0, 0.0);
+ aPlanes[4] = vec3 ( 0.0, 0.0,+1.0);
+ aPlanes[5] = vec3 ( 0.0, 0.0,-1.0);
+ vec3 aRayDirection;
+ if (uSide == 0)
+ {
+ // Positive X side
+ aRayDirection = aPlanes[0] + vec3 (0.0, +anUv.y, -anUv.x);
+ }
+ else if (uSide == 1)
+ {
+ // Negative X side
+ aRayDirection = aPlanes[1] + vec3 (0.0, +anUv.y, +anUv.x);
+ }
+ else if (uSide == 2)
+ {
+ // Positive Y side
+ aRayDirection = aPlanes[2] + vec3 (+anUv.x, 0.0, +anUv.y);
+ }
+ else if (uSide == 3)
+ {
+ // Negative Y side
+ aRayDirection = aPlanes[3] + vec3 (+anUv.x, 0.0, -anUv.y);
+ }
+ else if (uSide == 4)
+ {
+ // Positive Z side
+ aRayDirection = aPlanes[4] + vec3 (+anUv.x, +anUv.y, 0.0);
+ }
+ else if (uSide == 5)
+ {
+ // Negative Z side
+ aRayDirection = aPlanes[5] + vec3 (-anUv.x, +anUv.y, 0.0);
+ }
+
+ occFragColor = computeIncidentLight (normalize (aRayDirection), anUv, uTime);
+}
}
}
+//=============================================================================
+//function : SetBackgroundSkydome
+//purpose :
+//=============================================================================
+void V3d_View::SetBackgroundSkydome (const Aspect_SkydomeBackground& theAspect,
+ Standard_Boolean theToUpdatePBREnv)
+{
+ myView->SetBackgroundSkydome (theAspect, theToUpdatePBREnv);
+}
+
//=============================================================================
//function : IsImageBasedLighting
//purpose :
Standard_Boolean theToUpdatePBREnv = Standard_True,
Standard_Boolean theToUpdate = Standard_False);
+ //! Returns skydome aspect;
+ const Aspect_SkydomeBackground& BackgroundSkydome() const { return myView->BackgroundSkydome(); }
+
+ //! Sets skydome aspect
+ //! @param theAspect cubemap generation parameters
+ //! @param theToUpdatePBREnv defines whether IBL maps will be generated or not
+ Standard_EXPORT void SetBackgroundSkydome (const Aspect_SkydomeBackground& theAspect,
+ Standard_Boolean theToUpdatePBREnv = Standard_True);
+
//! Returns TRUE if IBL (Image Based Lighting) from background cubemap is enabled.
Standard_EXPORT Standard_Boolean IsImageBasedLighting() const;
Aspect_FillMethod anImageMode = Aspect_FM_CENTERED;
bool hasImageMode = false;
+ bool isSkydomeBg = false;
+ Aspect_SkydomeBackground aSkydomeAspect;
+
NCollection_Sequence<TCollection_AsciiString> aCubeMapSeq;
Graphic3d_CubeMapOrder aCubeOrder = Graphic3d_CubeMapOrder::Default();
bool isCubeZInverted = false;
{
anImagePath = theArgVec[++anArgIter];
}
+ else if (anArg == "-skydome"
+ || anArg == "-sky")
+ {
+ isSkydomeBg = true;
+ }
+ else if (anArgIter + 3 < theNbArgs
+ && isSkydomeBg
+ && anArg == "-sundir")
+ {
+ float aX = (float) Draw::Atof (theArgVec[++anArgIter]);
+ float aY = (float) Draw::Atof (theArgVec[++anArgIter]);
+ float aZ = (float) Draw::Atof (theArgVec[++anArgIter]);
+ aSkydomeAspect.SetSunDirection (gp_Dir(aX, aY, aZ));
+ }
+ else if (anArgIter + 1 < theNbArgs
+ && isSkydomeBg
+ && anArg == "-cloud")
+ {
+ float aCloudy = (float) Draw::Atof (theArgVec[++anArgIter]);
+ aSkydomeAspect.SetCloudiness (aCloudy);
+ }
+ else if (anArgIter + 1 < theNbArgs
+ && isSkydomeBg
+ && anArg == "-time")
+ {
+ float aTime = (float) Draw::Atof (theArgVec[++anArgIter]);
+ aSkydomeAspect.SetTimeParameter (aTime);
+ }
+ else if (anArgIter + 1 < theNbArgs
+ && isSkydomeBg
+ && anArg == "-fog")
+ {
+ float aFoggy = (float) Draw::Atof (theArgVec[++anArgIter]);
+ aSkydomeAspect.SetFogginess (aFoggy);
+ }
+ else if (anArgIter + 1 < theNbArgs
+ && isSkydomeBg
+ && anArg == "-size")
+ {
+ Standard_Integer aSize = Draw::Atoi (theArgVec[++anArgIter]);
+ aSkydomeAspect.SetSize (aSize);
+ }
else if (anArgIter + 1 < theNbArgs
&& aCubeMapSeq.IsEmpty()
&& (anArg == "-cubemap"
aView->SetBgImageStyle (anImageMode);
}
+ if (isSkydomeBg)
+ {
+ aView->SetBackgroundSkydome (aSkydomeAspect, toUseIBL != -1);
+ }
+
if (!aCubeMapSeq.IsEmpty())
{
Handle(Graphic3d_CubeMap) aCubeMap;
[-gradientMode {NONE|HORIZONTAL|VERTICAL|DIAG1|DIAG2|CORNER1|CORNER2|CORNER3|ELLIPTICAL}]=VERT]
[-imageFile ImageFile [-imageMode {CENTERED|TILED|STRETCH|NONE}]=CENTERED [-srgb {0|1}]=1]
[-cubemap CubemapFile1 [CubeMapFiles2-5] [-order TilesIndexes1-6] [-invertedz]=0]
+ [-skydome [-sunDir X Y Z=0 1 0] [-cloud Cloudy=0.2] [-time Time=0.0]
+ [-fog Haze=0.0] [-size SizePx=512]]
[-pbrEnv {ibl|noibl|keep}]
Changes background or some background settings.
-color sets background color
-order defines order of tiles in one image cubemap
TileIndexi defubes an index in range [0, 5] for i tile of one image packed cubemap
(has no effect in case of multi-image cubemaps).
+Skydome background parameters (generated cubemap):
+ -skydome sets procedurally generated skydome as background
+ -sunDir sets direction to the sun, direction with negative y component represents moon direction (-x, -y, -z)
+ -cloud sets cloud intensity (0.0 - clear sky, 1.0 - very high cloudy)
+ -time might be tweaked to slightly change appearance of clouds
+ -fog sets mist intensity (0.0 - no mist at all, 1.0 - high mist)
+ -size sets size in pixels of cubemap side
)" /* [vbackground] */);
addCmd ("vsetbg", VBackground, /* [vsetbg] */ R"(
--- /dev/null
+puts "============"
+puts "0032606: Visualization - add a shader for sky"
+puts "============"
+puts ""
+
+set THE_DIM 256
+
+pload MODELING VISUALIZATION
+psphere s 1
+
+vinit View1 -width 768 -height 512
+vcamera -persp -fovy 120
+
+chrono t restart
+vbackground -skydome -size $THE_DIM -cloud 0.3 -sunDir 1.0 0.5 0.0 -time 10 -fog 0.3
+chrono t show
+vaxo
+vdump $imagedir/${casename}_day.png
+
+chrono t restart
+vbackground -skydome -size $THE_DIM -cloud 0.3 -sunDir 1.0 -0.5 0.0 -time -10 -fog 0.05
+chrono t show
+vaxo
+vdump $imagedir/${casename}_night.png
+
+chrono t restart
+vbackground -skydome -size $THE_DIM -cloud 0.15 -sunDir 1.0 0.15 0.0 -time 10
+chrono t show
+vaxo
+vdump $imagedir/${casename}_sunset.png
+
+chrono t restart
+vbackground -skydome -size $THE_DIM
+chrono t show
+vaxo
+vdump $imagedir/${casename}_defaults.png
+
+vdisplay -dispMode 1 s
+vfit
+vaspects s -material SILVER
+vrenderparams -shadingModel pbr
+vlight headlight -enabled 0
+vdump $imagedir/${casename}_pbr.png