Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/kernel')
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume_all.h24
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume_all.h24
-rw-r--r--intern/cycles/kernel/closure/bsdf.h14
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair_principled.h502
-rw-r--r--intern/cycles/kernel/geom/geom_curve.h27
-rw-r--r--intern/cycles/kernel/geom/geom_curve_intersect.h25
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h1
-rw-r--r--intern/cycles/kernel/kernel_light.h25
-rw-r--r--intern/cycles/kernel/kernel_montecarlo.h29
-rw-r--r--intern/cycles/kernel/kernel_types.h2
-rw-r--r--intern/cycles/kernel/kernel_volume.h6
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp61
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h1
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/shaders/node_bump.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_normal_map.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl105
-rw-r--r--intern/cycles/kernel/shaders/stdosl.h31
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h120
-rw-r--r--intern/cycles/kernel/svm/svm_displace.h2
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h2
-rw-r--r--intern/cycles/kernel/svm/svm_types.h10
-rw-r--r--intern/cycles/kernel/svm/svm_voronoi.h3
24 files changed, 950 insertions, 70 deletions
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 092bec08a51..c4cad17429d 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -156,6 +156,7 @@ set(SRC_CLOSURE_HEADERS
closure/volume.h
closure/bsdf_principled_diffuse.h
closure/bsdf_principled_sheen.h
+ closure/bsdf_hair_principled.h
)
set(SRC_SVM_HEADERS
diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h
index f2379efc656..2ee29ac9c27 100644
--- a/intern/cycles/kernel/bvh/bvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/bvh_volume_all.h
@@ -212,14 +212,16 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
isect_array->t = isect_t;
if(num_hits == max_hits) {
#if BVH_FEATURE(BVH_INSTANCING)
+ if(object != OBJECT_NONE) {
# if BVH_FEATURE(BVH_MOTION)
- float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
# else
- Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
- float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
# endif
- for(int i = 0; i < num_hits_in_instance; i++) {
- (isect_array-i-1)->t *= t_fac;
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
}
#endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
@@ -257,14 +259,16 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
isect_array->t = isect_t;
if(num_hits == max_hits) {
# if BVH_FEATURE(BVH_INSTANCING)
+ if(object != OBJECT_NONE) {
# if BVH_FEATURE(BVH_MOTION)
- float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
# else
- Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
- float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
# endif
- for(int i = 0; i < num_hits_in_instance; i++) {
- (isect_array-i-1)->t *= t_fac;
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
}
# endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h
index ac5f58a9a51..1e454e4d36b 100644
--- a/intern/cycles/kernel/bvh/qbvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h
@@ -279,14 +279,16 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
isect_array->t = isect_t;
if(num_hits == max_hits) {
#if BVH_FEATURE(BVH_INSTANCING)
+ if(object != OBJECT_NONE) {
# if BVH_FEATURE(BVH_MOTION)
- float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
# else
- Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
- float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
# endif
- for(int i = 0; i < num_hits_in_instance; i++) {
- (isect_array-i-1)->t *= t_fac;
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
}
#endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
@@ -317,14 +319,16 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
isect_array->t = isect_t;
if(num_hits == max_hits) {
# if BVH_FEATURE(BVH_INSTANCING)
+ if(object != OBJECT_NONE) {
# if BVH_FEATURE(BVH_MOTION)
- float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
# else
- Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
- float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
# endif
- for(int i = 0; i < num_hits_in_instance; i++) {
- (isect_array-i-1)->t *= t_fac;
+ for(int i = 0; i < num_hits_in_instance; i++) {
+ (isect_array-i-1)->t *= t_fac;
+ }
}
# endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index f191b812f11..3a9629ea9d7 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -27,6 +27,7 @@
#include "kernel/closure/bsdf_ashikhmin_shirley.h"
#include "kernel/closure/bsdf_toon.h"
#include "kernel/closure/bsdf_hair.h"
+#include "kernel/closure/bsdf_hair_principled.h"
#include "kernel/closure/bsdf_principled_diffuse.h"
#include "kernel/closure/bsdf_principled_sheen.h"
#include "kernel/closure/bssrdf.h"
@@ -171,6 +172,10 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
label = bsdf_hair_transmission_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
+ case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
+ label = bsdf_principled_hair_sample(kg, sc, sd, randu, randv,
+ eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
#ifdef __PRINCIPLED__
case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
@@ -284,6 +289,9 @@ float3 bsdf_eval(KernelGlobals *kg,
case CLOSURE_BSDF_GLOSSY_TOON_ID:
eval = bsdf_glossy_toon_eval_reflect(sc, sd->I, omega_in, pdf);
break;
+ case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
+ eval = bsdf_principled_hair_eval(kg, sd, sc, omega_in, pdf);
+ break;
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
eval = bsdf_hair_reflection_eval_reflect(sc, sd->I, omega_in, pdf);
break;
@@ -366,6 +374,9 @@ float3 bsdf_eval(KernelGlobals *kg,
case CLOSURE_BSDF_GLOSSY_TOON_ID:
eval = bsdf_glossy_toon_eval_transmit(sc, sd->I, omega_in, pdf);
break;
+ case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
+ eval = bsdf_principled_hair_eval(kg, sd, sc, omega_in, pdf);
+ break;
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
eval = bsdf_hair_reflection_eval_transmit(sc, sd->I, omega_in, pdf);
break;
@@ -424,6 +435,9 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness)
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID:
bsdf_ashikhmin_shirley_blur(sc, roughness);
break;
+ case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
+ bsdf_principled_hair_blur(sc, roughness);
+ break;
default:
break;
}
diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h
new file mode 100644
index 00000000000..4ee58089384
--- /dev/null
+++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h
@@ -0,0 +1,502 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifdef __KERNEL_CPU__
+#include <fenv.h>
+#endif
+
+#include "kernel/kernel_color.h"
+
+#ifndef __BSDF_HAIR_PRINCIPLED_H__
+#define __BSDF_HAIR_PRINCIPLED_H__
+
+CCL_NAMESPACE_BEGIN
+
+typedef ccl_addr_space struct PrincipledHairExtra {
+ /* Geometry data. */
+ float4 geom;
+} PrincipledHairExtra;
+
+typedef ccl_addr_space struct PrincipledHairBSDF {
+ SHADER_CLOSURE_BASE;
+
+ /* Absorption coefficient. */
+ float3 sigma;
+ /* Variance of the underlying logistic distribution. */
+ float v;
+ /* Scale factor of the underlying logistic distribution. */
+ float s;
+ /* Cuticle tilt angle. */
+ float alpha;
+ /* IOR. */
+ float eta;
+ /* Effective variance for the diffuse bounce only. */
+ float m0_roughness;
+
+ /* Extra closure. */
+ PrincipledHairExtra *extra;
+} PrincipledHairBSDF;
+
+static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairBSDF), "PrincipledHairBSDF is too large!");
+static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairExtra), "PrincipledHairExtra is too large!");
+
+ccl_device_inline float cos_from_sin(const float s)
+{
+ return safe_sqrtf(1.0f - s*s);
+}
+
+/* Gives the change in direction in the normal plane for the given angles and p-th-order scattering. */
+ccl_device_inline float delta_phi(int p, float gamma_o, float gamma_t)
+{
+ return 2.0f * p * gamma_t - 2.0f * gamma_o + p * M_PI_F;
+}
+
+/* Remaps the given angle to [-pi, pi]. */
+ccl_device_inline float wrap_angle(float a)
+{
+ while(a > M_PI_F) {
+ a -= M_2PI_F;
+ }
+ while(a < -M_PI_F) {
+ a += M_2PI_F;
+ }
+ return a;
+}
+
+/* Logistic distribution function. */
+ccl_device_inline float logistic(float x, float s)
+{
+ float v = expf(-fabsf(x)/s);
+ return v / (s * sqr(1.0f + v));
+}
+
+/* Logistic cumulative density function. */
+ccl_device_inline float logistic_cdf(float x, float s)
+{
+ float arg = -x/s;
+ /* expf() overflows if arg >= 89.0. */
+ if(arg > 88.0f) {
+ return 0.0f;
+ }
+ else {
+ return 1.0f / (1.0f + expf(arg));
+ }
+}
+
+/* Numerical approximation to the Bessel function of the first kind. */
+ccl_device_inline float bessel_I0(float x)
+{
+ x = sqr(x);
+ float val = 1.0f + 0.25f*x;
+ float pow_x_2i = sqr(x);
+ uint64_t i_fac_2 = 1;
+ int pow_4_i = 16;
+ for(int i = 2; i < 10; i++) {
+ i_fac_2 *= i*i;
+ float newval = val + pow_x_2i / (pow_4_i * i_fac_2);
+ if(val == newval) {
+ return val;
+ }
+ val = newval;
+ pow_x_2i *= x;
+ pow_4_i *= 4;
+ }
+ return val;
+}
+
+/* Logarithm of the Bessel function of the first kind. */
+ccl_device_inline float log_bessel_I0(float x)
+{
+ if (x > 12.0f) {
+ /* log(1/x) == -log(x) iff x > 0.
+ * This is only used with positive cosines */
+ return x + 0.5f * (1.f / (8.0f * x) - M_LN_2PI_F - logf(x));
+ }
+ else {
+ return logf(bessel_I0(x));
+ }
+}
+
+/* Logistic distribution limited to the interval [-pi, pi]. */
+ccl_device_inline float trimmed_logistic(float x, float s)
+{
+ /* The logistic distribution is symmetric and centered around zero,
+ * so logistic_cdf(x, s) = 1 - logistic_cdf(-x, s).
+ * Therefore, logistic_cdf(x, s)-logistic_cdf(-x, s) = 1 - 2*logistic_cdf(-x, s) */
+ float scaling_fac = 1.0f - 2.0f*logistic_cdf(-M_PI_F, s);
+ float val = logistic(x, s);
+ return safe_divide(val, scaling_fac);
+}
+
+/* Sampling function for the trimmed logistic function. */
+ccl_device_inline float sample_trimmed_logistic(float u, float s)
+{
+ float cdf_minuspi = logistic_cdf(-M_PI_F, s);
+ float x = -s*logf(1.0f / (u*(1.0f - 2.0f*cdf_minuspi) + cdf_minuspi) - 1.0f);
+ return clamp(x, -M_PI_F, M_PI_F);
+}
+
+/* Azimuthal scattering function Np. */
+ccl_device_inline float azimuthal_scattering(float phi,
+ int p,
+ float s,
+ float gamma_o,
+ float gamma_t)
+{
+ float phi_o = wrap_angle(phi - delta_phi(p, gamma_o, gamma_t));
+ float val = trimmed_logistic(phi_o, s);
+ return val;
+}
+
+/* Longitudinal scattering function Mp. */
+ccl_device_inline float longitudinal_scattering(float sin_theta_i,
+ float cos_theta_i,
+ float sin_theta_o,
+ float cos_theta_o,
+ float v)
+{
+ float inv_v = 1.0f/v;
+ float cos_arg = cos_theta_i * cos_theta_o * inv_v;
+ float sin_arg = sin_theta_i * sin_theta_o * inv_v;
+ if(v <= 0.1f) {
+ float i0 = log_bessel_I0(cos_arg);
+ float val = expf(i0 - sin_arg - inv_v + 0.6931f + logf(0.5f*inv_v));
+ return val;
+ }
+ else {
+ float i0 = bessel_I0(cos_arg);
+ float val = (expf(-sin_arg) * i0) / (sinhf(inv_v) * 2.0f * v);
+ return val;
+ }
+}
+
+/* Combine the three values using their luminances. */
+ccl_device_inline float4 combine_with_energy(KernelGlobals *kg, float3 c)
+{
+ return make_float4(c.x, c.y, c.z, linear_rgb_to_gray(kg, c));
+}
+
+#ifdef __HAIR__
+/* Set up the hair closure. */
+ccl_device int bsdf_principled_hair_setup(ShaderData *sd, PrincipledHairBSDF *bsdf)
+{
+ bsdf->type = CLOSURE_BSDF_HAIR_PRINCIPLED_ID;
+ bsdf->v = clamp(bsdf->v, 0.001f, 1.0f);
+ bsdf->s = clamp(bsdf->s, 0.001f, 1.0f);
+ /* Apply Primary Reflection Roughness modifier. */
+ bsdf->m0_roughness = clamp(bsdf->m0_roughness*bsdf->v, 0.001f, 1.0f);
+
+ /* Map from roughness_u and roughness_v to variance and scale factor. */
+ bsdf->v = sqr(0.726f*bsdf->v + 0.812f*sqr(bsdf->v) + 3.700f*pow20(bsdf->v));
+ bsdf->s = (0.265f*bsdf->s + 1.194f*sqr(bsdf->s) + 5.372f*pow22(bsdf->s))*M_SQRT_PI_8_F;
+ bsdf->m0_roughness = sqr(0.726f*bsdf->m0_roughness + 0.812f*sqr(bsdf->m0_roughness) + 3.700f*pow20(bsdf->m0_roughness));
+
+ /* Compute local frame, aligned to curve tangent and ray direction. */
+ float3 X = safe_normalize(sd->dPdu);
+ float3 Y = safe_normalize(cross(X, sd->I));
+ float3 Z = safe_normalize(cross(X, Y));
+ /* TODO: the solution below works where sd->Ng is the normal
+ * pointing from the center of the curve to the shading point.
+ * It doesn't work for triangles, see https://developer.blender.org/T43625 */
+
+ /* h -1..0..1 means the rays goes from grazing the hair, to hitting it at
+ * the center, to grazing the other edge. This is the sine of the angle
+ * between sd->Ng and Z, as seen from the tangent X. */
+
+ /* TODO: we convert this value to a cosine later and discard the sign, so
+ * we could probably save some operations. */
+ float h = dot(cross(sd->Ng, X), Z);
+
+ kernel_assert(fabsf(h) < 1.0f + 1e-4f);
+ kernel_assert(isfinite3_safe(Y));
+ kernel_assert(isfinite_safe(h));
+
+ bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h);
+
+ return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG;
+}
+
+#endif /* __HAIR__ */
+
+/* Given the Fresnel term and transmittance, generate the attenuation terms for each bounce. */
+ccl_device_inline void hair_attenuation(KernelGlobals *kg,
+ float f,
+ float3 T,
+ float4 *Ap)
+{
+ /* Primary specular (R). */
+ Ap[0] = make_float4(f, f, f, f);
+
+ /* Transmission (TT). */
+ float3 col = sqr(1.0f - f) * T;
+ Ap[1] = combine_with_energy(kg, col);
+
+ /* Secondary specular (TRT). */
+ col *= T*f;
+ Ap[2] = combine_with_energy(kg, col);
+
+ /* Residual component (TRRT+). */
+ col *= safe_divide_color(T*f, make_float3(1.0f, 1.0f, 1.0f) - T*f);
+ Ap[3] = combine_with_energy(kg, col);
+
+ /* Normalize sampling weights. */
+ float totweight = Ap[0].w + Ap[1].w + Ap[2].w + Ap[3].w;
+ float fac = safe_divide(1.0f, totweight);
+
+ Ap[0].w *= fac;
+ Ap[1].w *= fac;
+ Ap[2].w *= fac;
+ Ap[3].w *= fac;
+}
+
+/* Given the tilt angle, generate the rotated theta_i for the different bounces. */
+ccl_device_inline void hair_alpha_angles(float sin_theta_i,
+ float cos_theta_i,
+ float alpha,
+ float *angles)
+{
+ float sin_1alpha = sinf(alpha);
+ float cos_1alpha = cos_from_sin(sin_1alpha);
+ float sin_2alpha = 2.0f*sin_1alpha*cos_1alpha;
+ float cos_2alpha = sqr(cos_1alpha) - sqr(sin_1alpha);
+ float sin_4alpha = 2.0f*sin_2alpha*cos_2alpha;
+ float cos_4alpha = sqr(cos_2alpha) - sqr(sin_2alpha);
+
+ angles[0] = sin_theta_i*cos_2alpha + cos_theta_i*sin_2alpha;
+ angles[1] = fabsf(cos_theta_i*cos_2alpha - sin_theta_i*sin_2alpha);
+ angles[2] = sin_theta_i*cos_1alpha - cos_theta_i*sin_1alpha;
+ angles[3] = fabsf(cos_theta_i*cos_1alpha + sin_theta_i*sin_1alpha);
+ angles[4] = sin_theta_i*cos_4alpha - cos_theta_i*sin_4alpha;
+ angles[5] = fabsf(cos_theta_i*cos_4alpha + sin_theta_i*sin_4alpha);
+}
+
+/* Evaluation function for our shader. */
+ccl_device float3 bsdf_principled_hair_eval(KernelGlobals *kg,
+ const ShaderData *sd,
+ const ShaderClosure *sc,
+ const float3 omega_in,
+ float *pdf)
+{
+ kernel_assert(isfinite3_safe(sd->P) && isfinite_safe(sd->ray_length));
+
+ const PrincipledHairBSDF *bsdf = (const PrincipledHairBSDF*) sc;
+ float3 Y = float4_to_float3(bsdf->extra->geom);
+
+ float3 X = safe_normalize(sd->dPdu);
+ kernel_assert(fabsf(dot(X, Y)) < 1e-4f);
+ float3 Z = safe_normalize(cross(X, Y));
+
+ float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z));
+ float3 wi = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
+
+ float sin_theta_o = wo.x;
+ float cos_theta_o = cos_from_sin(sin_theta_o);
+ float phi_o = atan2f(wo.z, wo.y);
+
+ float sin_theta_t = sin_theta_o / bsdf->eta;
+ float cos_theta_t = cos_from_sin(sin_theta_t);
+
+ float sin_gamma_o = bsdf->extra->geom.w;
+ float cos_gamma_o = cos_from_sin(sin_gamma_o);
+ float gamma_o = safe_asinf(sin_gamma_o);
+
+ float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o));
+ float cos_gamma_t = cos_from_sin(sin_gamma_t);
+ float gamma_t = safe_asinf(sin_gamma_t);
+
+ float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
+ float4 Ap[4];
+ hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap);
+
+ float sin_theta_i = wi.x;
+ float cos_theta_i = cos_from_sin(sin_theta_i);
+ float phi_i = atan2f(wi.z, wi.y);
+
+ float phi = phi_i - phi_o;
+
+ float angles[6];
+ hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles);
+
+ float4 F;
+ float Mp, Np;
+
+ /* Primary specular (R). */
+ Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness);
+ Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t);
+ F = Ap[0] * Mp * Np;
+ kernel_assert(isfinite3_safe(float4_to_float3(F)));
+
+ /* Transmission (TT). */
+ Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f*bsdf->v);
+ Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t);
+ F += Ap[1] * Mp * Np;
+ kernel_assert(isfinite3_safe(float4_to_float3(F)));
+
+ /* Secondary specular (TRT). */
+ Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f*bsdf->v);
+ Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t);
+ F += Ap[2] * Mp * Np;
+ kernel_assert(isfinite3_safe(float4_to_float3(F)));
+
+ /* Residual component (TRRT+). */
+ Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f*bsdf->v);
+ Np = M_1_2PI_F;
+ F += Ap[3] * Mp * Np;
+ kernel_assert(isfinite3_safe(float4_to_float3(F)));
+
+ *pdf = F.w;
+ return float4_to_float3(F);
+}
+
+/* Sampling function for the hair shader. */
+ccl_device int bsdf_principled_hair_sample(KernelGlobals *kg,
+ const ShaderClosure *sc,
+ ShaderData *sd,
+ float randu,
+ float randv,
+ float3 *eval,
+ float3 *omega_in,
+ float3 *domega_in_dx,
+ float3 *domega_in_dy,
+ float *pdf)
+{
+ PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*) sc;
+
+ float3 Y = float4_to_float3(bsdf->extra->geom);
+
+ float3 X = safe_normalize(sd->dPdu);
+ kernel_assert(fabsf(dot(X, Y)) < 1e-4f);
+ float3 Z = safe_normalize(cross(X, Y));
+
+ float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z));
+
+ float2 u[2];
+ u[0] = make_float2(randu, randv);
+ u[1].x = lcg_step_float_addrspace(&sd->lcg_state);
+ u[1].y = lcg_step_float_addrspace(&sd->lcg_state);
+
+ float sin_theta_o = wo.x;
+ float cos_theta_o = cos_from_sin(sin_theta_o);
+ float phi_o = atan2f(wo.z, wo.y);
+
+ float sin_theta_t = sin_theta_o / bsdf->eta;
+ float cos_theta_t = cos_from_sin(sin_theta_t);
+
+ float sin_gamma_o = bsdf->extra->geom.w;
+ float cos_gamma_o = cos_from_sin(sin_gamma_o);
+ float gamma_o = safe_asinf(sin_gamma_o);
+
+ float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o));
+ float cos_gamma_t = cos_from_sin(sin_gamma_t);
+ float gamma_t = safe_asinf(sin_gamma_t);
+
+ float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
+ float4 Ap[4];
+ hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap);
+
+ int p = 0;
+ for(; p < 3; p++) {
+ if(u[0].x < Ap[p].w) {
+ break;
+ }
+ u[0].x -= Ap[p].w;
+ }
+
+ float v = bsdf->v;
+ if(p == 1) {
+ v *= 0.25f;
+ }
+ if(p >= 2) {
+ v *= 4.0f;
+ }
+
+ u[1].x = max(u[1].x, 1e-5f);
+ float fac = 1.0f + v*logf(u[1].x + (1.0f - u[1].x)*expf(-2.0f/v));
+ float sin_theta_i = -fac * sin_theta_o + cos_from_sin(fac) * cosf(M_2PI_F * u[1].y) * cos_theta_o;
+ float cos_theta_i = cos_from_sin(sin_theta_i);
+
+ float angles[6];
+ if(p < 3) {
+ hair_alpha_angles(sin_theta_i, cos_theta_i, -bsdf->alpha, angles);
+ sin_theta_i = angles[2*p];
+ cos_theta_i = angles[2*p+1];
+ }
+
+ float phi;
+ if(p < 3) {
+ phi = delta_phi(p, gamma_o, gamma_t) + sample_trimmed_logistic(u[0].y, bsdf->s);
+ }
+ else {
+ phi = M_2PI_F*u[0].y;
+ }
+ float phi_i = phi_o + phi;
+
+ hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles);
+
+ float4 F;
+ float Mp, Np;
+
+ /* Primary specular (R). */
+ Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness);
+ Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t);
+ F = Ap[0] * Mp * Np;
+ kernel_assert(isfinite3_safe(float4_to_float3(F)));
+
+ /* Transmission (TT). */
+ Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f*bsdf->v);
+ Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t);
+ F += Ap[1] * Mp * Np;
+ kernel_assert(isfinite3_safe(float4_to_float3(F)));
+
+ /* Secondary specular (TRT). */
+ Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f*bsdf->v);
+ Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t);
+ F += Ap[2] * Mp * Np;
+ kernel_assert(isfinite3_safe(float4_to_float3(F)));
+
+ /* Residual component (TRRT+). */
+ Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f*bsdf->v);
+ Np = M_1_2PI_F;
+ F += Ap[3] * Mp * Np;
+ kernel_assert(isfinite3_safe(float4_to_float3(F)));
+
+ *eval = float4_to_float3(F);
+ *pdf = F.w;
+
+ *omega_in = X*sin_theta_i + Y*cos_theta_i*cosf(phi_i) + Z*cos_theta_i*sinf(phi_i);
+
+#ifdef __RAY_DIFFERENTIALS__
+ float3 N = safe_normalize(sd->I + *omega_in);
+ *domega_in_dx = (2 * dot(N, sd->dI.dx)) * N - sd->dI.dx;
+ *domega_in_dy = (2 * dot(N, sd->dI.dy)) * N - sd->dI.dy;
+#endif
+
+ return LABEL_GLOSSY|((p == 0)? LABEL_REFLECT : LABEL_TRANSMIT);
+}
+
+/* Implements Filter Glossy by capping the effective roughness. */
+ccl_device void bsdf_principled_hair_blur(ShaderClosure *sc, float roughness)
+{
+ PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*)sc;
+
+ bsdf->v = fmaxf(roughness, bsdf->v);
+ bsdf->s = fmaxf(roughness, bsdf->s);
+ bsdf->m0_roughness = fmaxf(roughness, bsdf->m0_roughness);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_HAIR_PRINCIPLED_H__ */
diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h
index e35267f02bf..dea0c742ed7 100644
--- a/intern/cycles/kernel/geom/geom_curve.h
+++ b/intern/cycles/kernel/geom/geom_curve.h
@@ -23,6 +23,33 @@ CCL_NAMESPACE_BEGIN
#ifdef __HAIR__
+/* Interpolation of curve geometry */
+
+ccl_device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3)
+{
+ float fc = 0.71f;
+ float data[4];
+ float t2 = t * t;
+ data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc;
+ data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t;
+ data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc;
+ data[3] = 3.0f * fc * t2 - 2.0f * fc * t;
+ return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3;
+}
+
+ccl_device_inline float3 curvepoint(float t, float3 p0, float3 p1, float3 p2, float3 p3)
+{
+ float data[4];
+ float fc = 0.71f;
+ float t2 = t * t;
+ float t3 = t2 * t;
+ data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t;
+ data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f;
+ data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t;
+ data[3] = fc * t3 - fc * t2;
+ return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3;
+}
+
/* Reading attributes on various curve elements */
ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
diff --git a/intern/cycles/kernel/geom/geom_curve_intersect.h b/intern/cycles/kernel/geom/geom_curve_intersect.h
index 46c3f408f0b..4cfbe21685c 100644
--- a/intern/cycles/kernel/geom/geom_curve_intersect.h
+++ b/intern/cycles/kernel/geom/geom_curve_intersect.h
@@ -752,31 +752,6 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals *kg,
#endif
}
-ccl_device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3)
-{
- float fc = 0.71f;
- float data[4];
- float t2 = t * t;
- data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc;
- data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t;
- data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc;
- data[3] = 3.0f * fc * t2 - 2.0f * fc * t;
- return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3;
-}
-
-ccl_device_inline float3 curvepoint(float t, float3 p0, float3 p1, float3 p2, float3 p3)
-{
- float data[4];
- float fc = 0.71f;
- float t2 = t * t;
- float t3 = t2 * t;
- data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t;
- data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f;
- data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t;
- data[3] = fc * t3 - fc * t2;
- return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3;
-}
-
ccl_device_inline float3 curve_refine(KernelGlobals *kg,
ShaderData *sd,
const Intersection *isect,
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index d1ae10a0384..3f7e264fbee 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -123,6 +123,7 @@
#define fmaxf(x, y) fmax(((float)(x)), ((float)(y)))
#define fminf(x, y) fmin(((float)(x)), ((float)(y)))
#define fmodf(x, y) fmod((float)(x), (float)(y))
+#define sinhf(x) sinh(((float)(x)))
#ifndef __CL_USE_NATIVE__
# define sinf(x) native_sin(((float)(x)))
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 32cb924d25f..262d7df1364 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -72,24 +72,17 @@ ccl_device_inline float rect_light_sample(float3 P,
float y0 = dot(dir, y);
float x1 = x0 + axisu_len;
float y1 = y0 + axisv_len;
- /* Create vectors to four vertices. */
- float3 v00 = make_float3(x0, y0, z0);
- float3 v01 = make_float3(x0, y1, z0);
- float3 v10 = make_float3(x1, y0, z0);
- float3 v11 = make_float3(x1, y1, z0);
- /* Compute normals to edges. */
- float3 n0 = normalize(cross(v00, v10));
- float3 n1 = normalize(cross(v10, v11));
- float3 n2 = normalize(cross(v11, v01));
- float3 n3 = normalize(cross(v01, v00));
/* Compute internal angles (gamma_i). */
- float g0 = safe_acosf(-dot(n0, n1));
- float g1 = safe_acosf(-dot(n1, n2));
- float g2 = safe_acosf(-dot(n2, n3));
- float g3 = safe_acosf(-dot(n3, n0));
+ float4 diff = make_float4(x0, y1, x1, y0) - make_float4(x1, y0, x0, y1);
+ float4 nz = make_float4(y0, x1, y1, x0) * diff;
+ nz = nz / sqrt(z0 * z0 * diff * diff + nz * nz);
+ float g0 = safe_acosf(-nz.x * nz.y);
+ float g1 = safe_acosf(-nz.y * nz.z);
+ float g2 = safe_acosf(-nz.z * nz.w);
+ float g3 = safe_acosf(-nz.w * nz.x);
/* Compute predefined constants. */
- float b0 = n0.z;
- float b1 = n2.z;
+ float b0 = nz.x;
+ float b1 = nz.z;
float b0sq = b0 * b0;
float k = M_2PI_F - g2 - g3;
/* Compute solid angle from internal angles. */
diff --git a/intern/cycles/kernel/kernel_montecarlo.h b/intern/cycles/kernel/kernel_montecarlo.h
index 49dc1f08cc1..09a3fe8f23d 100644
--- a/intern/cycles/kernel/kernel_montecarlo.h
+++ b/intern/cycles/kernel/kernel_montecarlo.h
@@ -184,6 +184,35 @@ ccl_device float2 regular_polygon_sample(float corners, float rotation, float u,
return make_float2(cr*p.x - sr*p.y, sr*p.x + cr*p.y);
}
+ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N)
+{
+ float3 R = 2*dot(N, I)*N - I;
+ if(dot(Ng, R) >= 0.05f) {
+ return N;
+ }
+
+ /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane.
+ * The X axis is found by normalizing the component of N that's orthogonal to Ng.
+ * The Y axis isn't actually needed.
+ */
+ float3 X = normalize(N - dot(N, Ng)*Ng);
+
+ /* Calculate N.z and N.x in the local coordinate system. */
+ float Iz = dot(I, Ng);
+ float Ix2 = sqr(dot(I, X)), Iz2 = sqr(Iz);
+ float Ix2Iz2 = Ix2 + Iz2;
+
+ float a = sqrtf(Ix2*(Ix2Iz2 - sqr(0.05f)));
+ float b = Iz*0.05f + Ix2Iz2;
+ float c = (a + b > 0.0f)? (a + b) : (-a + b);
+
+ float Nz = sqrtf(0.5f * c * (1.0f / Ix2Iz2));
+ float Nx = sqrtf(1.0f - sqr(Nz));
+
+ /* Transform back into global coordinates. */
+ return Nx*X + Nz*Ng;
+}
+
CCL_NAMESPACE_END
#endif /* __KERNEL_MONTECARLO_CL__ */
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 69ee66b3dd5..85548484873 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -54,7 +54,7 @@ CCL_NAMESPACE_BEGIN
#define PRIM_NONE (~0)
#define LAMP_NONE (~0)
-#define VOLUME_STACK_SIZE 16
+#define VOLUME_STACK_SIZE 32
/* Split kernel constants */
#define WORK_POOL_SIZE_GPU 64
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index a7072c3ad03..d71761a97bc 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -91,7 +91,7 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals *kg,
ccl_device float3 volume_color_transmittance(float3 sigma, float t)
{
- return make_float3(expf(-sigma.x * t), expf(-sigma.y * t), expf(-sigma.z * t));
+ return exp3(-sigma * t);
}
ccl_device float kernel_volume_channel_get(float3 value, int channel)
@@ -234,7 +234,7 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
sum += (-sigma_t * (new_t - t));
if((i & 0x07) == 0) { /* ToDo: Other interval? */
- tp = *throughput * make_float3(expf(sum.x), expf(sum.y), expf(sum.z));
+ tp = *throughput * exp3(sum);
/* stop if nearly all light is blocked */
if(tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps)
@@ -246,7 +246,7 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg,
t = new_t;
if(t == ray->t) {
/* Update throughput in case we haven't done it above */
- tp = *throughput * make_float3(expf(sum.x), expf(sum.y), expf(sum.z));
+ tp = *throughput * exp3(sum);
break;
}
}
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
index 581b38e65c0..8c7ae30725c 100644
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -4,7 +4,7 @@
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
* All Rights Reserved.
*
- * Modifications Copyright 2011, Blender Foundation.
+ * Modifications Copyright 2011-2018, Blender Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -59,6 +59,7 @@
#include "kernel/closure/bsdf_ashikhmin_shirley.h"
#include "kernel/closure/bsdf_toon.h"
#include "kernel/closure/bsdf_hair.h"
+#include "kernel/closure/bsdf_hair_principled.h"
#include "kernel/closure/bsdf_principled_diffuse.h"
#include "kernel/closure/bsdf_principled_sheen.h"
#include "kernel/closure/volume.h"
@@ -176,6 +177,61 @@ BSDF_CLOSURE_CLASS_BEGIN(PrincipledSheen, principled_sheen, PrincipledSheenBsdf,
CLOSURE_FLOAT3_PARAM(PrincipledSheenClosure, params.N),
BSDF_CLOSURE_CLASS_END(PrincipledSheen, principled_sheen)
+/* PRINCIPLED HAIR BSDF */
+class PrincipledHairClosure : public CBSDFClosure {
+public:
+ PrincipledHairBSDF params;
+
+ PrincipledHairBSDF *alloc(ShaderData *sd, int path_flag, float3 weight)
+ {
+ PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*)bsdf_alloc_osl(sd, sizeof(PrincipledHairBSDF), weight, &params);
+ if(!bsdf) {
+ return NULL;
+ }
+
+ PrincipledHairExtra *extra = (PrincipledHairExtra*)closure_alloc_extra(sd, sizeof(PrincipledHairExtra));
+ if(!extra) {
+ return NULL;
+ }
+
+ bsdf->extra = extra;
+ return bsdf;
+ }
+
+ void setup(ShaderData *sd, int path_flag, float3 weight)
+ {
+ if(!skip(sd, path_flag, LABEL_GLOSSY))
+ {
+ PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*)alloc(sd, path_flag, weight);
+ if (!bsdf)
+ {
+ return;
+ }
+
+ sd->flag |= (bsdf) ? bsdf_principled_hair_setup(sd, bsdf) : 0;
+ }
+ }
+};
+
+static ClosureParam *closure_bsdf_principled_hair_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(PrincipledHairClosure, params.N),
+ CLOSURE_FLOAT3_PARAM(PrincipledHairClosure, params.sigma),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.v),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.s),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.m0_roughness),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.alpha),
+ CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.eta),
+ CLOSURE_STRING_KEYPARAM(PrincipledHairClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(PrincipledHairClosure)
+ };
+
+ return params;
+}
+
+CCLOSURE_PREPARE(closure_bsdf_principled_hair_prepare, PrincipledHairClosure)
+
/* DISNEY PRINCIPLED CLEARCOAT */
class PrincipledClearcoatClosure : public CBSDFClosure {
public:
@@ -322,6 +378,9 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
register_closure(ss, "hair_transmission", id++,
bsdf_hair_transmission_params(), bsdf_hair_transmission_prepare);
+ register_closure(ss, "principled_hair", id++,
+ closure_bsdf_principled_hair_params(), closure_bsdf_principled_hair_prepare);
+
register_closure(ss, "henyey_greenstein", id++,
closure_henyey_greenstein_params(), closure_henyey_greenstein_prepare);
register_closure(ss, "absorption", id++,
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
index 857cc84afd2..d9aeb9ab9fb 100644
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ b/intern/cycles/kernel/osl/osl_closures.h
@@ -79,6 +79,7 @@ void closure_bsdf_microfacet_multi_ggx_fresnel_prepare(OSL::RendererServices *,
void closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare(OSL::RendererServices *, int id, void *data);
void closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare(OSL::RendererServices *, int id, void *data);
void closure_bsdf_principled_clearcoat_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bsdf_principled_hair_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/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 9ee78d160a4..4740db27d4e 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -85,6 +85,7 @@ set(SRC_OSL
node_wave_texture.osl
node_wireframe.osl
node_hair_bsdf.osl
+ node_principled_hair_bsdf.osl
node_uv_map.osl
node_principled_bsdf.osl
node_rgb_to_bw.osl
diff --git a/intern/cycles/kernel/shaders/node_bump.osl b/intern/cycles/kernel/shaders/node_bump.osl
index 7f01cf2ca91..a2a4468d5f3 100644
--- a/intern/cycles/kernel/shaders/node_bump.osl
+++ b/intern/cycles/kernel/shaders/node_bump.osl
@@ -64,5 +64,7 @@ surface node_bump(
if (use_object_space) {
NormalOut = normalize(transform("object", "world", NormalOut));
}
+
+ NormalOut = ensure_valid_reflection(Ng, I, NormalOut);
}
diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl
index 41bcac4fb10..fda6f12a5da 100644
--- a/intern/cycles/kernel/shaders/node_normal_map.osl
+++ b/intern/cycles/kernel/shaders/node_normal_map.osl
@@ -88,5 +88,7 @@ shader node_normal_map(
if (Strength != 1.0)
Normal = normalize(NormalIn + (Normal - NormalIn) * max(Strength, 0.0));
+
+ Normal = ensure_valid_reflection(Ng, I, Normal);
}
diff --git a/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl b/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl
new file mode 100644
index 00000000000..757a88f8ece
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "stdosl.h"
+
+color log3(color a)
+{
+ return color(log(a[0]), log(a[1]), log(a[2]));
+}
+
+color sigma_from_concentration(float eumelanin, float pheomelanin)
+{
+ return eumelanin*color(0.506, 0.841, 1.653) + pheomelanin*color(0.343, 0.733, 1.924);
+}
+
+color sigma_from_reflectance(color c, float azimuthal_roughness)
+{
+ float x = azimuthal_roughness;
+ float roughness_fac = (((((0.245*x) + 5.574)*x - 10.73)*x + 2.532)*x - 0.215)*x + 5.969;
+ color sigma = log3(c) / roughness_fac;
+ return sigma * sigma;
+}
+
+shader node_principled_hair_bsdf(
+ color Color = color(0.017513, 0.005763, 0.002059),
+ float Melanin = 0.8,
+ float MelaninRedness = 1.0,
+ float RandomColor = 0.0,
+ color Tint = 1.0,
+ color AbsorptionCoefficient = color(0.245531, 0.52, 1.365),
+ normal Normal = Ng,
+ string parametrization = "Absorption coefficient",
+ float Offset = radians(2),
+ float Roughness = 0.3,
+ float RadialRoughness = 0.3,
+ float RandomRoughness = 0.0,
+ float Coat = 0.0,
+ float IOR = 1.55,
+ string AttrRandom = "geom:curve_random",
+ float Random = 0.0,
+
+ output closure color BSDF = 0)
+{
+ /* Get random value from curve in none is specified. */
+ float random_value = 0.0;
+
+ if (isconnected(Random)) {
+ random_value = Random;
+ }
+ else {
+ getattribute(AttrRandom, random_value);
+ }
+
+ /* Compute roughness. */
+ float factor_random_roughness = 1.0 + 2.0*(random_value - 0.5)*RandomRoughness;
+ float m0_roughness = 1.0 - clamp(Coat, 0.0, 1.0);
+ float roughness = Roughness*factor_random_roughness;
+ float radial_roughness = RadialRoughness*factor_random_roughness;
+
+ /* Compute absorption. */
+ color sigma;
+
+ if (parametrization == "Absorption coefficient") {
+ sigma = AbsorptionCoefficient;
+ }
+ else if (parametrization == "Melanin concentration") {
+ /* Randomize melanin. */
+ float factor_random_color = 1.0 + 2.0*(random_value - 0.5) * RandomColor;
+ float melanin = Melanin * factor_random_color;
+
+ /* Map melanin 0..inf from more perceptually linear 0..1. */
+ melanin = -log(max(1.0 - melanin, 0.0001));
+
+ /* Benedikt Bitterli's melanin ratio remapping. */
+ float eumelanin = melanin * (1.0 - MelaninRedness);
+ float pheomelanin = melanin * MelaninRedness;
+ color melanin_sigma = sigma_from_concentration(eumelanin, pheomelanin);
+
+ /* Optional tint. */
+ color tint_sigma = sigma_from_reflectance(Tint, radial_roughness);
+ sigma = melanin_sigma + tint_sigma;
+ }
+ else if (parametrization == "Direct coloring"){
+ sigma = sigma_from_reflectance(Color, radial_roughness);
+ }
+ else {
+ /* Fallback to brownish hair, same as defaults for melanin. */
+ sigma = sigma_from_concentration(0.0, 0.8054375);
+ }
+
+ BSDF = principled_hair(Normal, sigma, roughness, radial_roughness, m0_roughness, Offset, IOR);
+}
diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h
index 82223ca0219..4a8378796ba 100644
--- a/intern/cycles/kernel/shaders/stdosl.h
+++ b/intern/cycles/kernel/shaders/stdosl.h
@@ -282,6 +282,36 @@ point rotate (point p, float angle, point a, point b)
return transform (M, p-a) + a;
}
+normal ensure_valid_reflection(normal Ng, vector I, normal N)
+{
+ float sqr(float x) { return x*x; }
+
+ vector R = 2*dot(N, I)*N - I;
+ if (dot(Ng, R) >= 0.05) {
+ return N;
+ }
+
+ /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane.
+ * The X axis is found by normalizing the component of N that's orthogonal to Ng.
+ * The Y axis isn't actually needed.
+ */
+ vector X = normalize(N - dot(N, Ng)*Ng);
+
+ /* Calculate N.z and N.x in the local coordinate system. */
+ float Ix = dot(I, X), Iz = dot(I, Ng);
+ float Ix2 = sqr(dot(I, X)), Iz2 = sqr(dot(I, Ng));
+ float Ix2Iz2 = Ix2 + Iz2;
+
+ float a = sqrt(Ix2*(Ix2Iz2 - sqr(0.05)));
+ float b = Iz*0.05 + Ix2Iz2;
+ float c = (a + b > 0.0)? (a + b) : (-a + b);
+
+ float Nz = sqrt(0.5 * c * (1.0 / Ix2Iz2));
+ float Nx = sqrt(1.0 - sqr(Nz));
+
+ /* Transform back into global coordinates. */
+ return Nx*X + Nz*Ng;
+}
// Color functions
@@ -554,6 +584,7 @@ closure color bssrdf(string method, normal N, vector radius, color albedo) BUILT
// Hair
closure color hair_reflection(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;
closure color hair_transmission(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;
+closure color principled_hair(normal N, color sigma, float roughnessu, float roughnessv, float coat, float alpha, float eta) BUILTIN;
// Volume
closure color henyey_greenstein(float g) BUILTIN;
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index 4de9cfb88db..aa253223c93 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -16,6 +16,21 @@
CCL_NAMESPACE_BEGIN
+/* Hair Melanin */
+
+ccl_device_inline float3 sigma_from_concentration(float eumelanin, float pheomelanin)
+{
+ return eumelanin*make_float3(0.506f, 0.841f, 1.653f) + pheomelanin*make_float3(0.343f, 0.733f, 1.924f);
+}
+
+ccl_device_inline float3 sigma_from_reflectance(float3 color, float azimuthal_roughness)
+{
+ float x = azimuthal_roughness;
+ float roughness_fac = (((((0.245f*x) + 5.574f)*x - 10.73f)*x + 2.532f)*x - 0.215f)*x + 5.969f;
+ float3 sigma = log3(color) / roughness_fac;
+ return sigma * sigma;
+}
+
/* Closure Nodes */
ccl_device void svm_node_glass_setup(ShaderData *sd, MicrofacetBsdf *bsdf, int type, float eta, float roughness, bool refract)
@@ -243,7 +258,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
float3 spec_weight = weight * specular_weight;
MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), spec_weight);
- if(!bsdf){
+ if(!bsdf) {
break;
}
@@ -722,6 +737,107 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
break;
}
#ifdef __HAIR__
+ case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: {
+ uint4 data_node2 = read_node(kg, offset);
+ uint4 data_node3 = read_node(kg, offset);
+ uint4 data_node4 = read_node(kg, offset);
+
+ float3 weight = sd->svm_closure_weight * mix_weight;
+
+ uint offset_ofs, ior_ofs, color_ofs, parametrization;
+ decode_node_uchar4(data_node.y, &offset_ofs, &ior_ofs, &color_ofs, &parametrization);
+ float alpha = stack_load_float_default(stack, offset_ofs, data_node.z);
+ float ior = stack_load_float_default(stack, ior_ofs, data_node.w);
+
+ uint coat_ofs, melanin_ofs, melanin_redness_ofs, absorption_coefficient_ofs;
+ decode_node_uchar4(data_node2.x, &coat_ofs, &melanin_ofs, &melanin_redness_ofs, &absorption_coefficient_ofs);
+
+ uint tint_ofs, random_ofs, random_color_ofs, random_roughness_ofs;
+ decode_node_uchar4(data_node3.x, &tint_ofs, &random_ofs, &random_color_ofs, &random_roughness_ofs);
+
+ const AttributeDescriptor attr_descr_random = find_attribute(kg, sd, data_node4.y);
+ float random = 0.0f;
+ if (attr_descr_random.offset != ATTR_STD_NOT_FOUND) {
+ random = primitive_attribute_float(kg, sd, attr_descr_random, NULL, NULL);
+ }
+ else {
+ random = stack_load_float_default(stack, random_ofs, data_node3.y);
+ }
+
+
+ PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*)bsdf_alloc(sd, sizeof(PrincipledHairBSDF), weight);
+ if(bsdf) {
+ PrincipledHairExtra *extra = (PrincipledHairExtra*)closure_alloc_extra(sd, sizeof(PrincipledHairExtra));
+
+ if (!extra)
+ break;
+
+ /* Random factors range: [-randomization/2, +randomization/2]. */
+ float random_roughness = stack_load_float_default(stack, random_roughness_ofs, data_node3.w);
+ float factor_random_roughness = 1.0f + 2.0f*(random - 0.5f)*random_roughness;
+ float roughness = param1 * factor_random_roughness;
+ float radial_roughness = param2 * factor_random_roughness;
+
+ /* Remap Coat value to [0, 100]% of Roughness. */
+ float coat = stack_load_float_default(stack, coat_ofs, data_node2.y);
+ float m0_roughness = 1.0f - clamp(coat, 0.0f, 1.0f);
+
+ bsdf->N = N;
+ bsdf->v = roughness;
+ bsdf->s = radial_roughness;
+ bsdf->m0_roughness = m0_roughness;
+ bsdf->alpha = alpha;
+ bsdf->eta = ior;
+ bsdf->extra = extra;
+
+ switch(parametrization) {
+ case NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION: {
+ float3 absorption_coefficient = stack_load_float3(stack, absorption_coefficient_ofs);
+ bsdf->sigma = absorption_coefficient;
+ break;
+ }
+ case NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION: {
+ float melanin = stack_load_float_default(stack, melanin_ofs, data_node2.z);
+ float melanin_redness = stack_load_float_default(stack, melanin_redness_ofs, data_node2.w);
+
+ /* Randomize melanin. */
+ float random_color = stack_load_float_default(stack, random_color_ofs, data_node3.z);
+ random_color = clamp(random_color, 0.0f, 1.0f);
+ float factor_random_color = 1.0f + 2.0f * (random - 0.5f) * random_color;
+ melanin *= factor_random_color;
+
+ /* Map melanin 0..inf from more perceptually linear 0..1. */
+ melanin = -logf(fmaxf(1.0f - melanin, 0.0001f));
+
+ /* Benedikt Bitterli's melanin ratio remapping. */
+ float eumelanin = melanin * (1.0f - melanin_redness);
+ float pheomelanin = melanin * melanin_redness;
+ float3 melanin_sigma = sigma_from_concentration(eumelanin, pheomelanin);
+
+ /* Optional tint. */
+ float3 tint = stack_load_float3(stack, tint_ofs);
+ float3 tint_sigma = sigma_from_reflectance(tint, radial_roughness);
+
+ bsdf->sigma = melanin_sigma + tint_sigma;
+ break;
+ }
+ case NODE_PRINCIPLED_HAIR_REFLECTANCE: {
+ float3 color = stack_load_float3(stack, color_ofs);
+ bsdf->sigma = sigma_from_reflectance(color, radial_roughness);
+ break;
+ }
+ default: {
+ /* Fallback to brownish hair, same as defaults for melanin. */
+ kernel_assert(!"Invalid Principled Hair parametrization!");
+ bsdf->sigma = sigma_from_concentration(0.0f, 0.8054375f);
+ break;
+ }
+ }
+
+ sd->flag |= bsdf_principled_hair_setup(sd, bsdf);
+ }
+ break;
+ }
case CLOSURE_BSDF_HAIR_REFLECTION_ID:
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: {
float3 weight = sd->svm_closure_weight * mix_weight;
@@ -764,7 +880,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
break;
}
-#endif
+#endif /* __HAIR__ */
#ifdef __SUBSURFACE__
case CLOSURE_BSSRDF_CUBIC_ID:
diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h
index b85eb9c0458..0f5b3abef87 100644
--- a/intern/cycles/kernel/svm/svm_displace.h
+++ b/intern/cycles/kernel/svm/svm_displace.h
@@ -75,6 +75,8 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
object_normal_transform(kg, sd, &normal_out);
}
+ normal_out = ensure_valid_reflection(sd->Ng, sd->I, normal_out);
+
stack_store_float3(stack, node.w, normal_out);
#endif
}
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index 7c207083929..45c38d64763 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -345,6 +345,8 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
N = safe_normalize(sd->N + (N - sd->N)*strength);
}
+ N = ensure_valid_reflection(sd->Ng, sd->I, N);
+
if(is_zero(N)) {
N = sd->N;
}
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index e03ad3a0cfe..910537a2539 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -418,6 +418,13 @@ typedef enum ShaderType {
SHADER_TYPE_BUMP,
} ShaderType;
+typedef enum NodePrincipledHairParametrization {
+ NODE_PRINCIPLED_HAIR_REFLECTANCE = 0,
+ NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION = 1,
+ NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION = 2,
+ NODE_PRINCIPLED_HAIR_NUM,
+} NodePrincipledHairParametrization;
+
/* Closure */
typedef enum ClosureType {
@@ -464,6 +471,7 @@ typedef enum ClosureType {
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID,
CLOSURE_BSDF_SHARP_GLASS_ID,
+ CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
/* Special cases */
@@ -495,7 +503,7 @@ typedef enum ClosureType {
/* watch this, being lazy with memory usage */
#define CLOSURE_IS_BSDF(type) (type <= CLOSURE_BSDF_TRANSPARENT_ID)
#define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_DIFFUSE_TOON_ID)
-#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID)
+#define CLOSURE_IS_BSDF_GLOSSY(type) ((type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID )|| (type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID))
#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSLUCENT_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
#define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID || type == CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID)
#define CLOSURE_IS_BSDF_SINGULAR(type) (type == CLOSURE_BSDF_REFLECTION_ID || \
diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h
index e5e350bf76a..75af910d940 100644
--- a/intern/cycles/kernel/svm/svm_voronoi.h
+++ b/intern/cycles/kernel/svm/svm_voronoi.h
@@ -52,7 +52,7 @@ ccl_device void voronoi_neighbors(float3 p, NodeVoronoiDistanceMetric distance,
case NODE_VORONOI_CHEBYCHEV:
d = max3(fabs(vp - p));
break;
- case NODE_VORONOI_MINKOWSKI:
+ case NODE_VORONOI_MINKOWSKI: {
float3 n = fabs(vp - p);
if(e == 0.5f) {
d = sqr(reduce_add(sqrt(n)));
@@ -61,6 +61,7 @@ ccl_device void voronoi_neighbors(float3 p, NodeVoronoiDistanceMetric distance,
d = powf(reduce_add(pow3(n, e)), 1.0f/e);
}
break;
+ }
}
/* To keep the shortest four distances and associated points we have to keep them in sorted order. */