diff options
29 files changed, 1045 insertions, 56 deletions
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 78a28b7feed..7ca23f23cb4 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -393,6 +393,9 @@ static ShaderNode *add_node(Scene *scene, case BL::ShaderNodeBsdfAnisotropic::distribution_GGX: aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; break; + case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX: + aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID; + break; case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY: aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; break; @@ -439,6 +442,9 @@ static ShaderNode *add_node(Scene *scene, case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY: glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; break; + case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX: + glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + break; } node = glossy; } @@ -455,6 +461,9 @@ static ShaderNode *add_node(Scene *scene, case BL::ShaderNodeBsdfGlass::distribution_GGX: glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; break; + case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX: + glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + break; } node = glass; } diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index ddf12435336..f0adbc03e22 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -76,6 +76,8 @@ set(SRC_CLOSURE_HEADERS closure/bsdf_diffuse.h closure/bsdf_diffuse_ramp.h closure/bsdf_microfacet.h + closure/bsdf_microfacet_multi.h + closure/bsdf_microfacet_multi_impl.h closure/bsdf_oren_nayar.h closure/bsdf_phong_ramp.h closure/bsdf_reflection.h diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index f0add804c32..f318a61f3a3 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -20,6 +20,7 @@ #include "../closure/bsdf_phong_ramp.h" #include "../closure/bsdf_diffuse_ramp.h" #include "../closure/bsdf_microfacet.h" +#include "../closure/bsdf_microfacet_multi.h" #include "../closure/bsdf_reflection.h" #include "../closure/bsdf_refraction.h" #include "../closure/bsdf_transparent.h" @@ -35,7 +36,7 @@ CCL_NAMESPACE_BEGIN -ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) +ccl_device int bsdf_sample(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) { int label; @@ -85,6 +86,14 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader label = bsdf_microfacet_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + label = bsdf_microfacet_multi_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -130,7 +139,7 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader return label; } -ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_eval(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf) { float3 eval; @@ -172,6 +181,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -234,6 +249,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -286,6 +307,10 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness) #ifdef __SVM__ switch(sc->type) { + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + bsdf_microfacet_multi_ggx_blur(sc, roughness); + break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h new file mode 100644 index 00000000000..21fbfa9b025 --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -0,0 +1,472 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* Most of the code is based on the supplemental implementations from https://eheitzresearch.wordpress.com/240-2/. */ + +/* === GGX Microfacet distribution functions === */ + +/* Isotropic GGX microfacet distribution */ +ccl_device_inline float D_ggx(float3 wm, float alpha) +{ + wm.z *= wm.z; + alpha *= alpha; + float tmp = (1.0f - wm.z) + alpha * wm.z; + return alpha / max(M_PI_F * tmp*tmp, 1e-7f); +} + +/* Anisotropic GGX microfacet distribution */ +ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha) +{ + float slope_x = -wm.x/alpha.x; + float slope_y = -wm.y/alpha.y; + float tmp = wm.z*wm.z + slope_x*slope_x + slope_y*slope_y; + + return 1.0f / max(M_PI_F * tmp*tmp * alpha.x*alpha.y, 1e-7f); +} + +/* Sample slope distribution (based on page 14 of the supplemental implementation). */ +ccl_device_inline float2 mf_sampleP22_11(const float cosI, const float2 randU) +{ + if(cosI > 0.9999f) { + const float r = sqrtf(randU.x / (1.0f - randU.x)); + const float phi = M_2PI_F * randU.y; + return make_float2(r*cosf(phi), r*sinf(phi)); + } + + const float sinI = sqrtf(1.0f - cosI*cosI); + const float tanI = sinI/cosI; + const float projA = 0.5f * (cosI + 1.0f); + if(projA < 0.0001f) + return make_float2(0.0f, 0.0f); + const float A = 2.0f*randU.x*projA / cosI - 1.0f; + float tmp = A*A-1.0f; + if(fabsf(tmp) < 1e-7f) + return make_float2(0.0f, 0.0f); + tmp = 1.0f / tmp; + const float D = safe_sqrtf(tanI*tanI*tmp*tmp - (A*A-tanI*tanI)*tmp); + + const float slopeX2 = tanI*tmp + D; + const float slopeX = (A < 0.0f || slopeX2 > 1.0f/tanI)? (tanI*tmp - D) : slopeX2; + + float U2; + if(randU.y >= 0.5f) + U2 = 2.0f*(randU.y - 0.5f); + else + U2 = 2.0f*(0.5f - randU.y); + const float z = (U2*(U2*(U2*0.27385f-0.73369f)+0.46341f)) / (U2*(U2*(U2*0.093073f+0.309420f)-1.0f)+0.597999f); + const float slopeY = z * sqrtf(1.0f + slopeX*slopeX); + + if(randU.y >= 0.5f) + return make_float2(slopeX, slopeY); + else + return make_float2(slopeX, -slopeY); +} + +/* Visible normal sampling for the GGX distribution (based on page 7 of the supplemental implementation). */ +ccl_device_inline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float2 randU) +{ + const float3 wi_11 = normalize(make_float3(alpha.x*wi.x, alpha.y*wi.y, wi.z)); + const float2 slope_11 = mf_sampleP22_11(wi_11.z, randU); + + const float2 cossin_phi = normalize(make_float2(wi_11.x, wi_11.y)); + const float slope_x = alpha.x*(cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y); + const float slope_y = alpha.y*(cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y); + + kernel_assert(isfinite(slope_x)); + return normalize(make_float3(-slope_x, -slope_y, 1.0f)); +} + +/* === Phase functions: Glossy, Diffuse and Glass === */ + +/* Phase function for reflective materials, either without a fresnel term (for compatibility) or with the conductive fresnel term. */ +ccl_device_inline float3 mf_sample_phase_glossy(const float3 wi, float3 *n, float3 *k, float3 *weight, const float3 wm) +{ + if(n && k) + *weight *= fresnel_conductor(dot(wi, wm), *n, *k); + + return -wi + 2.0f * wm * dot(wi, wm); +} + +ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha, float3 *n, float3 *k) +{ + if(w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float3 wh = normalize(wo - w); + if(wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + + const float dotW_WH = dot(-w, wh); + if(dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float phase = max(0.0f, dotW_WH) * 0.25f / (pArea * dotW_WH); + if(alpha.x == alpha.y) + phase *= D_ggx(wh, alpha.x); + else + phase *= D_ggx_aniso(wh, alpha); + + if(n && k) { + /* Apply conductive fresnel term. */ + return phase * fresnel_conductor(dotW_WH, *n, *k); + } + + return make_float3(phase, phase, phase); +} + +/* Phase function for rough lambertian diffuse surfaces. */ +ccl_device_inline float3 mf_sample_phase_diffuse(const float3 wm, const float randu, const float randv) +{ + float3 tm, bm; + make_orthonormals(wm, &tm, &bm); + + float2 disk = concentric_sample_disk(randu, randv); + return disk.x*tm + disk.y*bm + safe_sqrtf(1.0f - disk.x*disk.x - disk.y*disk.y)*wm; +} + +ccl_device_inline float3 mf_eval_phase_diffuse(const float3 w, const float3 wm) +{ + const float v = max(0.0f, dot(w, wm)) * M_1_PI_F; + return make_float3(v, v, v); +} + +/* Phase function for dielectric transmissive materials, including both reflection and refraction according to the dielectric fresnel term. */ +ccl_device_inline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside) +{ + float cosI = dot(wi, wm); + float f = fresnel_dielectric_cos(cosI, eta); + if(randV < f) { + *outside = true; + return -wi + 2.0f * wm * cosI; + } + *outside = false; + float inv_eta = 1.0f/eta; + float cosT = -safe_sqrtf(1.0f - (1.0f - cosI*cosI) * inv_eta*inv_eta); + return normalize(wm*(cosI*inv_eta + cosT) - wi*inv_eta); +} + +ccl_device_inline float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta) +{ + if(w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + float v; + if(wo_outside) { + const float3 wh = normalize(wo - w); + if(wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float dotW_WH = dot(-w, wh); + v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / (pArea * dotW_WH); + } + else { + float3 wh = normalize(wo*eta - w); + if(wh.z < 0.0f) + wh = -wh; + const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh); + if(dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float temp = dotW_WH + eta*dotWO_WH; + v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * D_ggx(wh, alpha.x) / (pArea * temp * temp); + } + + return make_float3(v, v, v); +} + +/* === Utility functions for the random walks === */ + +/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */ +ccl_device_inline float mf_lambda(const float3 w, const float2 alpha) +{ + if(w.z > 0.9999f) + return 0.0f; + else if(w.z < -0.9999f) + return -1.0f; + + const float inv_wz2 = 1.0f / (w.z*w.z); + const float2 wa = make_float2(w.x, w.y)*alpha; + float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2); + if(w.z <= 0.0f) + v = -v; + + return 0.5f*(v - 1.0f); +} + +/* Height distribution CDF (based on page 4 of the supplemental implementation). */ +ccl_device_inline float mf_invC1(const float h) +{ + return 2.0f * saturate(h) - 1.0f; +} + +ccl_device_inline float mf_C1(const float h) +{ + return saturate(0.5f * (h + 1.0f)); +} + +/* Masking function (based on page 16 of the supplemental implementation). */ +ccl_device_inline float mf_G1(const float3 w, const float C1, const float lambda) +{ + if(w.z > 0.9999f) + return 1.0f; + if(w.z < 1e-5f) + return 0.0f; + return powf(C1, lambda); +} + +/* Sampling from the visible height distribution (based on page 17 of the supplemental implementation). */ +ccl_device_inline bool mf_sample_height(const float3 w, float *h, float *C1, float *G1, float *lambda, const float U) +{ + if(w.z > 0.9999f) + return false; + if(w.z < -0.9999f) { + *C1 *= U; + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + else if(fabsf(w.z) >= 0.0001f) { + if(U > 1.0f - *G1) + return false; + if(*lambda >= 0.0f) { + *C1 = 1.0f; + } + else { + *C1 *= powf(1.0f-U, -1.0f / *lambda); + } + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + return true; +} + +/* === PDF approximations for the different phase functions. === + * As explained in bsdf_microfacet_multi_impl.h, using approximations with MIS still produces an unbiased result. */ + +/* Approximation for the albedo of the single-scattering GGX distribution, + * the missing energy is then approximated as a diffuse reflection for the PDF. */ +ccl_device_inline float mf_ggx_albedo(float r) +{ + float albedo = 0.806495f*expf(-1.98712f*r*r) + 0.199531f; + albedo -= ((((((1.76741f*r - 8.43891f)*r + 15.784f)*r - 14.398f)*r + 6.45221f)*r - 1.19722f)*r + 0.027803f)*r + 0.00568739f; + return saturate(albedo); +} + +ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha) +{ + return 0.25f * D_ggx(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, make_float2(alpha, alpha))) * wi.z) + (1.0f - mf_ggx_albedo(alpha)) * wo.z; +} + +ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha) +{ + return 0.25f * D_ggx_aniso(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, alpha)) * wi.z) + (1.0f - mf_ggx_albedo(sqrtf(alpha.x*alpha.y))) * wo.z; +} + +ccl_device_inline float mf_diffuse_pdf(const float3 wo) +{ + return M_1_PI_F * wo.z; +} + +ccl_device_inline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta) +{ + float3 wh; + float fresnel; + if(wi.z*wo.z > 0.0f) { + wh = normalize(wi + wo); + fresnel = fresnel_dielectric_cos(dot(wi, wh), eta); + } + else { + wh = normalize(wi + wo*eta); + fresnel = 1.0f - fresnel_dielectric_cos(dot(wi, wh), eta); + } + if(wh.z < 0.0f) + wh = -wh; + float3 r_wi = (wi.z < 0.0f)? -wi: wi; + return fresnel * max(0.0f, dot(r_wi, wh)) * D_ggx(wh, alpha) / ((1.0f + mf_lambda(r_wi, make_float2(alpha, alpha))) * r_wi.z) + fabsf(wo.z); +} + +/* === Actual random walk implementations, one version of mf_eval and mf_sample per phase function. === */ + +#define MF_NAME_JOIN(x,y) x ## _ ## y +#define MF_NAME_EVAL(x,y) MF_NAME_JOIN(x,y) +#define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION) + +#define MF_PHASE_FUNCTION glass +#define MF_MULTI_GLASS +#include "bsdf_microfacet_multi_impl.h" + +/* The diffuse phase function is not implemented as a node yet. */ +#if 0 +#define MF_PHASE_FUNCTION diffuse +#define MF_MULTI_DIFFUSE +#include "bsdf_microfacet_multi_impl.h" +#endif + +#define MF_PHASE_FUNCTION glossy +#define MF_MULTI_GLOSSY +#include "bsdf_microfacet_multi_impl.h" + +ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness) +{ + sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */ + sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */ +} + +/* === Closure implementations === */ + +/* Multiscattering GGX Glossy closure */ + +ccl_device int bsdf_microfacet_multi_ggx_common_setup(ShaderClosure *sc) +{ + sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */ + sc->data1 = clamp(sc->data1, 1e-4f, 1.0f); + sc->custom1 = saturate(sc->custom1); /* color */ + sc->custom2 = saturate(sc->custom2); + sc->custom3 = saturate(sc->custom3); + + sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM; +} + +ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(ShaderClosure *sc) +{ + if(sc->T == make_float3(0.0f, 0.0f, 0.0f)) + sc->T = make_float3(1.0f, 0.0f, 0.0f); + + return bsdf_microfacet_multi_ggx_common_setup(sc); +} + +ccl_device int bsdf_microfacet_multi_ggx_setup(ShaderClosure *sc) +{ + sc->data1 = sc->data0; + + return bsdf_microfacet_multi_ggx_common_setup(sc); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, uint *lcg_state) { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, uint *lcg_state) { + bool is_aniso = (sc->data0 != sc->data1); + float3 X, Y, Z; + Z = sc->N; + if(is_aniso) + make_orthonormals_tangent(Z, sc->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + if(is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1)); + else + *pdf = mf_ggx_pdf(localI, localO, sc->data0); + return mf_eval_glossy(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL); +} + +ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, uint *lcg_state) +{ + bool is_aniso = (sc->data0 != sc->data1); + float3 X, Y, Z; + Z = sc->N; + if(is_aniso) + make_orthonormals_tangent(Z, sc->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glossy(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL); + if(is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1)); + else + *pdf = mf_ggx_pdf(localI, localO, sc->data0); + *eval *= *pdf; + + *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + return LABEL_REFLECT|LABEL_GLOSSY; +} + +/* Multiscattering GGX Glass closure */ + +ccl_device int bsdf_microfacet_multi_ggx_glass_setup(ShaderClosure *sc) +{ + sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */ + sc->data1 = sc->data0; + sc->data2 = max(0.0f, sc->data2); /* ior */ + sc->custom1 = saturate(sc->custom1); /* color */ + sc->custom2 = saturate(sc->custom2); + sc->custom3 = saturate(sc->custom3); + + sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM; +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, uint *lcg_state) { + float3 X, Y, Z; + Z = sc->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2); + return mf_eval_glass(localI, localO, false, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, uint *lcg_state) { + float3 X, Y, Z; + Z = sc->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2); + return mf_eval_glass(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2); +} + +ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, uint *lcg_state) +{ + float3 X, Y, Z; + Z = sc->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glass(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2); + *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2); + *eval *= *pdf; + + *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + if(localO.z*localI.z > 0.0f) + return LABEL_REFLECT|LABEL_GLOSSY; + else + return LABEL_TRANSMIT|LABEL_GLOSSY; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h new file mode 100644 index 00000000000..52cb4d242d5 --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h @@ -0,0 +1,220 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Evaluate the BSDF from wi to wo. + * Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF, + * which is evaluated stochastically through a random walk. At each bounce (except for the first one), + * the amount of reflection from here towards wo is evaluated before bouncing again. + * + * Because of the random walk, the evaluation is not deterministic, but its expected value is equal to + * the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined + * analytically, so the single-scattering PDF plus a diffuse term to account for the multi-scattered + * energy is used. In combination with MIS, that is enough to produce an unbiased result, although + * the balance heuristic isn't necessarily optimal anymore. + */ +ccl_device float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi, float3 wo, const bool wo_outside, const float3 color, const float alpha_x, const float alpha_y, uint* lcg_state +#ifdef MF_MULTI_GLASS + , const float eta +#elif defined(MF_MULTI_GLOSSY) + , float3 *n, float3 *k +#endif +) +{ + /* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */ + bool swapped = false; +#ifdef MF_MULTI_GLASS + if(wi.z*wo.z < 0.0f) { + /* Glass transmission is a special case and requires the directions to change hemisphere. */ + if(-wo.z < wi.z) { + swapped = true; + float3 tmp = -wo; + wo = -wi; + wi = tmp; + } + } + else +#endif + if(wo.z < wi.z) { + swapped = true; + float3 tmp = wo; + wo = wi; + wi = tmp; + } + + if(wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside)) + return make_float3(0.0f, 0.0f, 0.0f); + + const float2 alpha = make_float2(alpha_x, alpha_y); + + float lambda_r = mf_lambda(-wi, alpha); + float shadowing_lambda = mf_lambda(wo_outside? wo: -wo, alpha); + + /* Analytically compute single scattering for lower noise. */ + float3 eval; +#ifdef MF_MULTI_GLASS + eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta); + if(wo_outside) + eval *= -lambda_r / (shadowing_lambda - lambda_r); + else + eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f); +#elif defined(MF_MULTI_DIFFUSE) + /* Diffuse has no special closed form for the single scattering bounce */ + eval = make_float3(0.0f, 0.0f, 0.0f); +#else /* MF_MULTI_GLOSSY */ + const float3 wh = normalize(wi+wo); + const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda); + float val = G2 * 0.25f / wi.z; + if(alpha.x == alpha.y) + val *= D_ggx(wh, alpha.x); + else + val *= D_ggx_aniso(wh, alpha); + if(n && k) { + eval = fresnel_conductor(dot(wh, wi), *n, *k) * val; + } + else { + eval = make_float3(val, val, val); + } +#endif + + float3 wr = -wi; + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + + for(int order = 0; order < 10; order++) { + /* Sample microfacet height and normal */ + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float(lcg_state))) + break; + float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float(lcg_state), lcg_step_float(lcg_state))); + +#ifdef MF_MULTI_DIFFUSE + if(order == 0) { + /* Compute single-scattering for diffuse. */ + const float G2_G1 = -lambda_r / (shadowing_lambda - lambda_r); + eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm); + } +#endif + if(order > 0) { + /* Evaluate amount of scattering towards wo on this microfacet. */ + float3 phase; +#ifdef MF_MULTI_GLASS + if(outside) + phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); + else + phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f/eta); +#elif defined(MF_MULTI_DIFFUSE) + phase = mf_eval_phase_diffuse(wo, wm); +#else /* MF_MULTI_GLOSSY */ + phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha, n, k) * throughput; +#endif + eval += throughput * phase * mf_G1(wo_outside? wo: -wo, mf_C1((outside == wo_outside)? hr: -hr), shadowing_lambda); + } + if(order+1 < 10) { + /* Bounce from the microfacet. */ +#ifdef MF_MULTI_GLASS + bool next_outside; + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float(lcg_state), &next_outside); + if(!next_outside) { + outside = !outside; + wr = -wr; + hr = -hr; + } +#elif defined(MF_MULTI_DIFFUSE) + wr = mf_sample_phase_diffuse(wm, lcg_step_float(lcg_state), lcg_step_float(lcg_state)); +#else /* MF_MULTI_GLOSSY */ + wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); +#endif + + lambda_r = mf_lambda(wr, alpha); + + throughput *= color; + + C1_r = mf_C1(hr); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + } + + if(swapped) + eval *= fabsf(wi.z / wo.z); + return eval; +} + +/* Perform a random walk on the microsurface starting from wi, returning the direction in which the walk + * escaped the surface in wo. The function returns the throughput between wi and wo. + * Without reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal. + */ +ccl_device float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, uint *lcg_state +#ifdef MF_MULTI_GLASS + , const float eta +#elif defined(MF_MULTI_GLOSSY) + , float3 *n, float3 *k +#endif +) +{ + const float2 alpha = make_float2(alpha_x, alpha_y); + + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + float3 wr = -wi; + float lambda_r = mf_lambda(wr, alpha); + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; + + int order; + for(order = 0; order < 10; order++) { + /* Sample microfacet height. */ + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float(lcg_state))) { + /* The random walk has left the surface. */ + *wo = outside? wr: -wr; + return throughput; + } + /* Sample microfacet normal. */ + float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float(lcg_state), lcg_step_float(lcg_state))); + + /* First-bounce color is already accounted for in mix weight. */ + if(order > 0) + throughput *= color; + + /* Bounce from the microfacet. */ +#ifdef MF_MULTI_GLASS + bool next_outside; + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float(lcg_state), &next_outside); + if(!next_outside) { + hr = -hr; + wr = -wr; + outside = !outside; + } +#elif defined(MF_MULTI_DIFFUSE) + wr = mf_sample_phase_diffuse(wm, lcg_step_float(lcg_state), lcg_step_float(lcg_state)); +#else /* MF_MULTI_GLOSSY */ + wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); +#endif + + /* Update random walk parameters. */ + lambda_r = mf_lambda(wr, alpha); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + *wo = make_float3(0.0f, 0.0f, 1.0f); + return make_float3(0.0f, 0.0f, 0.0f); +} + +#undef MF_MULTI_GLASS +#undef MF_MULTI_DIFFUSE +#undef MF_MULTI_GLOSSY +#undef MF_PHASE_FUNCTION diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index 05816bac2c1..89b1998d1ce 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -111,10 +111,9 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta) return 1.0f; // TIR(no refracted component) } -#if 0 ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k) { - float3 cosi2 = make_float3(cosi*cosi); + float3 cosi2 = make_float3(cosi*cosi, cosi*cosi, cosi*cosi); float3 one = make_float3(1.0f, 1.0f, 1.0f); float3 tmp_f = eta * eta + k * k; float3 tmp = tmp_f * cosi2; @@ -124,7 +123,6 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k (tmp_f + (2.0f * eta * cosi) + cosi2); return(Rparl2 + Rperp2) * 0.5f; } -#endif ccl_device float smooth_step(float edge0, float edge1, float x) { diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index 8d05befe1d4..9ee0b09529e 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -48,7 +48,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian /* evaluate surface shader */ float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF); - shader_eval_surface(kg, sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, &rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* TODO, disable the closures we won't need */ @@ -220,6 +220,7 @@ ccl_device_inline float3 kernel_bake_shader_bsdf(KernelGlobals *kg, ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, ShaderData *sd, + RNG *rng, PathState *state, float3 direct, float3 indirect, @@ -239,12 +240,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, } else { /* surface color of the pass only */ - shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); return kernel_bake_shader_bsdf(kg, sd, type); } } else { - shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); color = kernel_bake_shader_bsdf(kg, sd, type); } @@ -336,7 +337,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, case SHADER_EVAL_NORMAL: { if((sd.flag & SD_HAS_BUMP)) { - shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_MAIN); } /* compression: normal = (2 * color) - 1 */ @@ -350,7 +351,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, } case SHADER_EVAL_EMISSION: { - shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_EMISSION); out = shader_emissive_eval(kg, &sd); break; } @@ -403,6 +404,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_diffuse, L.indirect_diffuse, @@ -414,6 +416,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_glossy, L.indirect_glossy, @@ -425,6 +428,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_transmission, L.indirect_transmission, @@ -437,6 +441,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, #ifdef __SUBSURFACE__ out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_subsurface, L.indirect_subsurface, diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index e22bcead404..149ac3ed4f9 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -57,7 +57,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg, /* no path flag, we're evaluating this for all closures. that's weak but * we'd have to do multiple evaluations otherwise */ path_state_modify_bounce(state, true); - shader_eval_surface(kg, emission_sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, emission_sd, NULL, state, 0.0f, 0, SHADER_CONTEXT_EMISSION); path_state_modify_bounce(state, false); /* evaluate emissive closure */ diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 0dded397ffa..3c3503eab8b 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -253,7 +253,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, &isect, ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); + shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); #ifdef __BRANCHED_PATH__ shader_merge_closures(sd); #endif @@ -791,7 +791,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, /* setup shading */ shader_setup_from_ray(kg, &sd, &isect, &ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); - shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* holdout */ #ifdef __HOLDOUT__ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index fdba1a7b025..56516967d8f 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -463,7 +463,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* setup shading */ shader_setup_from_ray(kg, &sd, &isect, &ray); - shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); shader_merge_closures(&sd); /* holdout */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index a0b56118ab7..3a4770f82f1 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -468,6 +468,9 @@ ccl_device void shader_merge_closures(ShaderData *sd) continue; } + if((sd->flag & SD_BSDF_HAS_CUSTOM) && !(sci->custom1 == scj->custom1 && sci->custom2 == scj->custom2 && sci->custom3 == scj->custom3)) + continue; + sci->weight += scj->weight; sci->sample_weight += scj->sample_weight; @@ -488,7 +491,7 @@ ccl_device void shader_merge_closures(ShaderData *sd) /* BSDF */ -ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderData *sd, const float3 omega_in, float *pdf, +ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd, const float3 omega_in, float *pdf, int skip_bsdf, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight) { /* this is the veach one-sample model with balance heuristic, some pdf @@ -517,7 +520,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa #ifdef __BRANCHED_PATH__ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg, - const ShaderData *sd, + ShaderData *sd, const float3 omega_in, BsdfEval *result_eval, float light_pdf, @@ -563,7 +566,7 @@ ccl_device void shader_bsdf_eval(KernelGlobals *kg, } } -ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, +ccl_device int shader_bsdf_sample(KernelGlobals *kg, ShaderData *sd, float randu, float randv, BsdfEval *bsdf_eval, float3 *omega_in, differential3 *domega_in, float *pdf) { @@ -620,7 +623,7 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, return label; } -ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *sd, +ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, BsdfEval *bsdf_eval, float3 *omega_in, differential3 *domega_in, float *pdf) { @@ -824,7 +827,7 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd) /* Surface Evaluation */ -ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, +ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, RNG *rng, ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx) { ccl_fetch(sd, num_closure) = 0; @@ -846,6 +849,10 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_fetch(sd, flag) |= bsdf_diffuse_setup(ccl_fetch_array(sd, closure, 0)); #endif } + + if(rng && (ccl_fetch(sd, flag) & SD_BSDF_NEEDS_LCG)) { + ccl_fetch(sd, lcg_state) = lcg_state_init(rng, state, 0xb4bc3953); + } } /* Background Evaluation */ diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index 1abbbb2ddad..db2fc84834a 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -117,7 +117,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, /* attenuation from transparent surface */ if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) { path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); + shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); path_state_modify_bounce(state, false); throughput *= shader_bsdf_transparency(kg, shadow_sd); @@ -252,7 +252,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg, /* attenuation from transparent surface */ if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) { path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); + shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); path_state_modify_bounce(state, false); throughput *= shader_bsdf_transparency(kg, shadow_sd); diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index 705b57ba6ff..b048bd38fc9 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -198,7 +198,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg, if(bump || texture_blur > 0.0f) { /* average color and normal at incoming point */ - shader_eval_surface(kg, sd, state, 0.0f, state_flag, SHADER_CONTEXT_SSS); + shader_eval_surface(kg, sd, NULL, state, 0.0f, state_flag, SHADER_CONTEXT_SSS); float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL); /* we simply divide out the average color and multiply with the average diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index aa5eeebda7b..76d2a6b98e6 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -679,31 +679,34 @@ typedef enum ShaderContext { enum ShaderDataFlag { /* runtime flags */ - SD_BACKFACING = (1 << 0), /* backside of surface? */ - SD_EMISSION = (1 << 1), /* have emissive closure? */ - SD_BSDF = (1 << 2), /* have bsdf closure? */ - SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */ - SD_BSSRDF = (1 << 4), /* have bssrdf */ - SD_HOLDOUT = (1 << 5), /* have holdout closure? */ - SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */ - SD_SCATTER = (1 << 7), /* have volume phase closure? */ - SD_AO = (1 << 8), /* have ao closure? */ - SD_TRANSPARENT = (1 << 9), /* have transparent closure? */ + SD_BACKFACING = (1 << 0), /* backside of surface? */ + SD_EMISSION = (1 << 1), /* have emissive closure? */ + SD_BSDF = (1 << 2), /* have bsdf closure? */ + SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */ + SD_BSSRDF = (1 << 4), /* have bssrdf */ + SD_HOLDOUT = (1 << 5), /* have holdout closure? */ + SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */ + SD_SCATTER = (1 << 7), /* have volume phase closure? */ + SD_AO = (1 << 8), /* have ao closure? */ + SD_TRANSPARENT = (1 << 9), /* have transparent closure? */ + SD_BSDF_NEEDS_LCG = (1 << 10), + SD_BSDF_HAS_CUSTOM = (1 << 11), /* are the custom variables relevant? */ SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF| - SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO), + SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO| + SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM), /* shader flags */ - SD_USE_MIS = (1 << 10), /* direct light sample */ - SD_HAS_TRANSPARENT_SHADOW = (1 << 11), /* has transparent shadow */ - SD_HAS_VOLUME = (1 << 12), /* has volume shader */ - SD_HAS_ONLY_VOLUME = (1 << 13), /* has only volume shader, no surface */ - SD_HETEROGENEOUS_VOLUME = (1 << 14), /* has heterogeneous volume */ - SD_HAS_BSSRDF_BUMP = (1 << 15), /* bssrdf normal uses bump */ - SD_VOLUME_EQUIANGULAR = (1 << 16), /* use equiangular sampling */ - SD_VOLUME_MIS = (1 << 17), /* use multiple importance sampling */ - SD_VOLUME_CUBIC = (1 << 18), /* use cubic interpolation for voxels */ - SD_HAS_BUMP = (1 << 19), /* has data connected to the displacement input */ + SD_USE_MIS = (1 << 12), /* direct light sample */ + SD_HAS_TRANSPARENT_SHADOW = (1 << 13), /* has transparent shadow */ + SD_HAS_VOLUME = (1 << 14), /* has volume shader */ + SD_HAS_ONLY_VOLUME = (1 << 15), /* has only volume shader, no surface */ + SD_HETEROGENEOUS_VOLUME = (1 << 16), /* has heterogeneous volume */ + SD_HAS_BSSRDF_BUMP = (1 << 17), /* bssrdf normal uses bump */ + SD_VOLUME_EQUIANGULAR = (1 << 18), /* use equiangular sampling */ + SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */ + SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */ + SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */ SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME| SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME| @@ -711,13 +714,13 @@ enum ShaderDataFlag { SD_VOLUME_CUBIC|SD_HAS_BUMP), /* object flags */ - SD_HOLDOUT_MASK = (1 << 20), /* holdout for camera rays */ - SD_OBJECT_MOTION = (1 << 21), /* has object motion blur */ - SD_TRANSFORM_APPLIED = (1 << 22), /* vertices have transform applied */ - SD_NEGATIVE_SCALE_APPLIED = (1 << 23), /* vertices have negative scale applied */ - SD_OBJECT_HAS_VOLUME = (1 << 24), /* object has a volume shader */ - SD_OBJECT_INTERSECTS_VOLUME = (1 << 25), /* object intersects AABB of an object with volume shader */ - SD_OBJECT_HAS_VERTEX_MOTION = (1 << 26), /* has position for motion vertices */ + SD_HOLDOUT_MASK = (1 << 22), /* holdout for camera rays */ + SD_OBJECT_MOTION = (1 << 23), /* has object motion blur */ + SD_TRANSFORM_APPLIED = (1 << 24), /* vertices have transform applied */ + SD_NEGATIVE_SCALE_APPLIED = (1 << 25), /* vertices have negative scale applied */ + SD_OBJECT_HAS_VOLUME = (1 << 26), /* object has a volume shader */ + SD_OBJECT_INTERSECTS_VOLUME = (1 << 27), /* object intersects AABB of an object with volume shader */ + SD_OBJECT_HAS_VERTEX_MOTION = (1 << 28), /* has position for motion vertices */ SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED| SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME| @@ -806,6 +809,9 @@ typedef ccl_addr_space struct ShaderData { int num_closure; float randb_closure; + /* LCG state for closures that require additional random numbers. */ + uint lcg_state; + /* ray start position, only set for backgrounds */ float3 ray_P; differential3 ray_dP; diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index 95b8cea0922..02b1491489c 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -44,11 +44,13 @@ #include "kernel_compat_cpu.h" #include "kernel_globals.h" #include "kernel_montecarlo.h" +#include "kernel_random.h" #include "closure/bsdf_util.h" #include "closure/bsdf_ashikhmin_velvet.h" #include "closure/bsdf_diffuse.h" #include "closure/bsdf_microfacet.h" +#include "closure/bsdf_microfacet_multi.h" #include "closure/bsdf_oren_nayar.h" #include "closure/bsdf_reflection.h" #include "closure/bsdf_refraction.h" @@ -205,6 +207,12 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) bsdf_microfacet_ggx_aniso_params(), bsdf_microfacet_ggx_aniso_prepare); register_closure(ss, "microfacet_ggx_refraction", id++, bsdf_microfacet_ggx_refraction_params(), bsdf_microfacet_ggx_refraction_prepare); + register_closure(ss, "microfacet_multi_ggx", id++, + closure_bsdf_microfacet_multi_ggx_params(), closure_bsdf_microfacet_multi_ggx_prepare); + register_closure(ss, "microfacet_multi_ggx_glass", id++, + closure_bsdf_microfacet_multi_ggx_glass_params(), closure_bsdf_microfacet_multi_ggx_glass_prepare); + register_closure(ss, "microfacet_multi_ggx_aniso", id++, + closure_bsdf_microfacet_multi_ggx_aniso_params(), closure_bsdf_microfacet_multi_ggx_aniso_prepare); register_closure(ss, "microfacet_beckmann", id++, bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare); register_closure(ss, "microfacet_beckmann_aniso", id++, @@ -250,5 +258,127 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) volume_absorption_params(), volume_absorption_prepare); } +/* Multiscattering GGX closures */ + +class MicrofacetMultiClosure : public CBSDFClosure { +public: + float3 color; + + /* Technically, the MultiGGX Glass closure may also transmit. + * However, since this is set statically and only used for caustic flags, this is probably as good as it gets. */ + MicrofacetMultiClosure() : CBSDFClosure(LABEL_GLOSSY|LABEL_REFLECT) + { + } + + void setup() + { + sc.prim = NULL; + sc.custom1 = color.x; + sc.custom2 = color.y; + sc.custom3 = color.z; + } + + void blur(float roughness) + { + } + + float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const + { + pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } + + float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const + { + pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } + + int sample(const float3 &Ng, + const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy, + float randu, float randv, + float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy, + float &pdf, float3 &eval) const + { + pdf = 0; + return LABEL_NONE; + } +}; + +class MicrofacetMultiGGXClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXClosure() : MicrofacetMultiClosure() {} + + void setup() + { + MicrofacetMultiClosure::setup(); + m_shaderdata_flag = bsdf_microfacet_multi_ggx_setup(&sc); + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_prepare, MicrofacetMultiGGXClosure); + +class MicrofacetMultiGGXAnisoClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXAnisoClosure() : MicrofacetMultiClosure() {} + + void setup() + { + MicrofacetMultiClosure::setup(); + m_shaderdata_flag = bsdf_microfacet_multi_ggx_aniso_setup(&sc); + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.T), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data1), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_prepare, MicrofacetMultiGGXAnisoClosure); + +class MicrofacetMultiGGXGlassClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXGlassClosure() : MicrofacetMultiClosure() {} + + void setup() + { + MicrofacetMultiClosure::setup(); + m_shaderdata_flag = bsdf_microfacet_multi_ggx_glass_setup(&sc); + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data2), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure); + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 1578d06cd56..c5a1a29b6af 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -52,6 +52,9 @@ OSL::ClosureParam *closure_bssrdf_cubic_params(); OSL::ClosureParam *closure_bssrdf_gaussian_params(); OSL::ClosureParam *closure_bssrdf_burley_params(); OSL::ClosureParam *closure_henyey_greenstein_volume_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params(); void closure_emission_prepare(OSL::RendererServices *, int id, void *data); void closure_background_prepare(OSL::RendererServices *, int id, void *data); @@ -63,6 +66,9 @@ void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_burley_prepare(OSL::RendererServices *, int id, void *data); void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data); #define CCLOSURE_PREPARE(name, classname) \ void name(RendererServices *, int id, void *data) \ diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index f58368e6789..6cde7419e10 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -177,6 +177,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, case CClosurePrimitive::BSDF: { CBSDFClosure *bsdf = (CBSDFClosure *)prim; int scattering = bsdf->scattering(); + int shaderdata_flag = bsdf->shaderdata_flag(); /* caustic options */ if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) { @@ -201,11 +202,16 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, sc.data1 = bsdf->sc.data1; sc.data2 = bsdf->sc.data2; sc.prim = bsdf->sc.prim; + if(shaderdata_flag & SD_BSDF_HAS_CUSTOM) { + sc.custom1 = bsdf->sc.custom1; + sc.custom2 = bsdf->sc.custom2; + sc.custom3 = bsdf->sc.custom3; + } /* add */ if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) { sd->closure[sd->num_closure++] = sc; - sd->flag |= bsdf->shaderdata_flag(); + sd->flag |= shaderdata_flag; } break; } diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl index f7f89543aa9..bef6d7e8809 100644 --- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl @@ -51,6 +51,8 @@ shader node_anisotropic_bsdf( BSDF = Color * microfacet_beckmann_aniso(Normal, T, RoughnessU, RoughnessV); else if (distribution == "GGX") BSDF = Color * microfacet_ggx_aniso(Normal, T, RoughnessU, RoughnessV); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, RoughnessU, RoughnessV, Color); else BSDF = Color * ashikhmin_shirley(Normal, T, RoughnessU, RoughnessV); } diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/shaders/node_glass_bsdf.osl index 8fd0a2fd714..a9723a8300a 100644 --- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_glass_bsdf.osl @@ -35,6 +35,8 @@ shader node_glass_bsdf( else if (distribution == "beckmann") BSDF = Color * (Fr * microfacet_beckmann(Normal, Roughness) + (1.0 - Fr) * microfacet_beckmann_refraction(Normal, Roughness, eta)); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_glass(Normal, Roughness, eta, Color); else if (distribution == "GGX") BSDF = Color * (Fr * microfacet_ggx(Normal, Roughness) + (1.0 - Fr) * microfacet_ggx_refraction(Normal, Roughness, eta)); diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl index cc2a66fd46a..f4ea7e7dc6a 100644 --- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl @@ -30,6 +30,8 @@ shader node_glossy_bsdf( BSDF = Color * microfacet_beckmann(Normal, Roughness); else if (distribution == "GGX") BSDF = Color * microfacet_ggx(Normal, Roughness); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx(Normal, Roughness, Color); else BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), Roughness, Roughness); diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index 8d5d3746caf..a8dda8a12c9 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -527,6 +527,9 @@ closure color transparent() BUILTIN; closure color microfacet_ggx(normal N, float ag) BUILTIN; closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN; closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; +closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN; +closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN; +closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN; closure color microfacet_beckmann(normal N, float ab) BUILTIN; closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN; closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h index e816a818915..cef64bf5f36 100644 --- a/intern/cycles/kernel/split/kernel_shader_eval.h +++ b/intern/cycles/kernel/split/kernel_shader_eval.h @@ -65,6 +65,6 @@ ccl_device void kernel_shader_eval( isect, &ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); } } diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 65512a0105c..fae89aade60 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -186,7 +186,8 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * case CLOSURE_BSDF_REFLECTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: - case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: { + case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: { #ifdef __CAUSTICS_TRICKS__ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) break; @@ -206,6 +207,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc); else if(type == CLOSURE_BSDF_MICROFACET_GGX_ID) ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc); + else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) { + kernel_assert(stack_valid(data_node.z)); + float3 color = stack_load_float3(stack, data_node.z); + sc->custom1 = color.x; + sc->custom2 = color.y; + sc->custom3 = color.z; + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_setup(sc); + } else ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(sc); } @@ -307,8 +316,36 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * break; } + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: { +#ifdef __CAUSTICS_TRICKS__ + if(!kernel_data.integrator.caustics_reflective && !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) + break; +#endif + ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + + if(sc) { + sc->N = N; + + sc->data0 = param1; + sc->data1 = param1; + float eta = fmaxf(param2, 1e-5f); + sc->data2 = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta; + + kernel_assert(stack_valid(data_node.z)); + float3 color = stack_load_float3(stack, data_node.z); + sc->custom1 = color.x; + sc->custom2 = color.y; + sc->custom3 = color.z; + + /* setup bsdf */ + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_glass_setup(sc); + } + + break; + } case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID: case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: { #ifdef __CAUSTICS_TRICKS__ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) @@ -346,6 +383,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(sc); else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID) ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(sc); + else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) { + kernel_assert(stack_valid(data_node.w)); + float3 color = stack_load_float3(stack, data_node.w); + sc->custom1 = color.x; + sc->custom2 = color.y; + sc->custom3 = color.z; + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_aniso_setup(sc); + } else ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(sc); } diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index e57d22b1b13..e1a8ced6a34 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -396,8 +396,10 @@ typedef enum ClosureType { CLOSURE_BSDF_REFLECTION_ID, CLOSURE_BSDF_MICROFACET_GGX_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, @@ -413,6 +415,7 @@ typedef enum ClosureType { CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, CLOSURE_BSDF_SHARP_GLASS_ID, CLOSURE_BSDF_HAIR_TRANSMISSION_ID, diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 5e53b66f710..87020823df9 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1828,6 +1828,7 @@ NODE_DEFINE(AnisotropicBsdfNode) static NodeEnum distribution_enum; distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID); distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID); distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID); SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); @@ -1864,7 +1865,10 @@ void AnisotropicBsdfNode::compile(SVMCompiler& compiler) { closure = distribution; - BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); + if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) + BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color")); + else + BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); } void AnisotropicBsdfNode::compile(OSLCompiler& compiler) @@ -1888,6 +1892,7 @@ NODE_DEFINE(GlossyBsdfNode) distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID); distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID); SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID); SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f); @@ -1937,6 +1942,8 @@ void GlossyBsdfNode::compile(SVMCompiler& compiler) if(closure == CLOSURE_BSDF_REFLECTION_ID) BsdfNode::compile(compiler, NULL, NULL); + else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) + BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color")); else BsdfNode::compile(compiler, input("Roughness"), NULL); } @@ -1961,6 +1968,7 @@ NODE_DEFINE(GlassBsdfNode) distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID); distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); @@ -2011,6 +2019,8 @@ void GlassBsdfNode::compile(SVMCompiler& compiler) if(closure == CLOSURE_BSDF_SHARP_GLASS_ID) BsdfNode::compile(compiler, NULL, input("IOR")); + else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) + BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color")); else BsdfNode::compile(compiler, input("Roughness"), input("IOR")); } diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 53944ec1cc4..cfe6fa65143 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -545,6 +545,11 @@ ccl_device_inline float3 normalize(const float3 a) #endif +ccl_device_inline float3 saturate3(float3 a) +{ + return make_float3(saturate(a.x), saturate(a.y), saturate(a.z)); +} + ccl_device_inline float3 normalize_len(const float3 a, float *t) { *t = len(a); @@ -1329,6 +1334,15 @@ ccl_device float safe_modulo(float a, float b) return (b != 0.0f)? fmodf(a, b): 0.0f; } +ccl_device_inline float beta(float x, float y) +{ +#ifndef __KERNEL_OPENCL__ + return expf(lgammaf(x) + lgammaf(y) - lgammaf(x+y)); +#else + return expf(lgamma(x) + lgamma(y) - lgamma(x+y)); +#endif +} + /* Ray Intersection */ ccl_device bool ray_sphere_intersect( diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6cba3322135..46b30f41f5b 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -912,7 +912,8 @@ typedef struct NodeSunBeams { #define SHD_GLOSSY_BECKMANN 0 #define SHD_GLOSSY_SHARP 1 #define SHD_GLOSSY_GGX 2 -#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_MULTI_GGX 4 /* vector transform */ #define SHD_VECT_TRANSFORM_TYPE_VECTOR 0 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index bf7e4634c2f..7f2cd1e6080 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3193,12 +3193,14 @@ static EnumPropertyItem node_glossy_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem node_anisotropic_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, {0, NULL, 0, NULL, NULL} }; @@ -3207,6 +3209,14 @@ static EnumPropertyItem node_glass_items[] = { {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem node_refraction_items[] = { + {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, + {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, + {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {0, NULL, 0, NULL, NULL} }; @@ -4159,6 +4169,17 @@ static void def_glass(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_refraction(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, node_refraction_items); + RNA_def_property_ui_text(prop, "Distribution", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_anisotropic(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 9e1a0c926fa..171d5313c1d 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -82,7 +82,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BS DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" ) -DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glass, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) +DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" ) |