--- /dev/null
+#########################################################################
+# 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
IsReflectionEnabled (Standard_False),
IsAntialiasingEnabled (Standard_False),
IsTransparentShadowEnabled (Standard_False),
+ CoherentPathTracingMode (Standard_False),
UseEnvironmentMapBackground (Standard_False),
StereoMode (Graphic3d_StereoMode_QuadBuffer),
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
const Aspect_CLayer2d& theCOverLayer,
const Standard_Boolean theToDrawImmediate);
-
void DrawBackground (const Handle(OpenGl_Workspace)& theWorkspace);
//! Returns list of OpenGL Z-layers.
OpenGl_RT_uSphereMapEnabled,
OpenGl_RT_uSphereMapForBack,
OpenGl_RT_uTexSamplersArray,
+ OpenGl_RT_uBlockedRngEnabled,
// sampled frame params
OpenGl_RT_uSampleWeight,
const Handle(OpenGl_Context)& theGlContext);
//! Adds OpenGL groups to ray-traced scene geometry.
- Standard_Boolean addRaytraceGroups (const OpenGl_Structure* theStructure,
- const Standard_Integer theStructMat,
- const Standard_ShortReal* theTransform,
- const Handle(OpenGl_Context)& theGlContext);
+ Standard_Boolean addRaytraceGroups (const OpenGl_Structure* theStructure,
+ const OpenGl_RaytraceMaterial& theStructMat,
+ const Standard_ShortReal* theTransform,
+ const Handle(OpenGl_Context)& theGlContext);
//! Creates ray-tracing material properties.
OpenGl_RaytraceMaterial convertMaterial (const OpenGl_AspectFace* theAspect,
}
// 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];
}
}
- Standard_Boolean aResult = addRaytraceGroups (theStructure, aStructMatID,
+ Standard_Boolean aResult = addRaytraceGroups (theStructure, aStructMaterial,
theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext);
// Process all connected OpenGL structures
if (anInstanced != NULL && anInstanced->IsRaytracable())
{
- aResult &= addRaytraceGroups (anInstanced, aStructMatID,
+ aResult &= addRaytraceGroups (anInstanced, aStructMaterial,
theStructure->Transformation()->mat ? aStructTransform : NULL, theGlContext);
}
// function : addRaytraceGroups
// purpose : Adds OpenGL groups to ray-traced scene geometry
// =======================================================================
-Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure* theStructure,
- const Standard_Integer theStructMat,
- const Standard_ShortReal* theTransform,
- const Handle(OpenGl_Context)& theGlContext)
+Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure* theStructure,
+ 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)
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");
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())
{
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)
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);
- 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;
}
//=======================================================================
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);
-
-#ifndef RUSSIAN_ROULETTE
- theWeight *= theMaterial.Kr.rgb * (aReflection / aPr);
-#else
- theWeight *= theMaterial.Kr.rgb * (aReflection / aPr / aSurvival);
-#endif
+ theWeight *= theMaterial.Kr.rgb * (aReflection / aPr) *
+ sampleSpecularReflection (theOutput, theInput, theMaterial.Fresnel);
- 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));
}
//////////////////////////////////////////////////////////////////////////////////////////////
// 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);
+
+ float aCosMax = inversesqrt (1.f + theRadius * theRadius / aDistance);
- return step (aCosMax, dot (theInput, theToLight));
+ return float (aDistance < theDistance * theDistance) *
+ step (aCosMax, dot (theToLight, theInput) * inversesqrt (aDistance));
}
//=======================================================================
}
//=======================================================================
-// 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;
-
- 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();
+ anInput.xy *= sqrt (1.f - aTmp * aTmp);
- 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));
}
}
// =======================================================================
-// 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));
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 */);
}
#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
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);
+
+ // check implicit path
+ vec3 aLe = intersectLight (theRay,
+ aDepth == 0 /* is view ray */, aBounce, aHit.Time);
- if (aTriIndex.x == -1)
+ 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)));
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))),
}
#endif
+ // compute smooth normal
vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
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;
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));
-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)
{
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));
theRay = SRay (theRay.Origin + anInput * uSceneEpsilon +
// 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);
ivec4 aTriIndex = INALID_HIT;
- bool toContinue = true;
-
- while (toContinue)
+ for (bool toContinue = true; toContinue;)
{
ivec3 aData = texelFetch (uSceneNodeInfoTexture, aNode).xyz;
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);
}
else
{
-#ifdef TRANSPARENT_SHADOWS
- if (aHead == theSentinel)
- return aFactor;
-#else
- if (aHead == theSentinel)
- return 1.0f;
-#endif
+ toContinue = (aHead != theSentinel);
- aNode = Stack[aHead--];
+ if (toContinue)
+ aNode = Stack[aHead--];
}
}
}
#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);
- aNode = Stack[aHead--];
+ 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);
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),
aTriIndex.z, // vertex 2
aTriIndex.w); // material
- theObjectId = anObjectId;
+ theTrsfId = aTrsfId;
}
}
- if (aHead < 0)
- return aHitObject;
+ toContinue = aHead >= 0;
- aNode = Stack[aHead--];
+ if (toContinue)
+ aNode = Stack[aHead--];
}
else // if inner node
{
}
else
{
- if (aHead < 0)
- return aHitObject;
+ toContinue = aHead >= 0;
- aNode = Stack[aHead--];
+ if (toContinue)
+ aNode = Stack[aHead--];
}
}
}
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),
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
- aNode = Stack[aHead--];
+ if (toContinue)
+ aNode = Stack[aHead--];
}
else // if inner node
{
vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
-
+
vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
-
+
aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
-
+
int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
if (bool(aHitLft & aHitRgh))
}
else
{
-#ifdef TRANSPARENT_SHADOWS
- if (aHead < 0)
- return aFactor;
-#else
- if (aHead < 0)
- return 1.0f;
-#endif
+ toContinue = aHead >= 0;
- aNode = Stack[aHead--];
+ if (toContinue)
+ aNode = Stack[aHead--];
}
}
}
}
-#ifdef TRANSPARENT_SHADOWS
return aFactor;
-#else
- return 1.0f;
-#endif
}
#define PI 3.1415926f
vec3 aResult = vec3 (0.0f);
vec4 aWeight = vec4 (1.0f);
- int anObjectId;
+ int aTrsfId;
float anOpenGlDepth = ComputeOpenGlDepth (theRay);
{
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)
{
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),
//! 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 :
#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));
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;
}
- OutColor = mix (texture2D (uAccumTexture, vPixel), aColor, uSampleWeight);
+ 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
}
\ No newline at end of file
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_ShortReal aMRays = aSizeX * aSizeY * aFpsAver * aParams.RaytracingDepth * 2 / 1.0e6f;
+
+ theDI << "MRays/sec (upper bound): " << aMRays << "\n";
+ }
+
return 0;
}
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())
{
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)
"\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"