diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3fb26aefd..0ff552ad3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,7 +104,7 @@ jobs: cxx_std: 17 openimageio_ver: master python_ver: 3.9 - pybind11_ver: v2.6.2 + pybind11_ver: v2.7.0 simd: avx2,f16c batched: b8_AVX2,b8_AVX512,b16_AVX512 setenvs: USE_OPENVDB=0 @@ -180,7 +180,7 @@ jobs: openexr_ver: v2.4.3 openimageio_ver: v2.4.13.0 python_ver: 2.7 - pybind11_ver: v2.6.2 + pybind11_ver: v2.7.0 simd: 0 setenvs: export PUGIXML_VERSION=v1.8 CMAKE_VERSION=3.15.5 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7fcdcc21a..7e45d5204 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,7 +143,7 @@ add_definitions (-DOSL_INTERNAL=1) # To make sure we aren't relying on deprecated OIIO features, we define # OIIO_DISABLE_DEPRECATED before including any OIIO headers. -add_definitions (-DOIIO_DISABLE_DEPRECATED=1) +add_definitions (-DOIIO_DISABLE_DEPRECATED=900000) # Set the default namespace. For symbol hiding reasons, it's important that # the project name is a subset of the namespace name. diff --git a/src/build-scripts/ci-startup.bash b/src/build-scripts/ci-startup.bash index 407dc0db8..a3d7b7d64 100755 --- a/src/build-scripts/ci-startup.bash +++ b/src/build-scripts/ci-startup.bash @@ -47,6 +47,9 @@ export DYLD_LIBRARY_PATH=${LOCAL_DEPS_DIR}/dist/lib:$DYLD_LIBRARY_PATH export TESTSUITE_CLEANUP_ON_SUCCESS=${TESTSUITE_CLEANUP_ON_SUCCESS:=1} +# For CI, default to building missing dependencies automatically +export OpenImageIO_BUILD_MISSING_DEPS=${OpenImageIO_BUILD_MISSING_DEPS:=all} + # Parallel builds if [[ `uname -s` == "Linux" ]] ; then echo "procs: " `nproc` diff --git a/src/cmake/compiler.cmake b/src/cmake/compiler.cmake index c97316681..81ac2092f 100644 --- a/src/cmake/compiler.cmake +++ b/src/cmake/compiler.cmake @@ -25,7 +25,7 @@ message (STATUS "CMAKE_CXX_COMPILER_ID = ${CMAKE_CXX_COMPILER_ID}") ########################################################################### # C++ language standard # -set (CMAKE_CXX_STANDARD 14 CACHE STRING +set (CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to build with (14, 17, 20, etc.)") set (DOWNSTREAM_CXX_STANDARD 14 CACHE STRING "C++ minimum standard to impose on downstream clients") diff --git a/src/doc/languagespec.tex b/src/doc/languagespec.tex index 206b35b04..7c90ed198 100644 --- a/src/doc/languagespec.tex +++ b/src/doc/languagespec.tex @@ -5049,27 +5049,19 @@ \subsection{Surface BSDF closures} \apiitem{albedo} \vspace{12pt} - Single-scattering albedo of the medium. - \apiend - \vspace{-16pt} - - \apiitem{transmission_depth} - \vspace{12pt} - Distance travelled inside the medium by white light before its color becomes - transmission_color by Beer's law. Given in scene length units, range - [0,infinity). Together with transmission_color this determines the - extinction coefficient of the medium. + Effective albedo of the medium (after multiple scattering). The renderer is expected to + invert this color to derive the appropriate single-scattering albedo that will produce + this color for the average random walk. \apiend \vspace{-16pt} - \apiitem{transmission_color} + \apiitem{radius} \vspace{12pt} - Desired color resulting from white light transmitted a distance of - 'transmission_depth' through the medium. Together with transmission_depth - this determines the extinction coefficient of the medium. + Average distance travelled inside the medium per color channel. This is typically taken + to be the mean-free path of the volume. \apiend \vspace{-16pt} - + \apiitem{anisotropy} \vspace{12pt} Scattering anisotropy [-1,1]. Negative values give backwards scattering, diff --git a/src/doc/stdlib.md b/src/doc/stdlib.md index 289bd9356..2fce1e09d 100644 --- a/src/doc/stdlib.md +++ b/src/doc/stdlib.md @@ -1506,14 +1506,11 @@ properties of the physically-based shading nodes of MaterialX v1.38 : Normal vector of the surface point being shaded. `albedo` - : Single-scattering albedo of the medium. - - `transmission_depth` - : Distance travelled inside the medium by white light before its color becomes transmission_color by Beer's law. Given in scene length units, range [0,infinity). Together with transmission_color this determines the extinction coefficient of the medium. - - `transmission_color` - : Desired color resulting from white light transmitted a distance of 'transmission_depth' through the medium. Together with transmission_depth this determines the extinction coefficient of the medium. + : Effective albedo of the medium (after multiple scattering). The renderer is expected to invert this color to derive the appropriate single-scattering albedo that will produce this color for the average random walk. + `radius` + : Average distance travelled inside the medium per color channel. This is typically taken to be the mean-free path of the volume. + `anisotropy` : Scattering anisotropy [-1,1]. Negative values give backwards scattering, positive values give forward scattering, and 0.0 gives uniform scattering. diff --git a/src/include/OSL/oslnoise.h b/src/include/OSL/oslnoise.h index 2e22b949e..7183d1c5f 100644 --- a/src/include/OSL/oslnoise.h +++ b/src/include/OSL/oslnoise.h @@ -154,28 +154,28 @@ bitcast_to_uint (float x) OSL_FORCEINLINE void bjmix(vint4& a, vint4& b, vint4& c) { - using OIIO::simd::rotl32; - a -= c; a ^= rotl32(c, 4); c += b; - b -= a; b ^= rotl32(a, 6); a += c; - c -= b; c ^= rotl32(b, 8); b += a; - a -= c; a ^= rotl32(c,16); c += b; - b -= a; b ^= rotl32(a,19); a += c; - c -= b; c ^= rotl32(b, 4); b += a; + using OIIO::simd::rotl; + a -= c; a ^= rotl(c, 4); c += b; + b -= a; b ^= rotl(a, 6); a += c; + c -= b; c ^= rotl(b, 8); b += a; + a -= c; a ^= rotl(c,16); c += b; + b -= a; b ^= rotl(a,19); a += c; + c -= b; c ^= rotl(b, 4); b += a; } // Perform a bjfinal (see OpenImageIO/hash.h) on 4 sets of values at once. OSL_FORCEINLINE vint4 bjfinal(const vint4& a_, const vint4& b_, const vint4& c_) { - using OIIO::simd::rotl32; + using OIIO::simd::rotl; vint4 a(a_), b(b_), c(c_); - c ^= b; c -= rotl32(b,14); - a ^= c; a -= rotl32(c,11); - b ^= a; b -= rotl32(a,25); - c ^= b; c -= rotl32(b,16); - a ^= c; a -= rotl32(c,4); - b ^= a; b -= rotl32(a,14); - c ^= b; c -= rotl32(b,24); + c ^= b; c -= rotl(b,14); + a ^= c; a -= rotl(c,11); + b ^= a; b -= rotl(a,25); + c ^= b; c -= rotl(b,16); + a ^= c; a -= rotl(c,4); + b ^= a; b -= rotl(a,14); + c ^= b; c -= rotl(b,24); return c; } #endif diff --git a/src/liboslexec/builtindecl_wide_xmacro.h b/src/liboslexec/builtindecl_wide_xmacro.h index db0263cd9..2ff97fd63 100644 --- a/src/liboslexec/builtindecl_wide_xmacro.h +++ b/src/liboslexec/builtindecl_wide_xmacro.h @@ -520,8 +520,8 @@ DECL(__OSL_MASKED_OP3(transform_normal, Wdv, Wdv, Wm), "xXXXii") DECL(__OSL_MASKED_OP3(transform_normal, Wv, Wv, m), "xXXXii") DECL(__OSL_MASKED_OP3(transform_normal, Wdv, Wdv, m), "xXXXii") -DECL(__OSL_MASKED_OP3(transform_color, Wv, s, s), "xXXiXissi") -DECL(__OSL_OP3(transform_color, v, s, s), "xXXiXiss") +DECL(__OSL_MASKED_OP3(transform_color, Wv, s, s), "xXXiXihhi") +DECL(__OSL_OP3(transform_color, v, s, s), "xXXiXihh") DECL(__OSL_OP3(dot, Wf, Wv, Wv), "xXXX") DECL(__OSL_MASKED_OP3(dot, Wf, Wv, Wv), "xXXXi") diff --git a/src/liboslexec/llvm_ops.cpp b/src/liboslexec/llvm_ops.cpp index 959d86c01..66b30ce84 100644 --- a/src/liboslexec/llvm_ops.cpp +++ b/src/liboslexec/llvm_ops.cpp @@ -628,19 +628,19 @@ osl_step_vvv(void* result, void* edge, void* x) OSL_SHADEOP int osl_isnan_if(float f) { - return OIIO::isnan(f); + return std::isnan(f); } OSL_SHADEOP int osl_isinf_if(float f) { - return OIIO::isinf(f); + return std::isinf(f); } OSL_SHADEOP int osl_isfinite_if(float f) { - return OIIO::isfinite(f); + return std::isfinite(f); } @@ -694,7 +694,7 @@ safe_div(float a, float b) // to see if is finite and return 0.0f when it is not. // Typical implementation isfinite is (fabs(v) != INF), so not too expensive. float q = a / b; - return OIIO::isfinite(q) ? q : 0.0f; + return std::isfinite(q) ? q : 0.0f; // TODO: add a FTZ mode and only add checking the result when FTZ is disabled #endif } diff --git a/src/liboslexec/optexture.cpp b/src/liboslexec/optexture.cpp index 44abd2214..aee915e80 100644 --- a/src/liboslexec/optexture.cpp +++ b/src/liboslexec/optexture.cpp @@ -184,8 +184,7 @@ OSL_SHADEOP void osl_texture_set_interp(void* opt, ustringhash_pod modename_) { ustringhash modename_hash = ustringhash_from(modename_); - ustring modename = ustring_from(modename_hash); - int mode = tex_interp_to_code(modename); + int mode = tex_interp_to_code(modename_hash); if (mode >= 0) ((TextureOpt*)opt)->interpmode = (TextureOpt::InterpMode)mode; } diff --git a/src/liboslexec/runtimeoptimize.cpp b/src/liboslexec/runtimeoptimize.cpp index 7baf6ba34..ca8c8f6b2 100644 --- a/src/liboslexec/runtimeoptimize.cpp +++ b/src/liboslexec/runtimeoptimize.cpp @@ -3348,8 +3348,7 @@ RuntimeOptimizer::run() m_unknown_closures_needed = true; } } else if (op.opname() == u_backfacing) { - m_globals_needed.insert(u_N); - m_globals_needed.insert(u_I); + m_globals_needed.insert(u_backfacing); } else if (op.opname() == u_calculatenormal) { m_globals_needed.insert(u_flipHandedness); } else if (op.opname() == u_getattribute) { diff --git a/src/liboslexec/shadingsys.cpp b/src/liboslexec/shadingsys.cpp index 307d57355..7efc5b13d 100644 --- a/src/liboslexec/shadingsys.cpp +++ b/src/liboslexec/shadingsys.cpp @@ -4599,7 +4599,7 @@ osl_naninf_check(int ncomps, const void* vals_, int has_derivs, void* sg, for (int d = 0; d < (has_derivs ? 3 : 1); ++d) { for (int c = firstcheck, e = c + nchecks; c < e; ++c) { int i = d * ncomps + c; - if (!OIIO::isfinite(vals[i])) { + if (!std::isfinite(vals[i])) { OSL::errorfmt(ec, "Detected {} value in {}{} at {}:{} (op {})", vals[i], d > 0 ? "the derivatives of " : "", OSL::ustringhash_from(symbolname_), @@ -4635,7 +4635,7 @@ osl_uninit_check(long long typedesc_, void* vals_, void* sg, if (typedesc.basetype == TypeDesc::FLOAT) { float* vals = (float*)vals_; for (int c = firstcheck, e = firstcheck + nchecks; c < e; ++c) - if (!OIIO::isfinite(vals[c])) { + if (!std::isfinite(vals[c])) { uninit = true; vals[c] = 0; } diff --git a/src/liboslexec/wide/wide_optest_float.cpp b/src/liboslexec/wide/wide_optest_float.cpp index cc59f3787..d36b07386 100644 --- a/src/liboslexec/wide/wide_optest_float.cpp +++ b/src/liboslexec/wide/wide_optest_float.cpp @@ -25,17 +25,14 @@ OSL_USING_DATA_WIDTH(__OSL_WIDTH) #include "define_opname_macros.h" -#define __OSL_XMACRO_ARGS (isnan, OIIO::isnan) -//#define __OSL_XMACRO_ARGS (isnan,std::isnan) +#define __OSL_XMACRO_ARGS (isnan, std::isnan) #include "wide_optest_float_xmacro.h" -#define __OSL_XMACRO_ARGS (isinf, OIIO::isinf) +#define __OSL_XMACRO_ARGS (isinf, std::isinf) //#define __OSL_XMACRO_ARGS (isinf, sfm::isinf) -//#define __OSL_XMACRO_ARGS (isinf, std::isinf) #include "wide_optest_float_xmacro.h" -#define __OSL_XMACRO_ARGS (isfinite, OIIO::isfinite) -//#define __OSL_XMACRO_ARGS (isfinite,std::isfinite) +#define __OSL_XMACRO_ARGS (isfinite, std::isfinite) #include "wide_optest_float_xmacro.h" diff --git a/src/liboslexec/wide/wide_shadingsys.cpp b/src/liboslexec/wide/wide_shadingsys.cpp index 151178bc7..39bb61355 100644 --- a/src/liboslexec/wide/wide_shadingsys.cpp +++ b/src/liboslexec/wide/wide_shadingsys.cpp @@ -39,7 +39,7 @@ __OSL_OP(naninf_check)(int ncomps, const void* vals_, int has_derivs, for (int d = 0; d < (has_derivs ? 3 : 1); ++d) { for (int c = firstcheck, e = c + nchecks; c < e; ++c) { int i = d * ncomps + c; - if (!OIIO::isfinite(vals[i])) { + if (!std::isfinite(vals[i])) { ctx->errorfmt("Detected {} value in {}{} at {}:{} (op {})", vals[i], d > 0 ? "the derivatives of " : "", ustring_from(symbolname), @@ -69,7 +69,7 @@ __OSL_MASKED_OP1(naninf_check_offset, for (int c = firstcheck, e = c + nchecks; c < e; ++c) { int i = d * ncomps + c; mask.foreach ([=](ActiveLane lane) -> void { - if (!OIIO::isfinite(vals[i * __OSL_WIDTH + lane])) { + if (!std::isfinite(vals[i * __OSL_WIDTH + lane])) { ctx->errorfmt( "Detected {} value in {}{} at {}:{} (op {}) batch lane:{}", vals[i * __OSL_WIDTH + lane], @@ -108,7 +108,7 @@ __OSL_MASKED_OP1(naninf_check_offset, int firstcheck = wOffsets[lane]; for (int c = firstcheck, e = c + nchecks; c < e; ++c) { int i = d * ncomps + c; - if (!OIIO::isfinite(vals[i * __OSL_WIDTH + lane])) { + if (!std::isfinite(vals[i * __OSL_WIDTH + lane])) { ctx->errorfmt( "Detected {} value in {}{} at {}:{} (op {}) batch lane:{}", vals[i * __OSL_WIDTH + lane], @@ -145,7 +145,7 @@ __OSL_OP2(uninit_check_values_offset, X, if (typedesc.basetype == TypeDesc::FLOAT) { float* vals = (float*)vals_; for (int c = firstcheck, e = firstcheck + nchecks; c < e; ++c) - if (!OIIO::isfinite(vals[c])) { + if (!std::isfinite(vals[c])) { uninit = true; vals[c] = 0; } @@ -202,7 +202,7 @@ __OSL_MASKED_OP2(uninit_check_values_offset, WX, float* vals = (float*)vals_; for (int c = firstcheck, e = firstcheck + nchecks; c < e; ++c) mask.foreach ([=, &lanes_uninit](ActiveLane lane) -> void { - if (!OIIO::isfinite(vals[c * __OSL_WIDTH + lane])) { + if (!std::isfinite(vals[c * __OSL_WIDTH + lane])) { lanes_uninit.set_on(lane); vals[c * __OSL_WIDTH + lane] = 0; } @@ -268,7 +268,7 @@ __OSL_MASKED_OP2(uninit_check_values_offset, X, mask.foreach ([=, &lanes_uninit](ActiveLane lane) -> void { int firstcheck = wOffsets[lane]; for (int c = firstcheck, e = firstcheck + nchecks; c < e; ++c) - if (!OIIO::isfinite(vals[c])) { + if (!std::isfinite(vals[c])) { lanes_uninit.set_on(lane); vals[c] = 0; } @@ -335,7 +335,7 @@ __OSL_MASKED_OP2(uninit_check_values_offset, WX, mask.foreach ([=, &lanes_uninit](ActiveLane lane) -> void { int firstcheck = wOffsets[lane]; for (int c = firstcheck, e = firstcheck + nchecks; c < e; ++c) - if (!OIIO::isfinite(vals[c * __OSL_WIDTH + lane])) { + if (!std::isfinite(vals[c * __OSL_WIDTH + lane])) { lanes_uninit.set_on(lane); vals[c * __OSL_WIDTH + lane] = 0; } diff --git a/src/liboslnoise/gabornoise.cpp b/src/liboslnoise/gabornoise.cpp index c99002609..d589e6c48 100644 --- a/src/liboslnoise/gabornoise.cpp +++ b/src/liboslnoise/gabornoise.cpp @@ -175,7 +175,7 @@ gabor_cell(GaborParams& gp, const Vec3& c_i, const Dual2& x_c_i, Dual2 gk = gabor_kernel(w_i_t_s_f, omega_i_t_s_f, phi_i_t_s_f, a_i_t_s_f, x_k_i_t); // 2D - if (!OIIO::isfinite(gk.val())) { + if (!std::isfinite(gk.val())) { // Numeric failure of the filtered version. Fall // back on the unfiltered. gk = gabor_kernel(gp.weight, omega_i, phi_i, gp.a, diff --git a/src/liboslnoise/sfm_gabornoise.h b/src/liboslnoise/sfm_gabornoise.h index cd070282c..ac44708dc 100644 --- a/src/liboslnoise/sfm_gabornoise.h +++ b/src/liboslnoise/sfm_gabornoise.h @@ -367,7 +367,7 @@ gabor_cell(const sfm::GaborUniformParams& gup, const sfm::GaborParams& gp, //bool not_finite = std::isnan(gk.val()) | std::isinf(gk.val()); bool not_finite = std::isnan(gk.val()) || std::isinf(gk.val()); #else - bool not_finite = !OIIO::isfinite(gk.val()); + bool not_finite = !std::isfinite(gk.val()); #endif if (OSL_UNLIKELY(not_finite)) { // Numeric failure of the filtered version. Fall diff --git a/src/shaders/stdosl.h b/src/shaders/stdosl.h index b7db39dfd..98ecbf8da 100644 --- a/src/shaders/stdosl.h +++ b/src/shaders/stdosl.h @@ -587,17 +587,13 @@ closure color transparent_bsdf() BUILTIN; // Constructs a BSSRDF for subsurface scattering within a homogeneous medium. // // \param N Normal vector of the surface point being shaded. -// \param albedo Single-scattering albedo of the medium. -// \param transmission_depth Distance travelled inside the medium by white light before its color becomes transmission_color by Beer's law. -// Given in scene length units, range [0,infinity). Together with transmission_color this determines the extinction -// coefficient of the medium. -// \param transmission_color Desired color resulting from white light transmitted a distance of 'transmission_depth' through the medium. -// Together with transmission_depth this determines the extinction coefficient of the medium. +// \param albedo Effective albedo of the medium (after multiple scattering). The renderer is expected to invert this color to derive the appropriate single-scattering albedo that will produce this color for the average random walk. +// \param radius Average distance travelled inside the medium per color channel. This is typically taken to be the mean-free path of the volume. // \param anisotropy Scattering anisotropy [-1,1]. Negative values give backwards scattering, positive values give forward scattering, // and 0.0 gives uniform scattering. // \param label Optional string parameter to name this component. For use in AOVs / LPEs. // -closure color subsurface_bssrdf(normal N, color albedo, float transmission_depth, color transmission_color, float anisotropy) BUILTIN; +closure color subsurface_bssrdf(normal N, color albedo, color radius, float anisotropy) BUILTIN; // Constructs a microfacet BSDF for the back-scattering properties of cloth-like materials. // This closure may be vertically layered over a base BSDF, where energy that is not reflected diff --git a/src/testrender/sampling.h b/src/testrender/sampling.h index 3266e72d9..e69f3f5f1 100644 --- a/src/testrender/sampling.h +++ b/src/testrender/sampling.h @@ -14,18 +14,30 @@ OSL_NAMESPACE_ENTER struct TangentFrame { // build frame from unit normal - TangentFrame(const Vec3& n) : w(n) + static TangentFrame from_normal(const Vec3& n) { - u = (fabsf(w.x) > .01f ? Vec3(w.z, 0, -w.x) : Vec3(0, -w.z, w.y)) - .normalize(); - v = w.cross(u); + // https://graphics.pixar.com/library/OrthonormalB/paper.pdf + const float sign = copysignf(1.0f, n.z); + const float a = -1 / (sign + n.z); + const float b = n.x * n.y * a; + const Vec3 u = Vec3(1 + sign * n.x * n.x * a, sign * b, -sign * n.x); + const Vec3 v = Vec3(b, sign + n.y * n.y * a, -n.y); + return { u, v, n }; } // build frame from unit normal and unit tangent - TangentFrame(const Vec3& n, const Vec3& t) : w(n) + // fallsback to an arbitrary basis if the tangent is 0 or colinear with n + static TangentFrame from_normal_and_tangent(const Vec3& n, const Vec3& t) { - v = w.cross(t); - u = v.cross(w); + Vec3 x = t - n * dot(n, t); + float xlen2 = dot(x, x); + if (xlen2 > 0) { + x *= 1.0f / sqrtf(xlen2); + return { x, n.cross(x), n }; + } else { + // degenerate case, fallback to generic tangent frame + return from_normal(n); + } } // transform vector @@ -42,7 +54,6 @@ struct TangentFrame { } Vec3 toworld(const Vec3& a) const { return get(a.x, a.y, a.z); } -private: Vec3 u, v, w; }; @@ -76,8 +87,7 @@ struct Sampling { { to_unit_disk(rndx, rndy); float cos_theta = sqrtf(std::max(1 - rndx * rndx - rndy * rndy, 0.0f)); - TangentFrame f(N); - out = f.get(rndx, rndy, cos_theta); + out = TangentFrame::from_normal(N).get(rndx, rndy, cos_theta); pdf = cos_theta * float(M_1_PI); } @@ -87,8 +97,9 @@ struct Sampling { float phi = float(2 * M_PI) * rndx; float cos_theta = rndy; float sin_theta = sqrtf(1 - cos_theta * cos_theta); - TangentFrame f(N); - out = f.get(sin_theta * cosf(phi), sin_theta * sinf(phi), cos_theta); + out = TangentFrame::from_normal(N).get(sin_theta * cosf(phi), + sin_theta * sinf(phi), + cos_theta); pdf = float(0.5 * M_1_PI); } }; diff --git a/src/testrender/shading.cpp b/src/testrender/shading.cpp index 73821a73c..f6a376944 100644 --- a/src/testrender/shading.cpp +++ b/src/testrender/shading.cpp @@ -196,8 +196,7 @@ struct MxTranslucentParams { struct MxSubsurfaceParams { Vec3 N; Color3 albedo; - float transmission_depth; - Color3 transmission_color; + Color3 radius; float anisotropy; // optional ustringhash label; @@ -208,6 +207,7 @@ struct MxSheenParams { Color3 albedo; float roughness; // optional + int mode; ustringhash label; }; @@ -389,8 +389,7 @@ register_closures(OSL::ShadingSystem* shadingsys) MX_SUBSURFACE_ID, { CLOSURE_VECTOR_PARAM(MxSubsurfaceParams, N), CLOSURE_COLOR_PARAM(MxSubsurfaceParams, albedo), - CLOSURE_FLOAT_PARAM(MxSubsurfaceParams, transmission_depth), - CLOSURE_COLOR_PARAM(MxSubsurfaceParams, transmission_color), + CLOSURE_COLOR_PARAM(MxSubsurfaceParams, radius), CLOSURE_FLOAT_PARAM(MxSubsurfaceParams, anisotropy), CLOSURE_STRING_KEYPARAM(MxSubsurfaceParams, label, "label"), CLOSURE_FINISH_PARAM(MxSubsurfaceParams) } }, @@ -400,6 +399,7 @@ register_closures(OSL::ShadingSystem* shadingsys) CLOSURE_COLOR_PARAM(MxSheenParams, albedo), CLOSURE_FLOAT_PARAM(MxSheenParams, roughness), CLOSURE_STRING_KEYPARAM(MxSheenParams, label, "label"), + CLOSURE_INT_KEYPARAM(MxSheenParams, mode, "mode"), CLOSURE_FINISH_PARAM(MxSheenParams) } }, { "uniform_edf", MX_UNIFORM_EDF_ID, @@ -591,15 +591,15 @@ struct Phong final : public BSDF, PhongParams { float cosNO = N.dot(wo); if (cosNO > 0) { // reflect the view vector - Vec3 R = (2 * cosNO) * N - wo; - TangentFrame tf(R); + Vec3 R = (2 * cosNO) * N - wo; float phi = 2 * float(M_PI) * rx; float sp, cp; OIIO::fast_sincos(phi, &sp, &cp); float cosTheta = OIIO::fast_safe_pow(ry, 1 / (exponent + 1)); float sinTheta2 = 1 - cosTheta * cosTheta; float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0; - Vec3 wi = tf.get(cp * sinTheta, sp * sinTheta, cosTheta); + Vec3 wi = TangentFrame::from_normal(R).get(cp * sinTheta, + sp * sinTheta, cosTheta); return eval(wo, wi); } return {}; @@ -616,7 +616,7 @@ struct Ward final : public BSDF, WardParams { // get half vector and get x,y basis on the surface for anisotropy Vec3 H = wi + wo; H.normalize(); // normalize needed for pdf - TangentFrame tf(N, T); + TangentFrame tf = TangentFrame::from_normal_and_tangent(N, T); // eq. 4 float dotx = tf.getx(H) / ax; float doty = tf.gety(H) / ay; @@ -638,7 +638,7 @@ struct Ward final : public BSDF, WardParams { float cosNO = N.dot(wo); if (cosNO > 0) { // get x,y basis on the surface for anisotropy - TangentFrame tf(N, T); + TangentFrame tf = TangentFrame::from_normal_and_tangent(N, T); // generate random angles for the half vector float phi = 2 * float(M_PI) * rx; float sp, cp; @@ -811,8 +811,7 @@ struct Microfacet final : public BSDF, MicrofacetParams { Microfacet(const MicrofacetParams& params) : BSDF() , MicrofacetParams(params) - , tf(U == Vec3(0) || xalpha == yalpha ? TangentFrame(N) - : TangentFrame(N, U)) + , tf(TangentFrame::from_normal_and_tangent(N, U)) { } Color3 get_albedo(const Vec3& wo) const override @@ -1036,11 +1035,8 @@ struct MxMicrofacet final : public BSDF, MxMicrofacetParams { MxMicrofacet(const MxMicrofacetParams& params, float refraction_ior) : BSDF() , MxMicrofacetParams(params) - , tf(MxMicrofacetParams::U == Vec3(0) - || MxMicrofacetParams::roughness_x - == MxMicrofacetParams::roughness_y - ? TangentFrame(MxMicrofacetParams::N) - : TangentFrame(MxMicrofacetParams::N, MxMicrofacetParams::U)) + , tf(TangentFrame::from_normal_and_tangent(MxMicrofacetParams::N, + MxMicrofacetParams::U)) , refraction_ior(refraction_ior) { } @@ -1400,8 +1396,12 @@ struct MxBurleyDiffuse final : public BSDF, MxBurleyDiffuseParams { } }; -struct MxSheen final : public BSDF, MxSheenParams { - MxSheen(const MxSheenParams& params) : BSDF(), MxSheenParams(params) {} +// Implementation of the "Charlie Sheen" model [Conty & Kulla, 2017] +// https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_sheen.pdf +// To simplify the implementation, the simpler shadowing/masking visibility term below is used: +// https://dassaultsystemes-technology.github.io/EnterprisePBRShadingModel/spec-2022x.md.html#components/sheen +struct CharlieSheen final : public BSDF, MxSheenParams { + CharlieSheen(const MxSheenParams& params) : BSDF(), MxSheenParams(params) {} Color3 get_albedo(const Vec3& wo) const override { @@ -1446,6 +1446,114 @@ struct MxSheen final : public BSDF, MxSheenParams { } }; +// Implement the sheen model proposed in: +// "Practical Multiple-Scattering Sheen Using Linearly Transformed Cosines" +// Tizian Zeltner, Brent Burley, Matt Jen-Yuan Chiang - Siggraph 2022 +// https://tizianzeltner.com/projects/Zeltner2022Practical/ +struct ZeltnerBurleySheen final : public BSDF, MxSheenParams { + ZeltnerBurleySheen(const MxSheenParams& params) + : BSDF(), MxSheenParams(params) + { + } + +#define USE_LTC_SAMPLING 1 + + Color3 get_albedo(const Vec3& wo) const override + { + const float NdotV = clamp(N.dot(wo), 1e-5f, 1.0f); + return Color3(fetch_ltc(NdotV).z); + } + + Sample eval(const Vec3& wo, const Vec3& wi) const override + { + const Vec3 L = wi, V = wo; + const float NdotV = clamp(N.dot(V), 0.0f, 1.0f); + const Vec3 ltc = fetch_ltc(NdotV); + + const Vec3 localL = TangentFrame::from_normal_and_tangent(N, V).tolocal( + L); + + const float aInv = ltc.x, bInv = ltc.y, R = ltc.z; + Vec3 wiOriginal(aInv * localL.x + bInv * localL.z, aInv * localL.y, + localL.z); + const float len2 = dot(wiOriginal, wiOriginal); + + float det = aInv * aInv; + float jacobian = det / (len2 * len2); + +#if USE_LTC_SAMPLING == 1 + float pdf = jacobian * std::max(wiOriginal.z, 0.0f) * float(M_1_PI); + return { wi, Color3(R), pdf, 1.0f }; +#else + float pdf = float(0.5 * M_1_PI); + // NOTE: sheen closure has no fresnel/masking + return { wi, Color3(2 * R * jacobian * std::max(wiOriginal.z, 0.0f)), + pdf, 1.0f }; +#endif + } + + Sample sample(const Vec3& wo, float rx, float ry, float rz) const override + { +#if USE_LTC_SAMPLING == 1 + const Vec3 V = wo; + const float NdotV = clamp(N.dot(V), 0.0f, 1.0f); + const Vec3 ltc = fetch_ltc(NdotV); + const float aInv = ltc.x, bInv = ltc.y, R = ltc.z; + Vec3 wi; + float pdf; + Sampling::sample_cosine_hemisphere(Vec3(0, 0, 1), rx, ry, wi, pdf); + + const Vec3 w = Vec3(wi.x - wi.z * bInv, wi.y, wi.z * aInv); + const float len2 = dot(w, w); + const float jacobian = len2 * len2 / (aInv * aInv); + const Vec3 wn = w / sqrtf(len2); + + const Vec3 L = TangentFrame::from_normal_and_tangent(N, V).toworld(wn); + + pdf = jacobian * std::max(wn.z, 0.0f) * float(M_1_PI); + + return { L, Color3(R), pdf, 1.0f }; +#else + // plain uniform-sampling for validation + Vec3 out_dir; + float pdf; + Sampling::sample_uniform_hemisphere(N, rx, ry, out_dir, pdf); + return eval(wo, out_dir); +#endif + } + +private: + Vec3 fetch_ltc(float NdotV) const + { + // To avoid look-up tables, we use a fit of the LTC coefficients derived by Stephen Hill + // for the implementation in MaterialX: + // https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/pbrlib/genglsl/lib/mx_microfacet_sheen.glsl + const float x = NdotV; + const float y = std::max(roughness, 1e-3f); + const float A = ((2.58126f * x + 0.813703f * y) * y) + / (1.0f + 0.310327f * x * x + 2.60994f * x * y); + const float B = sqrtf(1.0f - x) * (y - 1.0f) * y * y * y + / (0.0000254053f + 1.71228f * x - 1.71506f * x * y + + 1.34174f * y * y); + const float invs = (0.0379424f + y * (1.32227f + y)) + / (y * (0.0206607f + 1.58491f * y)); + const float m = y + * (-0.193854f + + y * (-1.14885 + y * (1.7932f - 0.95943f * y * y))) + / (0.046391f + y); + const float o = y * (0.000654023f + (-0.0207818f + 0.119681f * y) * y) + / (1.26264f + y * (-1.92021f + y)); + float q = (x - m) * invs; + const float inv_sqrt2pi = 0.39894228040143f; + float R = expf(-0.5f * q * q) * invs * inv_sqrt2pi + o; + assert(isfinite(A)); + assert(isfinite(B)); + assert(isfinite(R)); + return Vec3(A, B, R); + } +}; + + Color3 evaluate_layer_opacity(const OSL::ShaderGlobals& sg, const ClosureColor* closure) @@ -1495,8 +1603,11 @@ evaluate_layer_opacity(const OSL::ShaderGlobals& sg, return w * mf.get_albedo(-sg.I); } case MX_SHEEN_ID: { - MxSheen bsdf(*comp->as()); - return w * bsdf.get_albedo(-sg.I); + const MxSheenParams& params = *comp->as(); + if (params.mode == 1) + return w * ZeltnerBurleySheen(params).get_albedo(-sg.I); + // otherwise, default to old sheen model + return w * CharlieSheen(params).get_albedo(-sg.I); } default: // Assume unhandled BSDFs are opaque return Color3(1); @@ -1767,7 +1878,11 @@ process_bsdf_closure(const OSL::ShaderGlobals& sg, ShadingResult& result, } case MX_SHEEN_ID: { const MxSheenParams& params = *comp->as(); - ok = result.bsdf.add_bsdf(cw, params); + if (params.mode == 1) + ok = result.bsdf.add_bsdf(cw, params); + else + ok = result.bsdf.add_bsdf( + cw, params); // default to legacy closure break; } case MX_LAYER_ID: { diff --git a/src/testshade/testshade.cpp b/src/testshade/testshade.cpp index 39834f638..db5bac164 100644 --- a/src/testshade/testshade.cpp +++ b/src/testshade/testshade.cpp @@ -1269,8 +1269,8 @@ save_outputs(SimpleRenderer* rend, ShadingSystem* shadingsys, // We are outputting an integer variable, so we need to // convert it to floating point. float* pixel = OSL_ALLOCA(float, nchans); - OIIO::convert_types(TypeDesc::BASETYPE(t.basetype), data, - TypeDesc::FLOAT, pixel, nchans); + OIIO::convert_pixel_values(TypeDesc::BASETYPE(t.basetype), data, + TypeDesc::FLOAT, pixel, nchans); outputimg->setpixel(x, y, &pixel[0]); if (print_outputs) { print(" {} :", outputvarnames[i]); diff --git a/testsuite/globals-needed/ref/out.txt b/testsuite/globals-needed/ref/out.txt index 344f7646b..234cbe3d8 100644 --- a/testsuite/globals-needed/ref/out.txt +++ b/testsuite/globals-needed/ref/out.txt @@ -1,2 +1,2 @@ -Need 2 globals: I N +Need 1 globals: backfacing Need 2 globals: P flipHandedness diff --git a/testsuite/render-background/ref/out.exr b/testsuite/render-background/ref/out.exr index 578f697e5..1ddac131f 100644 Binary files a/testsuite/render-background/ref/out.exr and b/testsuite/render-background/ref/out.exr differ diff --git a/testsuite/render-cornell/ref/out.exr b/testsuite/render-cornell/ref/out.exr index 790f2656b..742b86972 100644 Binary files a/testsuite/render-cornell/ref/out.exr and b/testsuite/render-cornell/ref/out.exr differ diff --git a/testsuite/render-microfacet/ref/out-alt1.exr b/testsuite/render-microfacet/ref/out-alt1.exr deleted file mode 100644 index fa2f1699d..000000000 Binary files a/testsuite/render-microfacet/ref/out-alt1.exr and /dev/null differ diff --git a/testsuite/render-microfacet/ref/out-linux-alt.exr b/testsuite/render-microfacet/ref/out-linux-alt.exr new file mode 100644 index 000000000..ed0fb8191 Binary files /dev/null and b/testsuite/render-microfacet/ref/out-linux-alt.exr differ diff --git a/testsuite/render-microfacet/ref/out-llvm14.exr b/testsuite/render-microfacet/ref/out-llvm14.exr deleted file mode 100644 index 1b8e2afc2..000000000 Binary files a/testsuite/render-microfacet/ref/out-llvm14.exr and /dev/null differ diff --git a/testsuite/render-microfacet/ref/out-macarm.exr b/testsuite/render-microfacet/ref/out-macarm.exr deleted file mode 100644 index 0def34816..000000000 Binary files a/testsuite/render-microfacet/ref/out-macarm.exr and /dev/null differ diff --git a/testsuite/render-microfacet/ref/out-macos-alt.exr b/testsuite/render-microfacet/ref/out-macos-alt.exr new file mode 100644 index 000000000..1d8f5b783 Binary files /dev/null and b/testsuite/render-microfacet/ref/out-macos-alt.exr differ diff --git a/testsuite/render-microfacet/ref/out.exr b/testsuite/render-microfacet/ref/out.exr index 976742e39..5b33f6026 100644 Binary files a/testsuite/render-microfacet/ref/out.exr and b/testsuite/render-microfacet/ref/out.exr differ diff --git a/testsuite/render-mx-burley-diffuse/ref/out.exr b/testsuite/render-mx-burley-diffuse/ref/out.exr index 090663647..75cdb1928 100644 Binary files a/testsuite/render-mx-burley-diffuse/ref/out.exr and b/testsuite/render-mx-burley-diffuse/ref/out.exr differ diff --git a/testsuite/render-mx-conductor/ref/out.exr b/testsuite/render-mx-conductor/ref/out.exr index 8cca6cd6f..877554971 100644 Binary files a/testsuite/render-mx-conductor/ref/out.exr and b/testsuite/render-mx-conductor/ref/out.exr differ diff --git a/testsuite/render-mx-dielectric-glass/ref/out.exr b/testsuite/render-mx-dielectric-glass/ref/out.exr index 0434a6901..1038a6705 100644 Binary files a/testsuite/render-mx-dielectric-glass/ref/out.exr and b/testsuite/render-mx-dielectric-glass/ref/out.exr differ diff --git a/testsuite/render-mx-dielectric/ref/out.exr b/testsuite/render-mx-dielectric/ref/out.exr index fa3c208c9..083ea9a9e 100644 Binary files a/testsuite/render-mx-dielectric/ref/out.exr and b/testsuite/render-mx-dielectric/ref/out.exr differ diff --git a/testsuite/render-mx-furnace-burley-diffuse/ref/out.exr b/testsuite/render-mx-furnace-burley-diffuse/ref/out.exr index 2b1bee0d0..ee615348c 100644 Binary files a/testsuite/render-mx-furnace-burley-diffuse/ref/out.exr and b/testsuite/render-mx-furnace-burley-diffuse/ref/out.exr differ diff --git a/testsuite/render-mx-furnace-oren-nayar/ref/out.exr b/testsuite/render-mx-furnace-oren-nayar/ref/out.exr index caa548aa7..69ac425dc 100644 Binary files a/testsuite/render-mx-furnace-oren-nayar/ref/out.exr and b/testsuite/render-mx-furnace-oren-nayar/ref/out.exr differ diff --git a/testsuite/render-mx-furnace-sheen/ref/out-linux-alt.exr b/testsuite/render-mx-furnace-sheen/ref/out-linux-alt.exr new file mode 100644 index 000000000..eb7c64b8e Binary files /dev/null and b/testsuite/render-mx-furnace-sheen/ref/out-linux-alt.exr differ diff --git a/testsuite/render-mx-furnace-sheen/ref/out.exr b/testsuite/render-mx-furnace-sheen/ref/out.exr index 31bf0c3a7..b356f840e 100644 Binary files a/testsuite/render-mx-furnace-sheen/ref/out.exr and b/testsuite/render-mx-furnace-sheen/ref/out.exr differ diff --git a/testsuite/render-mx-furnace-sheen/sheen.osl b/testsuite/render-mx-furnace-sheen/sheen.osl index a4d72f8d6..ae5547a23 100644 --- a/testsuite/render-mx-furnace-sheen/sheen.osl +++ b/testsuite/render-mx-furnace-sheen/sheen.osl @@ -15,5 +15,8 @@ sheen float UImin = 0, float UImax = 1 ]] ) { - Ci = sheen_bsdf (N, Cs, roughness); + if (N.y < 0) + Ci = sheen_bsdf (N, Cs, sqrt(roughness), "mode", 1); + else + Ci = sheen_bsdf (N, Cs, roughness); } diff --git a/testsuite/render-mx-generalized-schlick-glass/ref/out-linux-alt.exr b/testsuite/render-mx-generalized-schlick-glass/ref/out-linux-alt.exr new file mode 100644 index 000000000..1cf2687f7 Binary files /dev/null and b/testsuite/render-mx-generalized-schlick-glass/ref/out-linux-alt.exr differ diff --git a/testsuite/render-mx-generalized-schlick-glass/ref/out.exr b/testsuite/render-mx-generalized-schlick-glass/ref/out.exr index 94535977b..793ae8bf1 100644 Binary files a/testsuite/render-mx-generalized-schlick-glass/ref/out.exr and b/testsuite/render-mx-generalized-schlick-glass/ref/out.exr differ diff --git a/testsuite/render-mx-generalized-schlick/ref/out.exr b/testsuite/render-mx-generalized-schlick/ref/out.exr index 8215cd0fa..d7d549a0a 100644 Binary files a/testsuite/render-mx-generalized-schlick/ref/out.exr and b/testsuite/render-mx-generalized-schlick/ref/out.exr differ diff --git a/testsuite/render-mx-layer/ref/out.exr b/testsuite/render-mx-layer/ref/out.exr index cf24817c9..96f2e7019 100644 Binary files a/testsuite/render-mx-layer/ref/out.exr and b/testsuite/render-mx-layer/ref/out.exr differ diff --git a/testsuite/render-mx-sheen/ref/out.exr b/testsuite/render-mx-sheen/ref/out.exr index 6ad71ea9d..ea31ed4f7 100644 Binary files a/testsuite/render-mx-sheen/ref/out.exr and b/testsuite/render-mx-sheen/ref/out.exr differ diff --git a/testsuite/render-mx-sheen/sheen.osl b/testsuite/render-mx-sheen/sheen.osl index a4d72f8d6..891d292af 100644 --- a/testsuite/render-mx-sheen/sheen.osl +++ b/testsuite/render-mx-sheen/sheen.osl @@ -15,5 +15,8 @@ sheen float UImin = 0, float UImax = 1 ]] ) { - Ci = sheen_bsdf (N, Cs, roughness); + if (N.x < 0) + Ci = sheen_bsdf (N, Cs, sqrt(roughness), "mode", 1); + else + Ci = sheen_bsdf (N, Cs, roughness); } diff --git a/testsuite/render-oren-nayar/ref/out.exr b/testsuite/render-oren-nayar/ref/out.exr index eac5adcfe..dc6ef3fdc 100644 Binary files a/testsuite/render-oren-nayar/ref/out.exr and b/testsuite/render-oren-nayar/ref/out.exr differ diff --git a/testsuite/render-raytypes/ref/out.exr b/testsuite/render-raytypes/ref/out.exr index c65525155..08379e170 100644 Binary files a/testsuite/render-raytypes/ref/out.exr and b/testsuite/render-raytypes/ref/out.exr differ diff --git a/testsuite/render-uv/ref/out.exr b/testsuite/render-uv/ref/out.exr index 0dc485885..f371ebdc9 100644 Binary files a/testsuite/render-uv/ref/out.exr and b/testsuite/render-uv/ref/out.exr differ diff --git a/testsuite/render-veachmis/ref/out-alt-macarm.exr b/testsuite/render-veachmis/ref/out-alt-macarm.exr deleted file mode 100644 index 510aae780..000000000 Binary files a/testsuite/render-veachmis/ref/out-alt-macarm.exr and /dev/null differ diff --git a/testsuite/render-veachmis/ref/out-linux-alt.exr b/testsuite/render-veachmis/ref/out-linux-alt.exr new file mode 100644 index 000000000..27e12f21b Binary files /dev/null and b/testsuite/render-veachmis/ref/out-linux-alt.exr differ diff --git a/testsuite/render-veachmis/ref/out.exr b/testsuite/render-veachmis/ref/out.exr index 13fee6b45..1823fb0c8 100644 Binary files a/testsuite/render-veachmis/ref/out.exr and b/testsuite/render-veachmis/ref/out.exr differ diff --git a/testsuite/render-ward/ref/out.exr b/testsuite/render-ward/ref/out.exr index 4872d6640..25585daca 100644 Binary files a/testsuite/render-ward/ref/out.exr and b/testsuite/render-ward/ref/out.exr differ