Cycles / SSS:

* Remove the compatible falloff SSS implementation. We shouldn't support two implementations in the long term, and 2.7x is a good release number do break some compatibility as well. 

* Version patch added, so Files with Compatible falloff will automatically use Cubic now. 

It was already mentioned in the manual, that Compatible is deprecated. 
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Shaders#BSSRDF
This commit is contained in:
Thomas Dinges 2013-10-08 17:07:18 +00:00
parent 03f7885b0a
commit e6ce07a5d4
10 changed files with 48 additions and 220 deletions

@ -322,9 +322,6 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
SubsurfaceScatteringNode *subsurface = new SubsurfaceScatteringNode();
switch(b_subsurface_node.falloff()) {
case BL::ShaderNodeSubsurfaceScattering::falloff_COMPATIBLE:
subsurface->closure = CLOSURE_BSSRDF_COMPATIBLE_ID;
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
subsurface->closure = CLOSURE_BSSRDF_CUBIC_ID;
break;

@ -266,14 +266,9 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
if(sc) {
uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb);
if(old_subsurface_scatter_use(&sd)) {
old_subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
}
else {
float bssrdf_u, bssrdf_v;
path_rng_2D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false);
}
state.flag |= PATH_RAY_BSSRDF_ANCESTOR;
}
@ -664,10 +659,6 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
if(sc) {
uint lcg_state = lcg_init(*rng + rng_offset + sample*0x68bc21eb);
if(old_subsurface_scatter_use(&sd)) {
old_subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, false);
}
else {
ShaderData bssrdf_sd[BSSRDF_MAX_HITS];
float bssrdf_u, bssrdf_v;
path_rng_2D(kg, rng, sample, num_samples, rng_offset + PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
@ -696,11 +687,9 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
path_radiance_reset_indirect(&L);
}
}
break;
}
}
}
#endif
/* The following code is the same as in kernel_path_integrate_lighting(),
@ -1131,17 +1120,6 @@ __device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int
/* do subsurface scatter step with copy of shader data, this will
* replace the BSSRDF with a diffuse BSDF closure */
for(int j = 0; j < num_samples; j++) {
if(old_subsurface_scatter_use(&sd)) {
ShaderData bssrdf_sd = sd;
old_subsurface_scatter_step(kg, &bssrdf_sd, state.flag, sc, &lcg_state, true);
/* compute lighting with the BSDF closure */
kernel_branched_path_integrate_lighting(kg, rng, sample*num_samples + j,
aa_samples*num_samples,
&bssrdf_sd, throughput, num_samples_inv,
ray_pdf, ray_pdf, state, rng_offset, &L, buffer);
}
else {
ShaderData bssrdf_sd[BSSRDF_MAX_HITS];
float bssrdf_u, bssrdf_v;
path_rng_2D(kg, &bssrdf_rng, sample*num_samples + j, aa_samples*num_samples, rng_offset + PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
@ -1154,7 +1132,6 @@ __device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int
&bssrdf_sd[hit], throughput, num_samples_inv,
ray_pdf, ray_pdf, state, rng_offset+PRNG_BOUNCE_NUM, &L, buffer);
}
}
state.flag &= ~PATH_RAY_BSSRDF_ANCESTOR;
}

@ -403,164 +403,5 @@ __device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd,
subsurface_scatter_setup_diffuse_bsdf(sd, eval, (num_hits > 0), N);
}
/* OLD BSSRDF */
__device float old_bssrdf_sample_distance(KernelGlobals *kg, float radius, float refl, float u)
{
int table_offset = kernel_data.bssrdf.table_offset;
float r = lookup_table_read_2D(kg, u, refl, table_offset, BSSRDF_RADIUS_TABLE_SIZE, BSSRDF_REFL_TABLE_SIZE);
return r*radius;
}
#ifdef BSSRDF_MULTI_EVAL
__device float old_bssrdf_pdf(KernelGlobals *kg, float radius, float refl, float r)
{
if(r >= radius)
return 0.0f;
/* todo: when we use the real BSSRDF this will need to be divided by the maximum
* radius instead of the average radius */
float t = r/radius;
int table_offset = kernel_data.bssrdf.table_offset + BSSRDF_PDF_TABLE_OFFSET;
float pdf = lookup_table_read_2D(kg, t, refl, table_offset, BSSRDF_RADIUS_TABLE_SIZE, BSSRDF_REFL_TABLE_SIZE);
pdf /= radius;
return pdf;
}
#endif
#ifdef BSSRDF_MULTI_EVAL
__device float3 old_subsurface_scatter_multi_eval(KernelGlobals *kg, ShaderData *sd, bool hit, float refl, float *r, int num_r, bool all)
{
/* compute pdf */
float3 eval_sum = make_float3(0.0f, 0.0f, 0.0f);
float pdf_sum = 0.0f;
float sample_weight_sum = 0.0f;
int num_bssrdf = 0;
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_BSSRDF(sc->type)) {
float sample_weight = (all)? 1.0f: sc->sample_weight;
/* compute pdf */
float pdf = 1.0f;
for(int i = 0; i < num_r; i++)
pdf *= old_bssrdf_pdf(kg, sc->data0, refl, r[i]);
eval_sum += sc->weight*pdf;
pdf_sum += sample_weight*pdf;
sample_weight_sum += sample_weight;
num_bssrdf++;
}
}
float inv_pdf_sum;
if(pdf_sum > 0.0f) {
/* in case of branched path integrate we sample all bssrdf's once,
* for path trace we pick one, so adjust pdf for that */
if(all)
inv_pdf_sum = 1.0f/pdf_sum;
else
inv_pdf_sum = sample_weight_sum/pdf_sum;
}
else
inv_pdf_sum = 0.0f;
float3 weight = eval_sum * inv_pdf_sum;
return weight;
}
#endif
/* subsurface scattering step, from a point on the surface to another nearby point on the same object */
__device void old_subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, int state_flag, ShaderClosure *sc, uint *lcg_state, bool all)
{
float radius = sc->data0;
float refl = max(average(sc->weight)*3.0f, 0.0f);
float r = 0.0f;
bool hit = false;
float3 weight = make_float3(1.0f, 1.0f, 1.0f);
#ifdef BSSRDF_MULTI_EVAL
float r_attempts[BSSRDF_MAX_ATTEMPTS];
#endif
int num_attempts;
/* attempt to find a hit a given number of times before giving up */
for(num_attempts = 0; num_attempts < kernel_data.bssrdf.num_attempts; num_attempts++) {
/* random numbers for sampling */
float u1 = lcg_step_float(lcg_state);
float u2 = lcg_step_float(lcg_state);
float u3 = lcg_step_float(lcg_state);
float u4 = lcg_step_float(lcg_state);
float u5 = lcg_step_float(lcg_state);
r = old_bssrdf_sample_distance(kg, radius, refl, u5);
#ifdef BSSRDF_MULTI_EVAL
r_attempts[num_attempts] = r;
#endif
float3 p1 = sd->P + sample_uniform_sphere(u1, u2)*r;
float3 p2 = sd->P + sample_uniform_sphere(u3, u4)*r;
/* create ray */
Ray ray;
ray.P = p1;
ray.D = normalize_len(p2 - p1, &ray.t);
ray.dP = sd->dP;
ray.dD = differential3_zero();
ray.time = sd->time;
/* intersect with the same object. if multiple intersections are
* found it will randomly pick one of them */
Intersection isect;
if(scene_intersect_subsurface(kg, &ray, &isect, sd->object, lcg_state, 1) == 0)
continue;
/* setup new shading point */
shader_setup_from_subsurface(kg, sd, &isect, &ray);
hit = true;
num_attempts++;
break;
}
/* evaluate subsurface scattering closures */
#ifdef BSSRDF_MULTI_EVAL
weight *= old_subsurface_scatter_multi_eval(kg, sd, hit, refl, r_attempts, num_attempts, all);
#else
weight *= sc->weight;
#endif
if(!hit)
weight = make_float3(0.0f, 0.0f, 0.0f);
/* optionally blur colors and bump mapping */
float3 N = sd->N;
subsurface_color_bump_blur(kg, sd, sd, state_flag, &weight, &N);
/* replace closures with a single diffuse BSDF */
subsurface_scatter_setup_diffuse_bsdf(sd, weight, hit, N);
}
__device bool old_subsurface_scatter_use(ShaderData *sd)
{
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(sc->type == CLOSURE_BSSRDF_COMPATIBLE_ID)
return true;
}
return false;
}
CCL_NAMESPACE_END

@ -253,7 +253,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
/* 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(sc.type != CLOSURE_BSSRDF_COMPATIBLE_ID && (path_flag & PATH_RAY_DIFFUSE_ANCESTOR))
if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
bssrdf->radius = make_float3(0.0f, 0.0f, 0.0f);
/* create one closure for each color channel */

@ -378,7 +378,6 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
#endif
#ifdef __SUBSURFACE__
case CLOSURE_BSSRDF_COMPATIBLE_ID:
case CLOSURE_BSSRDF_CUBIC_ID:
case CLOSURE_BSSRDF_GAUSSIAN_ID: {
ShaderClosure *sc = &sd->closure[sd->num_closure];
@ -388,7 +387,7 @@ __device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *st
/* 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(type != CLOSURE_BSSRDF_COMPATIBLE_ID && (path_flag & PATH_RAY_DIFFUSE_ANCESTOR))
if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
param1 = 0.0f;
if(sample_weight > 1e-5f && sd->num_closure+2 < MAX_CLOSURE) {

@ -377,7 +377,6 @@ typedef enum ClosureType {
CLOSURE_BSDF_TRANSPARENT_ID,
/* BSSRDF */
CLOSURE_BSSRDF_COMPATIBLE_ID,
CLOSURE_BSSRDF_CUBIC_ID,
CLOSURE_BSSRDF_GAUSSIAN_ID,
@ -402,7 +401,7 @@ typedef enum ClosureType {
#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_BSSRDF(type) (type >= CLOSURE_BSSRDF_COMPATIBLE_ID && type <= CLOSURE_BSSRDF_GAUSSIAN_ID)
#define CLOSURE_IS_BSSRDF(type) (type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_GAUSSIAN_ID)
#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID)
#define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID)
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)

@ -42,7 +42,7 @@ extern "C" {
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 269
#define BLENDER_SUBVERSION 0
#define BLENDER_SUBVERSION 1
/* 262 was the last editmesh release but it has compatibility code for bmesh data */
#define BLENDER_MINVERSION 262
#define BLENDER_MINSUBVERSION 0

@ -9708,6 +9708,22 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
if (!MAIN_VERSION_ATLEAST(main, 269, 1)) {
/* Removal of Cycles SSS Compatible fallof */
FOREACH_NODETREE(main, ntree, id) {
if (ntree->type == NTREE_SHADER) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
if (node->type == SH_NODE_SUBSURFACE_SCATTERING) {
if (node->custom1 == SHD_SUBSURFACE_COMPATIBLE) {
node->custom1 = SHD_SUBSURFACE_CUBIC;
}
}
}
}
} FOREACH_NODETREE_END
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */

@ -976,7 +976,7 @@ typedef struct NodeShaderNormalMap {
#define SHD_NORMAL_MAP_BLENDER_WORLD 4
/* subsurface */
#define SHD_SUBSURFACE_COMPATIBLE 0
#define SHD_SUBSURFACE_COMPATIBLE 0 // Deprecated
#define SHD_SUBSURFACE_CUBIC 1
#define SHD_SUBSURFACE_GAUSSIAN 2

@ -3699,7 +3699,6 @@ static void def_sh_tangent(StructRNA *srna)
static void def_sh_subsurface(StructRNA *srna)
{
static EnumPropertyItem prop_subsurface_falloff_items[] = {
{SHD_SUBSURFACE_COMPATIBLE, "COMPATIBLE", 0, "Compatible", "Subsurface scattering falloff compatible with previous versions"},
{SHD_SUBSURFACE_CUBIC, "CUBIC", 0, "Cubic", "Simple cubic falloff function"},
{SHD_SUBSURFACE_GAUSSIAN, "GAUSSIAN", 0, "Gaussian", "Normal distribution, multiple can be combined to fit more complex profiles"},
{0, NULL, 0, NULL, NULL}