Merge remote-tracking branch 'origin/master' into blender2.8

This commit is contained in:
Dalai Felinto 2017-04-18 16:30:13 +02:00
commit c9d78b6c43
82 changed files with 2496 additions and 271 deletions

View File

@ -2593,7 +2593,6 @@ install_DEB() {
fi
# These libs should always be available in debian/ubuntu official repository...
OPENJPEG_DEV="libopenjpeg-dev"
VORBIS_DEV="libvorbis-dev"
OGG_DEV="libogg-dev"
THEORA_DEV="libtheora-dev"
@ -2601,16 +2600,24 @@ install_DEB() {
_packages="gawk cmake cmake-curses-gui build-essential libjpeg-dev libpng-dev libtiff-dev \
git libfreetype6-dev libx11-dev flex bison libtbb-dev libxxf86vm-dev \
libxcursor-dev libxi-dev wget libsqlite3-dev libxrandr-dev libxinerama-dev \
libbz2-dev libncurses5-dev libssl-dev liblzma-dev libreadline-dev $OPENJPEG_DEV \
libbz2-dev libncurses5-dev libssl-dev liblzma-dev libreadline-dev \
libopenal-dev libglew-dev yasm $THEORA_DEV $VORBIS_DEV $OGG_DEV \
libsdl1.2-dev libfftw3-dev patch bzip2 libxml2-dev libtinyxml-dev libjemalloc-dev"
# libglewmx-dev (broken in deb testing currently...)
OPENJPEG_USE=true
VORBIS_USE=true
OGG_USE=true
THEORA_USE=true
PRINT ""
# New Ubuntu crap (17.04 and more) have no openjpeg lib!
OPENJPEG_DEV="libopenjpeg-dev"
check_package_DEB $OPENJPEG_DEV
if [ $? -eq 0 ]; then
_packages="$_packages $OPENJPEG_DEV"
OPENJPEG_USE=true
fi
PRINT ""
# Some not-so-old distro (ubuntu 12.4) do not have it, do not fail in this case, just warn.
YAMLCPP_DEV="libyaml-cpp-dev"

View File

@ -379,27 +379,16 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
}
}
/* random number */
object->random_id = hash_string(object->name.c_str());
if(persistent_id) {
for(int i = 0; i < OBJECT_PERSISTENT_ID_SIZE; i++)
object->random_id = hash_int_2d(object->random_id, persistent_id[i]);
}
else
object->random_id = hash_int_2d(object->random_id, 0);
if(b_parent.ptr.data != b_ob.ptr.data)
object->random_id ^= hash_int(hash_string(b_parent.name().c_str()));
/* dupli texture coordinates */
/* dupli texture coordinates and random_id */
if(b_dupli_ob) {
object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f);
object->dupli_uv = get_float2(b_dupli_ob.uv());
object->random_id = b_dupli_ob.random_id();
}
else {
object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
object->dupli_uv = make_float2(0.0f, 0.0f);
object->random_id = hash_int_2d(hash_string(object->name.c_str()), 0);
}
object->tag_update(scene);

View File

@ -521,6 +521,19 @@ static ShaderNode *add_node(Scene *scene,
}
node = hair;
}
else if(b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) {
BL::ShaderNodeBsdfPrincipled b_principled_node(b_node);
PrincipledBsdfNode *principled = new PrincipledBsdfNode();
switch (b_principled_node.distribution()) {
case BL::ShaderNodeBsdfPrincipled::distribution_GGX:
principled->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
break;
case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX:
principled->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
break;
}
node = principled;
}
else if(b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
node = new TranslucentBsdfNode();
}

View File

@ -902,7 +902,7 @@ bool OpenCLInfo::get_platform_name(cl_platform_id platform_id,
string OpenCLInfo::get_platform_name(cl_platform_id platform_id)
{
string platform_name;
if (!get_platform_name(platform_id, &platform_name)) {
if(!get_platform_name(platform_id, &platform_name)) {
return "";
}
return platform_name;

View File

@ -120,6 +120,8 @@ set(SRC_CLOSURE_HEADERS
closure/bssrdf.h
closure/emissive.h
closure/volume.h
closure/bsdf_principled_diffuse.h
closure/bsdf_principled_sheen.h
)
set(SRC_SVM_HEADERS

View File

@ -27,6 +27,8 @@
#include "kernel/closure/bsdf_ashikhmin_shirley.h"
#include "kernel/closure/bsdf_toon.h"
#include "kernel/closure/bsdf_hair.h"
#include "kernel/closure/bsdf_principled_diffuse.h"
#include "kernel/closure/bsdf_principled_sheen.h"
#ifdef __SUBSURFACE__
# include "kernel/closure/bssrdf.h"
#endif
@ -86,16 +88,21 @@ ccl_device_forceinline int bsdf_sample(KernelGlobals *kg,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
label = bsdf_microfacet_ggx_sample(kg, 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_MICROFACET_MULTI_GGX_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
label = bsdf_microfacet_multi_ggx_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &sd->lcg_state);
break;
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv,
eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &sd->lcg_state);
break;
@ -130,6 +137,15 @@ ccl_device_forceinline 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_PRINCIPLED_DIFFUSE_ID:
case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
label = bsdf_principled_diffuse_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_PRINCIPLED_SHEEN_ID:
label = bsdf_principled_sheen_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;
#endif
#ifdef __VOLUME__
case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
@ -188,14 +204,19 @@ float3 bsdf_eval(KernelGlobals *kg,
eval = bsdf_transparent_eval_reflect(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_reflect(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, sd->I, omega_in, pdf, &sd->lcg_state);
break;
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, sd->I, omega_in, pdf, &sd->lcg_state);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
@ -222,6 +243,13 @@ float3 bsdf_eval(KernelGlobals *kg,
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
eval = bsdf_hair_transmission_eval_reflect(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
eval = bsdf_principled_diffuse_eval_reflect(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
eval = bsdf_principled_sheen_eval_reflect(sc, sd->I, omega_in, pdf);
break;
#endif
#ifdef __VOLUME__
case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
@ -256,14 +284,19 @@ float3 bsdf_eval(KernelGlobals *kg,
eval = bsdf_transparent_eval_transmit(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_transmit(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, sd->I, omega_in, pdf, &sd->lcg_state);
break;
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, sd->I, omega_in, pdf, &sd->lcg_state);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
@ -290,6 +323,13 @@ float3 bsdf_eval(KernelGlobals *kg,
case CLOSURE_BSDF_HAIR_TRANSMISSION_ID:
eval = bsdf_hair_transmission_eval_transmit(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID:
case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID:
eval = bsdf_principled_diffuse_eval_transmit(sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID:
eval = bsdf_principled_sheen_eval_transmit(sc, sd->I, omega_in, pdf);
break;
#endif
#ifdef __VOLUME__
case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
@ -311,11 +351,16 @@ 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_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
bsdf_microfacet_multi_ggx_blur(sc, roughness);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
bsdf_microfacet_ggx_blur(sc, roughness);
break;
@ -349,10 +394,15 @@ ccl_device bool bsdf_merge(ShaderClosure *a, ShaderClosure *b)
case CLOSURE_BSDF_REFLECTION_ID:
case CLOSURE_BSDF_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID:
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:

View File

@ -36,7 +36,8 @@
CCL_NAMESPACE_BEGIN
typedef ccl_addr_space struct MicrofacetExtra {
float3 color;
float3 color, cspec0;
float clearcoat;
} MicrofacetExtra;
typedef ccl_addr_space struct MicrofacetBsdf {
@ -233,6 +234,36 @@ ccl_device_forceinline float3 microfacet_sample_stretched(
return normalize(make_float3(-slope_x, -slope_y, 1.0f));
}
/* Calculate the reflection color
*
* If fresnel is used, the color is an interpolation of the F0 color and white
* with respect to the fresnel
*
* Else it is simply white
*/
ccl_device_forceinline float3 reflection_color(const MicrofacetBsdf *bsdf, float3 L, float3 H) {
float3 F = make_float3(1.0f, 1.0f, 1.0f);
bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID
|| bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID
|| bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID);
if(use_fresnel) {
float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior);
F = interpolate_fresnel_color(L, H, bsdf->ior, F0, bsdf->extra->cspec0);
}
return F;
}
ccl_device_forceinline float D_GTR1(float NdotH, float alpha)
{
if (alpha >= 1.0f) return M_1_PI_F;
float alpha2 = alpha*alpha;
float t = 1.0f + (alpha2 - 1.0f) * NdotH*NdotH;
return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t);
}
/* GGX microfacet with Smith shadow-masking from:
*
* Microfacet Models for Refraction through Rough Surfaces
@ -248,14 +279,44 @@ ccl_device_forceinline float3 microfacet_sample_stretched(
ccl_device int bsdf_microfacet_ggx_setup(MicrofacetBsdf *bsdf)
{
bsdf->extra = NULL;
bsdf->alpha_x = saturate(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device int bsdf_microfacet_ggx_fresnel_setup(MicrofacetBsdf *bsdf)
{
bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
bsdf->alpha_x = saturate(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device int bsdf_microfacet_ggx_clearcoat_setup(MicrofacetBsdf *bsdf)
{
bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
bsdf->alpha_x = saturate(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device bool bsdf_microfacet_merge(const ShaderClosure *a, const ShaderClosure *b)
{
const MicrofacetBsdf *bsdf_a = (const MicrofacetBsdf*)a;
@ -273,16 +334,34 @@ ccl_device bool bsdf_microfacet_merge(const ShaderClosure *a, const ShaderClosur
ccl_device int bsdf_microfacet_ggx_aniso_setup(MicrofacetBsdf *bsdf)
{
bsdf->extra = NULL;
bsdf->alpha_x = saturate(bsdf->alpha_x);
bsdf->alpha_y = saturate(bsdf->alpha_y);
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device int bsdf_microfacet_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf)
{
bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
bsdf->alpha_x = saturate(bsdf->alpha_x);
bsdf->alpha_y = saturate(bsdf->alpha_y);
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device int bsdf_microfacet_ggx_refraction_setup(MicrofacetBsdf *bsdf)
{
bsdf->extra = NULL;
bsdf->alpha_x = saturate(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
@ -319,6 +398,8 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
float alpha2 = alpha_x * alpha_y;
float D, G1o, G1i;
bool is_principled_clearcoat = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID);
if(alpha_x == alpha_y) {
/* isotropic
* eq. 20: (F*G*D)/(4*in*on)
@ -327,7 +408,18 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
float cosThetaM2 = cosThetaM * cosThetaM;
float cosThetaM4 = cosThetaM2 * cosThetaM2;
float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
if(is_principled_clearcoat) {
/* use GTR1 for clearcoat */
D = D_GTR1(cosThetaM, bsdf->alpha_x);
/* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */
alpha2 = 0.0625f;
}
else {
/* use GTR2 otherwise */
D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
}
/* eq. 34: now calculate G1(i,m) and G1(o,m) */
G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
@ -374,7 +466,13 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
/* eq. 20 */
float common = D * 0.25f / cosNO;
float out = G * common;
float3 F = reflection_color(bsdf, omega_in, m);
if(is_principled_clearcoat) {
F *= 0.25f * bsdf->extra->clearcoat;
}
float3 out = F * G * common;
/* eq. 2 in distribution of visible normals sampling
* pm = Dw = G1o * dot(m, I) * D / dot(N, I); */
@ -384,7 +482,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons
* pdf = pm * 0.25 / dot(m, I); */
*pdf = G1o * common;
return make_float3(out, out, out);
return out;
}
return make_float3(0.0f, 0.0f, 0.0f);
@ -489,6 +587,17 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
/* some high number for MIS */
*pdf = 1e6f;
*eval = make_float3(1e6f, 1e6f, 1e6f);
bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID
|| bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID
|| bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID);
/* if fresnel is used, calculate the color with reflection_color(...) */
if(use_fresnel) {
*pdf = 1.0f;
*eval = reflection_color(bsdf, *omega_in, m);
}
label = LABEL_REFLECT | LABEL_SINGULAR;
}
else {
@ -497,16 +606,32 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
float alpha2 = alpha_x * alpha_y;
float D, G1i;
bool is_principled_clearcoat = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID);
if(alpha_x == alpha_y) {
/* isotropic */
float cosThetaM2 = cosThetaM * cosThetaM;
float cosThetaM4 = cosThetaM2 * cosThetaM2;
float tanThetaM2 = 1/(cosThetaM2) - 1;
D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
/* eval BRDF*cosNI */
float cosNI = dot(N, *omega_in);
if(is_principled_clearcoat) {
/* use GTR1 for clearcoat */
D = D_GTR1(cosThetaM, bsdf->alpha_x);
/* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */
alpha2 = 0.0625f;
/* recalculate G1o */
G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
}
else {
/* use GTR2 otherwise */
D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
}
/* eq. 34: now calculate G1(i,m) */
G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
}
@ -538,10 +663,14 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure
/* see eval function for derivation */
float common = (G1o * D) * 0.25f / cosNO;
float out = G1i * common;
*pdf = common;
*eval = make_float3(out, out, out);
float3 F = reflection_color(bsdf, *omega_in, m);
if(is_principled_clearcoat) {
F *= 0.25f * bsdf->extra->clearcoat;
}
*eval = G1i * common * F;
}
#ifdef __RAY_DIFFERENTIALS__

View File

@ -345,8 +345,9 @@ ccl_device int bsdf_microfacet_multi_ggx_common_setup(MicrofacetBsdf *bsdf)
bsdf->extra->color.x = saturate(bsdf->extra->color.x);
bsdf->extra->color.y = saturate(bsdf->extra->color.y);
bsdf->extra->color.z = saturate(bsdf->extra->color.z);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG;
}
@ -356,6 +357,18 @@ ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(MicrofacetBsdf *bsdf)
if(is_zero(bsdf->T))
bsdf->T = make_float3(1.0f, 0.0f, 0.0f);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
ccl_device int bsdf_microfacet_multi_ggx_aniso_fresnel_setup(MicrofacetBsdf *bsdf)
{
if(is_zero(bsdf->T))
bsdf->T = make_float3(1.0f, 0.0f, 0.0f);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID;
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
@ -363,6 +376,26 @@ ccl_device int bsdf_microfacet_multi_ggx_setup(MicrofacetBsdf *bsdf)
{
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(MicrofacetBsdf *bsdf)
{
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID;
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(MicrofacetBsdf *bsdf)
{
bsdf->alpha_y = bsdf->alpha_x;
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
return bsdf_microfacet_multi_ggx_common_setup(bsdf);
}
@ -378,6 +411,8 @@ ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc
return make_float3(0.0f, 0.0f, 0.0f);
}
bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID);
bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y);
float3 X, Y, Z;
Z = bsdf->N;
@ -393,7 +428,7 @@ ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc
*pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y));
else
*pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x);
return mf_eval_glossy(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL);
return mf_eval_glossy(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL, bsdf->ior, use_fresnel, bsdf->extra->cspec0);
}
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, ccl_addr_space uint *lcg_state)
@ -410,6 +445,8 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderC
return LABEL_REFLECT|LABEL_SINGULAR;
}
bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID);
bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y);
if(is_aniso)
make_orthonormals_tangent(Z, bsdf->T, &X, &Y);
@ -419,7 +456,7 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderC
float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z));
float3 localO;
*eval = mf_sample_glossy(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL);
*eval = mf_sample_glossy(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, NULL, NULL, bsdf->ior, use_fresnel, bsdf->extra->cspec0);
if(is_aniso)
*pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y));
else
@ -450,6 +487,23 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_setup(MicrofacetBsdf *bsdf)
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG;
}
ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(MicrofacetBsdf *bsdf)
{
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->ior = max(0.0f, bsdf->ior);
bsdf->extra->color.x = saturate(bsdf->extra->color.x);
bsdf->extra->color.y = saturate(bsdf->extra->color.y);
bsdf->extra->color.z = saturate(bsdf->extra->color.z);
bsdf->extra->cspec0.x = saturate(bsdf->extra->cspec0.x);
bsdf->extra->cspec0.y = saturate(bsdf->extra->cspec0.y);
bsdf->extra->cspec0.z = saturate(bsdf->extra->cspec0.z);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG;
}
ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
@ -465,7 +519,7 @@ ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClos
float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
*pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior);
return mf_eval_glass(localI, localO, false, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior);
return mf_eval_glass(localI, localO, false, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, false, bsdf->extra->color);
}
ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) {
@ -475,6 +529,8 @@ ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosu
return make_float3(0.0f, 0.0f, 0.0f);
}
bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID);
float3 X, Y, Z;
Z = bsdf->N;
make_orthonormals(Z, &X, &Y);
@ -483,7 +539,7 @@ ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosu
float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z));
*pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior);
return mf_eval_glass(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior);
return mf_eval_glass(localI, localO, true, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0);
}
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, ccl_addr_space uint *lcg_state)
@ -525,12 +581,14 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const S
}
}
bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID);
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, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior);
*eval = mf_sample_glass(localI, &localO, bsdf->extra->color, bsdf->alpha_x, bsdf->alpha_y, lcg_state, bsdf->ior, use_fresnel, bsdf->extra->cspec0);
*pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior);
*eval *= *pdf;

View File

@ -35,8 +35,13 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
ccl_addr_space uint *lcg_state
#ifdef MF_MULTI_GLASS
, const float eta
, bool use_fresnel
, const float3 cspec0
#elif defined(MF_MULTI_GLOSSY)
, float3 *n, float3 *k
, float3 *n, float3 *k
, const float eta
, bool use_fresnel
, const float3 cspec0
#endif
)
{
@ -71,12 +76,20 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
/* Analytically compute single scattering for lower noise. */
float3 eval;
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
#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);
float F0 = fresnel_dielectric_cos(1.0f, eta);
if(use_fresnel) {
throughput = interpolate_fresnel_color(wi, normalize(wi + wo), eta, F0, cspec0);
eval *= throughput;
}
#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);
@ -94,6 +107,13 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
else {
eval = make_float3(val, val, val);
}
float F0 = fresnel_dielectric_cos(1.0f, eta);
if(use_fresnel) {
throughput = interpolate_fresnel_color(wi, wh, eta, F0, cspec0);
eval = throughput * val;
}
#endif
float3 wr = -wi;
@ -101,7 +121,6 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
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 */
@ -116,6 +135,18 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
const float G2_G1 = -lambda_r / (shadowing_lambda - lambda_r);
eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm);
}
#endif
#ifdef MF_MULTI_GLASS
if(order == 0 && use_fresnel) {
/* Evaluate amount of scattering towards wo on this microfacet. */
float3 phase;
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);
eval = throughput * phase * mf_G1(wo_outside ? wo : -wo, mf_C1((outside == wo_outside) ? hr : -hr), shadowing_lambda);
}
#endif
if(order > 0) {
/* Evaluate amount of scattering towards wo on this microfacet. */
@ -136,23 +167,39 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
/* Bounce from the microfacet. */
#ifdef MF_MULTI_GLASS
bool next_outside;
float3 wi_prev = -wr;
wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside);
if(!next_outside) {
outside = !outside;
wr = -wr;
hr = -hr;
}
if(use_fresnel && !next_outside) {
throughput *= color;
}
else if(use_fresnel && order > 0) {
throughput *= interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0);
}
#elif defined(MF_MULTI_DIFFUSE)
wr = mf_sample_phase_diffuse(wm,
lcg_step_float_addrspace(lcg_state),
lcg_step_float_addrspace(lcg_state));
#else /* MF_MULTI_GLOSSY */
if(use_fresnel && order > 0) {
throughput *= interpolate_fresnel_color(-wr, wm, eta, F0, cspec0);
}
wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
#endif
lambda_r = mf_lambda(wr, alpha);
#if defined(MF_MULTI_GLOSSY) || defined(MF_MULTI_GLASS)
if(!use_fresnel)
throughput *= color;
#else
throughput *= color;
#endif
C1_r = mf_C1(hr);
G1_r = mf_G1(wr, C1_r, lambda_r);
@ -171,8 +218,13 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_eval)(
ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state
#ifdef MF_MULTI_GLASS
, const float eta
, bool use_fresnel
, const float3 cspec0
#elif defined(MF_MULTI_GLOSSY)
, float3 *n, float3 *k
, const float eta
, bool use_fresnel
, const float3 cspec0
#endif
)
{
@ -185,6 +237,17 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3
float C1_r = 1.0f;
float G1_r = 0.0f;
bool outside = true;
#ifdef MF_MULTI_GLASS
float F0 = fresnel_dielectric_cos(1.0f, eta);
if(use_fresnel) {
throughput = interpolate_fresnel_color(wi, normalize(wi + wr), eta, F0, cspec0);
}
#elif defined(MF_MULTI_GLOSSY)
float F0 = fresnel_dielectric_cos(1.0f, eta);
if(use_fresnel) {
throughput = interpolate_fresnel_color(wi, normalize(wi + wr), eta, F0, cspec0);
}
#endif
int order;
for(order = 0; order < 10; order++) {
@ -199,23 +262,51 @@ ccl_device_forceinline float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3
lcg_step_float_addrspace(lcg_state)));
/* First-bounce color is already accounted for in mix weight. */
#if defined(MF_MULTI_GLASS) || defined(MF_MULTI_GLOSSY)
if(!use_fresnel && order > 0)
throughput *= color;
#else
if(order > 0)
throughput *= color;
#endif
/* Bounce from the microfacet. */
#ifdef MF_MULTI_GLASS
bool next_outside;
float3 wi_prev = -wr;
wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside);
if(!next_outside) {
hr = -hr;
wr = -wr;
outside = !outside;
}
if(use_fresnel) {
if(!next_outside) {
throughput *= color;
}
else {
float3 t_color = interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0);
if(order == 0)
throughput = t_color;
else
throughput *= t_color;
}
}
#elif defined(MF_MULTI_DIFFUSE)
wr = mf_sample_phase_diffuse(wm,
lcg_step_float_addrspace(lcg_state),
lcg_step_float_addrspace(lcg_state));
#else /* MF_MULTI_GLOSSY */
if(use_fresnel) {
float3 t_color = interpolate_fresnel_color(-wr, wm, eta, F0, cspec0);
if(order == 0)
throughput = t_color;
else
throughput *= t_color;
}
wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm);
#endif

View File

@ -0,0 +1,120 @@
/*
* Copyright 2011-2017 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.
*/
#ifndef __BSDF_PRINCIPLED_DIFFUSE_H__
#define __BSDF_PRINCIPLED_DIFFUSE_H__
/* DISNEY PRINCIPLED DIFFUSE BRDF
*
* Shading model by Brent Burley (Disney): "Physically Based Shading at Disney" (2012)
*/
CCL_NAMESPACE_BEGIN
typedef ccl_addr_space struct PrincipledDiffuseBsdf {
SHADER_CLOSURE_BASE;
float roughness;
float3 N;
} PrincipledDiffuseBsdf;
ccl_device float3 calculate_principled_diffuse_brdf(const PrincipledDiffuseBsdf *bsdf,
float3 N, float3 V, float3 L, float3 H, float *pdf)
{
float NdotL = max(dot(N, L), 0.0f);
float NdotV = max(dot(N, V), 0.0f);
if(NdotL < 0 || NdotV < 0) {
*pdf = 0.0f;
return make_float3(0.0f, 0.0f, 0.0f);
}
float LdotH = dot(L, H);
float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV);
const float Fd90 = 0.5f + 2.0f * LdotH*LdotH * bsdf->roughness;
float Fd = (1.0f * (1.0f - FL) + Fd90 * FL) * (1.0f * (1.0f - FV) + Fd90 * FV);
float value = M_1_PI_F * NdotL * Fd;
return make_float3(value, value, value);
}
ccl_device int bsdf_principled_diffuse_setup(PrincipledDiffuseBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device float3 bsdf_principled_diffuse_eval_reflect(const ShaderClosure *sc, const float3 I,
const float3 omega_in, float *pdf)
{
const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc;
float3 N = bsdf->N;
float3 V = I; // outgoing
float3 L = omega_in; // incoming
float3 H = normalize(L + V);
if(dot(N, omega_in) > 0.0f) {
*pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F;
return calculate_principled_diffuse_brdf(bsdf, N, V, L, H, pdf);
}
else {
*pdf = 0.0f;
return make_float3(0.0f, 0.0f, 0.0f);
}
}
ccl_device float3 bsdf_principled_diffuse_eval_transmit(const ShaderClosure *sc, const float3 I,
const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
ccl_device int bsdf_principled_diffuse_sample(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)
{
const PrincipledDiffuseBsdf *bsdf = (const PrincipledDiffuseBsdf *)sc;
float3 N = bsdf->N;
sample_cos_hemisphere(N, randu, randv, omega_in, pdf);
if(dot(Ng, *omega_in) > 0) {
float3 H = normalize(I + *omega_in);
*eval = calculate_principled_diffuse_brdf(bsdf, N, I, *omega_in, H, pdf);
#ifdef __RAY_DIFFERENTIALS__
// TODO: find a better approximation for the diffuse bounce
*domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx);
*domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy);
#endif
}
else {
*pdf = 0.0f;
}
return LABEL_REFLECT|LABEL_DIFFUSE;
}
CCL_NAMESPACE_END
#endif /* __BSDF_PRINCIPLED_DIFFUSE_H__ */

View File

@ -0,0 +1,114 @@
/*
* Copyright 2011-2017 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.
*/
#ifndef __BSDF_PRINCIPLED_SHEEN_H__
#define __BSDF_PRINCIPLED_SHEEN_H__
/* DISNEY PRINCIPLED SHEEN BRDF
*
* Shading model by Brent Burley (Disney): "Physically Based Shading at Disney" (2012)
*/
CCL_NAMESPACE_BEGIN
typedef ccl_addr_space struct PrincipledSheenBsdf {
SHADER_CLOSURE_BASE;
float3 N;
} PrincipledSheenBsdf;
ccl_device float3 calculate_principled_sheen_brdf(const PrincipledSheenBsdf *bsdf,
float3 N, float3 V, float3 L, float3 H, float *pdf)
{
float NdotL = dot(N, L);
float NdotV = dot(N, V);
if(NdotL < 0 || NdotV < 0) {
*pdf = 0.0f;
return make_float3(0.0f, 0.0f, 0.0f);
}
float LdotH = dot(L, H);
float value = schlick_fresnel(LdotH) * NdotL;
return make_float3(value, value, value);
}
ccl_device int bsdf_principled_sheen_setup(PrincipledSheenBsdf *bsdf)
{
bsdf->type = CLOSURE_BSDF_PRINCIPLED_SHEEN_ID;
return SD_BSDF|SD_BSDF_HAS_EVAL;
}
ccl_device float3 bsdf_principled_sheen_eval_reflect(const ShaderClosure *sc, const float3 I,
const float3 omega_in, float *pdf)
{
const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc;
float3 N = bsdf->N;
float3 V = I; // outgoing
float3 L = omega_in; // incoming
float3 H = normalize(L + V);
if(dot(N, omega_in) > 0.0f) {
*pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F;
return calculate_principled_sheen_brdf(bsdf, N, V, L, H, pdf);
}
else {
*pdf = 0.0f;
return make_float3(0.0f, 0.0f, 0.0f);
}
}
ccl_device float3 bsdf_principled_sheen_eval_transmit(const ShaderClosure *sc, const float3 I,
const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
ccl_device int bsdf_principled_sheen_sample(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)
{
const PrincipledSheenBsdf *bsdf = (const PrincipledSheenBsdf *)sc;
float3 N = bsdf->N;
sample_cos_hemisphere(N, randu, randv, omega_in, pdf);
if(dot(Ng, *omega_in) > 0) {
float3 H = normalize(I + *omega_in);
*eval = calculate_principled_sheen_brdf(bsdf, N, I, *omega_in, H, pdf);
#ifdef __RAY_DIFFERENTIALS__
// TODO: find a better approximation for the diffuse bounce
*domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx);
*domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy);
#endif
}
else {
*pdf = 0.0f;
}
return LABEL_REFLECT|LABEL_DIFFUSE;
}
CCL_NAMESPACE_END
#endif /* __BSDF_PRINCIPLED_SHEEN_H__ */

View File

@ -124,6 +124,13 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k
return(Rparl2 + Rperp2) * 0.5f;
}
ccl_device float schlick_fresnel(float u)
{
float m = clamp(1.0f - u, 0.0f, 1.0f);
float m2 = m * m;
return m2 * m2 * m; // pow(m, 5)
}
ccl_device float smooth_step(float edge0, float edge1, float x)
{
float result;
@ -136,6 +143,19 @@ ccl_device float smooth_step(float edge0, float edge1, float x)
return result;
}
/* Calculate the fresnel color which is a blend between white and the F0 color (cspec0) */
ccl_device_forceinline float3 interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0) {
/* Calculate the fresnel interpolation factor
* The value from fresnel_dielectric_cos(...) has to be normalized because
* the cspec0 keeps the F0 color
*/
float F0_norm = 1.0f / (1.0f - F0);
float FH = (fresnel_dielectric_cos(dot(L, H), ior) - F0) * F0_norm;
/* Blend between white and a specular color with respect to the fresnel */
return cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH;
}
CCL_NAMESPACE_END
#endif /* __BSDF_UTIL_H__ */

View File

@ -27,6 +27,7 @@ typedef ccl_addr_space struct Bssrdf {
float d;
float texture_blur;
float albedo;
float roughness;
float3 N;
} Bssrdf;
@ -360,10 +361,29 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type)
{
if(bssrdf->radius < BSSRDF_MIN_RADIUS) {
/* revert to diffuse BSDF if radius too small */
DiffuseBsdf *bsdf = (DiffuseBsdf*)bssrdf;
bsdf->N = bssrdf->N;
int flag = bsdf_diffuse_setup(bsdf);
bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
int flag;
if(type == CLOSURE_BSSRDF_PRINCIPLED_ID) {
float roughness = bssrdf->roughness;
float3 N = bssrdf->N;
float3 weight = bssrdf->weight;
float sample_weight = bssrdf->sample_weight;
PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bssrdf;
bsdf->N = N;
bsdf->roughness = roughness;
bsdf->weight = weight;
bsdf->sample_weight = sample_weight;
flag = bsdf_principled_diffuse_setup(bsdf);
bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID;
}
else {
DiffuseBsdf *bsdf = (DiffuseBsdf*)bssrdf;
bsdf->N = bssrdf->N;
flag = bsdf_diffuse_setup(bsdf);
bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
}
return flag;
}
else {
@ -371,7 +391,7 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type)
bssrdf->sharpness = saturate(bssrdf->sharpness);
bssrdf->type = type;
if(type == CLOSURE_BSSRDF_BURLEY_ID) {
if(type == CLOSURE_BSSRDF_BURLEY_ID || type == CLOSURE_BSSRDF_PRINCIPLED_ID) {
bssrdf_burley_setup(bssrdf);
}
@ -385,7 +405,7 @@ ccl_device void bssrdf_sample(const ShaderClosure *sc, float xi, float *r, float
bssrdf_cubic_sample(sc, xi, r, h);
else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID)
bssrdf_gaussian_sample(sc, xi, r, h);
else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID)*/
else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/
bssrdf_burley_sample(sc, xi, r, h);
}
@ -395,7 +415,7 @@ ccl_device_forceinline float bssrdf_pdf(const ShaderClosure *sc, float r)
return bssrdf_cubic_pdf(sc, r);
else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID)
return bssrdf_gaussian_pdf(sc, r);
else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID)*/
else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID || sc->type == CLOSURE_BSSRDF_PRINCIPLED_ID)*/
return bssrdf_burley_pdf(sc, r);
}

View File

@ -379,7 +379,7 @@ ccl_device bool shadow_blocked_transparent_stepped(
float3 *shadow)
{
bool blocked, is_transparent_isect;
if (skip_object == OBJECT_NONE) {
if(skip_object == OBJECT_NONE) {
blocked = scene_intersect(kg,
*ray,
PATH_RAY_SHADOW_OPAQUE,

View File

@ -140,7 +140,7 @@ ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd,
}
/* replace closures with a single diffuse bsdf closure after scatter step */
ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, float3 weight, bool hit, float3 N)
ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, ShaderClosure *sc, float3 weight, bool hit, float3 N)
{
sd->flag &= ~SD_CLOSURE_FLAGS;
sd->randb_closure = 0.0f;
@ -148,15 +148,31 @@ ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, float3 wei
sd->num_closure_extra = 0;
if(hit) {
DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight);
Bssrdf *bssrdf = (Bssrdf *)sc;
if(bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID) {
PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), weight);
if(bsdf) {
bsdf->N = N;
sd->flag |= bsdf_diffuse_setup(bsdf);
if(bsdf) {
bsdf->N = N;
bsdf->roughness = bssrdf->roughness;
sd->flag |= bsdf_principled_diffuse_setup(bsdf);
/* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes
* can recognize it as not being a regular diffuse closure */
bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
/* replace CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID with this special ID so render passes
* can recognize it as not being a regular Disney principled diffuse closure */
bsdf->type = CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID;
}
}
else if(CLOSURE_IS_BSSRDF(bssrdf->type)) {
DiffuseBsdf *bsdf = (DiffuseBsdf*)bsdf_alloc(sd, sizeof(DiffuseBsdf), weight);
if(bsdf) {
bsdf->N = N;
sd->flag |= bsdf_diffuse_setup(bsdf);
/* replace CLOSURE_BSDF_DIFFUSE_ID with this special ID so render passes
* can recognize it as not being a regular diffuse closure */
bsdf->type = CLOSURE_BSDF_BSSRDF_ID;
}
}
}
}
@ -388,7 +404,7 @@ ccl_device_noinline void subsurface_scatter_multi_setup(
subsurface_color_bump_blur(kg, sd, state, state_flag, &weight, &N);
/* Setup diffuse BSDF. */
subsurface_scatter_setup_diffuse_bsdf(sd, weight, true, N);
subsurface_scatter_setup_diffuse_bsdf(sd, sc, weight, true, N);
}
#ifndef __SPLIT_KERNEL__
@ -479,7 +495,7 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, PathS
subsurface_color_bump_blur(kg, sd, state, state_flag, &eval, &N);
/* setup diffuse bsdf */
subsurface_scatter_setup_diffuse_bsdf(sd, eval, (ss_isect.num_hits > 0), N);
subsurface_scatter_setup_diffuse_bsdf(sd, sc, eval, (ss_isect.num_hits > 0), N);
}
#endif /* ! __SPLIT_KERNEL__ */

View File

@ -39,7 +39,9 @@
#include "kernel/kernel_montecarlo.h"
#include "kernel/closure/alloc.h"
#include "kernel/closure/bsdf_util.h"
#include "kernel/closure/bsdf_diffuse.h"
#include "kernel/closure/bsdf_principled_diffuse.h"
#include "kernel/closure/bssrdf.h"
CCL_NAMESPACE_BEGIN
@ -78,6 +80,7 @@ public:
bssrdf->albedo = albedo.x;
bssrdf->sharpness = sharpness;
bssrdf->N = params.N;
bssrdf->roughness = params.roughness;
sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type);
}
@ -89,6 +92,7 @@ public:
bssrdf->albedo = albedo.y;
bssrdf->sharpness = sharpness;
bssrdf->N = params.N;
bssrdf->roughness = params.roughness;
sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type);
}
@ -100,6 +104,7 @@ public:
bssrdf->albedo = albedo.z;
bssrdf->sharpness = sharpness;
bssrdf->N = params.N;
bssrdf->roughness = params.roughness;
sd->flag |= bssrdf_setup(bssrdf, (ClosureType)type);
}
}
@ -180,5 +185,31 @@ ClosureParam *closure_bssrdf_burley_params()
CCLOSURE_PREPARE(closure_bssrdf_burley_prepare, BurleyBSSRDFClosure)
/* Disney principled */
class PrincipledBSSRDFClosure : public CBSSRDFClosure {
public:
void setup(ShaderData *sd, int path_flag, float3 weight)
{
alloc(sd, path_flag, weight * albedo, CLOSURE_BSSRDF_PRINCIPLED_ID);
}
};
ClosureParam *closure_bssrdf_principled_params()
{
static ClosureParam params[] = {
CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, params.N),
CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, radius),
CLOSURE_FLOAT_PARAM(PrincipledBSSRDFClosure, params.texture_blur),
CLOSURE_FLOAT3_PARAM(PrincipledBSSRDFClosure, albedo),
CLOSURE_FLOAT_PARAM(PrincipledBSSRDFClosure, params.roughness),
CLOSURE_STRING_KEYPARAM(PrincipledBSSRDFClosure, label, "label"),
CLOSURE_FINISH_PARAM(PrincipledBSSRDFClosure)
};
return params;
}
CCLOSURE_PREPARE(closure_bssrdf_principled_prepare, PrincipledBSSRDFClosure)
CCL_NAMESPACE_END

View File

@ -60,6 +60,8 @@
#include "kernel/closure/bsdf_ashikhmin_shirley.h"
#include "kernel/closure/bsdf_toon.h"
#include "kernel/closure/bsdf_hair.h"
#include "kernel/closure/bsdf_principled_diffuse.h"
#include "kernel/closure/bsdf_principled_sheen.h"
#include "kernel/closure/volume.h"
CCL_NAMESPACE_BEGIN
@ -176,6 +178,63 @@ VOLUME_CLOSURE_CLASS_END(VolumeHenyeyGreenstein, henyey_greenstein)
VOLUME_CLOSURE_CLASS_BEGIN(VolumeAbsorption, absorption, ShaderClosure, LABEL_SINGULAR)
VOLUME_CLOSURE_CLASS_END(VolumeAbsorption, absorption)
BSDF_CLOSURE_CLASS_BEGIN(PrincipledDiffuse, principled_diffuse, PrincipledDiffuseBsdf, LABEL_DIFFUSE)
CLOSURE_FLOAT3_PARAM(PrincipledDiffuseClosure, params.N),
CLOSURE_FLOAT_PARAM(PrincipledDiffuseClosure, params.roughness),
BSDF_CLOSURE_CLASS_END(PrincipledDiffuse, principled_diffuse)
BSDF_CLOSURE_CLASS_BEGIN(PrincipledSheen, principled_sheen, PrincipledSheenBsdf, LABEL_DIFFUSE)
CLOSURE_FLOAT3_PARAM(PrincipledSheenClosure, params.N),
BSDF_CLOSURE_CLASS_END(PrincipledSheen, principled_sheen)
/* DISNEY PRINCIPLED CLEARCOAT */
class PrincipledClearcoatClosure : public CBSDFClosure {
public:
MicrofacetBsdf params;
float clearcoat, clearcoat_gloss;
MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight)
{
MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc_osl(sd, sizeof(MicrofacetBsdf), weight, &params);
MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
if(bsdf && extra) {
bsdf->extra = extra;
bsdf->ior = 1.5f;
bsdf->alpha_x = 0.1f * (1.0f - clearcoat_gloss) + 0.001f * clearcoat_gloss;
bsdf->alpha_y = 0.1f * (1.0f - clearcoat_gloss) + 0.001f * clearcoat_gloss;
bsdf->extra->cspec0 = make_float3(0.04f, 0.04f, 0.04f);
bsdf->extra->clearcoat = clearcoat;
return bsdf;
}
return NULL;
}
void setup(ShaderData *sd, int path_flag, float3 weight)
{
MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
sd->flag |= (bsdf) ? bsdf_microfacet_ggx_clearcoat_setup(bsdf) : 0;
}
};
ClosureParam *closure_bsdf_principled_clearcoat_params()
{
static ClosureParam params[] = {
CLOSURE_FLOAT3_PARAM(PrincipledClearcoatClosure, params.N),
CLOSURE_FLOAT_PARAM(PrincipledClearcoatClosure, clearcoat),
CLOSURE_FLOAT_PARAM(PrincipledClearcoatClosure, clearcoat_gloss),
CLOSURE_STRING_KEYPARAM(PrincipledClearcoatClosure, label, "label"),
CLOSURE_FINISH_PARAM(PrincipledClearcoatClosure)
};
return params;
}
CCLOSURE_PREPARE(closure_bsdf_principled_clearcoat_prepare, PrincipledClearcoatClosure)
/* Registration */
static void register_closure(OSL::ShadingSystem *ss, const char *name, int id, OSL::ClosureParam *params, OSL::PrepareClosureFunc prepare)
@ -215,6 +274,16 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
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_ggx_fresnel", id++,
closure_bsdf_microfacet_ggx_fresnel_params(), closure_bsdf_microfacet_ggx_fresnel_prepare);
register_closure(ss, "microfacet_ggx_aniso_fresnel", id++,
closure_bsdf_microfacet_ggx_aniso_fresnel_params(), closure_bsdf_microfacet_ggx_aniso_fresnel_prepare);
register_closure(ss, "microfacet_multi_ggx_fresnel", id++,
closure_bsdf_microfacet_multi_ggx_fresnel_params(), closure_bsdf_microfacet_multi_ggx_fresnel_prepare);
register_closure(ss, "microfacet_multi_ggx_glass_fresnel", id++,
closure_bsdf_microfacet_multi_ggx_glass_fresnel_params(), closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare);
register_closure(ss, "microfacet_multi_ggx_aniso_fresnel", id++,
closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params(), closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare);
register_closure(ss, "microfacet_beckmann", id++,
bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare);
register_closure(ss, "microfacet_beckmann_aniso", id++,
@ -229,6 +298,12 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
bsdf_diffuse_toon_params(), bsdf_diffuse_toon_prepare);
register_closure(ss, "glossy_toon", id++,
bsdf_glossy_toon_params(), bsdf_glossy_toon_prepare);
register_closure(ss, "principled_diffuse", id++,
bsdf_principled_diffuse_params(), bsdf_principled_diffuse_prepare);
register_closure(ss, "principled_sheen", id++,
bsdf_principled_sheen_params(), bsdf_principled_sheen_prepare);
register_closure(ss, "principled_clearcoat", id++,
closure_bsdf_principled_clearcoat_params(), closure_bsdf_principled_clearcoat_prepare);
register_closure(ss, "emission", id++,
closure_emission_params(), closure_emission_prepare);
@ -248,6 +323,8 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
closure_bssrdf_gaussian_params(), closure_bssrdf_gaussian_prepare);
register_closure(ss, "bssrdf_burley", id++,
closure_bssrdf_burley_params(), closure_bssrdf_burley_prepare);
register_closure(ss, "bssrdf_principled", id++,
closure_bssrdf_principled_params(), closure_bssrdf_principled_prepare);
register_closure(ss, "hair_reflection", id++,
bsdf_hair_reflection_params(), bsdf_hair_reflection_prepare);
@ -278,6 +355,86 @@ bool CBSDFClosure::skip(const ShaderData *sd, int path_flag, int scattering)
return false;
}
/* GGX closures with Fresnel */
class MicrofacetFresnelClosure : public CBSDFClosure {
public:
MicrofacetBsdf params;
float3 color;
float3 cspec0;
MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight)
{
/* 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. */
if(!skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc_osl(sd, sizeof(MicrofacetBsdf), weight, &params);
MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
if(bsdf && extra) {
bsdf->extra = extra;
bsdf->extra->color = color;
bsdf->extra->cspec0 = cspec0;
return bsdf;
}
}
return NULL;
}
};
class MicrofacetGGXFresnelClosure : public MicrofacetFresnelClosure {
public:
void setup(ShaderData *sd, int path_flag, float3 weight)
{
MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
sd->flag |= (bsdf) ? bsdf_microfacet_ggx_fresnel_setup(bsdf) : 0;
}
};
ClosureParam *closure_bsdf_microfacet_ggx_fresnel_params()
{
static ClosureParam params[] = {
CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.N),
CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_x),
CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.ior),
CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, color),
CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, cspec0),
CLOSURE_STRING_KEYPARAM(MicrofacetGGXFresnelClosure, label, "label"),
CLOSURE_FINISH_PARAM(MicrofacetGGXFresnelClosure)
};
return params;
}
CCLOSURE_PREPARE(closure_bsdf_microfacet_ggx_fresnel_prepare, MicrofacetGGXFresnelClosure);
class MicrofacetGGXAnisoFresnelClosure : public MicrofacetFresnelClosure {
public:
void setup(ShaderData *sd, int path_flag, float3 weight)
{
MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
sd->flag |= (bsdf) ? bsdf_microfacet_ggx_aniso_fresnel_setup(bsdf) : 0;
}
};
ClosureParam *closure_bsdf_microfacet_ggx_aniso_fresnel_params()
{
static ClosureParam params[] = {
CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.N),
CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, params.T),
CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_x),
CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.alpha_y),
CLOSURE_FLOAT_PARAM(MicrofacetGGXFresnelClosure, params.ior),
CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, color),
CLOSURE_FLOAT3_PARAM(MicrofacetGGXFresnelClosure, cspec0),
CLOSURE_STRING_KEYPARAM(MicrofacetGGXFresnelClosure, label, "label"),
CLOSURE_FINISH_PARAM(MicrofacetGGXFresnelClosure)
};
return params;
}
CCLOSURE_PREPARE(closure_bsdf_microfacet_ggx_aniso_fresnel_prepare, MicrofacetGGXAnisoFresnelClosure);
/* Multiscattering GGX closures */
class MicrofacetMultiClosure : public CBSDFClosure {
@ -287,7 +444,7 @@ public:
MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight)
{
/* Technically, the MultiGGX Glass closure may also transmit. However,
/* Technically, the MultiGGX closure may also transmit. However,
* since this is set statically and only used for caustic flags, this
* is probably as good as it gets. */
if(!skip(sd, path_flag, LABEL_GLOSSY|LABEL_REFLECT)) {
@ -375,5 +532,110 @@ ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params()
}
CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure);
/* Multiscattering GGX closures with Fresnel */
class MicrofacetMultiFresnelClosure : public CBSDFClosure {
public:
MicrofacetBsdf params;
float3 color;
float3 cspec0;
MicrofacetBsdf *alloc(ShaderData *sd, int path_flag, float3 weight)
{
/* Technically, the MultiGGX closure may also transmit. However,
* since this is set statically and only used for caustic flags, this
* is probably as good as it gets. */
if(!skip(sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc_osl(sd, sizeof(MicrofacetBsdf), weight, &params);
MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
if(bsdf && extra) {
bsdf->extra = extra;
bsdf->extra->color = color;
bsdf->extra->cspec0 = cspec0;
return bsdf;
}
}
return NULL;
}
};
class MicrofacetMultiGGXFresnelClosure : public MicrofacetMultiFresnelClosure {
public:
void setup(ShaderData *sd, int path_flag, float3 weight)
{
MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_fresnel_setup(bsdf) : 0;
}
};
ClosureParam *closure_bsdf_microfacet_multi_ggx_fresnel_params()
{
static ClosureParam params[] = {
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N),
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x),
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior),
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color),
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0),
CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"),
CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure)
};
return params;
}
CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_fresnel_prepare, MicrofacetMultiGGXFresnelClosure);
class MicrofacetMultiGGXAnisoFresnelClosure : public MicrofacetMultiFresnelClosure {
public:
void setup(ShaderData *sd, int path_flag, float3 weight)
{
MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_aniso_fresnel_setup(bsdf) : 0;
}
};
ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params()
{
static ClosureParam params[] = {
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N),
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.T),
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x),
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_y),
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior),
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color),
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0),
CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"),
CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure)
};
return params;
}
CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare, MicrofacetMultiGGXAnisoFresnelClosure);
class MicrofacetMultiGGXGlassFresnelClosure : public MicrofacetMultiFresnelClosure {
public:
MicrofacetMultiGGXGlassFresnelClosure() : MicrofacetMultiFresnelClosure() {}
void setup(ShaderData *sd, int path_flag, float3 weight)
{
MicrofacetBsdf *bsdf = alloc(sd, path_flag, weight);
sd->flag |= (bsdf) ? bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf) : 0;
}
};
ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_fresnel_params()
{
static ClosureParam params[] = {
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, params.N),
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.alpha_x),
CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXFresnelClosure, params.ior),
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, color),
CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXFresnelClosure, cspec0),
CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXFresnelClosure, label, "label"),
CLOSURE_FINISH_PARAM(MicrofacetMultiGGXFresnelClosure)
};
return params;
}
CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare, MicrofacetMultiGGXGlassFresnelClosure);
CCL_NAMESPACE_END

View File

@ -51,10 +51,17 @@ OSL::ClosureParam *closure_bsdf_phong_ramp_params();
OSL::ClosureParam *closure_bssrdf_cubic_params();
OSL::ClosureParam *closure_bssrdf_gaussian_params();
OSL::ClosureParam *closure_bssrdf_burley_params();
OSL::ClosureParam *closure_bssrdf_principled_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();
OSL::ClosureParam *closure_bsdf_microfacet_ggx_fresnel_params();
OSL::ClosureParam *closure_bsdf_microfacet_ggx_aniso_fresnel_params();
OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_fresnel_params();
OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_fresnel_params();
OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_fresnel_params();
OSL::ClosureParam *closure_bsdf_principled_clearcoat_params();
void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
void closure_background_prepare(OSL::RendererServices *, int id, void *data);
@ -65,10 +72,17 @@ void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data
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_bssrdf_principled_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);
void closure_bsdf_microfacet_ggx_fresnel_prepare(OSL::RendererServices *, int id, void *data);
void closure_bsdf_microfacet_ggx_aniso_fresnel_prepare(OSL::RendererServices *, int id, void *data);
void closure_bsdf_microfacet_multi_ggx_fresnel_prepare(OSL::RendererServices *, int id, void *data);
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);
#define CCLOSURE_PREPARE(name, classname) \
void name(RendererServices *, int id, void *data) \

View File

@ -81,13 +81,15 @@ set(SRC_OSL
node_wireframe.osl
node_hair_bsdf.osl
node_uv_map.osl
node_principled_bsdf.osl
node_rgb_to_bw.osl
)
set(SRC_OSL_HEADERS
node_texture.h
node_color.h
node_fresnel.h
node_ramp_util.h
node_texture.h
stdosl.h
oslutil.h
)

View File

@ -0,0 +1,120 @@
/*
* Copyright 2011-2017 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"
#include "node_fresnel.h"
shader node_principled_bsdf(
string distribution = "Multiscatter GGX",
color BaseColor = color(0.8, 0.8, 0.8),
float Subsurface = 0.0,
vector SubsurfaceRadius = vector(1.0, 1.0, 1.0),
color SubsurfaceColor = color(0.7, 0.1, 0.1),
float Metallic = 0.0,
float Specular = 0.5,
float SpecularTint = 0.0,
float Roughness = 0.5,
float Anisotropic = 0.0,
float AnisotropicRotation = 0.0,
float Sheen = 0.0,
float SheenTint = 0.5,
float Clearcoat = 0.0,
float ClearcoatGloss = 1.0,
float IOR = 1.45,
float Transparency = 0.0,
float RefractionRoughness = 0.0,
normal Normal = N,
normal ClearcoatNormal = N,
normal Tangent = normalize(dPdu),
output closure color BSDF = 0)
{
float f = max(IOR, 1e-5);
float diffuse_weight = (1.0 - clamp(Metallic, 0.0, 1.0)) * (1.0 - clamp(Transparency, 0.0, 1.0));
float transp = clamp(Transparency, 0.0, 1.0) * (1.0 - clamp(Metallic, 0.0, 1.0));
float specular_weight = (1.0 - transp);
vector T = Tangent;
float m_cdlum = luminance(BaseColor);
color m_ctint = m_cdlum > 0.0 ? BaseColor / m_cdlum : color(0.0, 0.0, 0.0); // normalize lum. to isolate hue+sat
/* rotate tangent */
if (AnisotropicRotation != 0.0)
T = rotate(T, AnisotropicRotation * M_2PI, point(0.0, 0.0, 0.0), Normal);
if (diffuse_weight > 1e-5) {
if (Subsurface > 1e-5) {
color Albedo = SubsurfaceColor * Subsurface + BaseColor * (1.0 - Subsurface);
BSDF = bssrdf_principled(Normal, Subsurface * SubsurfaceRadius, 0.0, Albedo, Roughness);
} else {
BSDF = BaseColor * principled_diffuse(Normal, Roughness);
}
if (Sheen > 1e-5) {
color sheen_color = color(1.0, 1.0, 1.0) * (1.0 - SheenTint) + m_ctint * SheenTint;
BSDF = BSDF + sheen_color * Sheen * principled_sheen(Normal);
}
BSDF = BSDF * diffuse_weight;
}
if (specular_weight > 1e-5) {
float aspect = sqrt(1.0 - Anisotropic * 0.9);
float r2 = Roughness * Roughness;
float alpha_x = max(0.001, r2 / aspect);
float alpha_y = max(0.001, r2 * aspect);
color tmp_col = color(1.0, 1.0, 1.0) * (1.0 - SpecularTint) + m_ctint * SpecularTint;
color Cspec0 = (Specular * 0.08 * tmp_col) * (1.0 - Metallic) + BaseColor * Metallic;
if (distribution == "GGX" || Roughness <= 0.075) {
BSDF = BSDF + specular_weight * microfacet_ggx_aniso_fresnel(Normal, T, alpha_x, alpha_y, (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, BaseColor, Cspec0);
} else {
BSDF = BSDF + specular_weight * microfacet_multi_ggx_aniso_fresnel(Normal, T, alpha_x, alpha_y, (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, BaseColor, Cspec0);
}
}
if (transp > 1e-5) {
color Cspec0 = BaseColor * SpecularTint + color(1.0, 1.0, 1.0) * (1.0 - SpecularTint);
float eta = backfacing() ? 1.0 / f : f;
if (distribution == "GGX" || Roughness <= 5e-2) {
float cosNO = dot(Normal, I);
float Fr = fresnel_dielectric_cos(cosNO, eta);
float refl_roughness = Roughness;
if (Roughness <= 1e-2)
refl_roughness = 0.0;
float refraction_roughness = refl_roughness;
if (distribution == "GGX")
refraction_roughness = 1.0 - (1.0 - refl_roughness) * (1.0 - RefractionRoughness);
BSDF = BSDF + transp * (Fr * microfacet_ggx_fresnel(Normal, refl_roughness * refl_roughness, eta, BaseColor, Cspec0) +
(1.0 - Fr) * BaseColor * microfacet_ggx_refraction(Normal, refraction_roughness * refraction_roughness, eta));
} else {
BSDF = BSDF + transp * microfacet_multi_ggx_glass_fresnel(Normal, Roughness * Roughness, eta, BaseColor, Cspec0);
}
}
if (Clearcoat > 1e-5) {
BSDF = BSDF + principled_clearcoat(ClearcoatNormal, Clearcoat, ClearcoatGloss);
}
}

View File

@ -530,6 +530,11 @@ 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_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN;
closure color microfacet_ggx_aniso_fresnel(normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN;
closure color microfacet_multi_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN;
closure color microfacet_multi_ggx_aniso_fresnel(normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN;
closure color microfacet_multi_ggx_glass_fresnel(normal N, float ag, float eta, color C, color Cspec0) 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;
@ -539,11 +544,15 @@ closure color emission() BUILTIN;
closure color background() BUILTIN;
closure color holdout() BUILTIN;
closure color ambient_occlusion() BUILTIN;
closure color principled_diffuse(normal N, float roughness) BUILTIN;
closure color principled_sheen(normal N) BUILTIN;
closure color principled_clearcoat(normal N, float clearcoat, float clearcoat_gloss) BUILTIN;
// BSSRDF
closure color bssrdf_cubic(normal N, vector radius, float texture_blur, float sharpness) BUILTIN;
closure color bssrdf_gaussian(normal N, vector radius, float texture_blur) BUILTIN;
closure color bssrdf_burley(normal N, vector radius, float texture_blur, color albedo) BUILTIN;
closure color bssrdf_principled(normal N, vector radius, float texture_blur, color subsurface_color, float roughness) BUILTIN;
// Hair
closure color hair_reflection(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;

View File

@ -122,7 +122,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao(
#ifdef __SHADOW_TRICKS__
if((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) {
if (state->flag & PATH_RAY_CAMERA) {
if(state->flag & PATH_RAY_CAMERA) {
state->flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_SHADOW_CATCHER_ONLY);
state->catcher_object = sd->object;
if(!kernel_data.background.transparent) {

View File

@ -76,6 +76,338 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __uint_as_float(node.w);
switch(type) {
case CLOSURE_BSDF_PRINCIPLED_ID: {
uint specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset, sheen_offset,
sheen_tint_offset, clearcoat_offset, clearcoat_gloss_offset, eta_offset, transparency_offset,
anisotropic_rotation_offset, refraction_roughness_offset;
uint4 data_node2 = read_node(kg, offset);
float3 T = stack_load_float3(stack, data_node.y);
decode_node_uchar4(data_node.z, &specular_offset, &roughness_offset, &specular_tint_offset, &anisotropic_offset);
decode_node_uchar4(data_node.w, &sheen_offset, &sheen_tint_offset, &clearcoat_offset, &clearcoat_gloss_offset);
decode_node_uchar4(data_node2.x, &eta_offset, &transparency_offset, &anisotropic_rotation_offset, &refraction_roughness_offset);
// get Disney principled parameters
float metallic = param1;
float subsurface = param2;
float specular = stack_load_float(stack, specular_offset);
float roughness = stack_load_float(stack, roughness_offset);
float specular_tint = stack_load_float(stack, specular_tint_offset);
float anisotropic = stack_load_float(stack, anisotropic_offset);
float sheen = stack_load_float(stack, sheen_offset);
float sheen_tint = stack_load_float(stack, sheen_tint_offset);
float clearcoat = stack_load_float(stack, clearcoat_offset);
float clearcoat_gloss = stack_load_float(stack, clearcoat_gloss_offset);
float transparency = stack_load_float(stack, transparency_offset);
float anisotropic_rotation = stack_load_float(stack, anisotropic_rotation_offset);
float refraction_roughness = stack_load_float(stack, refraction_roughness_offset);
float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f);
ClosureType distribution = stack_valid(data_node2.y) ? (ClosureType) data_node2.y : CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
/* rotate tangent */
if(anisotropic_rotation != 0.0f)
T = rotate_around_axis(T, N, anisotropic_rotation * M_2PI_F);
/* calculate ior */
float ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
// calculate fresnel for refraction
float cosNO = dot(N, sd->I);
float fresnel = fresnel_dielectric_cos(cosNO, ior);
// calculate weights of the diffuse and specular part
float diffuse_weight = (1.0f - saturate(metallic)) * (1.0f - saturate(transparency));
float transp = saturate(transparency) * (1.0f - saturate(metallic));
float specular_weight = (1.0f - transp);
// get the base color
uint4 data_base_color = read_node(kg, offset);
float3 base_color = stack_valid(data_base_color.x) ? stack_load_float3(stack, data_base_color.x) :
make_float3(__uint_as_float(data_base_color.y), __uint_as_float(data_base_color.z), __uint_as_float(data_base_color.w));
// get the additional clearcoat normal and subsurface scattering radius
uint4 data_cn_ssr = read_node(kg, offset);
float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ? stack_load_float3(stack, data_cn_ssr.x) : sd->N;
float3 subsurface_radius = stack_valid(data_cn_ssr.y) ? stack_load_float3(stack, data_cn_ssr.y) : make_float3(1.0f, 1.0f, 1.0f);
// get the subsurface color
uint4 data_subsurface_color = read_node(kg, offset);
float3 subsurface_color = stack_valid(data_subsurface_color.x) ? stack_load_float3(stack, data_subsurface_color.x) :
make_float3(__uint_as_float(data_subsurface_color.y), __uint_as_float(data_subsurface_color.z), __uint_as_float(data_subsurface_color.w));
float3 weight = sd->svm_closure_weight * mix_weight;
#ifdef __SUBSURFACE__
float3 albedo = subsurface_color * subsurface + base_color * (1.0f - subsurface);
float3 subsurf_weight = weight * albedo * diffuse_weight;
float subsurf_sample_weight = fabsf(average(subsurf_weight));
/* disable in case of diffuse ancestor, can't see it well then and
* adds considerably noise due to probabilities of continuing path
* getting lower and lower */
if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR) {
subsurface = 0.0f;
}
/* diffuse */
if(fabsf(average(base_color)) > CLOSURE_WEIGHT_CUTOFF) {
if(subsurface < CLOSURE_WEIGHT_CUTOFF && diffuse_weight > CLOSURE_WEIGHT_CUTOFF) {
float3 diff_weight = weight * base_color * diffuse_weight;
PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), diff_weight);
if(bsdf) {
bsdf->N = N;
bsdf->roughness = roughness;
/* setup bsdf */
sd->flag |= bsdf_principled_diffuse_setup(bsdf);
}
}
else if(subsurface > CLOSURE_WEIGHT_CUTOFF && subsurf_sample_weight > CLOSURE_WEIGHT_CUTOFF) {
/* radius * scale */
float3 radius = subsurface_radius * subsurface;
/* sharpness */
float sharpness = 0.0f;
/* texture color blur */
float texture_blur = 0.0f;
/* create one closure per color channel */
Bssrdf *bssrdf = bssrdf_alloc(sd, make_float3(subsurf_weight.x, 0.0f, 0.0f));
if(bssrdf) {
bssrdf->sample_weight = subsurf_sample_weight;
bssrdf->radius = radius.x;
bssrdf->texture_blur = texture_blur;
bssrdf->albedo = albedo.x;
bssrdf->sharpness = sharpness;
bssrdf->N = N;
bssrdf->roughness = roughness;
/* setup bsdf */
sd->flag |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID);
}
bssrdf = bssrdf_alloc(sd, make_float3(0.0f, subsurf_weight.y, 0.0f));
if(bssrdf) {
bssrdf->sample_weight = subsurf_sample_weight;
bssrdf->radius = radius.y;
bssrdf->texture_blur = texture_blur;
bssrdf->albedo = albedo.y;
bssrdf->sharpness = sharpness;
bssrdf->N = N;
bssrdf->roughness = roughness;
/* setup bsdf */
sd->flag |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID);
}
bssrdf = bssrdf_alloc(sd, make_float3(0.0f, 0.0f, subsurf_weight.z));
if(bssrdf) {
bssrdf->sample_weight = subsurf_sample_weight;
bssrdf->radius = radius.z;
bssrdf->texture_blur = texture_blur;
bssrdf->albedo = albedo.z;
bssrdf->sharpness = sharpness;
bssrdf->N = N;
bssrdf->roughness = roughness;
/* setup bsdf */
sd->flag |= bssrdf_setup(bssrdf, (ClosureType)CLOSURE_BSSRDF_PRINCIPLED_ID);
}
}
}
#else
/* diffuse */
if(diffuse_weight > CLOSURE_WEIGHT_CUTOFF) {
float3 diff_weight = weight * base_color * diffuse_weight;
PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), diff_weight);
if(bsdf) {
bsdf->N = N;
bsdf->roughness = roughness;
/* setup bsdf */
sd->flag |= bsdf_principled_diffuse_setup(bsdf);
}
}
#endif
/* sheen */
if(diffuse_weight > CLOSURE_WEIGHT_CUTOFF && sheen > CLOSURE_WEIGHT_CUTOFF) {
float m_cdlum = linear_rgb_to_gray(base_color);
float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : make_float3(1.0f, 1.0f, 1.0f); // normalize lum. to isolate hue+sat
/* color of the sheen component */
float3 sheen_color = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - sheen_tint) + m_ctint * sheen_tint;
float3 sheen_weight = weight * sheen * sheen_color * diffuse_weight;
PrincipledSheenBsdf *bsdf = (PrincipledSheenBsdf*)bsdf_alloc(sd, sizeof(PrincipledSheenBsdf), sheen_weight);
if(bsdf) {
bsdf->N = N;
/* setup bsdf */
sd->flag |= bsdf_principled_sheen_setup(bsdf);
}
}
/* specular reflection */
#ifdef __CAUSTICS_TRICKS__
if(kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) {
#endif
if(specular_weight > CLOSURE_WEIGHT_CUTOFF && (specular > CLOSURE_WEIGHT_CUTOFF || metallic > CLOSURE_WEIGHT_CUTOFF)) {
float3 spec_weight = weight * specular_weight;
MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), spec_weight);
MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
if(bsdf && extra) {
bsdf->N = N;
bsdf->ior = (2.0f / (1.0f - safe_sqrtf(0.08f * specular))) - 1.0f;
bsdf->T = T;
bsdf->extra = extra;
float aspect = safe_sqrtf(1.0f - anisotropic * 0.9f);
float r2 = roughness * roughness;
bsdf->alpha_x = fmaxf(0.001f, r2 / aspect);
bsdf->alpha_y = fmaxf(0.001f, r2 * aspect);
float m_cdlum = 0.3f * base_color.x + 0.6f * base_color.y + 0.1f * base_color.z; // luminance approx.
float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : make_float3(0.0f, 0.0f, 0.0f); // normalize lum. to isolate hue+sat
float3 tmp_col = make_float3(1.0f, 1.0f, 1.0f) * (1.0f - specular_tint) + m_ctint * specular_tint;
bsdf->extra->cspec0 = (specular * 0.08f * tmp_col) * (1.0f - metallic) + base_color * metallic;
bsdf->extra->color = base_color;
/* setup bsdf */
if(distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID || roughness <= 0.075f) /* use single-scatter GGX */
sd->flag |= bsdf_microfacet_ggx_aniso_fresnel_setup(bsdf);
else /* use multi-scatter GGX */
sd->flag |= bsdf_microfacet_multi_ggx_aniso_fresnel_setup(bsdf);
}
}
#ifdef __CAUSTICS_TRICKS__
}
#endif
/* BSDF */
#ifdef __CAUSTICS_TRICKS__
if(kernel_data.integrator.caustics_reflective || kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) {
#endif
if(transp > CLOSURE_WEIGHT_CUTOFF) {
float3 glass_weight = weight * transp;
float3 cspec0 = base_color * specular_tint + make_float3(1.0f, 1.0f, 1.0f) * (1.0f - specular_tint);
if(roughness <= 5e-2f || distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) { /* use single-scatter GGX */
float refl_roughness = roughness;
/* reflection */
#ifdef __CAUSTICS_TRICKS__
if(kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0)
#endif
{
MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), glass_weight*fresnel);
MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
if(bsdf && extra) {
bsdf->N = N;
bsdf->extra = extra;
bsdf->alpha_x = refl_roughness * refl_roughness;
bsdf->alpha_y = refl_roughness * refl_roughness;
bsdf->ior = ior;
bsdf->extra->color = base_color;
bsdf->extra->cspec0 = cspec0;
/* setup bsdf */
sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf);
}
}
/* refraction */
#ifdef __CAUSTICS_TRICKS__
if(kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0)
#endif
{
MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), base_color*glass_weight*(1.0f - fresnel));
if(bsdf) {
bsdf->N = N;
if(distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID)
refraction_roughness = 1.0f - (1.0f - refl_roughness) * (1.0f - refraction_roughness);
else
refraction_roughness = refl_roughness;
bsdf->alpha_x = refraction_roughness * refraction_roughness;
bsdf->alpha_y = refraction_roughness * refraction_roughness;
bsdf->ior = ior;
/* setup bsdf */
sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf);
}
}
}
else { /* use multi-scatter GGX */
MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), glass_weight);
MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
if(bsdf && extra) {
bsdf->N = N;
bsdf->extra = extra;
bsdf->T = make_float3(0.0f, 0.0f, 0.0f);
bsdf->alpha_x = roughness * roughness;
bsdf->alpha_y = roughness * roughness;
bsdf->ior = ior;
bsdf->extra->color = base_color;
bsdf->extra->cspec0 = cspec0;
/* setup bsdf */
sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf);
}
}
}
#ifdef __CAUSTICS_TRICKS__
}
#endif
/* clearcoat */
#ifdef __CAUSTICS_TRICKS__
if(kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) {
#endif
if(clearcoat > CLOSURE_WEIGHT_CUTOFF) {
MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), weight);
MicrofacetExtra *extra = (MicrofacetExtra*)closure_alloc_extra(sd, sizeof(MicrofacetExtra));
if(bsdf && extra) {
bsdf->N = clearcoat_normal;
bsdf->ior = 1.5f;
bsdf->extra = extra;
bsdf->alpha_x = 0.1f * (1.0f - clearcoat_gloss) + 0.001f * clearcoat_gloss;
bsdf->alpha_y = 0.1f * (1.0f - clearcoat_gloss) + 0.001f * clearcoat_gloss;
bsdf->extra->cspec0 = make_float3(0.04f, 0.04f, 0.04f);
bsdf->extra->clearcoat = clearcoat;
/* setup bsdf */
sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf);
}
}
#ifdef __CAUSTICS_TRICKS__
}
#endif
break;
}
case CLOSURE_BSDF_DIFFUSE_ID: {
float3 weight = sd->svm_closure_weight * mix_weight;
OrenNayarBsdf *bsdf = (OrenNayarBsdf*)bsdf_alloc(sd, sizeof(OrenNayarBsdf), weight);

View File

@ -397,17 +397,24 @@ typedef enum ClosureType {
CLOSURE_BSDF_DIFFUSE_ID,
CLOSURE_BSDF_OREN_NAYAR_ID,
CLOSURE_BSDF_DIFFUSE_RAMP_ID,
CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID,
CLOSURE_BSDF_PRINCIPLED_SHEEN_ID,
CLOSURE_BSDF_DIFFUSE_TOON_ID,
/* Glossy */
CLOSURE_BSDF_GLOSSY_ID,
CLOSURE_BSDF_REFLECTION_ID,
CLOSURE_BSDF_MICROFACET_GGX_ID,
CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID,
CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID,
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID,
CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID,
CLOSURE_BSDF_MICROFACET_GGX_ANISO_FRESNEL_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_FRESNEL_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID,
CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID,
CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
@ -424,16 +431,19 @@ typedef enum ClosureType {
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID,
CLOSURE_BSDF_SHARP_GLASS_ID,
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
/* Special cases */
CLOSURE_BSDF_BSSRDF_ID,
CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID,
CLOSURE_BSDF_TRANSPARENT_ID,
/* BSSRDF */
CLOSURE_BSSRDF_CUBIC_ID,
CLOSURE_BSSRDF_GAUSSIAN_ID,
CLOSURE_BSSRDF_PRINCIPLED_ID,
CLOSURE_BSSRDF_BURLEY_ID,
/* Other */
@ -447,6 +457,8 @@ typedef enum ClosureType {
CLOSURE_VOLUME_ABSORPTION_ID,
CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID,
CLOSURE_BSDF_PRINCIPLED_ID,
NBUILTIN_CLOSURES
} ClosureType;
@ -455,7 +467,7 @@ typedef enum ClosureType {
#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_GLOSSY_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID)
#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
#define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID)
#define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID || type == CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID)
#define CLOSURE_IS_BSDF_ANISOTROPIC(type) (type >= CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID)
#define CLOSURE_IS_BSDF_MULTISCATTER(type) (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID ||\
type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID || \
@ -469,6 +481,7 @@ typedef enum ClosureType {
#define CLOSURE_IS_AMBIENT_OCCLUSION(type) (type == CLOSURE_AMBIENT_OCCLUSION_ID)
#define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
#define CLOSURE_IS_GLASS(type) (type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID)
#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID)
#define CLOSURE_WEIGHT_CUTOFF 1e-5f

View File

@ -423,7 +423,8 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
/* Graph simplification */
/* ******************** */
/* Step 1: Remove proxy nodes.
/* Remove proxy nodes.
*
* These only exists temporarily when exporting groups, and we must remove them
* early so that node->attributes() and default links do not see them.
*/
@ -493,7 +494,8 @@ void ShaderGraph::remove_proxy_nodes()
}
}
/* Step 2: Constant folding.
/* Constant folding.
*
* Try to constant fold some nodes, and pipe result directly to
* the input socket of connected nodes.
*/
@ -554,7 +556,7 @@ void ShaderGraph::constant_fold()
}
}
/* Step 3: Simplification. */
/* Simplification. */
void ShaderGraph::simplify_settings(Scene *scene)
{
foreach(ShaderNode *node, nodes) {
@ -562,7 +564,7 @@ void ShaderGraph::simplify_settings(Scene *scene)
}
}
/* Step 4: Deduplicate nodes with same settings. */
/* Deduplicate nodes with same settings. */
void ShaderGraph::deduplicate_nodes()
{
/* NOTES:
@ -638,6 +640,48 @@ void ShaderGraph::deduplicate_nodes()
}
}
/* Check whether volume output has meaningful nodes, otherwise
* disconnect the output.
*/
void ShaderGraph::verify_volume_output()
{
/* Check whether we can optimize the whole volume graph out. */
ShaderInput *volume_in = output()->input("Volume");
if(volume_in->link == NULL) {
return;
}
bool has_valid_volume = false;
ShaderNodeSet scheduled;
queue<ShaderNode*> traverse_queue;
/* Schedule volume output. */
traverse_queue.push(volume_in->link->parent);
scheduled.insert(volume_in->link->parent);
/* Traverse down the tree. */
while(!traverse_queue.empty()) {
ShaderNode *node = traverse_queue.front();
traverse_queue.pop();
/* Node is fully valid for volume, can't optimize anything out. */
if(node->has_volume_support()) {
has_valid_volume = true;
break;
}
foreach(ShaderInput *input, node->inputs) {
if(input->link == NULL) {
continue;
}
if(scheduled.find(input->link->parent) != scheduled.end()) {
continue;
}
traverse_queue.push(input->link->parent);
scheduled.insert(input->link->parent);
}
}
if(!has_valid_volume) {
VLOG(1) << "Disconnect meaningless volume output.";
disconnect(volume_in->link);
}
}
void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack)
{
visited[node->id] = true;
@ -666,16 +710,11 @@ void ShaderGraph::clean(Scene *scene)
{
/* Graph simplification */
/* 1: Remove proxy nodes was already done. */
/* 2: Constant folding. */
/* NOTE: Remove proxy nodes was already done. */
constant_fold();
/* 3: Simplification. */
simplify_settings(scene);
/* 4: De-duplication. */
deduplicate_nodes();
verify_volume_output();
/* we do two things here: find cycles and break them, and remove unused
* nodes that don't feed into the output. how cycles are broken is
@ -998,6 +1037,9 @@ int ShaderGraph::get_num_closures()
else if(CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) {
num_closures += 2;
}
else if(CLOSURE_IS_PRINCIPLED(closure_type)) {
num_closures += 8;
}
else {
++num_closures;
}

View File

@ -155,7 +155,7 @@ public:
virtual bool has_spatial_varying() { return false; }
virtual bool has_object_dependency() { return false; }
virtual bool has_integrator_dependency() { return false; }
virtual bool has_volume_support() { return false; }
vector<ShaderInput*> inputs;
vector<ShaderOutput*> outputs;
@ -284,6 +284,7 @@ protected:
void constant_fold();
void simplify_settings(Scene *scene);
void deduplicate_nodes();
void verify_volume_output();
};
CCL_NAMESPACE_END

View File

@ -2286,6 +2286,150 @@ void DiffuseBsdfNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_diffuse_bsdf");
}
/* Disney principled BSDF Closure */
NODE_DEFINE(PrincipledBsdfNode)
{
NodeType* type = NodeType::add("principled_bsdf", create, NodeType::SHADER);
static NodeEnum distribution_enum;
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_MULTI_GGX_GLASS_ID);
SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_COLOR(subsurface_color, "Subsurface Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f);
SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f);
SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f));
SOCKET_IN_FLOAT(specular, "Specular", 0.0f);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f);
SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f);
SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f);
SOCKET_IN_FLOAT(sheen_tint, "Sheen Tint", 0.0f);
SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f);
SOCKET_IN_FLOAT(clearcoat_gloss, "Clearcoat Gloss", 0.0f);
SOCKET_IN_FLOAT(ior, "IOR", 0.0f);
SOCKET_IN_FLOAT(transparency, "Transparency", 0.0f);
SOCKET_IN_FLOAT(refraction_roughness, "Refraction Roughness", 0.0f);
SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f);
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_NORMAL(clearcoat_normal, "Clearcoat Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
SOCKET_IN_NORMAL(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
PrincipledBsdfNode::PrincipledBsdfNode()
: ShaderNode(node_type)
{
special_type = SHADER_SPECIAL_TYPE_CLOSURE;
closure = CLOSURE_BSDF_PRINCIPLED_ID;
distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
distribution_orig = NBUILTIN_CLOSURES;
}
void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
ShaderInput *tangent_in = input("Tangent");
if(!tangent_in->link)
attributes->add(ATTR_STD_GENERATED);
}
ShaderNode::attributes(shader, attributes);
}
void PrincipledBsdfNode::compile(SVMCompiler& compiler, ShaderInput *p_metallic, ShaderInput *p_subsurface, ShaderInput *p_subsurface_radius,
ShaderInput *p_specular, ShaderInput *p_roughness, ShaderInput *p_specular_tint, ShaderInput *p_anisotropic,
ShaderInput *p_sheen, ShaderInput *p_sheen_tint, ShaderInput *p_clearcoat, ShaderInput *p_clearcoat_gloss,
ShaderInput *p_ior, ShaderInput *p_transparency, ShaderInput *p_anisotropic_rotation, ShaderInput *p_refraction_roughness)
{
ShaderInput *base_color_in = input("Base Color");
ShaderInput *subsurface_color_in = input("Subsurface Color");
ShaderInput *normal_in = input("Normal");
ShaderInput *clearcoat_normal_in = input("Clearcoat Normal");
ShaderInput *tangent_in = input("Tangent");
float3 weight = make_float3(1.0f, 1.0f, 1.0f);
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight);
int normal_offset = compiler.stack_assign_if_linked(normal_in);
int clearcoat_normal_offset = compiler.stack_assign_if_linked(clearcoat_normal_in);
int tangent_offset = compiler.stack_assign_if_linked(tangent_in);
int specular_offset = compiler.stack_assign(p_specular);
int roughness_offset = compiler.stack_assign(p_roughness);
int specular_tint_offset = compiler.stack_assign(p_specular_tint);
int anisotropic_offset = compiler.stack_assign(p_anisotropic);
int sheen_offset = compiler.stack_assign(p_sheen);
int sheen_tint_offset = compiler.stack_assign(p_sheen_tint);
int clearcoat_offset = compiler.stack_assign(p_clearcoat);
int clearcoat_gloss_offset = compiler.stack_assign(p_clearcoat_gloss);
int ior_offset = compiler.stack_assign(p_ior);
int transparency_offset = compiler.stack_assign(p_transparency);
int refraction_roughness_offset = compiler.stack_assign(p_refraction_roughness);
int anisotropic_rotation_offset = compiler.stack_assign(p_anisotropic_rotation);
int subsurface_radius_offset = compiler.stack_assign(p_subsurface_radius);
compiler.add_node(NODE_CLOSURE_BSDF,
compiler.encode_uchar4(closure,
compiler.stack_assign(p_metallic),
compiler.stack_assign(p_subsurface),
compiler.closure_mix_weight_offset()),
__float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f),
__float_as_int((p_subsurface) ? get_float(p_subsurface->socket_type) : 0.0f));
compiler.add_node(normal_offset, tangent_offset,
compiler.encode_uchar4(specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset),
compiler.encode_uchar4(sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_gloss_offset));
compiler.add_node(compiler.encode_uchar4(ior_offset, transparency_offset, anisotropic_rotation_offset, refraction_roughness_offset),
distribution, SVM_STACK_INVALID, SVM_STACK_INVALID);
float3 bc_default = get_float3(base_color_in->socket_type);
compiler.add_node(((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID),
__float_as_int(bc_default.x), __float_as_int(bc_default.y), __float_as_int(bc_default.z));
compiler.add_node(clearcoat_normal_offset, subsurface_radius_offset, SVM_STACK_INVALID, SVM_STACK_INVALID);
float3 ss_default = get_float3(subsurface_color_in->socket_type);
compiler.add_node(((subsurface_color_in->link) ? compiler.stack_assign(subsurface_color_in) : SVM_STACK_INVALID),
__float_as_int(ss_default.x), __float_as_int(ss_default.y), __float_as_int(ss_default.z));
}
bool PrincipledBsdfNode::has_integrator_dependency()
{
ShaderInput *roughness_input = input("Roughness");
return !roughness_input->link && roughness <= 1e-4f;
}
void PrincipledBsdfNode::compile(SVMCompiler& compiler)
{
compile(compiler, input("Metallic"), input("Subsurface"), input("Subsurface Radius"), input("Specular"),
input("Roughness"), input("Specular Tint"), input("Anisotropic"), input("Sheen"), input("Sheen Tint"),
input("Clearcoat"), input("Clearcoat Gloss"), input("IOR"), input("Transparency"),
input("Anisotropic Rotation"), input("Refraction Roughness"));
}
void PrincipledBsdfNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "distribution");
compiler.add(this, "node_principled_bsdf");
}
bool PrincipledBsdfNode::has_bssrdf_bump()
{
/* detect if anything is plugged into the normal input besides the default */
ShaderInput *normal_in = input("Normal");
return (normal_in->link && normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
}
/* Translucent BSDF Closure */
NODE_DEFINE(TranslucentBsdfNode)

View File

@ -361,6 +361,39 @@ public:
float roughness;
};
/* Disney principled BRDF */
class PrincipledBsdfNode : public ShaderNode {
public:
SHADER_NODE_CLASS(PrincipledBsdfNode)
bool has_spatial_varying() { return true; }
bool has_surface_bssrdf() { return true; }
bool has_bssrdf_bump();
void compile(SVMCompiler& compiler, ShaderInput *metallic, ShaderInput *subsurface, ShaderInput *subsurface_radius,
ShaderInput *specular, ShaderInput *roughness, ShaderInput *specular_tint, ShaderInput *anisotropic,
ShaderInput *sheen, ShaderInput *sheen_tint, ShaderInput *clearcoat, ShaderInput *clearcoat_gloss,
ShaderInput *ior, ShaderInput *transparency, ShaderInput *anisotropic_rotation, ShaderInput *refraction_roughness);
float3 base_color;
float3 subsurface_color, subsurface_radius;
float metallic, subsurface, specular, roughness, specular_tint, anisotropic,
sheen, sheen_tint, clearcoat, clearcoat_gloss, ior, transparency,
anisotropic_rotation, refraction_roughness;
float3 normal, clearcoat_normal, tangent;
float surface_mix_weight;
ClosureType closure, distribution, distribution_orig;
virtual bool equals(const ShaderNode * /*other*/)
{
/* TODO(sergey): With some care BSDF nodes can be de-duplicated. */
return false;
}
ClosureType get_closure_type() { return closure; }
bool has_integrator_dependency();
void attributes(Shader *shader, AttributeRequestSet *attributes);
};
class TranslucentBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(TranslucentBsdfNode)
@ -445,6 +478,7 @@ public:
virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; }
bool has_surface_emission() { return true; }
bool has_volume_support() { return true; }
float3 color;
float strength;
@ -496,6 +530,7 @@ public:
return ShaderNode::get_feature() | NODE_FEATURE_VOLUME;
}
virtual ClosureType get_closure_type() { return closure; }
virtual bool has_volume_support() { return true; }
float3 color;
float density;

View File

@ -1238,7 +1238,6 @@ class CLIP_MT_view(Menu):
layout.prop(sc, "show_seconds")
layout.prop(sc, "show_locked_time")
layout.separator()
layout.separator()
layout.operator("screen.area_dupli")

View File

@ -1677,7 +1677,7 @@ class VIEW3D_MT_brush(Menu):
layout = self.layout
settings = UnifiedPaintPanel.paint_settings(context)
brush = settings.brush
brush = getattr(settings, "brush", None)
ups = context.tool_settings.unified_paint_settings
layout.prop(ups, "use_unified_size", text="Unified Size")
@ -1686,6 +1686,11 @@ class VIEW3D_MT_brush(Menu):
layout.prop(ups, "use_unified_color", text="Unified Color")
layout.separator()
# skip if no active brush
if not brush:
layout.label(text="No Brushes currently available", icon="INFO")
return
# brush paint modes
layout.menu("VIEW3D_MT_brush_paint_modes")
@ -1698,10 +1703,6 @@ class VIEW3D_MT_brush(Menu):
elif context.vertex_paint_object or context.weight_paint_object:
layout.prop_menu_enum(brush, "vertex_tool")
# skip if no active brush
if not brush:
return
# TODO: still missing a lot of brush options here
# sculpt options

View File

@ -157,6 +157,7 @@ shader_node_categories = [
NodeItem("ShaderNodeGeometry"),
NodeItem("ShaderNodeExtendedMaterial"),
NodeItem("ShaderNodeParticleInfo"),
NodeItem("ShaderNodeObjectInfo"),
NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
]),
ShaderOldNodeCategory("SH_OUTPUT", "Output", items=[
@ -225,6 +226,7 @@ shader_node_categories = [
NodeItem("ShaderNodeMixShader"),
NodeItem("ShaderNodeAddShader"),
NodeItem("ShaderNodeBsdfDiffuse", poll=object_shader_nodes_poll),
NodeItem("ShaderNodeBsdfPrincipled", poll=object_shader_nodes_poll),
NodeItem("ShaderNodeBsdfGlossy", poll=object_shader_nodes_poll),
NodeItem("ShaderNodeBsdfTransparent", poll=object_shader_nodes_poll),
NodeItem("ShaderNodeBsdfRefraction", poll=object_shader_nodes_poll),

View File

@ -95,7 +95,7 @@ void AbcCurveWriter::do_write()
for (; nurbs; nurbs = nurbs->next) {
if (nurbs->bp) {
curve_basis = Alembic::AbcGeom::kNoBasis;
curve_type = Alembic::AbcGeom::kLinear;
curve_type = Alembic::AbcGeom::kVariableOrder;
const int totpoint = nurbs->pntsu * nurbs->pntsv;
@ -160,7 +160,7 @@ void AbcCurveWriter::do_write()
}
}
orders.push_back(nurbs->orderu + 1);
orders.push_back(nurbs->orderu);
vert_counts.push_back(verts.size());
}
@ -258,8 +258,8 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
case Alembic::AbcGeom::kVariableOrder:
if (orders && orders->size() > i) {
nu->orderu = static_cast<short>((*orders)[i]);
break;
}
break;
case Alembic::AbcGeom::kLinear:
default:
nu->orderu = 2;

View File

@ -290,13 +290,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index);
if (m_settings.flatten_hierarchy) {
createTransformWritersFlat();
}
else {
createTransformWritersHierarchy(bmain->eval_ctx);
}
createTransformWritersHierarchy(bmain->eval_ctx);
createShapeWriters(bmain->eval_ctx);
/* Make a list of frames to export. */
@ -381,20 +375,6 @@ void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
}
}
void AbcExporter::createTransformWritersFlat()
{
for (Base *base = static_cast<Base *>(m_settings.sl->object_bases.first); base; base = base->next) {
Object *ob = base->object;
if (export_object(&m_settings, base, false) && object_is_shape(ob)) {
std::string name = get_id_name(ob);
m_xforms[name] = new AbcTransformWriter(
ob, m_writer->archive().getTop(), NULL,
m_trans_sampling_index, m_settings);
}
}
}
void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Base *ob_base, Object *parent, Object *dupliObParent)
{
Object *ob = ob_base->object;
@ -440,12 +420,18 @@ void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Base *ob_base, O
AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
{
const std::string name = get_object_dag_path_name(ob, dupliObParent);
/* An object should not be its own parent, or we'll get infinite loops. */
BLI_assert(ob != parent);
BLI_assert(ob != dupliObParent);
std::string name;
if (m_settings.flatten_hierarchy) {
name = get_id_name(ob);
}
else {
name = get_object_dag_path_name(ob, dupliObParent);
}
/* check if we have already created a transform writer for this object */
AbcTransformWriter *my_writer = getXForm(name);
if (my_writer != NULL){
@ -455,13 +441,23 @@ AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *pare
AbcTransformWriter *parent_writer = NULL;
Alembic::Abc::OObject alembic_parent;
if (parent) {
if (m_settings.flatten_hierarchy || parent == NULL) {
/* Parentless objects still have the "top object" as parent
* in Alembic. */
alembic_parent = m_writer->archive().getTop();
}
else {
/* Since there are so many different ways to find parents (as evident
* in the number of conditions below), we can't really look up the
* parent by name. We'll just call createTransformWriter(), which will
* return the parent's AbcTransformWriter pointer. */
if (parent->parent) {
parent_writer = createTransformWriter(parent, parent->parent, dupliObParent);
if (parent == dupliObParent) {
parent_writer = createTransformWriter(parent, parent->parent, NULL);
}
else {
parent_writer = createTransformWriter(parent, parent->parent, dupliObParent);
}
}
else if (parent == dupliObParent) {
if (dupliObParent->parent == NULL) {
@ -478,14 +474,15 @@ AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *pare
BLI_assert(parent_writer);
alembic_parent = parent_writer->alembicXform();
}
else {
/* Parentless objects still have the "top object" as parent
* in Alembic. */
alembic_parent = m_writer->archive().getTop();
}
my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer,
m_trans_sampling_index, m_settings);
/* When flattening, the matrix of the dupliobject has to be added. */
if (m_settings.flatten_hierarchy && dupliObParent) {
my_writer->m_proxy_from = dupliObParent;
}
m_xforms[name] = my_writer;
return my_writer;
}

View File

@ -112,7 +112,6 @@ private:
void getFrameSet(double step, std::set<double> &frames);
void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
void createTransformWritersFlat();
AbcTransformWriter * createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
void exploreTransform(EvaluationContext *eval_ctx, Base *ob_base, Object *parent, Object *dupliObParent);
void exploreObject(EvaluationContext *eval_ctx, Base *ob_base, Object *dupliObParent);

View File

@ -62,6 +62,7 @@ AbcTransformWriter::AbcTransformWriter(Object *ob,
unsigned int time_sampling,
ExportSettings &settings)
: AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
, m_proxy_from(NULL)
{
m_is_animated = hasAnimation(m_object);
@ -90,7 +91,8 @@ void AbcTransformWriter::do_write()
float yup_mat[4][4];
create_transform_matrix(m_object, yup_mat,
m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD);
m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD,
m_proxy_from);
/* Only apply rotation to root camera, parenting will propagate it. */
if (m_object->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(m_object))) {

View File

@ -40,6 +40,9 @@ class AbcTransformWriter : public AbcObjectWriter {
bool m_visible;
bool m_inherits_xform;
public:
Object *m_proxy_from;
public:
AbcTransformWriter(Object *ob,
const Alembic::AbcGeom::OObject &abc_parent,

View File

@ -245,7 +245,8 @@ void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4])
/* Recompute transform matrix of object in new coordinate system
* (from Z-Up to Y-Up). */
void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode mode)
void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode mode,
Object *proxy_from)
{
float zup_mat[4][4];
@ -255,11 +256,16 @@ void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode m
* constraints and modifiers as well as the obj->parentinv matrix. */
invert_m4_m4(obj->parent->imat, obj->parent->obmat);
mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat);
copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP);
}
else {
copy_m44_axis_swap(r_yup_mat, obj->obmat, ABC_YUP_FROM_ZUP);
copy_m4_m4(zup_mat, obj->obmat);
}
if (proxy_from) {
mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat);
}
copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP);
}
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)

View File

@ -62,7 +62,8 @@ typedef enum {
ABC_MATRIX_WORLD = 1,
ABC_MATRIX_LOCAL = 2,
} AbcMatrixMode;
void create_transform_matrix(Object *obj, float r_transform_mat[4][4], AbcMatrixMode mode);
void create_transform_matrix(Object *obj, float r_transform_mat[4][4],
AbcMatrixMode mode, Object *proxy_from);
void split(const std::string &s, const char delim, std::vector<std::string> &tokens);

View File

@ -176,6 +176,7 @@ void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx,
struct bPoseChannel *pchan);
void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob,
struct bPoseChannel *pchan);

View File

@ -792,6 +792,7 @@ struct ShadeResult;
#define SH_NODE_OUTPUT_LINESTYLE 190
#define SH_NODE_UVALONGSTROKE 191
#define SH_NODE_TEX_POINTDENSITY 192
#define SH_NODE_BSDF_PRINCIPLED 193
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1

View File

@ -621,10 +621,10 @@ void BKE_pose_eval_bone(struct EvaluationContext *UNUSED(eval_ctx),
}
void BKE_pose_constraints_evaluate(struct EvaluationContext *UNUSED(eval_ctx),
Scene *scene,
Object *ob,
bPoseChannel *pchan)
{
Scene *scene = G.main->scene.first;
DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name);
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {

View File

@ -2216,8 +2216,10 @@ void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf)
ibuf->foptions.flag |= OPENEXR_HALF;
ibuf->foptions.flag |= (imf->exr_codec & OPENEXR_COMPRESS);
if (!(imf->flag & R_IMF_FLAG_ZBUF))
ibuf->zbuf_float = NULL; /* signal for exr saving */
if (!(imf->flag & R_IMF_FLAG_ZBUF)) {
/* Signal for exr saving. */
IMB_freezbuffloatImBuf(ibuf);
}
}
#endif

View File

@ -3568,6 +3568,7 @@ static void registerShaderNodes(void)
register_node_type_sh_background();
register_node_type_sh_bsdf_anisotropic();
register_node_type_sh_bsdf_diffuse();
register_node_type_sh_bsdf_principled();
register_node_type_sh_bsdf_glossy();
register_node_type_sh_bsdf_glass();
register_node_type_sh_bsdf_translucent();

View File

@ -64,6 +64,7 @@
#include "DEG_depsgraph.h"
#include "BLI_strict_flags.h"
#include "BLI_hash.h"
/* Dupli-Geometry */
@ -180,6 +181,22 @@ static DupliObject *make_dupli(const DupliContext *ctx,
if (ob->type == OB_MBALL)
dob->no_draw = true;
/* random number */
/* the logic here is designed to match Cycles */
dob->random_id = BLI_hash_string(dob->ob->id.name + 2);
if (dob->persistent_id[0] != INT_MAX) {
for(i = 0; i < MAX_DUPLI_RECUR*2; i++)
dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]);
}
else {
dob->random_id = BLI_hash_int_2d(dob->random_id, 0);
}
if (ctx->object != ob) {
dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2));
}
return dob;
}

View File

@ -0,0 +1,66 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BLI_HASH_H__
#define __BLI_HASH_H__
/** \file BLI_hash.h
* \ingroup bli
*/
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
{
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
unsigned int a, b, c;
a = b = c = 0xdeadbeef + (2 << 2) + 13;
a += kx;
b += ky;
c ^= b; c -= rot(b,14);
a ^= c; a -= rot(c,11);
b ^= a; b -= rot(a,25);
c ^= b; c -= rot(b,16);
a ^= c; a -= rot(c,4);
b ^= a; b -= rot(a,14);
c ^= b; c -= rot(b,24);
return c;
#undef rot
}
BLI_INLINE unsigned int BLI_hash_string(const char *str)
{
unsigned int i = 0, c;
while((c = *str++))
i = i * 37 + c;
return i;
}
BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
{
return BLI_hash_int_2d(k, 0);
}
#endif // __BLI_HASH_H__

View File

@ -44,7 +44,7 @@ void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
void BLI_make_exist(char *dir);
void BLI_make_existing_file(const char *name);
bool BLI_make_existing_file(const char *name);
void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen);
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen);
void BLI_split_file_part(const char *string, char *file, const size_t filelen);

View File

@ -152,6 +152,7 @@ set(SRC
BLI_ghash.h
BLI_graph.h
BLI_gsqueue.h
BLI_hash.h
BLI_hash_md5.h
BLI_hash_mm2a.h
BLI_heap.h

View File

@ -1234,14 +1234,16 @@ void BLI_make_exist(char *dir)
/**
* Ensures that the parent directory of *name exists.
*
* \return true on success (i.e. given path now exists on FS), false otherwise.
*/
void BLI_make_existing_file(const char *name)
bool BLI_make_existing_file(const char *name)
{
char di[FILE_MAX];
BLI_split_dir_part(name, di, sizeof(di));
/* make if the dir doesn't exist */
BLI_dir_create_recursive(di);
return BLI_dir_create_recursive(di);
}
/**

View File

@ -130,7 +130,7 @@ struct DepsgraphNodeBuilder {
void build_object(Scene *scene, Object *ob);
void build_object_transform(Scene *scene, Object *ob);
void build_object_constraints(Scene *scene, Object *ob);
void build_pose_constraints(Object *ob, bPoseChannel *pchan);
void build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan);
void build_rigidbody(Scene *scene);
void build_particles(Scene *scene, Object *ob);
void build_cloth(Scene *scene, Object *object);

View File

@ -64,11 +64,12 @@ extern "C" {
namespace DEG {
void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
void DepsgraphNodeBuilder::build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan)
{
/* create node for constraint stack */
add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
DEPSOP_TYPE_EXEC,
function_bind(BKE_pose_constraints_evaluate, _1, scene, ob, pchan),
DEG_OPCODE_BONE_CONSTRAINTS);
}
@ -201,7 +202,7 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
/* constraints */
if (pchan->constraints.first != NULL) {
build_pose_constraints(ob, pchan);
build_pose_constraints(scene, ob, pchan);
}
/**

View File

@ -6049,6 +6049,9 @@ int join_curve_exec(bContext *C, wmOperator *op)
cu = ob->data;
BLI_movelisttolist(&cu->nurb, &tempbase);
/* Account for mixed 2D/3D curves when joining */
BKE_curve_curve_dimension_update(cu);
DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode!
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);

View File

@ -486,7 +486,8 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
bGPdata *gpd = p->gpd;
bGPDbrush *brush = p->brush;
tGPspoint *pt;
ToolSettings *ts = p->scene->toolsettings;
/* check painting mode */
if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
/* straight lines only - i.e. only store start and end point in buffer */
@ -638,7 +639,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
View3D *v3d = p->sa->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->ar);
ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
ED_view3d_autodist_init(p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
@ -758,7 +759,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
int depth_margin = (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 4 : 0;
int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
/* get total number of points to allocate space for
* - drawing straight-lines only requires the endpoints
@ -912,7 +913,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
depth_arr[i] = 0.9999f;
}
else {
if (p->gpd->flag & GP_DATA_DEPTH_STROKE_ENDPOINTS) {
if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) {
/* remove all info between the valid endpoints */
int first_valid = 0;
int last_valid = 0;
@ -1797,6 +1798,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
static void gp_paint_strokeend(tGPsdata *p)
{
ToolSettings *ts = p->scene->toolsettings;
/* for surface sketching, need to set the right OpenGL context stuff so that
* the conversions will project the values correctly...
*/
@ -1805,7 +1807,7 @@ static void gp_paint_strokeend(tGPsdata *p)
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->ar);
ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
ED_view3d_autodist_init(p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0);
}
/* check if doing eraser or not */

View File

@ -631,71 +631,63 @@ static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDom
#define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp")
#define FLUID_SUFFIX_SURFACE "fluidsurface"
static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetFile, char *debugStrBuffer)
static bool fluid_init_filepaths(
ReportList *reports, FluidsimSettings *domainSettings, Object *fsDomain,
char *targetDir, char *targetFile)
{
FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
FluidsimSettings *domainSettings= fluidmd->fss;
FILE *fileCfg;
int dirExist = 0;
char newSurfdataPath[FILE_MAX]; /* modified output settings */
const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
int outStringsChanged = 0;
/* prepare names... */
const char *relbase= modifier_path_relbase(fsDomain);
const char *relbase = modifier_path_relbase(fsDomain);
/* We do not accept empty paths, they can end in random places silently, see T51176. */
if (domainSettings->surfdataPath[0] == '\0') {
modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath),
OB_FLUIDSIM_SURF_DIR_DEFAULT);
BKE_reportf(reports, RPT_WARNING, "Fluidsim: empty cache path, reset to default '%s'",
domainSettings->surfdataPath);
}
BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
BLI_strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); /* if 0'd out below, this value is never used! */
BLI_path_abs(targetDir, relbase); /* fixed #frame-no */
BLI_path_abs(targetDir, relbase);
/* .tmp: don't overwrite/delete original file */
BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
// make sure all directories exist
// as the bobjs use the same dir, this only needs to be checked
// for the cfg output
BLI_make_existing_file(targetFile);
// check selected directory
// simply try to open cfg file for writing to test validity of settings
fileCfg = BLI_fopen(targetFile, "w");
if (fileCfg) {
dirExist = 1; fclose(fileCfg);
// remove cfg dummy from directory test
BLI_delete(targetFile, false, false);
/* Ensure whole path exists and is wirtable. */
const bool dir_exists = BLI_dir_create_recursive(targetDir);
const bool is_writable = BLI_file_is_writable(targetFile);
/* We change path to some presumably valid default value, but do not allow bake process to continue,
* this gives user chance to set manually another path. */
if (!dir_exists || !is_writable) {
modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath),
OB_FLUIDSIM_SURF_DIR_DEFAULT);
if (!dir_exists) {
BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not create cache directory '%s', reset to default '%s'",
targetDir, domainSettings->surfdataPath);
}
else {
BKE_reportf(reports, RPT_ERROR, "Fluidsim: cache directory '%s' is not writable, reset to default '%s'",
targetDir, domainSettings->surfdataPath);
}
BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
BLI_path_abs(targetDir, relbase);
/* .tmp: don't overwrite/delete original file */
BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
/* Ensure whole path exists and is wirtable. */
if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) {
BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not use default cache directory '%s', "
"please define a valid cache path manually", targetDir);
}
return false;
}
if (targetDir[0] == '\0' || (!dirExist)) {
char blendFile[FILE_MAX];
// invalid dir, reset to current/previous
BLI_split_file_part(G.main->name, blendFile, sizeof(blendFile));
BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */
BLI_snprintf(newSurfdataPath, FILE_MAX, "//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
elbeemDebugOut(debugStrBuffer);
outStringsChanged=1;
}
/* check if modified output dir is ok */
#if 0
if (outStringsChanged) {
char dispmsg[FILE_MAX+256];
int selection=0;
BLI_strncpy(dispmsg, "Output settings set to: '", sizeof(dispmsg));
strcat(dispmsg, newSurfdataPath);
strcat(dispmsg, "'%t|Continue with changed settings %x1|Discard and abort %x0");
/* ask user if thats what he/she wants... */
selection = pupmenu(dispmsg);
if (selection < 1) return 0; /* 0 from menu, or -1 aborted */
BLI_strncpy(targetDir, newSurfdataPath, sizeof(targetDir));
strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR);
BLI_path_abs(targetDir, G.main->name); /* fixed #frame-no */
}
#endif
return outStringsChanged;
return true;
}
/* ******************************************************************************** */
@ -857,7 +849,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
char targetDir[FILE_MAX]; // store & modify output settings
char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
int outStringsChanged = 0; // modified? copy back before baking
float domainMat[4][4];
float invDomMat[4][4];
@ -943,7 +934,11 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
/* ******** prepare output file paths ******** */
outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer);
if (!fluid_init_filepaths(reports, domainSettings, fsDomain, targetDir, targetFile)) {
fluidbake_free_data(channels, fobjects, fsset, fb);
return false;
}
channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra)
channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames;
@ -968,11 +963,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
/* ******** start writing / exporting ******** */
// use .tmp, don't overwrite/delete original file
BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp);
// make sure these directories exist as well
if (outStringsChanged) {
BLI_make_existing_file(targetFile);
}
/* ******** export domain to elbeem ******** */
elbeemResetSettings(fsset);

View File

@ -1184,6 +1184,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_BSDF_GLOSSY:
case SH_NODE_BSDF_GLASS:
case SH_NODE_BSDF_REFRACTION:
case SH_NODE_BSDF_PRINCIPLED:
ntype->draw_buttons = node_shader_buts_glossy;
break;
case SH_NODE_BSDF_ANISOTROPIC:

View File

@ -97,6 +97,7 @@ typedef enum GPUBuiltin {
GPU_PARTICLE_ANG_VELOCITY = (1 << 12),
GPU_LOC_TO_VIEW_MATRIX = (1 << 13),
GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
GPU_OBJECT_INFO = (1 << 15)
} GPUBuiltin;
typedef enum GPUOpenGLBuiltin {
@ -212,6 +213,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
void GPU_material_enable_alpha(GPUMaterial *material);
GPUBuiltin GPU_get_material_builtins(GPUMaterial *material);
GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]);
/* High level functions to create and use GPU materials */
@ -228,7 +230,7 @@ void GPU_material_bind(
float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
void GPU_material_bind_uniforms(
GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
float autobumpscale, GPUParticleInfo *pi);
float autobumpscale, GPUParticleInfo *pi, float object_info[3]);
void GPU_material_unbind(GPUMaterial *material);
bool GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
@ -325,6 +327,7 @@ struct GPUParticleInfo
float location[3];
float velocity[3];
float angular_velocity[3];
int random_id;
};
#ifdef WITH_OPENSUBDIV

View File

@ -410,6 +410,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
return "unfparticlevel";
else if (builtin == GPU_PARTICLE_ANG_VELOCITY)
return "unfparticleangvel";
else if (builtin == GPU_OBJECT_INFO)
return "unfobjectinfo";
else
return "";
}

View File

@ -826,7 +826,9 @@ bool GPU_fx_do_composite_pass(
ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp);
if (ssao_shader) {
const GPUSSAOSettings *fx_ssao = fx->settings.ssao;
float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f};
/* adjust attenuation to be scale invariant */
float attenuation = fx_ssao->attenuation / (fx_ssao->distance_max * fx_ssao->distance_max);
float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, attenuation, 0.0f};
float sample_params[3];
sample_params[0] = fx->ssao_sample_count_cache;

View File

@ -43,6 +43,7 @@
#include "BLI_math.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_hash.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@ -1880,6 +1881,21 @@ static int gpu_get_particle_info(GPUParticleInfo *pi)
return 0;
}
static void GPU_get_object_info(float oi[3], Material *mat)
{
Object *ob = GMS.gob;
oi[0] = ob->index;
oi[1] = mat->index;
unsigned int random;
if (GMS.dob) {
random = GMS.dob->random_id;
}
else {
random = BLI_hash_int_2d(BLI_hash_string(GMS.gob->id.name + 2), 0);
}
oi[2] = random * (1.0f/(float)0xFFFFFFFF);
}
int GPU_object_material_bind(int nr, void *attribs)
{
GPUVertexAttribs *gattribs = attribs;
@ -1939,21 +1955,27 @@ int GPU_object_material_bind(int nr, void *attribs)
/* bind glsl material and get attributes */
Material *mat = GMS.gmatbuf[nr];
GPUParticleInfo partile_info;
float object_info[3] = {0};
float auto_bump_scale;
GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv);
GPU_material_vertex_attributes(gpumat, gattribs);
if (GMS.dob)
if (GMS.dob) {
gpu_get_particle_info(&partile_info);
}
if ((GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) != 0) {
GPU_get_object_info(object_info, mat);
}
GPU_material_bind(
gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT),
GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info);
GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info);
GMS.gboundmat = mat;
/* for glsl use alpha blend mode, unless it's set to solid and

View File

@ -124,6 +124,8 @@ struct GPUMaterial {
int partvel;
int partangvel;
int objectinfoloc;
ListBase lamps;
bool bound;
@ -226,6 +228,8 @@ static int gpu_material_construct_end(GPUMaterial *material, const char *passnam
material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY));
if (material->builtins & GPU_PARTICLE_ANG_VELOCITY)
material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY));
if (material->builtins & GPU_OBJECT_INFO)
material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO));
return 1;
}
else {
@ -346,9 +350,14 @@ void GPU_material_bind(
}
}
GPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
{
return material->builtins;
}
void GPU_material_bind_uniforms(
GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
float autobumpscale, GPUParticleInfo *pi)
float autobumpscale, GPUParticleInfo *pi, float object_info[3])
{
if (material->pass) {
GPUShader *shader = GPU_pass_shader(material->pass);
@ -397,6 +406,9 @@ void GPU_material_bind_uniforms(
if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) {
GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity);
}
if (material->builtins & GPU_OBJECT_INFO) {
GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info);
}
}
}

View File

@ -35,10 +35,10 @@
#include "GPU_compositing.h"
#include "GPU_extensions.h"
#include "GPU_shader.h"
#include "GPU_uniformbuffer.h"
#include "GPU_texture.h"
#include "GPU_matrix.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "GPU_uniformbuffer.h"
#include "gpu_shader_private.h"

View File

@ -85,7 +85,7 @@ float calculate_ssao_factor(float depth)
float f = dot(dir, normal);
/* use minor bias here to avoid self shadowing */
if (f > 0.05 * len + 0.0001)
if (f > 0.05 * len)
factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z));
}
}

View File

@ -2393,11 +2393,19 @@ void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
/*********** NEW SHADER UTILITIES **************/
float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
float fresnel_dielectric_0(float eta)
{
/* compute fresnel reflactance at normal incidence => cosi = 1.0 */
float A = (eta - 1.0) / (eta + 1.0);
return A * A;
}
float fresnel_dielectric_cos(float cosi, float eta)
{
/* compute fresnel reflectance without explicitly computing
* the refracted direction */
float c = abs(dot(Incoming, Normal));
float c = abs(cosi);
float g = eta * eta - 1.0 + c * c;
float result;
@ -2414,6 +2422,13 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
return result;
}
float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta)
{
/* compute fresnel reflectance without explicitly computing
* the refracted direction */
return fresnel_dielectric_cos(dot(Incoming, Normal), eta);
}
float hypot(float x, float y)
{
return sqrt(x * x + y * y);
@ -2507,6 +2522,57 @@ float floorfrac(float x, out int i)
return x - i;
}
/* Principled BSDF operations */
float sqr(float a)
{
return a*a;
}
float schlick_fresnel(float u)
{
float m = clamp(1.0 - u, 0.0, 1.0);
float m2 = m * m;
return m2 * m2 * m; // pow(m,5)
}
float GTR1(float NdotH, float a)
{
if (a >= 1.0) return M_1_PI;
float a2 = a*a;
float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
return (a2 - 1.0) / (M_PI * log(a2) * t);
}
float GTR2(float NdotH, float a)
{
float a2 = a*a;
float t = 1.0 + (a2 - 1.0) * NdotH*NdotH;
return a2 / (M_PI * t*t);
}
float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
{
return 1.0 / (M_PI * ax*ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH*NdotH));
}
float smithG_GGX(float NdotV, float alphaG)
{
float a = alphaG*alphaG;
float b = NdotV*NdotV;
return 1.0 / (NdotV + sqrt(a + b - a * b));
}
vec3 rotate_vector(vec3 p, vec3 n, float theta) {
return (
p * cos(theta) + cross(n, p) *
sin(theta) + n * dot(p, n) *
(1.0 - cos(theta))
);
}
/*********** NEW SHADER NODES ***************/
#define NUM_LIGHTS 3
@ -2568,6 +2634,126 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 resu
node_bsdf_diffuse(color, 0.0, N, result);
}
void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
float clearcoat_gloss, float ior, float transparency, float refraction_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
{
/* ambient light */
// TODO: set ambient light to an appropriate value
vec3 L = vec3(mix(0.1, 0.03, metallic)) * base_color.rgb;
float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
/* set the viewing vector */
vec3 V = -normalize(I);
/* get the tangent */
vec3 Tangent = T;
if (T == vec3(0.0)) {
// if no tangent is set, use a default tangent
Tangent = vec3(1.0, 0.0, 0.0);
if (N.x != 0.0 || N.y != 0.0) {
vec3 N_xz = normalize(vec3(N.x, 0.0, N.z));
vec3 axis = normalize(cross(vec3(0.0, 0.0, 1.0), N_xz));
float angle = acos(dot(vec3(0.0, 0.0, 1.0), N_xz));
Tangent = normalize(rotate_vector(vec3(1.0, 0.0, 0.0), axis, angle));
}
}
/* rotate tangent */
if (anisotropic_rotation != 0.0) {
Tangent = rotate_vector(Tangent, N, anisotropic_rotation * 2.0 * M_PI);
}
/* calculate the tangent and bitangent */
vec3 Y = normalize(cross(N, Tangent));
vec3 X = cross(Y, N);
/* fresnel normalization parameters */
float F0 = fresnel_dielectric_0(eta);
float F0_norm = 1.0 / (1.0 - F0);
/* directional lights */
for (int i = 0; i < NUM_LIGHTS; i++) {
vec3 light_position_world = gl_LightSource[i].position.xyz;
vec3 light_position = normalize(gl_NormalMatrix * light_position_world);
vec3 H = normalize(light_position + V);
vec3 light_specular = gl_LightSource[i].specular.rgb;
float NdotL = dot(N, light_position);
float NdotV = dot(N, V);
float LdotH = dot(light_position, H);
vec3 diffuse_and_specular_bsdf = vec3(0.0);
if (NdotL >= 0.0 && NdotV >= 0.0) {
float NdotH = dot(N, H);
float Cdlum = 0.3 * base_color.r + 0.6 * base_color.g + 0.1 * base_color.b; // luminance approx.
vec3 Ctint = Cdlum > 0 ? base_color.rgb / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat
vec3 Cspec0 = mix(specular * 0.08 * mix(vec3(1.0), Ctint, specular_tint), base_color.rgb, metallic);
vec3 Csheen = mix(vec3(1.0), Ctint, sheen_tint);
// Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
// and mix in diffuse retro-reflection based on roughness
float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV);
float Fd90 = 0.5 + 2.0 * LdotH*LdotH * roughness;
float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV);
// Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
// 1.25 scale is used to (roughly) preserve albedo
// Fss90 used to "flatten" retroreflection based on roughness
float Fss90 = LdotH*LdotH * roughness;
float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV);
float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5);
// specular
float aspect = sqrt(1.0 - anisotropic * 0.9);
float a = sqr(roughness);
float ax = max(0.001, a / aspect);
float ay = max(0.001, a * aspect);
float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); //GTR2(NdotH, a);
float FH = (fresnel_dielectric_cos(LdotH, eta) - F0) * F0_norm;
vec3 Fs = mix(Cspec0, vec3(1.0), FH);
float roughg = sqr(roughness * 0.5 + 0.5);
float Gs = smithG_GGX(NdotL, roughg) * smithG_GGX(NdotV, roughg);
// sheen
vec3 Fsheen = schlick_fresnel(LdotH) * sheen * Csheen;
diffuse_and_specular_bsdf = (M_1_PI * mix(Fd, ss, subsurface) * base_color.rgb + Fsheen)
* (1.0 - metallic) + Gs * Fs * Ds;
}
diffuse_and_specular_bsdf *= max(NdotL, 0.0);
float CNdotL = dot(CN, light_position);
float CNdotV = dot(CN, V);
vec3 clearcoat_bsdf = vec3(0.0);
if (CNdotL >= 0.0 && CNdotV >= 0.0 && clearcoat > 0.0) {
float CNdotH = dot(CN, H);
//float FH = schlick_fresnel(LdotH);
// clearcoat (ior = 1.5 -> F0 = 0.04)
float Dr = GTR1(CNdotH, mix(0.1, 0.001, clearcoat_gloss));
float Fr = fresnel_dielectric_cos(LdotH, 1.5); //mix(0.04, 1.0, FH);
float Gr = smithG_GGX(CNdotL, 0.25) * smithG_GGX(CNdotV, 0.25);
clearcoat_bsdf = clearcoat * Gr * Fr * Dr * vec3(0.25);
}
clearcoat_bsdf *= max(CNdotL, 0.0);
L += light_specular * (diffuse_and_specular_bsdf + clearcoat_bsdf);
}
result = vec4(L, 1.0);
}
void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result)
{
node_bsdf_diffuse(color, 0.0, N, result);
@ -3578,12 +3764,12 @@ void node_light_falloff(float strength, float tsmooth, out float quadratic, out
constant = strength;
}
void node_object_info(out vec3 location, out float object_index, out float material_index, out float random)
void node_object_info(mat4 obmat, vec3 info, out vec3 location, out float object_index, out float material_index, out float random)
{
location = vec3(0.0);
object_index = 0.0;
material_index = 0.0;
random = 0.0;
location = obmat[3].xyz;
object_index = info.x;
material_index = info.y;
random = info.z;
}
void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal)

View File

@ -179,6 +179,7 @@ typedef struct FluidsimSettings {
#define OB_FLUIDSIM_ACTIVE (1 << 1)
#define OB_FLUIDSIM_OVERRIDE_TIME (1 << 2)
#define OB_FLUIDSIM_SURF_DIR_DEFAULT "cache_fluid"
#define OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME "fluidsurface_preview_####.bobj.gz"
#define OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME "fluidsurface_final_####.bobj.gz"
#define OB_FLUIDSIM_SURF_FINAL_VEL_FNAME "fluidsurface_final_####.bvel.gz"

View File

@ -342,6 +342,8 @@ typedef struct DupliObject {
/* particle this dupli was generated from */
struct ParticleSystem *particle_system;
unsigned int random_id;
unsigned int pad;
} DupliObject;
/* **************** OBJECT ********************* */

View File

@ -342,7 +342,7 @@ static void rna_ID_user_clear(ID *id)
static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id)
{
if (GS(id->name) == GS(new_id->name)) {
if ((GS(id->name) == GS(new_id->name)) && (id != new_id)) {
/* For now, do not allow remapping data in linked data from here... */
BKE_libblock_remap(bmain, id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
}

View File

@ -2995,6 +2995,15 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
ED_node_tag_update_nodetree(bmain, ntree, node);
}
static void rna_ShaderNodePrincipled_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
bNode *node = (bNode *)ptr->data;
nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_ShaderNodeSubsurface_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
@ -3254,6 +3263,12 @@ static EnumPropertyItem node_script_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem node_principled_distribution_items[] = {
{ SHD_GLOSSY_GGX, "GGX", 0, "GGX", "" },
{ SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "" },
{ 0, NULL, 0, NULL, NULL }
};
/* -- Common nodes ---------------------------------------------------------- */
static void def_group_input(StructRNA *srna)
@ -4188,6 +4203,17 @@ static void def_glass(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_principled(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_principled_distribution_items);
RNA_def_property_ui_text(prop, "Distribution", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodePrincipled_update");
}
static void def_refraction(StructRNA *srna)
{
PropertyRNA *prop;

View File

@ -2889,6 +2889,10 @@ static void rna_def_dupli_object(BlenderRNA *brna)
RNA_def_property_enum_items(prop, dupli_items);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object");
prop = RNA_def_property(srna, "random_id", PROP_INT, PROP_UNSIGNED);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dupli random id", "Random id for this dupli object");
}
static void rna_def_object_base_legacy(BlenderRNA *brna)

View File

@ -379,49 +379,55 @@ static void rna_Object_ray_cast(
float origin[3], float direction[3], float distance,
int *r_success, float r_location[3], float r_normal[3], int *r_index)
{
BVHTreeFromMesh treeData = {NULL};
bool success = false;
if (ob->derivedFinal == NULL) {
BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", ob->id.name + 2);
return;
}
/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6);
/* Test BoundBox first (efficiency) */
BoundBox *bb = BKE_object_boundbox_get(ob);
float distmin;
if (!bb || (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) && distmin <= distance)) {
/* may fail if the mesh has no faces, in that case the ray-cast misses */
if (treeData.tree != NULL) {
BVHTreeRayHit hit;
BVHTreeFromMesh treeData = {NULL};
hit.index = -1;
hit.dist = distance;
normalize_v3(direction);
/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6);
/* may fail if the mesh has no faces, in that case the ray-cast misses */
if (treeData.tree != NULL) {
BVHTreeRayHit hit;
hit.index = -1;
hit.dist = distance;
normalize_v3(direction);
if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit,
treeData.raycast_callback, &treeData) != -1)
{
if (hit.dist <= distance) {
*r_success = true;
if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit,
treeData.raycast_callback, &treeData) != -1)
{
if (hit.dist <= distance) {
*r_success = success = true;
copy_v3_v3(r_location, hit.co);
copy_v3_v3(r_normal, hit.no);
*r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
goto finally;
copy_v3_v3(r_location, hit.co);
copy_v3_v3(r_normal, hit.no);
*r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
}
}
free_bvhtree_from_mesh(&treeData);
}
}
if (success == false) {
*r_success = false;
*r_success = false;
zero_v3(r_location);
zero_v3(r_normal);
*r_index = -1;
finally:
free_bvhtree_from_mesh(&treeData);
zero_v3(r_location);
zero_v3(r_normal);
*r_index = -1;
}
}
static void rna_Object_closest_point_on_mesh(

View File

@ -78,8 +78,8 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
fss->resolutionxyz = 65;
fss->previewresxyz = 45;
fss->realsize = 0.5;
fss->guiDisplayMode = 2; // preview
fss->renderDisplayMode = 3; // render
fss->guiDisplayMode = OB_FSDOM_PREVIEW;
fss->renderDisplayMode = OB_FSDOM_FINAL;
fss->viscosityValue = 1.0;
fss->viscosityExponent = 6;
@ -98,7 +98,7 @@ void fluidsim_init(FluidsimModifierData *fluidmd)
/* fluid/inflow settings
* fss->iniVel --> automatically set to 0 */
modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), "cache_fluid");
modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT);
/* first init of bounding box */
/* no bounding box needed */
@ -423,8 +423,6 @@ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *
static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
{
int displaymode = 0;
int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */
/* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway. (See physics_fluid.c for that. - DG */
/* If we start with frame 0, we need to remap all animation channels, too, because they will all be 1 frame late if using frame-1! - DG */
@ -435,25 +433,23 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
MPoly *mpoly;
MPoly mp_example = {0};
if (!useRenderParams) {
displaymode = fss->guiDisplayMode;
}
else {
displaymode = fss->renderDisplayMode;
}
const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode;
switch (displaymode) {
case 1:
case OB_FSDOM_GEOM:
/* just display original object */
return NULL;
case 2:
case OB_FSDOM_PREVIEW:
/* use preview mesh */
BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
break;
default: /* 3 */
/* 3. use final mesh */
case OB_FSDOM_FINAL:
/* use final mesh */
BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
break;
default:
BLI_assert(!"Wrong fluidsim display type");
return NULL;
}
/* offset baked frame */
@ -494,7 +490,7 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm,
/* load vertex velocities, if they exist...
* TODO? use generate flag as loading flag as well?
* warning, needs original .bobj.gz mesh loading filename */
if (displaymode == 3) {
if (displaymode == OB_FSDOM_FINAL) {
fluidsim_read_vel_cache(fluidmd, dm, targetFile);
}
else {

View File

@ -163,6 +163,7 @@ set(SRC
shader/nodes/node_shader_background.c
shader/nodes/node_shader_bsdf_anisotropic.c
shader/nodes/node_shader_bsdf_diffuse.c
shader/nodes/node_shader_bsdf_principled.c
shader/nodes/node_shader_bsdf_glass.c
shader/nodes/node_shader_bsdf_glossy.c
shader/nodes/node_shader_bsdf_toon.c

View File

@ -106,6 +106,7 @@ void register_node_type_sh_bsdf_transparent(void);
void register_node_type_sh_bsdf_velvet(void);
void register_node_type_sh_bsdf_toon(void);
void register_node_type_sh_bsdf_anisotropic(void);
void register_node_type_sh_bsdf_principled(void);
void register_node_type_sh_emission(void);
void register_node_type_sh_holdout(void);
void register_node_type_sh_volume_absorption(void);

View File

@ -80,6 +80,7 @@ DefNode( ShaderNode, SH_NODE_BACKGROUND, 0, "BA
DefNode( ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "" )
DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled 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_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )

View File

@ -0,0 +1,114 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "../node_shader_util.h"
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_bsdf_principled_in[] = {
{ SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_VECTOR, 1, N_("Subsurface Radius"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f},
{ SOCK_RGBA, 1, N_("Subsurface Color"), 0.7f, 0.1f, 0.1f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Specular Tint"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Anisotropic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Anisotropic Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Sheen"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Sheen Tint"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Clearcoat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Clearcoat Gloss"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
{ SOCK_FLOAT, 1, N_("Transparency"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("Refraction Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
{ SOCK_VECTOR, 1, N_("Clearcoat Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
{ SOCK_VECTOR, 1, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
{ -1, 0, "" }
};
static bNodeSocketTemplate sh_node_bsdf_principled_out[] = {
{ SOCK_SHADER, 0, N_("BSDF")},
{ -1, 0, "" }
};
static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = SHD_GLOSSY_MULTI_GGX;
}
static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
// normal
if (!in[17].link)
in[17].link = GPU_builtin(GPU_VIEW_NORMAL);
else
GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link);
// clearcoat normal
if (!in[18].link)
in[18].link = GPU_builtin(GPU_VIEW_NORMAL);
else
GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link);
return GPU_stack_link(mat, "node_bsdf_principled", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node)
{
bNodeSocket *sock;
int distribution = node->custom1;
for (sock = node->inputs.first; sock; sock = sock->next) {
if (STREQ(sock->name, "Refraction Roughness")) {
if (distribution == SHD_GLOSSY_GGX)
sock->flag &= ~SOCK_UNAVAIL;
else
sock->flag |= SOCK_UNAVAIL;
}
}
}
/* node type definition */
void register_node_type_sh_bsdf_principled(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0);
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_principled);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_bsdf_principled);
node_type_update(&ntype, node_shader_update_principled, NULL);
nodeRegisterType(&ntype);
}

View File

@ -39,7 +39,16 @@ static bNodeSocketTemplate sh_node_object_info_out[] = {
static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
return GPU_stack_link(mat, "node_object_info", in, out);
return GPU_stack_link(mat, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_OBJECT_INFO));
}
static void node_shader_exec_object_info(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out)
{
ShaderCallData *scd = (ShaderCallData *)data;
copy_v4_v4(out[0]->vec, RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB)[3]);
out[1]->vec[0] = RE_object_instance_get_object_pass_index(scd->shi->obi);
out[2]->vec[0] = scd->shi->mat->index;
out[3]->vec[0] = RE_object_instance_get_random_id(scd->shi->obi) * (1.0f/(float)0xFFFFFFFF);;
}
/* node type definition */
@ -53,6 +62,7 @@ void register_node_type_sh_object_info(void)
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_object_info);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_object_info);
nodeRegisterType(&ntype);
}

View File

@ -381,7 +381,7 @@ bool RE_allow_render_generic_object(struct Object *ob);
/* RE_updateRenderInstances flag */
enum {
RE_OBJECT_INSTANCES_UPDATE_VIEW = (1 << 0),
RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1),
RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1)
};
void RE_updateRenderInstances(Render *re, int flag);

View File

@ -178,6 +178,7 @@ typedef struct ShadeInput {
unsigned int lay;
int layflag, passflag, combinedflag;
short object_pass_index;
struct Group *light_override;
struct Material *mat_override;
@ -241,6 +242,9 @@ enum {
const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4];
float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi);
float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi);
enum {
RE_VIEW_MATRIX,
RE_VIEWINV_MATRIX,

View File

@ -382,6 +382,8 @@ typedef struct ObjectInstanceRen {
float part_co[3];
float part_vel[3];
float part_avel[3];
unsigned int random_id;
} ObjectInstanceRen;
/* ------------------------------------------------------------------------- */

View File

@ -66,6 +66,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_hash.h"
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
@ -1458,6 +1459,14 @@ ObjectInstanceRen *RE_addRenderInstance(
}
}
/* Fill object info */
if (dob) {
obi->random_id = dob->random_id;
}
else {
obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0);
}
RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW);
if (mat) {

View File

@ -2141,6 +2141,16 @@ const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int m
return NULL;
}
float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi)
{
return obi->ob->index;
}
float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi)
{
return obi->random_id;
}
const float (*RE_render_current_get_matrix(int matrix_id))[4]
{
switch (matrix_id) {

View File

@ -278,6 +278,8 @@ struct Object *RE_GetCamera(struct Render *re) RET_NULL
float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO
const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4] RET_NULL
const float (*RE_render_current_get_matrix(int matrix_id))[4] RET_NULL
float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi) RET_ZERO
float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi) RET_ZERO
/* blenkernel */
bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil) RET_ZERO

View File

@ -169,7 +169,7 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
rasty->GetViewMatrix().getValue(&viewmat[0][0]);
float auto_bump_scale = ms.m_pDerivedMesh!=0 ? ms.m_pDerivedMesh->auto_bump_scale : 1.0f;
GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL);
GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL, NULL);
mAlphaBlend = GPU_material_alpha_blend(gpumat, obcol);
}

View File

@ -59,12 +59,6 @@ class AbstractAlembicTest(unittest.TestCase):
def setUpClass(cls):
import re
parser = argparse.ArgumentParser()
parser.add_argument('--blender', required=True)
parser.add_argument('--testdir', required=True)
parser.add_argument('--alembic-root', required=True)
args, _ = parser.parse_known_args()
cls.blender = args.blender
cls.testdir = pathlib.Path(args.testdir)
cls.alembic_root = pathlib.Path(args.alembic_root)
@ -116,6 +110,7 @@ class AbstractAlembicTest(unittest.TestCase):
The Python bindings for Alembic are old, and only compatible with Python 2.x,
so that's why we can't use them here, and have to rely on other tooling.
"""
import collections
abcls = self.alembic_root / 'bin' / 'abcls'
@ -133,14 +128,19 @@ class AbstractAlembicTest(unittest.TestCase):
converters = {
'bool_t': int,
'uint8_t': int,
'int32_t': int,
'float64_t': float,
'float32_t': float,
}
result = {}
# Ideally we'd get abcls to output JSON, see https://github.com/alembic/alembic/issues/121
lines = output.split('\n')
for info, value in zip(lines[0::2], lines[1::2]):
lines = collections.deque(output.split('\n'))
while lines:
info = lines.popleft()
if not info:
continue
proptype, valtype_and_arrsize, name_and_extent = info.split()
# Parse name and extent
@ -152,22 +152,41 @@ class AbstractAlembicTest(unittest.TestCase):
if extent != '1':
self.fail('Unsupported extent %s for property %s/%s' % (extent, proppath, name))
# Parse type and convert values
# Parse type
m = self.abcls_array.match(valtype_and_arrsize)
if not m:
self.fail('Unparsable value type from abcls: %s' % valtype_and_arrsize)
valtype, arraysize = m.group('name'), m.group('arraysize')
valtype, scalarsize = m.group('name'), m.group('arraysize')
# Convert values
try:
conv = converters[valtype]
except KeyError:
self.fail('Unsupported type %s for property %s/%s' % (valtype, proppath, name))
if arraysize is None:
result[name] = conv(value)
def convert_single_line(linevalue):
try:
if scalarsize is None:
return conv(linevalue)
else:
return [conv(v.strip()) for v in linevalue.split(',')]
except ValueError as ex:
return str(ex)
if proptype == 'ScalarProperty':
value = lines.popleft()
result[name] = convert_single_line(value)
elif proptype == 'ArrayProperty':
arrayvalue = []
# Arrays consist of a variable number of items, and end in a blank line.
while True:
linevalue = lines.popleft()
if not linevalue:
break
arrayvalue.append(convert_single_line(linevalue))
result[name] = arrayvalue
else:
values = [conv(v.strip()) for v in value.split(',')]
result[name] = values
self.fail('Unsupported type %s for property %s/%s' % (proptype, proppath, name))
return result
@ -221,5 +240,63 @@ class HierarchicalAndFlatExportTest(AbstractAlembicTest):
)
class DupliGroupExportTest(AbstractAlembicTest):
@with_tempdir
def test_hierarchical_export(self, tempdir: pathlib.Path):
abc = tempdir / 'dupligroup_hierarchical.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
"renderable_only=True, visible_layers_only=True, flatten=False)" % abc
self.run_blender('dupligroup-scene.blend', script)
# Now check the resulting Alembic file.
xform = self.abcprop(abc, '/Real_Cube/Linked_Suzanne/Cylinder/Suzanne/.xform')
self.assertEqual(1, xform['.inherits'])
self.assertAlmostEqualFloatArray(
xform['.vals'],
[1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 2.0, 0.0, 1.0]
)
@with_tempdir
def test_flat_export(self, tempdir: pathlib.Path):
abc = tempdir / 'dupligroup_hierarchical.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
"renderable_only=True, visible_layers_only=True, flatten=True)" % abc
self.run_blender('dupligroup-scene.blend', script)
# Now check the resulting Alembic file.
xform = self.abcprop(abc, '/Suzanne/.xform')
self.assertEqual(0, xform['.inherits'])
self.assertAlmostEqualFloatArray(
xform['.vals'],
[1.5, 0.0, 0.0, 0.0,
0.0, 1.5, 0.0, 0.0,
0.0, 0.0, 1.5, 0.0,
2.0, 3.0, 0.0, 1.0]
)
class CurveExportTest(AbstractAlembicTest):
@with_tempdir
def test_export_single_curve(self, tempdir: pathlib.Path):
abc = tempdir / 'single-curve.abc'
script = "import bpy; bpy.ops.wm.alembic_export(filepath='%s', start=1, end=1, " \
"renderable_only=True, visible_layers_only=True, flatten=False)" % abc
self.run_blender('single-curve.blend', script)
# Now check the resulting Alembic file.
abcprop = self.abcprop(abc, '/NurbsCurve/NurbsCurveShape/.geom')
self.assertEqual(abcprop['.orders'], [4])
if __name__ == '__main__':
unittest.main(argv=sys.argv[0:1])
parser = argparse.ArgumentParser()
parser.add_argument('--blender', required=True)
parser.add_argument('--testdir', required=True)
parser.add_argument('--alembic-root', required=True)
args, remaining = parser.parse_known_args()
unittest.main(argv=sys.argv[0:1] + remaining)