diff --git a/src/Graphic3d/Graphic3d_RenderingParams.hxx b/src/Graphic3d/Graphic3d_RenderingParams.hxx index 86f3389f83..60c8212ec1 100644 --- a/src/Graphic3d/Graphic3d_RenderingParams.hxx +++ b/src/Graphic3d/Graphic3d_RenderingParams.hxx @@ -28,9 +28,6 @@ public: //! 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; @@ -53,7 +50,6 @@ public: NbMsaaSamples (0), // ray tracing parameters IsGlobalIlluminationEnabled (Standard_False), - SamplesPerPixel (THE_DEFAULT_SPP), RaytracingDepth (THE_DEFAULT_DEPTH), IsShadowEnabled (Standard_True), IsReflectionEnabled (Standard_False), @@ -63,6 +59,7 @@ public: CoherentPathTracingMode (Standard_False), AdaptiveScreenSampling (Standard_False), ShowSamplingTiles (Standard_False), + TwoSidedBsdfModels (Standard_False), RebuildRayTracingShaders (Standard_False), // stereoscopic parameters StereoMode (Graphic3d_StereoMode_QuadBuffer), @@ -104,6 +101,7 @@ public: 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 diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index ba07b70f5e..463b980d63 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -696,6 +696,9 @@ protected: //! @name data types related to ray-tracing //! 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; @@ -703,13 +706,11 @@ protected: //! @name data types related to ray-tracing 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. diff --git a/src/OpenGl/OpenGl_View_Raytrace.cxx b/src/OpenGl/OpenGl_View_Raytrace.cxx index 062e558664..ba286a25f4 100644 --- a/src/OpenGl/OpenGl_View_Raytrace.cxx +++ b/src/OpenGl/OpenGl_View_Raytrace.cxx @@ -1144,6 +1144,11 @@ TCollection_AsciiString OpenGl_View::generateShaderPrefix (const Handle(OpenGl_C 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; @@ -1354,27 +1359,18 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context } } - 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; } diff --git a/src/Shaders/PathtraceBase.fs b/src/Shaders/PathtraceBase.fs index 916ac69b8e..6b743d423b 100644 --- a/src/Shaders/PathtraceBase.fs +++ b/src/Shaders/PathtraceBase.fs @@ -244,12 +244,12 @@ void transmitted (in float theIndex, in vec3 theIncident, out vec3 theTransmit) ////////////////////////////////////////////////////////////////////////////////////////////// //======================================================================= -// 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); } //======================================================================= @@ -285,13 +285,13 @@ float SmithG1 (in vec3 theDirection, in vec3 theM, in float theRoughness) } //======================================================================= -// 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); @@ -300,41 +300,55 @@ vec3 HandleBlinnReflection (in vec3 theInput, in vec3 theOutput, in vec3 theFres 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)); - theInput = vec3 (aTemp * cos (M_2_PI * aKsi1), - aTemp * sin (M_2_PI * aKsi1), - sqrt (1.f - aKsi2)); + theWi.xy *= sqrt (aKsi2); - thePDF *= abs (theInput.z) * (1.f / M_PI); +#ifdef TWO_SIDED_BXDF + theWi.z *= sign (theWo.z); +#endif - return (theInput.z <= 0.f || theOutput.z <= 0.f) ? ZERO : UNIT; + thePDF *= theWi.z * (1.f / M_PI); + +#ifdef TWO_SIDED_BXDF + return UNIT; +#else + return mix (UNIT, ZERO, theWo.z <= 0.f); +#endif } //======================================================================= @@ -347,7 +361,7 @@ vec3 SampleLambertianReflection (in vec3 theOutput, out vec3 theInput, inout flo // 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(); @@ -367,56 +381,72 @@ vec3 SampleBlinnReflection (in vec3 theOutput, out vec3 theInput, in vec3 theFre // 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); - return aG * aCosDelta / (theOutput.z * aM.z) * fresnelMedia (aCosDelta, theFresnel); +#ifdef TWO_SIDED_BXDF + if (toFlip) + theWi.z = -theWi.z; +#endif + + 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); + theWi = vec3 (-theWo.x, + -theWo.y, + theWo.z); - return fresnelMedia (theOutput.z, theFresnel); +#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); } @@ -424,7 +454,7 @@ vec3 SampleSpecularTransmission (in vec3 theOutput, { theInside = !theInside; - transmitted (theFresnel.y, theOutput, theInput); + transmitted (theFresnel.y, theWo, theWi); theWeight = (UNIT - aFactor) * (1.f / (1.f - aReflection)); } @@ -438,10 +468,7 @@ vec3 SampleSpecularTransmission (in vec3 theOutput, // 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); @@ -452,15 +479,15 @@ float BsdfPdf (in SMaterial theBSDF, 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; @@ -473,11 +500,7 @@ float BsdfPdf (in SMaterial theBSDF, // 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); @@ -497,13 +520,13 @@ float SampleBsdf (in SMaterial theBSDF, { 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 { @@ -511,7 +534,7 @@ float SampleBsdf (in SMaterial theBSDF, aPDF = MAXFLOAT; - theWeight *= SampleSpecularReflection (theOutput, theInput, theBSDF.Fresnel); + theWeight *= SampleSpecularReflection (theWo, theWi, theBSDF.Fresnel); } else if (aKsi < aReflection) // specular transmission { @@ -519,7 +542,7 @@ float SampleBsdf (in SMaterial theBSDF, aPDF = MAXFLOAT; - theWeight *= SampleSpecularTransmission (theOutput, theInput, theWeight, theBSDF.Fresnel, theInside); + theWeight *= SampleSpecularTransmission (theWo, theWi, theWeight, theBSDF.Fresnel, theInside); } // path termination for extra small weights @@ -810,7 +833,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse) // 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 diff --git a/src/Shaders/Shaders_PathtraceBase_fs.pxx b/src/Shaders/Shaders_PathtraceBase_fs.pxx index 187e127cbb..59b0fb378e 100644 --- a/src/Shaders/Shaders_PathtraceBase_fs.pxx +++ b/src/Shaders/Shaders_PathtraceBase_fs.pxx @@ -247,12 +247,12 @@ static const char Shaders_PathtraceBase_fs[] = "//////////////////////////////////////////////////////////////////////////////////////////////\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" @@ -288,13 +288,13 @@ static const char Shaders_PathtraceBase_fs[] = "}\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" @@ -303,41 +303,55 @@ static const char Shaders_PathtraceBase_fs[] = " 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" - " theInput = vec3 (aTemp * cos (M_2_PI * aKsi1),\n" - " aTemp * sin (M_2_PI * aKsi1),\n" - " sqrt (1.f - aKsi2));\n" + " theWi.xy *= sqrt (aKsi2);\n" "\n" - " thePDF *= abs (theInput.z) * (1.f / M_PI);\n" + "#ifdef TWO_SIDED_BXDF\n" + " theWi.z *= sign (theWo.z);\n" + "#endif\n" "\n" - " return (theInput.z <= 0.f || theOutput.z <= 0.f) ? ZERO : UNIT;\n" + " thePDF *= theWi.z * (1.f / M_PI);\n" + "\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" @@ -350,7 +364,7 @@ static const char Shaders_PathtraceBase_fs[] = "// 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" @@ -370,56 +384,72 @@ static const char Shaders_PathtraceBase_fs[] = " // 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" - " return aG * aCosDelta / (theOutput.z * aM.z) * fresnelMedia (aCosDelta, theFresnel);\n" + "#ifdef TWO_SIDED_BXDF\n" + " if (toFlip)\n" + " theWi.z = -theWi.z;\n" + "#endif\n" + "\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" + " theWi = vec3 (-theWo.x,\n" + " -theWo.y,\n" + " theWo.z);\n" "\n" - " return fresnelMedia (theOutput.z, theFresnel);\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" @@ -427,7 +457,7 @@ static const char Shaders_PathtraceBase_fs[] = " {\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" @@ -441,10 +471,7 @@ static const char Shaders_PathtraceBase_fs[] = "// 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" @@ -455,15 +482,15 @@ static const char Shaders_PathtraceBase_fs[] = "\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" @@ -476,11 +503,7 @@ static const char Shaders_PathtraceBase_fs[] = "// 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" @@ -500,13 +523,13 @@ static const char Shaders_PathtraceBase_fs[] = " {\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" @@ -514,7 +537,7 @@ static const char Shaders_PathtraceBase_fs[] = "\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" @@ -522,7 +545,7 @@ static const char Shaders_PathtraceBase_fs[] = "\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" @@ -813,7 +836,7 @@ static const char Shaders_PathtraceBase_fs[] = " // 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" diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index a50ffc7ad2..4f99edc02b 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -9077,16 +9077,17 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, 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()) { @@ -9360,6 +9361,22 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, } 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") @@ -10633,6 +10650,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "\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)" diff --git a/tests/v3d/raytrace/sample_cube_twosided b/tests/v3d/raytrace/sample_cube_twosided new file mode 100644 index 0000000000..ac872ad495 --- /dev/null +++ b/tests/v3d/raytrace/sample_cube_twosided @@ -0,0 +1,19 @@ +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