//! Default pixels density.
static const unsigned int THE_DEFAULT_RESOLUTION = 72u;
- //! Default number of samples per pixel.
- static const Standard_Integer THE_DEFAULT_SPP = 1;
-
//! Default ray-tracing depth.
static const Standard_Integer THE_DEFAULT_DEPTH = 3;
NbMsaaSamples (0),
// ray tracing parameters
IsGlobalIlluminationEnabled (Standard_False),
- SamplesPerPixel (THE_DEFAULT_SPP),
RaytracingDepth (THE_DEFAULT_DEPTH),
IsShadowEnabled (Standard_True),
IsReflectionEnabled (Standard_False),
CoherentPathTracingMode (Standard_False),
AdaptiveScreenSampling (Standard_False),
ShowSamplingTiles (Standard_False),
+ TwoSidedBsdfModels (Standard_False),
RebuildRayTracingShaders (Standard_False),
// stereoscopic parameters
StereoMode (Graphic3d_StereoMode_QuadBuffer),
Standard_Boolean CoherentPathTracingMode; //!< enables/disables 'coherent' tracing mode (single RNG seed within 16x16 image blocks)
Standard_Boolean AdaptiveScreenSampling; //!< enables/disables adaptive screen sampling mode for path tracing, FALSE by default
Standard_Boolean ShowSamplingTiles; //!< enables/disables debug mode for adaptive screen sampling, FALSE by default
+ Standard_Boolean TwoSidedBsdfModels; //!< forces path tracing to use two-sided versions of original one-sided scattering models
Standard_Boolean RebuildRayTracingShaders; //!< forces rebuilding ray tracing shaders at the next frame
Graphic3d_StereoMode StereoMode; //!< stereoscopic output mode, Graphic3d_StereoMode_QuadBuffer by default
//! Enables/disables the use of OpenGL bindless textures.
Standard_Boolean UseBindlessTextures;
+ //! Enables/disables two-sided BSDF models instead of one-sided.
+ Standard_Boolean TwoSidedBsdfModels;
+
//! Enables/disables adaptive screen sampling for path tracing.
Standard_Boolean AdaptiveScreenSampling;
RaytracingParams()
: StackSize (THE_DEFAULT_STACK_SIZE),
NbBounces (THE_DEFAULT_NB_BOUNCES),
- TransparentShadows (Standard_False),
- GlobalIllumination (Standard_False),
- UseBindlessTextures (Standard_False),
- AdaptiveScreenSampling (Standard_False)
- {
- //
- }
+ TransparentShadows (Standard_False),
+ GlobalIllumination (Standard_False),
+ UseBindlessTextures (Standard_False),
+ TwoSidedBsdfModels (Standard_False),
+ AdaptiveScreenSampling (Standard_False) { }
};
//! Describes state of OpenGL structure.
TCollection_AsciiString ("\n#define BLOCK_SIZE ") + TCollection_AsciiString (OpenGl_TileSampler::TileSize());
}
}
+
+ if (myRaytraceParameters.TwoSidedBsdfModels) // two-sided BSDFs requested
+ {
+ aPrefixString += TCollection_AsciiString ("\n#define TWO_SIDED_BXDF");
+ }
}
return aPrefixString;
}
}
- if (myRenderParams.RaytracingDepth != myRaytraceParameters.NbBounces)
- {
- myRaytraceParameters.NbBounces = myRenderParams.RaytracingDepth;
- aToRebuildShaders = Standard_True;
- }
-
- if (myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures)
+ if (myRenderParams.RaytracingDepth != myRaytraceParameters.NbBounces
+ || myRenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows
+ || myRenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination
+ || myRenderParams.TwoSidedBsdfModels != myRaytraceParameters.TwoSidedBsdfModels
+ || myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures)
{
+ myRaytraceParameters.NbBounces = myRenderParams.RaytracingDepth;
+ myRaytraceParameters.TransparentShadows = myRenderParams.IsTransparentShadowEnabled;
+ myRaytraceParameters.GlobalIllumination = myRenderParams.IsGlobalIlluminationEnabled;
+ myRaytraceParameters.TwoSidedBsdfModels = myRenderParams.TwoSidedBsdfModels;
myRaytraceParameters.UseBindlessTextures = myRaytraceGeometry.HasTextures();
- aToRebuildShaders = Standard_True;
- }
- if (myRenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows)
- {
- myRaytraceParameters.TransparentShadows = myRenderParams.IsTransparentShadowEnabled;
- aToRebuildShaders = Standard_True;
- }
-
- if (myRenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination)
- {
- myRaytraceParameters.GlobalIllumination = myRenderParams.IsGlobalIlluminationEnabled;
aToRebuildShaders = Standard_True;
}
//////////////////////////////////////////////////////////////////////////////////////////////
//=======================================================================
-// function : HandleLambertianReflection
-// purpose : Handles Lambertian BRDF, with cos(N, PSI)
+// function : EvalLambertianReflection
+// purpose : Evaluates Lambertian BRDF, with cos(N, PSI)
//=======================================================================
-float HandleLambertianReflection (in vec3 theInput, in vec3 theOutput)
+float EvalLambertianReflection (in vec3 theWi, in vec3 theWo)
{
- return (theInput.z <= 0.f || theOutput.z <= 0.f) ? 0.f : theInput.z * (1.f / M_PI);
+ return (theWi.z <= 0.f || theWo.z <= 0.f) ? 0.f : theWi.z * (1.f / M_PI);
}
//=======================================================================
}
//=======================================================================
-// function : HandleBlinnReflection
-// purpose : Handles Blinn glossy BRDF, with cos(N, PSI)
+// function : EvalBlinnReflection
+// purpose : Evaluates Blinn glossy BRDF, with cos(N, PSI)
//=======================================================================
-vec3 HandleBlinnReflection (in vec3 theInput, in vec3 theOutput, in vec3 theFresnel, in float theRoughness)
+vec3 EvalBlinnReflection (in vec3 theWi, in vec3 theWo, in vec3 theFresnel, in float theRoughness)
{
// calculate the reflection half-vec
- vec3 aH = normalize (theInput + theOutput);
+ vec3 aH = normalize (theWi + theWo);
// roughness value -> Blinn exponent
float aPower = max (2.f / (theRoughness * theRoughness) - 2.f, 0.f);
float aD = (aPower + 2.f) * (1.f / M_2_PI) * pow (aH.z, aPower);
// calculate shadow-masking function
- float aG = SmithG1 (theOutput, aH, theRoughness) * SmithG1 (theInput, aH, theRoughness);
+ float aG = SmithG1 (theWo, aH, theRoughness) *
+ SmithG1 (theWi, aH, theRoughness);
// return total amount of reflection
- return (theInput.z <= 0.f || theOutput.z <= 0.f) ? ZERO :
- aD * aG / (4.f * theOutput.z) * fresnelMedia (dot (theOutput, aH), theFresnel);
+ return (theWi.z <= 0.f || theWo.z <= 0.f) ? ZERO :
+ aD * aG / (4.f * theWo.z) * fresnelMedia (dot (theWo, aH), theFresnel);
}
//=======================================================================
-// function : HandleMaterial
-// purpose : Returns BSDF value for specified material, with cos(N, PSI)
+// function : EvalMaterial
+// purpose : Evaluates BSDF for specified material, with cos(N, PSI)
//=======================================================================
-vec3 HandleMaterial (in SMaterial theBSDF, in vec3 theInput, in vec3 theOutput)
+vec3 EvalMaterial (in SMaterial theBSDF, in vec3 theWi, in vec3 theWo)
{
- return theBSDF.Kd.rgb * HandleLambertianReflection (theInput, theOutput) +
- theBSDF.Ks.rgb * HandleBlinnReflection (theInput, theOutput, theBSDF.Fresnel, theBSDF.Ks.w);
+#ifdef TWO_SIDED_BXDF
+ theWi.z *= sign (theWi.z);
+ theWo.z *= sign (theWo.z);
+#endif
+
+ return theBSDF.Kd.rgb * EvalLambertianReflection (theWi, theWo) +
+ theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.Fresnel, theBSDF.Ks.w);
}
//=======================================================================
// function : SampleLambertianReflection
// purpose : Samples Lambertian BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)
//=======================================================================
-vec3 SampleLambertianReflection (in vec3 theOutput, out vec3 theInput, inout float thePDF)
+vec3 SampleLambertianReflection (in vec3 theWo, out vec3 theWi, inout float thePDF)
{
float aKsi1 = RandFloat();
float aKsi2 = RandFloat();
- float aTemp = sqrt (aKsi2);
+ theWi = vec3 (cos (M_2_PI * aKsi1),
+ sin (M_2_PI * aKsi1),
+ sqrt (1.f - aKsi2));
+
+ theWi.xy *= sqrt (aKsi2);
- theInput = vec3 (aTemp * cos (M_2_PI * aKsi1),
- aTemp * sin (M_2_PI * aKsi1),
- sqrt (1.f - aKsi2));
+#ifdef TWO_SIDED_BXDF
+ theWi.z *= sign (theWo.z);
+#endif
- thePDF *= abs (theInput.z) * (1.f / M_PI);
+ thePDF *= theWi.z * (1.f / M_PI);
- return (theInput.z <= 0.f || theOutput.z <= 0.f) ? ZERO : UNIT;
+#ifdef TWO_SIDED_BXDF
+ return UNIT;
+#else
+ return mix (UNIT, ZERO, theWo.z <= 0.f);
+#endif
}
//=======================================================================
// terms would be complex, and it is the D term that accounts
// for most of the variation.
//=======================================================================
-vec3 SampleBlinnReflection (in vec3 theOutput, out vec3 theInput, in vec3 theFresnel, in float theRoughness, inout float thePDF)
+vec3 SampleBlinnReflection (in vec3 theWo, out vec3 theWi, in vec3 theFresnel, in float theRoughness, inout float thePDF)
{
float aKsi1 = RandFloat();
float aKsi2 = RandFloat();
// calculate PDF of sampled direction
thePDF *= (aPower + 2.f) * (1.f / M_2_PI) * pow (aCosThetaM, aPower + 1.f);
- float aCosDelta = dot (theOutput, aM);
+#ifdef TWO_SIDED_BXDF
+ bool toFlip = theWo.z < 0.f;
+
+ if (toFlip)
+ theWo.z = -theWo.z;
+#endif
+
+ float aCosDelta = dot (theWo, aM);
// pick input based on half direction
- theInput = -theOutput + 2.f * aCosDelta * aM;
+ theWi = -theWo + 2.f * aCosDelta * aM;
- if (theInput.z <= 0.f || theOutput.z <= 0.f)
+ if (theWi.z <= 0.f || theWo.z <= 0.f)
{
return ZERO;
}
// Jacobian of half-direction mapping
- thePDF /= 4.f * dot (theInput, aM);
+ thePDF /= 4.f * dot (theWi, aM);
// compute shadow-masking coefficient
- float aG = SmithG1 (theOutput, aM, theRoughness) * SmithG1 (theInput, aM, theRoughness);
+ float aG = SmithG1 (theWo, aM, theRoughness) *
+ SmithG1 (theWi, aM, theRoughness);
+
+#ifdef TWO_SIDED_BXDF
+ if (toFlip)
+ theWi.z = -theWi.z;
+#endif
- return aG * aCosDelta / (theOutput.z * aM.z) * fresnelMedia (aCosDelta, theFresnel);
+ return (aG * aCosDelta) / (theWo.z * aM.z) * fresnelMedia (aCosDelta, theFresnel);
}
//=======================================================================
// function : SampleSpecularReflection
// purpose : Samples specular BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)
//=======================================================================
-vec3 SampleSpecularReflection (in vec3 theOutput, out vec3 theInput, in vec3 theFresnel)
+vec3 SampleSpecularReflection (in vec3 theWo, out vec3 theWi, in vec3 theFresnel)
{
// Sample input direction
- theInput = vec3 (-theOutput.x,
- -theOutput.y,
- theOutput.z);
-
- return fresnelMedia (theOutput.z, theFresnel);
+ theWi = vec3 (-theWo.x,
+ -theWo.y,
+ theWo.z);
+
+#ifdef TWO_SIDED_BXDF
+ return fresnelMedia (theWo.z, theFresnel);
+#else
+ return fresnelMedia (theWo.z, theFresnel) * step (0.f, theWo.z);
+#endif
}
//=======================================================================
// function : SampleSpecularTransmission
// purpose : Samples specular BTDF, W = BRDF * cos(N, PSI) / PDF(PSI)
//=======================================================================
-vec3 SampleSpecularTransmission (in vec3 theOutput,
- out vec3 theInput, in vec3 theWeight, in vec3 theFresnel, inout bool theInside)
+vec3 SampleSpecularTransmission (in vec3 theWo, out vec3 theWi, in vec3 theWeight, in vec3 theFresnel, inout bool theInside)
{
- vec3 aFactor = fresnelMedia (theOutput.z, theFresnel);
+ vec3 aFactor = fresnelMedia (theWo.z, theFresnel);
float aReflection = convolve (aFactor, theWeight);
// sample specular BRDF/BTDF
if (RandFloat() <= aReflection)
{
- theInput = vec3 (-theOutput.x,
- -theOutput.y,
- theOutput.z);
+ theWi = vec3 (-theWo.x,
+ -theWo.y,
+ theWo.z);
theWeight = aFactor * (1.f / aReflection);
}
{
theInside = !theInside;
- transmitted (theFresnel.y, theOutput, theInput);
+ transmitted (theFresnel.y, theWo, theWi);
theWeight = (UNIT - aFactor) * (1.f / (1.f - aReflection));
}
// function : BsdfPdf
// purpose : Calculates BSDF of sampling input knowing output
//=======================================================================
-float BsdfPdf (in SMaterial theBSDF,
- in vec3 theOutput,
- in vec3 theInput,
- in vec3 theWeight)
+float BsdfPdf (in SMaterial theBSDF, in vec3 theWo, in vec3 theWi, in vec3 theWeight)
{
float aPd = convolve (theBSDF.Kd.rgb, theWeight);
float aPs = convolve (theBSDF.Ks.rgb, theWeight);
float aPDF = 0.f; // PDF of sampling input direction
- if (theInput.z * theOutput.z > 0.f)
+ if (theWi.z * theWo.z > 0.f)
{
- vec3 aHalf = normalize (theInput + theOutput);
+ vec3 aH = normalize (theWi + theWo);
// roughness value --> Blinn exponent
float aPower = max (2.f / (theBSDF.Ks.w * theBSDF.Ks.w) - 2.f, 0.f);
- aPDF = aPd * abs (theInput.z / M_PI) +
- aPs * (aPower + 2.f) * (1.f / M_2_PI) * pow (aHalf.z, aPower + 1.f) / (4.f * dot (theInput, aHalf));
+ aPDF = aPd * abs (theWi.z / M_PI) +
+ aPs * (aPower + 2.f) * (1.f / M_2_PI) * pow (abs (aH.z), aPower + 1.f) / (4.f * dot (theWi, aH));
}
return aPDF / aReflection;
// function : SampleBsdf
// purpose : Samples specified composite material (BSDF)
//=======================================================================
-float SampleBsdf (in SMaterial theBSDF,
- in vec3 theOutput,
- out vec3 theInput,
- inout vec3 theWeight,
- inout bool theInside)
+float SampleBsdf (in SMaterial theBSDF, in vec3 theWo, out vec3 theWi, inout vec3 theWeight, inout bool theInside)
{
// compute probability of each reflection type (BxDF)
float aPd = convolve (theBSDF.Kd.rgb, theWeight);
{
PICK_BXDF (aPd, theBSDF.Kd.rgb);
- theWeight *= SampleLambertianReflection (theOutput, theInput, aPDF);
+ theWeight *= SampleLambertianReflection (theWo, theWi, aPDF);
}
else if (aKsi < aPd + aPs) // glossy reflection
{
PICK_BXDF (aPs, theBSDF.Ks.rgb);
- theWeight *= SampleBlinnReflection (theOutput, theInput, theBSDF.Fresnel, theBSDF.Ks.w, aPDF);
+ theWeight *= SampleBlinnReflection (theWo, theWi, theBSDF.Fresnel, theBSDF.Ks.w, aPDF);
}
else if (aKsi < aPd + aPs + aPr) // specular reflection
{
aPDF = MAXFLOAT;
- theWeight *= SampleSpecularReflection (theOutput, theInput, theBSDF.Fresnel);
+ theWeight *= SampleSpecularReflection (theWo, theWi, theBSDF.Fresnel);
}
else if (aKsi < aReflection) // specular transmission
{
aPDF = MAXFLOAT;
- theWeight *= SampleSpecularTransmission (theOutput, theInput, theWeight, theBSDF.Fresnel, theInside);
+ theWeight *= SampleSpecularTransmission (theWo, theWi, theWeight, theBSDF.Fresnel, theInside);
}
// path termination for extra small weights
// MIS weight including division by explicit PDF
float aMIS = (aExpPDF == MAXFLOAT) ? 1.f : aExpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);
- vec3 aContrib = aMIS * aParam.rgb /* Le */ * HandleMaterial (
+ vec3 aContrib = aMIS * aParam.rgb /* Le */ * EvalMaterial (
aMaterial, toLocalSpace (aLight.xyz, aSpace), toLocalSpace (-theRay.Direct, aSpace));
if (any (greaterThan (aContrib, MIN_CONTRIBUTION))) // check if light source is important
"//////////////////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"//=======================================================================\n"
- "// function : HandleLambertianReflection\n"
- "// purpose : Handles Lambertian BRDF, with cos(N, PSI)\n"
+ "// function : EvalLambertianReflection\n"
+ "// purpose : Evaluates Lambertian BRDF, with cos(N, PSI)\n"
"//=======================================================================\n"
- "float HandleLambertianReflection (in vec3 theInput, in vec3 theOutput)\n"
+ "float EvalLambertianReflection (in vec3 theWi, in vec3 theWo)\n"
"{\n"
- " return (theInput.z <= 0.f || theOutput.z <= 0.f) ? 0.f : theInput.z * (1.f / M_PI);\n"
+ " return (theWi.z <= 0.f || theWo.z <= 0.f) ? 0.f : theWi.z * (1.f / M_PI);\n"
"}\n"
"\n"
"//=======================================================================\n"
"}\n"
"\n"
"//=======================================================================\n"
- "// function : HandleBlinnReflection\n"
- "// purpose : Handles Blinn glossy BRDF, with cos(N, PSI)\n"
+ "// function : EvalBlinnReflection\n"
+ "// purpose : Evaluates Blinn glossy BRDF, with cos(N, PSI)\n"
"//=======================================================================\n"
- "vec3 HandleBlinnReflection (in vec3 theInput, in vec3 theOutput, in vec3 theFresnel, in float theRoughness)\n"
+ "vec3 EvalBlinnReflection (in vec3 theWi, in vec3 theWo, in vec3 theFresnel, in float theRoughness)\n"
"{\n"
" // calculate the reflection half-vec\n"
- " vec3 aH = normalize (theInput + theOutput);\n"
+ " vec3 aH = normalize (theWi + theWo);\n"
"\n"
" // roughness value -> Blinn exponent\n"
" float aPower = max (2.f / (theRoughness * theRoughness) - 2.f, 0.f);\n"
" float aD = (aPower + 2.f) * (1.f / M_2_PI) * pow (aH.z, aPower);\n"
"\n"
" // calculate shadow-masking function\n"
- " float aG = SmithG1 (theOutput, aH, theRoughness) * SmithG1 (theInput, aH, theRoughness);\n"
+ " float aG = SmithG1 (theWo, aH, theRoughness) *\n"
+ " SmithG1 (theWi, aH, theRoughness);\n"
"\n"
" // return total amount of reflection\n"
- " return (theInput.z <= 0.f || theOutput.z <= 0.f) ? ZERO :\n"
- " aD * aG / (4.f * theOutput.z) * fresnelMedia (dot (theOutput, aH), theFresnel);\n"
+ " return (theWi.z <= 0.f || theWo.z <= 0.f) ? ZERO :\n"
+ " aD * aG / (4.f * theWo.z) * fresnelMedia (dot (theWo, aH), theFresnel);\n"
"}\n"
"\n"
"//=======================================================================\n"
- "// function : HandleMaterial\n"
- "// purpose : Returns BSDF value for specified material, with cos(N, PSI)\n"
+ "// function : EvalMaterial\n"
+ "// purpose : Evaluates BSDF for specified material, with cos(N, PSI)\n"
"//=======================================================================\n"
- "vec3 HandleMaterial (in SMaterial theBSDF, in vec3 theInput, in vec3 theOutput)\n"
+ "vec3 EvalMaterial (in SMaterial theBSDF, in vec3 theWi, in vec3 theWo)\n"
"{\n"
- " return theBSDF.Kd.rgb * HandleLambertianReflection (theInput, theOutput) +\n"
- " theBSDF.Ks.rgb * HandleBlinnReflection (theInput, theOutput, theBSDF.Fresnel, theBSDF.Ks.w);\n"
+ "#ifdef TWO_SIDED_BXDF\n"
+ " theWi.z *= sign (theWi.z);\n"
+ " theWo.z *= sign (theWo.z);\n"
+ "#endif\n"
+ "\n"
+ " return theBSDF.Kd.rgb * EvalLambertianReflection (theWi, theWo) +\n"
+ " theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.Fresnel, theBSDF.Ks.w);\n"
"}\n"
"\n"
"//=======================================================================\n"
"// function : SampleLambertianReflection\n"
"// purpose : Samples Lambertian BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n"
"//=======================================================================\n"
- "vec3 SampleLambertianReflection (in vec3 theOutput, out vec3 theInput, inout float thePDF)\n"
+ "vec3 SampleLambertianReflection (in vec3 theWo, out vec3 theWi, inout float thePDF)\n"
"{\n"
" float aKsi1 = RandFloat();\n"
" float aKsi2 = RandFloat();\n"
"\n"
- " float aTemp = sqrt (aKsi2);\n"
+ " theWi = vec3 (cos (M_2_PI * aKsi1),\n"
+ " sin (M_2_PI * aKsi1),\n"
+ " sqrt (1.f - aKsi2));\n"
+ "\n"
+ " theWi.xy *= sqrt (aKsi2);\n"
"\n"
- " theInput = vec3 (aTemp * cos (M_2_PI * aKsi1),\n"
- " aTemp * sin (M_2_PI * aKsi1),\n"
- " sqrt (1.f - aKsi2));\n"
+ "#ifdef TWO_SIDED_BXDF\n"
+ " theWi.z *= sign (theWo.z);\n"
+ "#endif\n"
"\n"
- " thePDF *= abs (theInput.z) * (1.f / M_PI);\n"
+ " thePDF *= theWi.z * (1.f / M_PI);\n"
"\n"
- " return (theInput.z <= 0.f || theOutput.z <= 0.f) ? ZERO : UNIT;\n"
+ "#ifdef TWO_SIDED_BXDF\n"
+ " return UNIT;\n"
+ "#else\n"
+ " return mix (UNIT, ZERO, theWo.z <= 0.f);\n"
+ "#endif\n"
"}\n"
"\n"
"//=======================================================================\n"
"// terms would be complex, and it is the D term that accounts\n"
"// for most of the variation.\n"
"//=======================================================================\n"
- "vec3 SampleBlinnReflection (in vec3 theOutput, out vec3 theInput, in vec3 theFresnel, in float theRoughness, inout float thePDF)\n"
+ "vec3 SampleBlinnReflection (in vec3 theWo, out vec3 theWi, in vec3 theFresnel, in float theRoughness, inout float thePDF)\n"
"{\n"
" float aKsi1 = RandFloat();\n"
" float aKsi2 = RandFloat();\n"
" // calculate PDF of sampled direction\n"
" thePDF *= (aPower + 2.f) * (1.f / M_2_PI) * pow (aCosThetaM, aPower + 1.f);\n"
"\n"
- " float aCosDelta = dot (theOutput, aM);\n"
+ "#ifdef TWO_SIDED_BXDF\n"
+ " bool toFlip = theWo.z < 0.f;\n"
+ "\n"
+ " if (toFlip)\n"
+ " theWo.z = -theWo.z;\n"
+ "#endif\n"
+ "\n"
+ " float aCosDelta = dot (theWo, aM);\n"
"\n"
" // pick input based on half direction\n"
- " theInput = -theOutput + 2.f * aCosDelta * aM;\n"
+ " theWi = -theWo + 2.f * aCosDelta * aM;\n"
"\n"
- " if (theInput.z <= 0.f || theOutput.z <= 0.f)\n"
+ " if (theWi.z <= 0.f || theWo.z <= 0.f)\n"
" {\n"
" return ZERO;\n"
" }\n"
"\n"
" // Jacobian of half-direction mapping\n"
- " thePDF /= 4.f * dot (theInput, aM);\n"
+ " thePDF /= 4.f * dot (theWi, aM);\n"
"\n"
" // compute shadow-masking coefficient\n"
- " float aG = SmithG1 (theOutput, aM, theRoughness) * SmithG1 (theInput, aM, theRoughness);\n"
+ " float aG = SmithG1 (theWo, aM, theRoughness) *\n"
+ " SmithG1 (theWi, aM, theRoughness);\n"
+ "\n"
+ "#ifdef TWO_SIDED_BXDF\n"
+ " if (toFlip)\n"
+ " theWi.z = -theWi.z;\n"
+ "#endif\n"
"\n"
- " return aG * aCosDelta / (theOutput.z * aM.z) * fresnelMedia (aCosDelta, theFresnel);\n"
+ " return (aG * aCosDelta) / (theWo.z * aM.z) * fresnelMedia (aCosDelta, theFresnel);\n"
"}\n"
"\n"
"//=======================================================================\n"
"// function : SampleSpecularReflection\n"
"// purpose : Samples specular BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n"
"//=======================================================================\n"
- "vec3 SampleSpecularReflection (in vec3 theOutput, out vec3 theInput, in vec3 theFresnel)\n"
+ "vec3 SampleSpecularReflection (in vec3 theWo, out vec3 theWi, in vec3 theFresnel)\n"
"{\n"
" // Sample input direction\n"
- " theInput = vec3 (-theOutput.x,\n"
- " -theOutput.y,\n"
- " theOutput.z);\n"
- "\n"
- " return fresnelMedia (theOutput.z, theFresnel);\n"
+ " theWi = vec3 (-theWo.x,\n"
+ " -theWo.y,\n"
+ " theWo.z);\n"
+ "\n"
+ "#ifdef TWO_SIDED_BXDF\n"
+ " return fresnelMedia (theWo.z, theFresnel);\n"
+ "#else\n"
+ " return fresnelMedia (theWo.z, theFresnel) * step (0.f, theWo.z);\n"
+ "#endif\n"
"}\n"
"\n"
"//=======================================================================\n"
"// function : SampleSpecularTransmission\n"
"// purpose : Samples specular BTDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n"
"//=======================================================================\n"
- "vec3 SampleSpecularTransmission (in vec3 theOutput,\n"
- " out vec3 theInput, in vec3 theWeight, in vec3 theFresnel, inout bool theInside)\n"
+ "vec3 SampleSpecularTransmission (in vec3 theWo, out vec3 theWi, in vec3 theWeight, in vec3 theFresnel, inout bool theInside)\n"
"{\n"
- " vec3 aFactor = fresnelMedia (theOutput.z, theFresnel);\n"
+ " vec3 aFactor = fresnelMedia (theWo.z, theFresnel);\n"
"\n"
" float aReflection = convolve (aFactor, theWeight);\n"
"\n"
" // sample specular BRDF/BTDF\n"
" if (RandFloat() <= aReflection)\n"
" {\n"
- " theInput = vec3 (-theOutput.x,\n"
- " -theOutput.y,\n"
- " theOutput.z);\n"
+ " theWi = vec3 (-theWo.x,\n"
+ " -theWo.y,\n"
+ " theWo.z);\n"
"\n"
" theWeight = aFactor * (1.f / aReflection);\n"
" }\n"
" {\n"
" theInside = !theInside;\n"
"\n"
- " transmitted (theFresnel.y, theOutput, theInput);\n"
+ " transmitted (theFresnel.y, theWo, theWi);\n"
"\n"
" theWeight = (UNIT - aFactor) * (1.f / (1.f - aReflection));\n"
" }\n"
"// function : BsdfPdf\n"
"// purpose : Calculates BSDF of sampling input knowing output\n"
"//=======================================================================\n"
- "float BsdfPdf (in SMaterial theBSDF,\n"
- " in vec3 theOutput,\n"
- " in vec3 theInput,\n"
- " in vec3 theWeight)\n"
+ "float BsdfPdf (in SMaterial theBSDF, in vec3 theWo, in vec3 theWi, in vec3 theWeight)\n"
"{\n"
" float aPd = convolve (theBSDF.Kd.rgb, theWeight);\n"
" float aPs = convolve (theBSDF.Ks.rgb, theWeight);\n"
"\n"
" float aPDF = 0.f; // PDF of sampling input direction\n"
"\n"
- " if (theInput.z * theOutput.z > 0.f)\n"
+ " if (theWi.z * theWo.z > 0.f)\n"
" {\n"
- " vec3 aHalf = normalize (theInput + theOutput);\n"
+ " vec3 aH = normalize (theWi + theWo);\n"
"\n"
" // roughness value --> Blinn exponent\n"
" float aPower = max (2.f / (theBSDF.Ks.w * theBSDF.Ks.w) - 2.f, 0.f);\n"
"\n"
- " aPDF = aPd * abs (theInput.z / M_PI) +\n"
- " aPs * (aPower + 2.f) * (1.f / M_2_PI) * pow (aHalf.z, aPower + 1.f) / (4.f * dot (theInput, aHalf));\n"
+ " aPDF = aPd * abs (theWi.z / M_PI) +\n"
+ " aPs * (aPower + 2.f) * (1.f / M_2_PI) * pow (abs (aH.z), aPower + 1.f) / (4.f * dot (theWi, aH));\n"
" }\n"
"\n"
" return aPDF / aReflection;\n"
"// function : SampleBsdf\n"
"// purpose : Samples specified composite material (BSDF)\n"
"//=======================================================================\n"
- "float SampleBsdf (in SMaterial theBSDF,\n"
- " in vec3 theOutput,\n"
- " out vec3 theInput,\n"
- " inout vec3 theWeight,\n"
- " inout bool theInside)\n"
+ "float SampleBsdf (in SMaterial theBSDF, in vec3 theWo, out vec3 theWi, inout vec3 theWeight, inout bool theInside)\n"
"{\n"
" // compute probability of each reflection type (BxDF)\n"
" float aPd = convolve (theBSDF.Kd.rgb, theWeight);\n"
" {\n"
" PICK_BXDF (aPd, theBSDF.Kd.rgb);\n"
"\n"
- " theWeight *= SampleLambertianReflection (theOutput, theInput, aPDF);\n"
+ " theWeight *= SampleLambertianReflection (theWo, theWi, aPDF);\n"
" }\n"
" else if (aKsi < aPd + aPs) // glossy reflection\n"
" {\n"
" PICK_BXDF (aPs, theBSDF.Ks.rgb);\n"
"\n"
- " theWeight *= SampleBlinnReflection (theOutput, theInput, theBSDF.Fresnel, theBSDF.Ks.w, aPDF);\n"
+ " theWeight *= SampleBlinnReflection (theWo, theWi, theBSDF.Fresnel, theBSDF.Ks.w, aPDF);\n"
" }\n"
" else if (aKsi < aPd + aPs + aPr) // specular reflection\n"
" {\n"
"\n"
" aPDF = MAXFLOAT;\n"
"\n"
- " theWeight *= SampleSpecularReflection (theOutput, theInput, theBSDF.Fresnel);\n"
+ " theWeight *= SampleSpecularReflection (theWo, theWi, theBSDF.Fresnel);\n"
" }\n"
" else if (aKsi < aReflection) // specular transmission\n"
" {\n"
"\n"
" aPDF = MAXFLOAT;\n"
"\n"
- " theWeight *= SampleSpecularTransmission (theOutput, theInput, theWeight, theBSDF.Fresnel, theInside);\n"
+ " theWeight *= SampleSpecularTransmission (theWo, theWi, theWeight, theBSDF.Fresnel, theInside);\n"
" }\n"
"\n"
" // path termination for extra small weights\n"
" // MIS weight including division by explicit PDF\n"
" float aMIS = (aExpPDF == MAXFLOAT) ? 1.f : aExpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n"
"\n"
- " vec3 aContrib = aMIS * aParam.rgb /* Le */ * HandleMaterial (\n"
+ " vec3 aContrib = aMIS * aParam.rgb /* Le */ * EvalMaterial (\n"
" aMaterial, toLocalSpace (aLight.xyz, aSpace), toLocalSpace (-theRay.Direct, aSpace));\n"
"\n"
" if (any (greaterThan (aContrib, MIN_CONTRIBUTION))) // check if light source is important\n"
case Graphic3d_RM_RAYTRACING: theDI << "raytrace "; break;
}
theDI << "\n";
- theDI << "msaa: " << aParams.NbMsaaSamples << "\n";
- theDI << "rayDepth: " << aParams.RaytracingDepth << "\n";
- theDI << "fsaa: " << (aParams.IsAntialiasingEnabled ? "on" : "off") << "\n";
- theDI << "shadows: " << (aParams.IsShadowEnabled ? "on" : "off") << "\n";
- theDI << "reflections: " << (aParams.IsReflectionEnabled ? "on" : "off") << "\n";
- theDI << "gleam: " << (aParams.IsTransparentShadowEnabled ? "on" : "off") << "\n";
- theDI << "GI: " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
- theDI << "blocked RNG: " << (aParams.CoherentPathTracingMode ? "on" : "off") << "\n";
- theDI << "iss: " << (aParams.AdaptiveScreenSampling ? "on" : "off") << "\n";
- theDI << "iss debug: " << (aParams.ShowSamplingTiles ? "on" : "off") << "\n";
+ theDI << "msaa: " << aParams.NbMsaaSamples << "\n";
+ theDI << "rayDepth: " << aParams.RaytracingDepth << "\n";
+ theDI << "fsaa: " << (aParams.IsAntialiasingEnabled ? "on" : "off") << "\n";
+ theDI << "shadows: " << (aParams.IsShadowEnabled ? "on" : "off") << "\n";
+ theDI << "reflections: " << (aParams.IsReflectionEnabled ? "on" : "off") << "\n";
+ theDI << "gleam: " << (aParams.IsTransparentShadowEnabled ? "on" : "off") << "\n";
+ theDI << "GI: " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
+ theDI << "blocked RNG: " << (aParams.CoherentPathTracingMode ? "on" : "off") << "\n";
+ theDI << "iss: " << (aParams.AdaptiveScreenSampling ? "on" : "off") << "\n";
+ theDI << "iss debug: " << (aParams.ShowSamplingTiles ? "on" : "off") << "\n";
+ theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels ? "on" : "off") << "\n";
theDI << "shadingModel: ";
switch (aView->ShadingModel())
{
}
aParams.UseEnvironmentMapBackground = toEnable;
}
+ else if (aFlag == "-twoside")
+ {
+ if (toPrint)
+ {
+ theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
+ continue;
+ }
+
+ Standard_Boolean toEnable = Standard_True;
+ if (++anArgIter < theArgNb
+ && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
+ {
+ --anArgIter;
+ }
+ aParams.TwoSidedBsdfModels = toEnable;
+ }
else if (aFlag == "-shademodel"
|| aFlag == "-shadingmodel"
|| aFlag == "-shading")
"\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 '-twoside on|off' Enables/disables two-sided BSDF models (PT mode)"
"\n '-iss on|off' Enables/disables adaptive screen sampling (PT mode)"
"\n '-issd on|off' Shows screen sampling distribution in ISS mode"
"\n '-rebuildGlsl on|off' Rebuild Ray-Tracing GLSL programs (for debugging)"
--- /dev/null
+puts "============"
+puts "Visualization - Path Tracing, Cube sample"
+puts "============"
+puts ""
+
+source $env(CSF_OCCTSamplesPath)/tcl/pathtrace_cube.tcl
+
+vaxo
+vfit
+vfps 100
+
+# Dump image produced with one-sided BSDFs
+vdump $imagedir/${casename}_onesided.png
+
+vrenderparams -twoside
+vfps 100
+
+# Dump image produced with two-sided BSDFs
+vdump $imagedir/${casename}_twosided.png