1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-09-08 14:17:06 +03:00

0027974: Visualization, ray tracing - Improve ray tracing engine

* Multiple importance sampling for path tracing
* Improved light sources sampling (better handling several light sources)
* Fixed issues in light source intersection (light distance is taken into account)
* Add new TCL sample - OCCT Ball model for demonstrating physically-based materials
* Fix potential issue on NVIDIA GPUs ("Error: Failed to upload light source buffer")
* Path tracing materials reviewed; directional light source was smoother by default
This commit is contained in:
dbp
2016-10-20 12:10:47 +03:00
committed by apn
parent 0d0481c787
commit 6e728f3b5c
19 changed files with 2186 additions and 747 deletions

View File

@@ -42,6 +42,24 @@ namespace
{
static const OpenGl_Vec4 THE_WHITE_COLOR (1.0f, 1.0f, 1.0f, 1.0f);
static const OpenGl_Vec4 THE_BLACK_COLOR (0.0f, 0.0f, 0.0f, 1.0f);
//! Operator returning TRUE for positional light sources.
struct IsLightPositional
{
bool operator() (const OpenGl_Light& theLight)
{
return theLight.Type != Graphic3d_TOLS_DIRECTIONAL;
}
};
//! Operator returning TRUE for any non-ambient light sources.
struct IsNotAmbient
{
bool operator() (const OpenGl_Light& theLight)
{
return theLight.Type != Graphic3d_TOLS_AMBIENT;
}
};
}
// =======================================================================
@@ -1402,10 +1420,20 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
return safeFailBack ("Failed to load source into ray-tracing fragment shaders", theGlContext);
}
TCollection_AsciiString aLog;
if (!myRaytraceShader->Compile (theGlContext)
|| !myPostFSAAShader->Compile (theGlContext)
|| !myOutImageShader->Compile (theGlContext))
{
#ifdef RAY_TRACE_PRINT_INFO
myRaytraceShader->FetchInfoLog (theGlContext, aLog);
if (!aLog.IsEmpty())
{
std::cout << "Failed to compile ray-tracing shader: " << aLog << "\n";
}
#endif
return safeFailBack ("Failed to compile ray-tracing fragment shaders", theGlContext);
}
@@ -1417,6 +1445,14 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
|| !myPostFSAAProgram->Link (theGlContext)
|| !myOutImageProgram->Link (theGlContext))
{
#ifdef RAY_TRACE_PRINT_INFO
myRaytraceProgram->FetchInfoLog (theGlContext, aLog);
if (!aLog.IsEmpty())
{
std::cout << "Failed to compile ray-tracing shader: " << aLog << "\n";
}
#endif
return safeFailBack ("Failed to initialize vertex attributes for ray-tracing program", theGlContext);
}
}
@@ -1424,7 +1460,7 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
if (myRaytraceInitStatus == OpenGl_RT_NONE)
{
myAccumFrames = 0; // reject accumulated frames
myAccumFrames = 0; // accumulation should be restarted
if (!theGlContext->IsGlGreaterEqual (3, 1))
{
@@ -2266,14 +2302,31 @@ Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)&
// =======================================================================
Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& theInvModelView, const Handle(OpenGl_Context)& theGlContext)
{
myRaytraceGeometry.Sources.clear();
std::vector<OpenGl_Light> aLightSources;
myRaytraceGeometry.Ambient = BVH_Vec4f (0.0f, 0.0f, 0.0f, 0.0f);
OpenGl_ListOfLight::Iterator aLightIter (myShadingModel == Graphic3d_TOSM_NONE ? myNoShadingLight : myLights);
for (; aLightIter.More(); aLightIter.Next())
if (myShadingModel != Graphic3d_TOSM_NONE)
{
const OpenGl_Light& aLight = aLightIter.Value();
aLightSources.assign (myLights.begin(), myLights.end());
// move positional light sources at the front of the list
std::partition (aLightSources.begin(), aLightSources.end(), IsLightPositional());
}
// get number of 'real' (not ambient) light sources
const size_t aNbLights = std::count_if (aLightSources.begin(), aLightSources.end(), IsNotAmbient());
Standard_Boolean wasUpdated = myRaytraceGeometry.Sources.size () != aNbLights;
if (wasUpdated)
{
myRaytraceGeometry.Sources.resize (aNbLights);
}
myRaytraceGeometry.Ambient = BVH_Vec4f (0.f, 0.f, 0.f, 0.f);
for (size_t aLightIdx = 0, aRealIdx = 0; aLightIdx < aLightSources.size(); ++aLightIdx)
{
const OpenGl_Light& aLight = aLightSources[aLightIdx];
if (aLight.Type == Graphic3d_TOLS_AMBIENT)
{
@@ -2284,10 +2337,10 @@ Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& the
continue;
}
BVH_Vec4f aDiffuse (aLight.Color.r() * aLight.Intensity,
aLight.Color.g() * aLight.Intensity,
aLight.Color.b() * aLight.Intensity,
1.0f);
BVH_Vec4f aEmission (aLight.Color.r() * aLight.Intensity,
aLight.Color.g() * aLight.Intensity,
aLight.Color.b() * aLight.Intensity,
1.0f);
BVH_Vec4f aPosition (-aLight.Direction.x(),
-aLight.Direction.y(),
@@ -2301,13 +2354,13 @@ Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& the
static_cast<float>(aLight.Position.z()),
1.0f);
// store smoothing radius in w-component
aDiffuse.w() = Max (aLight.Smoothness, 0.f);
// store smoothing radius in W-component
aEmission.w() = Max (aLight.Smoothness, 0.f);
}
else
{
// store cosine of smoothing angle in w-component
aDiffuse.w() = cosf (Min (Max (aLight.Smoothness, 0.f), static_cast<Standard_ShortReal> (M_PI / 2.0)));
// store cosine of smoothing angle in W-component
aEmission.w() = cosf (Min (Max (aLight.Smoothness, 0.f), static_cast<Standard_ShortReal> (M_PI / 2.0)));
}
if (aLight.IsHeadlight)
@@ -2315,23 +2368,26 @@ Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& the
aPosition = theInvModelView * aPosition;
}
myRaytraceGeometry.Sources.push_back (OpenGl_RaytraceLight (aDiffuse, aPosition));
for (int aK = 0; aK < 4; ++aK)
{
wasUpdated |= (aEmission[aK] != myRaytraceGeometry.Sources[aRealIdx].Emission[aK])
|| (aPosition[aK] != myRaytraceGeometry.Sources[aRealIdx].Position[aK]);
}
if (wasUpdated)
{
myRaytraceGeometry.Sources[aRealIdx] = OpenGl_RaytraceLight (aEmission, aPosition);
}
++aRealIdx;
}
if (myRaytraceLightSrcTexture.IsNull()) // create light source buffer
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)
if (myRaytraceGeometry.Sources.size() != 0 && wasUpdated)
{
const GLfloat* aDataPtr = myRaytraceGeometry.Sources.front().Packed();
if (!myRaytraceLightSrcTexture->Init (theGlContext, 4, GLsizei (myRaytraceGeometry.Sources.size() * 2), aDataPtr))
@@ -2341,56 +2397,13 @@ Standard_Boolean OpenGl_View::updateRaytraceLightSources (const OpenGl_Mat4& the
#endif
return Standard_False;
}
myAccumFrames = 0; // accumulation should be restarted
}
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;
}
Handle(OpenGl_ShaderProgram) aPrograms[] = { myRaytraceProgram,
myPostFSAAProgram };
for (Standard_Integer anIdx = 0; anIdx < 2; ++anIdx)
{
if (!aPrograms[anIdx].IsNull())
{
aResult &= theGlContext->BindProgram (aPrograms[anIdx]);
if (!myTextureEnv.IsNull())
{
myTextureEnv->Bind (theGlContext,
GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture);
aResult &= aPrograms[anIdx]->SetUniform (theGlContext,
myUniformLocations[anIdx][OpenGl_RT_uSphereMapEnabled], 1);
}
else
{
aResult &= aPrograms[anIdx]->SetUniform (theGlContext,
myUniformLocations[anIdx][OpenGl_RT_uSphereMapEnabled], 0);
}
}
}
myToUpdateEnvironmentMap = Standard_False;
theGlContext->BindProgram (NULL);
return aResult;
}
// =======================================================================
// function : setUniformState
// purpose : Sets uniform state for the given ray-tracing shader program
@@ -2461,7 +2474,7 @@ Standard_Boolean OpenGl_View::setUniformState (const Standard_Integer the
theProgram->SetUniform (theGlContext,
myUniformLocations[theProgramId][OpenGl_RT_uLightAmbnt], myRaytraceGeometry.Ambient);
// Enable/disable run time rendering effects
// Enable/disable run-time rendering effects
theProgram->SetUniform (theGlContext,
myUniformLocations[theProgramId][OpenGl_RT_uShadowsEnabled], myRenderParams.IsShadowEnabled ? 1 : 0);
theProgram->SetUniform (theGlContext,
@@ -2506,6 +2519,11 @@ Standard_Boolean OpenGl_View::setUniformState (const Standard_Integer the
myUniformLocations[theProgramId][OpenGl_RT_uBackColorBot], aBackColor);
}
const Standard_Boolean toDisableEnvironmentMap = myTextureEnv.IsNull() || !myTextureEnv->IsValid();
theProgram->SetUniform (theGlContext,
myUniformLocations[theProgramId][OpenGl_RT_uSphereMapEnabled], toDisableEnvironmentMap ? 0 : 1);
theProgram->SetUniform (theGlContext,
myUniformLocations[theProgramId][OpenGl_RT_uSphereMapForBack], myRenderParams.UseEnvironmentMapBackground ? 1 : 0);
@@ -2533,6 +2551,11 @@ void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlConte
#endif
}
if (!myTextureEnv.IsNull() && myTextureEnv->IsValid())
{
myTextureEnv->Bind (theGlContext, GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture);
}
mySceneMinPointTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMinPointTexture);
mySceneMaxPointTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMaxPointTexture);
mySceneNodeInfoTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneNodeInfoTexture);
@@ -2731,6 +2754,11 @@ Standard_Boolean OpenGl_View::runPathtrace (const Graphic3d_Camera::Projection
{
Standard_Boolean aResult = Standard_True;
if (myToUpdateEnvironmentMap) // check whether the map was changed
{
myAccumFrames = myToUpdateEnvironmentMap = 0;
}
if (myRaytraceParameters.AdaptiveScreenSampling)
{
if (myAccumFrames == 0)
@@ -2875,11 +2903,6 @@ Standard_Boolean OpenGl_View::raytrace (const Standard_Integer theSizeX,
return Standard_False;
}
if (!updateRaytraceEnvironmentMap (theGlContext))
{
return Standard_False;
}
OpenGl_Mat4 aLightSourceMatrix;
// Get inversed model-view matrix for transforming lights