Code cleanup: refactor BSSRDF closure sampling, for next commit.
This commit is contained in:
parent
d029399e6b
commit
b3afc8917c
Notes:
blender-bot
2023-05-03 10:14:48 +02:00
Referenced by issue #55306, Cycles Glass BSDF broken on GPU
|
@ -400,7 +400,7 @@ ccl_device int bssrdf_setup(Bssrdf *bssrdf, ClosureType type)
|
|||
bssrdf_burley_setup(bssrdf);
|
||||
}
|
||||
|
||||
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF;
|
||||
return SD_BSSRDF;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -483,11 +483,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
|||
/* bssrdf scatter to a different location on the same object, replacing
|
||||
* the closures with a diffuse BSDF */
|
||||
if(sd->flag & SD_BSSRDF) {
|
||||
float bssrdf_probability;
|
||||
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability);
|
||||
|
||||
/* modify throughput for picking bssrdf or bsdf */
|
||||
throughput *= bssrdf_probability;
|
||||
const ShaderClosure *sc = shader_bssrdf_pick(sd, &throughput);
|
||||
|
||||
/* do bssrdf scatter step if we picked a bssrdf closure */
|
||||
if(sc) {
|
||||
|
|
|
@ -32,11 +32,7 @@ bool kernel_path_subsurface_scatter(
|
|||
ccl_addr_space float3 *throughput,
|
||||
ccl_addr_space SubsurfaceIndirectRays *ss_indirect)
|
||||
{
|
||||
float bssrdf_probability;
|
||||
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability);
|
||||
|
||||
/* modify throughput for picking bssrdf or bsdf */
|
||||
*throughput *= bssrdf_probability;
|
||||
const ShaderClosure *sc = shader_bssrdf_pick(sd, throughput);
|
||||
|
||||
/* do bssrdf scatter step if we picked a bssrdf closure */
|
||||
if(sc) {
|
||||
|
|
|
@ -497,17 +497,14 @@ ccl_device_inline void shader_merge_closures(ShaderData *sd)
|
|||
/* BSDF */
|
||||
|
||||
ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd, const float3 omega_in, float *pdf,
|
||||
int skip_bsdf, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight)
|
||||
const ShaderClosure *skip_sc, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight)
|
||||
{
|
||||
/* this is the veach one-sample model with balance heuristic, some pdf
|
||||
* factors drop out when using balance heuristic weighting */
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
if(i == skip_bsdf)
|
||||
continue;
|
||||
|
||||
const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if(CLOSURE_IS_BSDF(sc->type)) {
|
||||
if(sc != skip_sc && CLOSURE_IS_BSDF(sc->type)) {
|
||||
float bsdf_pdf = 0.0f;
|
||||
float3 eval = bsdf_eval(kg, sd, sc, omega_in, &bsdf_pdf);
|
||||
|
||||
|
@ -570,7 +567,7 @@ void shader_bsdf_eval(KernelGlobals *kg,
|
|||
#endif
|
||||
{
|
||||
float pdf;
|
||||
_shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, -1, eval, 0.0f, 0.0f);
|
||||
_shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, NULL, eval, 0.0f, 0.0f);
|
||||
if(use_mis) {
|
||||
float weight = power_heuristic(light_pdf, pdf);
|
||||
bsdf_eval_mis(eval, weight);
|
||||
|
@ -578,6 +575,90 @@ void shader_bsdf_eval(KernelGlobals *kg,
|
|||
}
|
||||
}
|
||||
|
||||
ccl_device_inline const ShaderClosure *shader_bsdf_pick(ShaderData *sd)
|
||||
{
|
||||
int sampled = 0;
|
||||
|
||||
if(sd->num_closure > 1) {
|
||||
/* Pick a BSDF or based on sample weights. */
|
||||
float sum = 0.0f;
|
||||
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if(CLOSURE_IS_BSDF(sc->type)) {
|
||||
sum += sc->sample_weight;
|
||||
}
|
||||
}
|
||||
|
||||
float r = sd->randb_closure*sum;
|
||||
float partial_sum = 0.0f;
|
||||
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if(CLOSURE_IS_BSDF(sc->type)) {
|
||||
partial_sum += sc->sample_weight;
|
||||
|
||||
if(r <= partial_sum) {
|
||||
sampled = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &sd->closure[sampled];
|
||||
}
|
||||
|
||||
ccl_device_inline const ShaderClosure *shader_bssrdf_pick(ShaderData *sd,
|
||||
ccl_addr_space float3 *throughput)
|
||||
{
|
||||
int sampled = 0;
|
||||
|
||||
if(sd->num_closure > 1) {
|
||||
/* Pick a BSDF or BSSRDF or based on sample weights. */
|
||||
float sum_bsdf = 0.0f;
|
||||
float sum_bssrdf = 0.0f;
|
||||
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if(CLOSURE_IS_BSDF(sc->type)) {
|
||||
sum_bsdf += sc->sample_weight;
|
||||
}
|
||||
else if(CLOSURE_IS_BSSRDF(sc->type)) {
|
||||
sum_bssrdf += sc->sample_weight;
|
||||
}
|
||||
}
|
||||
|
||||
float r = sd->randb_closure*(sum_bsdf + sum_bssrdf);
|
||||
float partial_sum = 0.0f;
|
||||
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if(CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
|
||||
partial_sum += sc->sample_weight;
|
||||
|
||||
if(r <= partial_sum) {
|
||||
if(CLOSURE_IS_BSDF(sc->type)) {
|
||||
*throughput *= (sum_bsdf + sum_bssrdf) / sum_bsdf;
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
*throughput *= (sum_bsdf + sum_bssrdf) / sum_bssrdf;
|
||||
sampled = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &sd->closure[sampled];
|
||||
}
|
||||
|
||||
ccl_device_inline int shader_bsdf_sample(KernelGlobals *kg,
|
||||
ShaderData *sd,
|
||||
float randu, float randv,
|
||||
|
@ -586,40 +667,14 @@ ccl_device_inline int shader_bsdf_sample(KernelGlobals *kg,
|
|||
differential3 *domega_in,
|
||||
float *pdf)
|
||||
{
|
||||
int sampled = 0;
|
||||
|
||||
if(sd->num_closure > 1) {
|
||||
/* pick a BSDF closure based on sample weights */
|
||||
float sum = 0.0f;
|
||||
|
||||
for(sampled = 0; sampled < sd->num_closure; sampled++) {
|
||||
const ShaderClosure *sc = &sd->closure[sampled];
|
||||
|
||||
if(CLOSURE_IS_BSDF(sc->type))
|
||||
sum += sc->sample_weight;
|
||||
}
|
||||
|
||||
float r = sd->randb_closure*sum;
|
||||
sum = 0.0f;
|
||||
|
||||
for(sampled = 0; sampled < sd->num_closure; sampled++) {
|
||||
const ShaderClosure *sc = &sd->closure[sampled];
|
||||
|
||||
if(CLOSURE_IS_BSDF(sc->type)) {
|
||||
sum += sc->sample_weight;
|
||||
|
||||
if(r <= sum)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(sampled == sd->num_closure) {
|
||||
*pdf = 0.0f;
|
||||
return LABEL_NONE;
|
||||
}
|
||||
const ShaderClosure *sc = shader_bsdf_pick(sd);
|
||||
if(!sc) {
|
||||
*pdf = 0.0f;
|
||||
return LABEL_NONE;
|
||||
}
|
||||
|
||||
const ShaderClosure *sc = &sd->closure[sampled];
|
||||
/* BSSRDF should already have been handled elsewhere. */
|
||||
kernel_assert(CLOSURE_IS_BSDF(sc->type));
|
||||
|
||||
int label;
|
||||
float3 eval;
|
||||
|
@ -632,7 +687,7 @@ ccl_device_inline int shader_bsdf_sample(KernelGlobals *kg,
|
|||
|
||||
if(sd->num_closure > 1) {
|
||||
float sweight = sc->sample_weight;
|
||||
_shader_bsdf_multi_eval(kg, sd, *omega_in, pdf, sampled, bsdf_eval, *pdf*sweight, sweight);
|
||||
_shader_bsdf_multi_eval(kg, sd, *omega_in, pdf, sc, bsdf_eval, *pdf*sweight, sweight);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,87 +28,31 @@ CCL_NAMESPACE_BEGIN
|
|||
* - try to reduce one sample model variance
|
||||
*/
|
||||
|
||||
#define BSSRDF_MULTI_EVAL
|
||||
|
||||
ccl_device ShaderClosure *subsurface_scatter_pick_closure(KernelGlobals *kg, ShaderData *sd, float *probability)
|
||||
{
|
||||
/* sum sample weights of bssrdf and bsdf */
|
||||
float bsdf_sum = 0.0f;
|
||||
float bssrdf_sum = 0.0f;
|
||||
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if(CLOSURE_IS_BSDF(sc->type))
|
||||
bsdf_sum += sc->sample_weight;
|
||||
else if(CLOSURE_IS_BSSRDF(sc->type))
|
||||
bssrdf_sum += sc->sample_weight;
|
||||
}
|
||||
|
||||
/* use bsdf or bssrdf? */
|
||||
float r = sd->randb_closure*(bsdf_sum + bssrdf_sum);
|
||||
|
||||
if(r < bsdf_sum) {
|
||||
/* use bsdf, and adjust randb so we can reuse it for picking a bsdf */
|
||||
sd->randb_closure = r/bsdf_sum;
|
||||
*probability = (bsdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/bsdf_sum: 1.0f;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* use bssrdf */
|
||||
r -= bsdf_sum;
|
||||
|
||||
float sum = 0.0f;
|
||||
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if(CLOSURE_IS_BSSRDF(sc->type)) {
|
||||
sum += sc->sample_weight;
|
||||
|
||||
if(r <= sum) {
|
||||
sd->randb_closure = (r - (sum - sc->sample_weight))/sc->sample_weight;
|
||||
|
||||
#ifdef BSSRDF_MULTI_EVAL
|
||||
*probability = (bssrdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/bssrdf_sum: 1.0f;
|
||||
#else
|
||||
*probability = (bssrdf_sum > 0.0f)? (bsdf_sum + bssrdf_sum)/sc->sample_weight: 1.0f;
|
||||
#endif
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* should never happen */
|
||||
sd->randb_closure = 0.0f;
|
||||
*probability = 1.0f;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd,
|
||||
ShaderClosure *sc,
|
||||
const ShaderClosure *sc,
|
||||
float disk_r,
|
||||
float r,
|
||||
bool all)
|
||||
{
|
||||
#ifdef BSSRDF_MULTI_EVAL
|
||||
/* this is the veach one-sample model with balance heuristic, some pdf
|
||||
* factors drop out when using balance heuristic weighting */
|
||||
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;
|
||||
float sample_weight_inv = 0.0f;
|
||||
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
sc = &sd->closure[i];
|
||||
|
||||
if(CLOSURE_IS_BSSRDF(sc->type)) {
|
||||
float sample_weight = (all)? 1.0f: sc->sample_weight;
|
||||
sample_weight_sum += sample_weight;
|
||||
if(!all) {
|
||||
float sample_weight_sum = 0.0f;
|
||||
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
sc = &sd->closure[i];
|
||||
|
||||
if(CLOSURE_IS_BSSRDF(sc->type)) {
|
||||
sample_weight_sum += sc->sample_weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float sample_weight_inv = 1.0f/sample_weight_sum;
|
||||
sample_weight_inv = 1.0f/sample_weight_sum;
|
||||
}
|
||||
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
sc = &sd->closure[i];
|
||||
|
@ -125,22 +69,14 @@ ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd,
|
|||
/* TODO power heuristic is not working correct here */
|
||||
eval_sum += sc->weight*pdf; //*sample_weight*disk_pdf;
|
||||
pdf_sum += sample_weight*disk_pdf; //*sample_weight*disk_pdf;
|
||||
|
||||
num_bssrdf++;
|
||||
}
|
||||
}
|
||||
|
||||
return (pdf_sum > 0.0f)? eval_sum / pdf_sum : make_float3(0.0f, 0.0f, 0.0f);
|
||||
#else
|
||||
float pdf = bssrdf_pdf(pick_sc, r);
|
||||
float disk_pdf = bssrdf_pdf(pick_sc, disk_r);
|
||||
|
||||
return pick_sc->weight * pdf / disk_pdf;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* replace closures with a single diffuse bsdf closure after scatter step */
|
||||
ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, ShaderClosure *sc, float3 weight, bool hit, float3 N)
|
||||
ccl_device void subsurface_scatter_setup_diffuse_bsdf(ShaderData *sd, const ShaderClosure *sc, float3 weight, bool hit, float3 N)
|
||||
{
|
||||
sd->flag &= ~SD_CLOSURE_FLAGS;
|
||||
sd->randb_closure = 0.0f;
|
||||
|
@ -242,7 +178,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect(
|
|||
KernelGlobals *kg,
|
||||
SubsurfaceIntersection *ss_isect,
|
||||
ShaderData *sd,
|
||||
ShaderClosure *sc,
|
||||
const ShaderClosure *sc,
|
||||
uint *lcg_state,
|
||||
float disk_u,
|
||||
float disk_v,
|
||||
|
@ -255,26 +191,20 @@ ccl_device_inline int subsurface_scatter_multi_intersect(
|
|||
disk_N = sd->Ng;
|
||||
make_orthonormals(disk_N, &disk_T, &disk_B);
|
||||
|
||||
/* reusing variable for picking the closure gives a bit nicer stratification
|
||||
* for path tracer, for branched we do all closures so it doesn't help */
|
||||
float axisu = (all)? disk_u: sd->randb_closure;
|
||||
|
||||
if(axisu < 0.5f) {
|
||||
if(disk_u < 0.5f) {
|
||||
pick_pdf_N = 0.5f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.25f;
|
||||
if(all)
|
||||
disk_u *= 2.0f;
|
||||
disk_u *= 2.0f;
|
||||
}
|
||||
else if(axisu < 0.75f) {
|
||||
else if(disk_u < 0.75f) {
|
||||
float3 tmp = disk_N;
|
||||
disk_N = disk_T;
|
||||
disk_T = tmp;
|
||||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.5f;
|
||||
pick_pdf_B = 0.25f;
|
||||
if(all)
|
||||
disk_u = (disk_u - 0.5f)*4.0f;
|
||||
disk_u = (disk_u - 0.5f)*4.0f;
|
||||
}
|
||||
else {
|
||||
float3 tmp = disk_N;
|
||||
|
@ -283,8 +213,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect(
|
|||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.5f;
|
||||
if(all)
|
||||
disk_u = (disk_u - 0.75f)*4.0f;
|
||||
disk_u = (disk_u - 0.75f)*4.0f;
|
||||
}
|
||||
|
||||
/* sample point on disk */
|
||||
|
@ -390,7 +319,7 @@ ccl_device_noinline void subsurface_scatter_multi_setup(
|
|||
ShaderData *sd,
|
||||
ccl_addr_space PathState *state,
|
||||
int state_flag,
|
||||
ShaderClosure *sc,
|
||||
const ShaderClosure *sc,
|
||||
bool all)
|
||||
{
|
||||
#ifdef __SPLIT_KERNEL__
|
||||
|
@ -419,7 +348,7 @@ ccl_device_noinline void subsurface_scatter_multi_setup(
|
|||
|
||||
/* subsurface scattering step, from a point on the surface to another nearby point on the same object */
|
||||
ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state,
|
||||
int state_flag, ShaderClosure *sc, uint *lcg_state, float disk_u, float disk_v, bool all)
|
||||
int state_flag, const ShaderClosure *sc, uint *lcg_state, float disk_u, float disk_v, bool all)
|
||||
{
|
||||
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
|
@ -430,18 +359,20 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_a
|
|||
disk_N = sd->Ng;
|
||||
make_orthonormals(disk_N, &disk_T, &disk_B);
|
||||
|
||||
if(sd->randb_closure < 0.5f) {
|
||||
if(disk_u < 0.5f) {
|
||||
pick_pdf_N = 0.5f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.25f;
|
||||
disk_u *= 2.0f;
|
||||
}
|
||||
else if(sd->randb_closure < 0.75f) {
|
||||
else if(disk_u < 0.75f) {
|
||||
float3 tmp = disk_N;
|
||||
disk_N = disk_T;
|
||||
disk_T = tmp;
|
||||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.5f;
|
||||
pick_pdf_B = 0.25f;
|
||||
disk_u = (disk_u - 0.5f)*4.0f;
|
||||
}
|
||||
else {
|
||||
float3 tmp = disk_N;
|
||||
|
@ -450,6 +381,7 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, ccl_a
|
|||
pick_pdf_N = 0.25f;
|
||||
pick_pdf_T = 0.25f;
|
||||
pick_pdf_B = 0.5f;
|
||||
disk_u = (disk_u - 0.75f)*4.0f;
|
||||
}
|
||||
|
||||
/* sample point on disk */
|
||||
|
|
|
@ -250,11 +250,7 @@ ccl_device void kernel_subsurface_scatter(KernelGlobals *kg)
|
|||
#ifdef __BRANCHED_PATH__
|
||||
}
|
||||
else if(IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) {
|
||||
float bssrdf_probability;
|
||||
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability);
|
||||
|
||||
/* modify throughput for picking bssrdf or bsdf */
|
||||
*throughput *= bssrdf_probability;
|
||||
const ShaderClosure *sc = shader_bssrdf_pick(sd, throughput);
|
||||
|
||||
/* do bssrdf scatter step if we picked a bssrdf closure */
|
||||
if(sc) {
|
||||
|
|
Loading…
Reference in New Issue