1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-06 18:26:22 +03:00

0026437: Visualization - Improve path tracing rendering engine

Fix compile warnings.
This commit is contained in:
dbp 2015-07-30 12:49:43 +03:00 committed by bugmaster
parent c14cd5a20e
commit 8c820969cc
8 changed files with 322 additions and 276 deletions

78
samples/tcl/pathtrace.tcl Normal file
View File

@ -0,0 +1,78 @@
#########################################################################
# 26437: Visualization - Improve path tracing rendering engine
#########################################################################
pload ALL
# setup 3D viewer content
vinit name=View1 w=512 h=512
vglinfo
vvbo 0
vsetdispmode 1
vcamera -persp
box b 1 1 1
explode b FACE
vdisplay b_1 b_2 b_3 b_5 b_6
vright
vfit
vsetmaterial b_1 plastic
vsetmaterial b_2 plastic
vsetmaterial b_3 plastic
vsetmaterial b_5 plastic
vsetmaterial b_6 plastic
vbsdf b_1 -kd 1 -ks 0
vbsdf b_2 -kd 1 -ks 0
vbsdf b_3 -kd 1 -ks 0
vbsdf b_5 -kd 1 -ks 0
vbsdf b_6 -kd 1 -ks 0
vbsdf b_2 -kd 0.3 0.5 1
vbsdf b_1 -kd 1 0.3 0.3
vsetlocation b_1 1 0 0
vsetlocation b_2 -1 0 0
vsetlocation b_5 0 0 1
vsetlocation b_6 0 0 -1
vsetlocation b_3 0 1 0
vlight del 0
vlight del 1
vlight add positional head 0 pos 0.5 0.5 0.85
vlight change 0 sm 0.06
vlight change 0 int 60.0
psphere s 0.2
vdisplay s
vsetlocation s 0.21 0.3 0.2
vsetmaterial s glass
vbsdf s -absorpcolor 0.8 0.8 1.0
vbsdf s -absorpcoeff 6
box c 0.3 0.3 0.2
vdisplay c
vsetlocation c 0.55 0.3 0.0
vlocrotate c 0 0 0 0 0 1 -30
vsetmaterial c plastic
vbsdf c -kd 1.0 0.8 0.2 -ks 0.3 -n
box g 0.15 0.15 0.3
vdisplay g
vsetlocation g 0.7 0.25 0.2
vlocrotate g 0 0 0 0 0 1 10
vsetmaterial g glass
vbsdf g -absorpcolor 0.8 1.0 0.8
vbsdf g -absorpcoeff 6
psphere r 0.1
vdisplay r
vsetmaterial r plastic
vbsdf r -kd 0.5 0.9 0.3 -ks 0.0 -kr 0.3 -n
vbsdf r -fresnel Constant 1.0
vsetlocation r 0.5 0.65 0.1
vrenderparams -ray -gi -rayDepth 8

View File

@ -55,8 +55,9 @@ public:
IsReflectionEnabled (Standard_False),
IsAntialiasingEnabled (Standard_False),
IsTransparentShadowEnabled (Standard_False),
UseEnvironmentMapBackground (Standard_False),
CoherentPathTracingMode (Standard_False),
StereoMode (Graphic3d_StereoMode_QuadBuffer),
AnaglyphFilter (Anaglyph_RedCyan_Optimized),
ToReverseStereo (Standard_False)
@ -84,6 +85,7 @@ public:
Standard_Boolean IsAntialiasingEnabled; //!< enables/disables adaptive anti-aliasing, False by default
Standard_Boolean IsTransparentShadowEnabled; //!< enables/disables light propagation through transparent media, False by default
Standard_Boolean UseEnvironmentMapBackground; //!< enables/disables environment map background
Standard_Boolean CoherentPathTracingMode; //!< enables/disables 'coherent' tracing mode (single RNG seed within 16x16 image blocks)
Graphic3d_StereoMode StereoMode; //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
Anaglyph AnaglyphFilter; //!< filter for anaglyph output, Anaglyph_RedCyan_Optimized by default

View File

@ -170,7 +170,6 @@ class OpenGl_View : public MMgt_TShared
const Aspect_CLayer2d& theCOverLayer,
const Standard_Boolean theToDrawImmediate);
void DrawBackground (const Handle(OpenGl_Workspace)& theWorkspace);
//! Returns list of OpenGL Z-layers.
@ -334,6 +333,7 @@ protected: //! @name data types related to ray-tracing
OpenGl_RT_uSphereMapEnabled,
OpenGl_RT_uSphereMapForBack,
OpenGl_RT_uTexSamplersArray,
OpenGl_RT_uBlockedRngEnabled,
// sampled frame params
OpenGl_RT_uSampleWeight,
@ -503,7 +503,7 @@ protected: //! @name methods related to ray-tracing
//! Adds OpenGL groups to ray-traced scene geometry.
Standard_Boolean addRaytraceGroups (const OpenGl_Structure* theStructure,
const Standard_Integer theStructMat,
const OpenGl_RaytraceMaterial& theStructMat,
const Standard_ShortReal* theTransform,
const Handle(OpenGl_Context)& theGlContext);

View File

@ -407,15 +407,11 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
}
// Get structure material
Standard_Integer aStructMatID = -1;
OpenGl_RaytraceMaterial aStructMaterial;
if (theStructure->AspectFace() != NULL)
{
aStructMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
OpenGl_RaytraceMaterial aStructMaterial = convertMaterial (theStructure->AspectFace(), theGlContext);
myRaytraceGeometry.Materials.push_back (aStructMaterial);
aStructMaterial = convertMaterial (theStructure->AspectFace(), theGlContext);
}
Standard_ShortReal aStructTransform[16];
@ -431,7 +427,7 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
}
}
Standard_Boolean aResult = addRaytraceGroups (theStructure, aStructMatID,
Standard_Boolean aResult = addRaytraceGroups (theStructure, aStructMaterial,
theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext);
// Process all connected OpenGL structures
@ -439,7 +435,7 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
if (anInstanced != NULL && anInstanced->IsRaytracable())
{
aResult &= addRaytraceGroups (anInstanced, aStructMatID,
aResult &= addRaytraceGroups (anInstanced, aStructMaterial,
theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext);
}
@ -453,31 +449,25 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
// purpose : Adds OpenGL groups to ray-traced scene geometry
// =======================================================================
Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure* theStructure,
const Standard_Integer theStructMat,
const OpenGl_RaytraceMaterial& 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;
OpenGl_RaytraceMaterial aGroupMaterial;
if (aGroupIter.Value()->AspectFace() != NULL)
{
aGroupMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
OpenGl_RaytraceMaterial aGroupMaterial = convertMaterial (
aGroupMaterial = convertMaterial (
aGroupIter.Value()->AspectFace(), theGlContext);
myRaytraceGeometry.Materials.push_back (aGroupMaterial);
}
Standard_Integer aMatID = aGroupMatID < 0 ? theStructMat : aGroupMatID;
if (aMatID < 0)
{
aMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
Standard_Integer aMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
myRaytraceGeometry.Materials.push_back (OpenGl_RaytraceMaterial());
}
// Use group material if available, otherwise use structure material
myRaytraceGeometry.Materials.push_back (
aGroupIter.Value()->AspectFace() != NULL ? aGroupMaterial : theStructMat);
// Add OpenGL elements from group (extract primitives arrays and aspects)
for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next)
@ -1573,6 +1563,8 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Graphic3d_CView& theC
aShaderProgram->GetUniformLocation (theGlContext, "uSphereMapEnabled");
myUniformLocations[anIndex][OpenGl_RT_uSphereMapForBack] =
aShaderProgram->GetUniformLocation (theGlContext, "uSphereMapForBack");
myUniformLocations[anIndex][OpenGl_RT_uBlockedRngEnabled] =
aShaderProgram->GetUniformLocation (theGlContext, "uBlockedRngEnabled");
myUniformLocations[anIndex][OpenGl_RT_uSampleWeight] =
aShaderProgram->GetUniformLocation (theGlContext, "uSampleWeight");
@ -2256,6 +2248,12 @@ Standard_Boolean OpenGl_View::setUniformState (const Graphic3d_CView& the
theProgram->SetUniform (theGlContext,
myUniformLocations[theProgramId][OpenGl_RT_uReflectEnabled], theCView.RenderParams.IsReflectionEnabled ? 1 : 0);
if (theCView.RenderParams.IsGlobalIlluminationEnabled)
{
theProgram->SetUniform (theGlContext,
myUniformLocations[theProgramId][OpenGl_RT_uBlockedRngEnabled], theCView.RenderParams.CoherentPathTracingMode ? 1 : 0);
}
// Set array of 64-bit texture handles
if (theGlContext->arbTexBindless != NULL && myRaytraceGeometry.HasTextures())
{

View File

@ -301,17 +301,6 @@ vec3 handleMaterial (in SMaterial theMaterial, in vec3 theInput, in vec3 theOutp
theMaterial.Ks.rgb * handleBlinnReflection (theInput, theOutput, theMaterial.Fresnel, theMaterial.Ks.w);
}
//=======================================================================
// function : sampleSpecularReflection
// purpose : Samples specular BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)
//=======================================================================
void sampleSpecularReflection (in vec3 theOutput, out vec3 theInput)
{
theInput = vec3 (-theOutput.x,
-theOutput.y,
theOutput.z);
}
//=======================================================================
// function : sampleLambertianReflection
// purpose : Samples Lambertian BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)
@ -327,38 +316,51 @@ void sampleLambertianReflection (in vec3 theOutput, out vec3 theInput)
aTemp * sin (2.f * M_PI * aKsi1),
sqrt (1.f - aKsi2));
if (theOutput.z < 0.f)
theInput.z = -theInput.z;
theInput.z = mix (-theInput.z, theInput.z, step (0.f, theOutput.z));
}
// Types of bounces
#define NON_SPECULAR_BOUNCE 0
#define SPEC_REFLECT_BOUNCE 1
#define SPEC_REFRACT_BOUNCE 2
#define IS_NON_SPEC_BOUNCE(theBounce) (theBounce == 0)
#define IS_ANY_SPEC_BOUNCE(theBounce) (theBounce != 0)
#define IS_REFL_SPEC_BOUNCE(theBounce) (theBounce == 1)
#define IS_REFR_SPEC_BOUNCE(theBounce) (theBounce == 2)
//=======================================================================
// function : sampleSpecularTransmission
// purpose : Samples specular BTDF, W = BRDF * cos(N, PSI) / PDF(PSI)
//=======================================================================
vec3 sampleSpecularTransmission (in vec3 theOutput, out vec3 theInput,
out bool isTransmit, in vec3 theThroughput, in vec3 theFresnelCoeffs)
out int theBounce, in vec3 theWeight, in vec3 theFresnelCoeffs)
{
vec3 aFresnel = fresnelMedia (theOutput.z, theFresnelCoeffs);
float aProbability = convolve (aFresnel, theThroughput);
float aProbability = convolve (aFresnel, theWeight);
// Check if transmission takes place
theBounce = RandFloat() <= aProbability ?
SPEC_REFLECT_BOUNCE : SPEC_REFRACT_BOUNCE;
// Sample input direction
if (RandFloat() <= aProbability)
if (theBounce == SPEC_REFLECT_BOUNCE)
{
theInput = vec3 (-theOutput.x,
-theOutput.y,
theOutput.z);
isTransmit = false;
return aFresnel * (1.f / aProbability);
theWeight = aFresnel * (1.f / aProbability);
}
else
{
transmitted (theFresnelCoeffs.y, theOutput, theInput);
isTransmit = true;
theWeight = (UNIT - aFresnel) * (1.f / (1.f - aProbability));
}
return (UNIT - aFresnel) * (1.f / (1.f - aProbability));
return theWeight;
}
//=======================================================================
@ -430,98 +432,55 @@ vec3 sampleBlinnReflection (in vec3 theOutput, out vec3 theInput, in vec3 theFre
return aFresnel * ((theExponent + 2.f) / (theExponent + 1.f) * aGeom / aCosThetaO);
}
// Enables expiremental russian roulette sampling
// #define RUSSIAN_ROULETTE
//=======================================================================
// function : sampleMaterial
// purpose : Samples specified composite material (BSDF)
//=======================================================================
bool sampleMaterial (in SMaterial theMaterial,
void sampleMaterial (in SMaterial theMaterial,
in vec3 theOutput,
in vec3 theFactor,
out vec3 theInput,
out vec3 theWeight,
inout bool isTransmit)
inout vec3 theWeight,
inout int theBounce)
{
theWeight = ZERO;
// Compute the probability of ray reflection
float aPd = convolve (theMaterial.Kd.rgb, theFactor);
float aPs = convolve (theMaterial.Ks.rgb, theFactor);
float aPr = convolve (theMaterial.Kr.rgb, theFactor);
float aPt = convolve (theMaterial.Kt.rgb, theFactor);
float aPd = convolve (theMaterial.Kd.rgb, theWeight);
float aPs = convolve (theMaterial.Ks.rgb, theWeight);
float aPr = convolve (theMaterial.Kr.rgb, theWeight);
float aPt = convolve (theMaterial.Kt.rgb, theWeight);
float aReflection = aPd + aPs + aPr + aPt;
#ifndef RUSSIAN_ROULETTE
if (aReflection < 1e-2f)
{
return false; // path termination
}
#else
float aSurvival = max (dot (theFactor, LUMA), 0.1f);
if (RandFloat() > aSurvival)
{
return false; // path termination
}
#endif
isTransmit = false;
// Choose BSDF component to sample
float aKsi = aReflection * RandFloat();
theBounce = NON_SPECULAR_BOUNCE;
if (aKsi < aPd) // diffuse reflection
{
sampleLambertianReflection (theOutput, theInput);
#ifndef RUSSIAN_ROULETTE
theWeight = theMaterial.Kd.rgb * (aReflection / aPd);
#else
theWeight = theMaterial.Kd.rgb * (aReflection / aPd / aSurvival);
#endif
return false; // non-specular bounce
theWeight *= theMaterial.Kd.rgb * (aReflection / aPd);
}
else if (aKsi < aPd + aPs) // glossy reflection
{
theWeight = sampleBlinnReflection (theOutput, theInput, theMaterial.Fresnel, theMaterial.Ks.w);
#ifndef RUSSIAN_ROULETTE
theWeight *= theMaterial.Ks.rgb * (aReflection / aPs);
#else
theWeight *= theMaterial.Ks.rgb * (aReflection / aPs / aSurvival);
#endif
return false; // non-specular bounce
theWeight *= theMaterial.Ks.rgb * (aReflection / aPs) *
sampleBlinnReflection (theOutput, theInput, theMaterial.Fresnel, theMaterial.Ks.w);
}
else if (aKsi < aPd + aPs + aPr) // specular reflection
{
theWeight = sampleSpecularReflection (theOutput, theInput, theMaterial.Fresnel);
theWeight *= theMaterial.Kr.rgb * (aReflection / aPr) *
sampleSpecularReflection (theOutput, theInput, theMaterial.Fresnel);
#ifndef RUSSIAN_ROULETTE
theWeight *= theMaterial.Kr.rgb * (aReflection / aPr);
#else
theWeight *= theMaterial.Kr.rgb * (aReflection / aPr / aSurvival);
#endif
return true; // specular bounce
theBounce = SPEC_REFLECT_BOUNCE; // specular bounce
}
else // specular transmission
{
theWeight = sampleSpecularTransmission (theOutput, theInput,
isTransmit, theFactor, theMaterial.Fresnel);
#ifndef RUSSIAN_ROULETTE
theWeight *= theMaterial.Kt.rgb * (aReflection / aPt);
#else
theWeight *= theMaterial.Kt.rgb * (aReflection / aPt / aSurvival);
#endif
return true; // specular bounce
theWeight *= theMaterial.Kt.rgb * (aReflection / aPt) *
sampleSpecularTransmission (theOutput, theInput, theBounce, theWeight, theMaterial.Fresnel);
}
// path termination for extra small weights
theWeight = mix (theWeight, ZERO, float (aReflection < 1e-3f));
}
//////////////////////////////////////////////////////////////////////////////////////////////
@ -532,11 +491,14 @@ bool sampleMaterial (in SMaterial theMaterial,
// function : handlePointLight
// purpose :
//=======================================================================
float handlePointLight (in vec3 theInput, in vec3 theToLight, in float theRadius)
float handlePointLight (in vec3 theInput, in vec3 theToLight, in float theRadius, in float theDistance)
{
float aCosMax = sqrt (1.f - theRadius * theRadius / dot (theToLight, theToLight));
float aDistance = dot (theToLight, theToLight);
return step (aCosMax, dot (theInput, theToLight));
float aCosMax = inversesqrt (1.f + theRadius * theRadius / aDistance);
return float (aDistance < theDistance * theDistance) *
step (aCosMax, dot (theToLight, theInput) * inversesqrt (aDistance));
}
//=======================================================================
@ -549,47 +511,29 @@ float handleDirectLight (in vec3 theInput, in vec3 theToLight, in float theCosMa
}
//=======================================================================
// function : samplePointLight
// purpose :
// function : sampleLight
// purpose : general sampling function for directional and point lights
//=======================================================================
vec3 samplePointLight (in vec3 theToLight, in float theRadius, inout float thePDF)
vec3 sampleLight (in vec3 theToLight, in bool isDirectional, in float theSmoothness, inout float thePDF)
{
SLocalSpace aSpace = LocalSpace (theToLight);
float aCosMax = sqrt (1.f - theRadius * theRadius / dot (theToLight, theToLight));
// for point lights smoothness defines radius
float aCosMax = isDirectional ? theSmoothness :
inversesqrt (1.f + theSmoothness * theSmoothness / dot (theToLight, theToLight));
float aKsi1 = RandFloat();
float aKsi2 = RandFloat();
float aTmp = 1.f - aKsi2 * (1.f - aCosMax);
vec3 anInput = vec3 (sqrt (1.f - aTmp * aTmp) * cos (2.f * M_PI * aKsi1),
sqrt (1.f - aTmp * aTmp) * sin (2.f * M_PI * aKsi1),
vec3 anInput = vec3 (cos (2.f * M_PI * aKsi1),
sin (2.f * M_PI * aKsi1),
aTmp);
thePDF *= (theRadius > 0.f) ? 1.f / (2.f * M_PI) / (1.f - aCosMax) : 1.f;
anInput.xy *= sqrt (1.f - aTmp * aTmp);
return normalize (fromLocalSpace (anInput, aSpace));
}
//=======================================================================
// function : sampleDirectLight
// purpose :
//=======================================================================
vec3 sampleDirectLight (in vec3 theToLight, in float theCosMax, inout float thePDF)
{
SLocalSpace aSpace = LocalSpace (theToLight);
float aKsi1 = RandFloat();
float aKsi2 = RandFloat();
float aTmp = 1.f - aKsi2 * (1.f - theCosMax);
vec3 anInput = vec3 (sqrt (1.f - aTmp * aTmp) * cos (2.f * M_PI * aKsi1),
sqrt (1.f - aTmp * aTmp) * sin (2.f * M_PI * aKsi1),
aTmp);
thePDF *= (theCosMax < 1.f) ? 1.f / (2.f * M_PI) / (1.f - theCosMax) : 1.f;
thePDF *= (aCosMax < 1.f) ? 1.f / (2.f * M_PI) / (1.f - aCosMax) : 1.f;
return normalize (fromLocalSpace (anInput, aSpace));
}
@ -609,26 +553,26 @@ vec2 Latlong (in vec3 thePoint)
}
// =======================================================================
// function : EnvironmentRadiance
// purpose :
// function: intersectLight
// purpose : Checks intersections with light sources
// =======================================================================
vec3 EnvironmentRadiance (in SRay theRay, in bool isSpecular, in bool isBackground)
vec3 intersectLight (in SRay theRay, in bool isViewRay, in int theBounce, in float theDistance)
{
vec3 aRadiance = ZERO;
if (uSphereMapForBack != 0 || !isBackground)
if ((isViewRay || IS_REFR_SPEC_BOUNCE(theBounce)) && uSphereMapForBack == 0)
{
aRadiance += FetchEnvironment (Latlong (theRay.Direct)).xyz;
aRadiance = BackgroundColor().xyz;
}
else
{
aRadiance += BackgroundColor().xyz;
aRadiance = FetchEnvironment (Latlong (theRay.Direct)).xyz;
}
// Apply gamma correction (gamma is 2)
aRadiance *= aRadiance;
aRadiance = aRadiance * aRadiance * float (theDistance == MAXFLOAT);
for (int aLightIdx = 0; aLightIdx < uLightCount && isSpecular; ++aLightIdx)
for (int aLightIdx = 0; aLightIdx < uLightCount && (isViewRay || IS_ANY_SPEC_BOUNCE(theBounce)); ++aLightIdx)
{
vec4 aLight = texelFetch (
uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
@ -637,9 +581,10 @@ vec3 EnvironmentRadiance (in SRay theRay, in bool isSpecular, in bool isBackgrou
if (aLight.w != 0.f) // point light source
{
aRadiance += aParam.rgb * handlePointLight (theRay.Direct, aLight.xyz - theRay.Origin, aParam.w /* radius */);
aRadiance += aParam.rgb * handlePointLight (
theRay.Direct, aLight.xyz - theRay.Origin, aParam.w /* radius */, theDistance);
}
else // directional light source
else if (theDistance == MAXFLOAT) // directional light source
{
aRadiance += aParam.rgb * handleDirectLight (theRay.Direct, aLight.xyz, aParam.w /* angle cosine */);
}
@ -659,6 +604,9 @@ vec3 EnvironmentRadiance (in SRay theRay, in bool isSpecular, in bool isBackgrou
#define MATERIAL_FRESNEL(index) (18 * index + 16)
#define MATERIAL_ABSORPT(index) (18 * index + 17)
// Enables expiremental russian roulette sampling
#define RUSSIAN_ROULETTE
//=======================================================================
// function : PathTrace
// purpose : Calculates radiance along the given ray
@ -670,28 +618,31 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
vec3 aRadiance = ZERO;
vec3 aThroughput = UNIT;
bool isInMedium = false;
bool isSpecular = false;
bool isTransmit = false;
int aBounce = 0; // type of previous hit point
int aTrsfId = 0; // offset of object transform
int anObjectId; // ID of intersected triangle
bool isInMedium = false;
for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)
{
SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId);
if (aTriIndex.x == -1)
// check implicit path
vec3 aLe = intersectLight (theRay,
aDepth == 0 /* is view ray */, aBounce, aHit.Time);
if (any (greaterThan (aLe, ZERO)) || aTriIndex.x == -1)
{
return vec4 (aRadiance + aThroughput *
EnvironmentRadiance (theRay, isSpecular, aDepth == 0 || isTransmit), 0.f);
aRadiance += aThroughput * aLe; break; // terminate path
}
vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0).xyz;
vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1).xyz;
vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2).xyz;
vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0).xyz;
vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1).xyz;
vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2).xyz;
// compute geometrical normal
aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),
dot (aInvTransf1, aHit.Normal),
dot (aInvTransf2, aHit.Normal)));
@ -711,9 +662,9 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
aThroughput *= aSrcColorRGBA.w;
}
theRay.Origin += theRay.Direct * aHit.Time; // intersection point
theRay.Origin += theRay.Direct * aHit.Time; // get new intersection point
// Fetch material (BSDF)
// fetch material (BSDF)
SMaterial aMaterial = SMaterial (
vec4 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriIndex.w))),
vec3 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KR (aTriIndex.w))),
@ -742,6 +693,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
}
#endif
// compute smooth normal
vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
@ -750,7 +702,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
SLocalSpace aSpace = LocalSpace (aNormal);
// Account for self-emission (not stored in the material)
// account for self-emission (not stored in the material)
aRadiance += aThroughput * texelFetch (
uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w)).rgb;
@ -763,18 +715,13 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
vec4 aParam = texelFetch (
uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));
float aPDF = 1.f / uLightCount, aDistance = MAXFLOAT;
// 'w' component is 0 for infinite light and 1 for point light
aLight.xyz -= mix (ZERO, theRay.Origin, aLight.w);
if (aLight.w != 0.f) // point light source
{
aDistance = length (aLight.xyz -= theRay.Origin);
float aPDF = 1.f / uLightCount, aDistance = length (aLight.xyz);
aLight.xyz = samplePointLight (aLight.xyz, aParam.w /* radius */, aPDF);
}
else // directional light source
{
aLight.xyz = sampleDirectLight (aLight.xyz, aParam.w /* angle cosine */, aPDF);
}
aLight.xyz = sampleLight (aLight.xyz * (1.f / aDistance),
aLight.w == 0.f /* is infinite */, aParam.w /* angle cosine */, aPDF);
vec3 aContrib = (1.f / aPDF) * aParam.rgb /* Le */ * handleMaterial (
aMaterial, toLocalSpace (aLight.xyz, aSpace), toLocalSpace (-theRay.Direct, aSpace));
@ -787,17 +734,16 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
-uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, aLight.xyz)));
float aVisibility = SceneAnyHit (aShadow,
InverseDirection (aLight.xyz), aDistance);
InverseDirection (aLight.xyz), aLight.w == 0.f ? MAXFLOAT : aDistance);
aRadiance += aVisibility * aThroughput * aContrib;
}
}
vec3 anInput;
vec3 aWeight;
isSpecular = sampleMaterial (aMaterial,
toLocalSpace (-theRay.Direct, aSpace), aThroughput, anInput, aWeight, isTransmit);
sampleMaterial (aMaterial,
toLocalSpace (-theRay.Direct, aSpace), anInput, aThroughput, aBounce);
if (isInMedium)
{
@ -805,14 +751,23 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
aMaterial.Absorption.w * (UNIT - aMaterial.Absorption.rgb));
}
isInMedium = isTransmit ? !isInMedium : isInMedium;
aThroughput *= aWeight;
isInMedium = IS_REFR_SPEC_BOUNCE(aBounce) ? !isInMedium : isInMedium;
#ifndef RUSSIAN_ROULETTE
if (all (lessThan (aThroughput, MIN_THROUGHPUT)))
{
return vec4 (aRadiance, 0.f);
aDepth = INVALID_BOUNCES; // terminate path
}
#else
float aSurvive = aDepth < 3 ? 1.f : min (dot (LUMA, aThroughput), 0.95f);
if (RandFloat() > aSurvive)
{
aDepth = INVALID_BOUNCES; // terminate path
}
aThroughput /= aSurvive;
#endif
anInput = normalize (fromLocalSpace (anInput, aSpace));

View File

@ -158,9 +158,9 @@ uint RandState;
// purpose : Applies hash function by Thomas Wang to randomize seeds
// (see http://www.burtleburtle.net/bob/hash/integer.html)
// =======================================================================
void SeedRand (in int theSeed, in int theSizeX)
void SeedRand (in int theSeed, in int theSizeX, in int theRadius)
{
RandState = uint (int (gl_FragCoord.y) * theSizeX + int (gl_FragCoord.x) + theSeed);
RandState = uint (int (gl_FragCoord.y) / theRadius * theSizeX + int (gl_FragCoord.x) / theRadius + theSeed);
RandState = (RandState + 0x479ab41du) + (RandState << 8);
RandState = (RandState ^ 0xe4aa10ceu) ^ (RandState >> 5);
@ -365,9 +365,7 @@ ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgO
ivec4 aTriIndex = INALID_HIT;
bool toContinue = true;
while (toContinue)
for (bool toContinue = true; toContinue;)
{
ivec3 aData = texelFetch (uSceneNodeInfoTexture, aNode).xyz;
@ -487,11 +485,9 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
int aHead = theSentinel; // stack pointer
int aNode = theBVHOffset; // node to visit
#ifdef TRANSPARENT_SHADOWS
float aFactor = 1.0f;
#endif
float aFactor = 1.f;
while (true)
for (bool toContinue = true; toContinue;)
{
ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
@ -545,14 +541,9 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
}
else
{
#ifdef TRANSPARENT_SHADOWS
if (aHead == theSentinel)
return aFactor;
#else
if (aHead == theSentinel)
return 1.0f;
#endif
toContinue = (aHead != theSentinel);
if (toContinue)
aNode = Stack[aHead--];
}
}
@ -580,45 +571,38 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
#ifdef TRANSPARENT_SHADOWS
if (aTime < theDistance)
{
aFactor *= 1.0f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
aFactor *= 1.f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
}
#else
if (aTime < theDistance)
return 0.0f;
{
aFactor = 0.f;
}
#endif
}
#ifdef TRANSPARENT_SHADOWS
if (aHead == theSentinel || aFactor < 0.1f)
return aFactor;
#else
if (aHead == theSentinel)
return 1.0f;
#endif
toContinue = (aHead != theSentinel) && (aFactor > 0.1f);
if (toContinue)
aNode = Stack[aHead--];
}
}
#ifdef TRANSPARENT_SHADOWS
return aFactor;
#else
return 1.0f;
#endif
}
// =======================================================================
// function : SceneNearestHit
// purpose : Finds intersection with nearest scene triangle
// =======================================================================
ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theObjectId)
ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
{
int aHead = -1; // stack pointer
int aNode = 0; // node to visit
ivec4 aHitObject = INALID_HIT;
while (true)
for (bool toContinue = true; toContinue;)
{
ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
@ -635,12 +619,12 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
{
// fetch object transformation
int anObjectId = aData.x - 1;
int aTrsfId = (aData.x - 1) * 4;
vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0);
vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1);
vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2);
vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, aTrsfId + 3);
SRay aTrsfRay = SRay (
MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
@ -660,13 +644,13 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
aTriIndex.z, // vertex 2
aTriIndex.w); // material
theObjectId = anObjectId;
theTrsfId = aTrsfId;
}
}
if (aHead < 0)
return aHitObject;
toContinue = aHead >= 0;
if (toContinue)
aNode = Stack[aHead--];
}
else // if inner node
@ -716,9 +700,9 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
}
else
{
if (aHead < 0)
return aHitObject;
toContinue = aHead >= 0;
if (toContinue)
aNode = Stack[aHead--];
}
}
@ -737,23 +721,21 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
int aHead = -1; // stack pointer
int aNode = 0; // node to visit
#ifdef TRANSPARENT_SHADOWS
float aFactor = 1.0f;
#endif
float aFactor = 1.f;
while (true)
for (bool toContinue = true; toContinue;)
{
ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
if (aData.x != 0) // if leaf node
{
// fetch object transformation
int anObjectId = aData.x - 1;
int aTrsfId = (aData.x - 1) * 4;
vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0);
vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1);
vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2);
vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, aTrsfId + 3);
SRay aTrsfRay = SRay (
MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
@ -767,16 +749,15 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
aFactor *= ObjectAnyHit (
aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
if (aHead < 0 || aFactor < 0.1f)
return aFactor;
toContinue = aHead >= 0 && aFactor >= 0.1f;
#else
bool isShadow = 0.0f == ObjectAnyHit (
aFactor = ObjectAnyHit (
aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
if (aHead < 0 || isShadow)
return isShadow ? 0.0f : 1.0f;
toContinue = aHead >= 0 && aFactor != 0.0f;
#endif
if (toContinue)
aNode = Stack[aHead--];
}
else // if inner node
@ -826,25 +807,16 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
}
else
{
#ifdef TRANSPARENT_SHADOWS
if (aHead < 0)
return aFactor;
#else
if (aHead < 0)
return 1.0f;
#endif
toContinue = aHead >= 0;
if (toContinue)
aNode = Stack[aHead--];
}
}
}
}
#ifdef TRANSPARENT_SHADOWS
return aFactor;
#else
return 1.0f;
#endif
}
#define PI 3.1415926f
@ -955,7 +927,7 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
vec3 aResult = vec3 (0.0f);
vec4 aWeight = vec4 (1.0f);
int anObjectId;
int aTrsfId;
float anOpenGlDepth = ComputeOpenGlDepth (theRay);
@ -963,7 +935,7 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
{
SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId);
if (aTriIndex.x == -1)
{
@ -982,12 +954,14 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
aColor = vec4 (BackgroundColor().rgb * aGlColor.w + ComputeOpenGlColor().rgb, aGlColor.w);
}
return vec4 (aResult.xyz + aWeight.xyz * aColor.xyz, aWeight.w * aColor.w);
aResult += aWeight.xyz * aColor.xyz; aWeight.w *= aColor.w;
break; // terminate path
}
vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0).xyz;
vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1).xyz;
vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2).xyz;
vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0).xyz;
vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1).xyz;
vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2).xyz;
aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),
dot (aInvTransf1, aHit.Normal),

View File

@ -9,6 +9,12 @@ uniform float uSampleWeight;
//! Input accumulated image.
uniform sampler2D uAccumTexture;
//! Enabled/disbales using of single RNG seed for image 16x16 blocks.
//! Increases performance up to 4 times, but noise becomes structured.
uniform int uBlockedRngEnabled;
#define MAX_RADIANCE vec3 (10.f)
// =======================================================================
// function : main
// purpose :
@ -20,7 +26,7 @@ void main (void)
#else
ivec2 aWinSize = textureSize (uAccumTexture, 0);
SeedRand (uFrameRndSeed, aWinSize.x);
SeedRand (uFrameRndSeed, aWinSize.x, uBlockedRngEnabled == 0 ? 1 : 16);
SRay aRay = GenerateRay (vPixel +
vec2 (RandFloat() + 1.f, RandFloat() + 1.f) / vec2 (aWinSize));
@ -33,19 +39,17 @@ void main (void)
aRay.Direct.z < 0.f ? -aInvDirect.z : aInvDirect.z);
#ifdef PATH_TRACING
vec4 aColor = PathTrace (aRay, aInvDirect);
if (any (isnan (aColor.xyz)))
{
aColor.xyz = ZERO;
aColor.rgb = ZERO;
}
aColor.rgb = min (aColor.rgb, MAX_RADIANCE);
OutColor = mix (texture2D (uAccumTexture, vPixel), aColor, uSampleWeight);
#else
OutColor = clamp (Radiance (aRay, aInvDirect), 0.f, 1.f);
#endif
}

View File

@ -5320,6 +5320,22 @@ static int VFps (Draw_Interpretor& theDI,
theDI << "FPS: " << aFpsAver << "\n"
<< "CPU: " << (1000.0 * aCpuAver) << " msec\n";
// compute additional statistics in ray-tracing mode
Graphic3d_RenderingParams& aParams = aView->ChangeRenderingParams();
if (aParams.Method == Graphic3d_RM_RAYTRACING)
{
Standard_Integer aSizeX;
Standard_Integer aSizeY;
aView->Window()->Size (aSizeX, aSizeY);
// 1 shadow ray and 1 secondary ray pew each bounce
const Standard_Real aMRays = aSizeX * aSizeY * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
theDI << "MRays/sec (upper bound): " << aMRays << "\n";
}
return 0;
}
@ -8389,6 +8405,7 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
theDI << "rayDepth: " << aParams.RaytracingDepth << "\n";
theDI << "gleam: " << (aParams.IsTransparentShadowEnabled ? "on" : "off") << "\n";
theDI << "GI: " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
theDI << "blocked RNG: " << (aParams.CoherentPathTracingMode ? "on" : "off") << "\n";
theDI << "shadingModel: ";
switch (aView->ShadingModel())
{
@ -8573,6 +8590,23 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
aParams.RaytracingDepth = Min (aParams.RaytracingDepth, 10);
}
}
else if (aFlag == "-blockedrng"
|| aFlag == "-brng")
{
if (toPrint)
{
theDI << (aParams.CoherentPathTracingMode ? "on" : "off") << " ";
continue;
}
Standard_Boolean toEnable = Standard_True;
if (++anArgIter < theArgNb
&& !parseOnOff (theArgVec[anArgIter], toEnable))
{
--anArgIter;
}
aParams.CoherentPathTracingMode = toEnable;
}
else if (aFlag == "-env")
{
if (toPrint)
@ -9360,6 +9394,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
"\n '-fsaa on|off' Enables/disables adaptive anti-aliasing"
"\n '-gleam on|off' Enables/disables transparency shadow effects"
"\n '-gi on|off' Enables/disables global illumination effects"
"\n '-brng on|off' Enables/disables blocked RNG (fast coherent PT)"
"\n '-env on|off' Enables/disables environment map background"
"\n '-shadingModel model' Controls shading model from enumeration"
"\n color, flat, gouraud, phong"