Cycles Volume Render: add support for overlapping volume objects.

This works pretty much as you would expect, overlapping volume objects gives
a more dense volume. What did change is that world volume shaders are now
active everywhere, they are no longer excluded inside objects.

This may not be desirable and we need to think of better control over this.
In some cases you clearly want it to happen, for example if you are rendering
a fire in a foggy environment. In other cases like the inside of a house you
may not want any fog, but it doesn't seem possible in general for the renderer
to automatically determine what is inside or outside of the house.

This is implemented using a simple fixed size array of shader/object ID pairs,
limited to max 15 overlapping objects. The closures from all shaders are put
into a single closure array, exactly the same as if an add shader was used to
combine them.
This commit is contained in:
Brecht Van Lommel 2013-12-28 20:02:40 +01:00
parent e369a5c485
commit 2b39214c4d
9 changed files with 227 additions and 118 deletions

View File

@ -34,7 +34,6 @@
#include "kernel_light.h"
#include "kernel_emission.h"
#include "kernel_passes.h"
#include "kernel_path_state.h"
#ifdef __SUBSURFACE__
#include "kernel_subsurface.h"
@ -44,6 +43,7 @@
#include "kernel_volume.h"
#endif
#include "kernel_path_state.h"
#include "kernel_shadow.h"
CCL_NAMESPACE_BEGIN
@ -93,10 +93,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
#ifdef __VOLUME__
/* volume attenuation */
if(state.volume_shader != SHADER_NO_ID) {
if(state.volume_stack[0].shader != SHADER_NO_ID) {
Ray segment_ray = ray;
segment_ray.t = (hit)? isect.t: FLT_MAX;
throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);
throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray);
}
#endif
@ -116,7 +116,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
float rbsdf = path_rng_1D(kg, rng, sample, num_total_samples, rng_offset + PRNG_BSDF);
shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_INDIRECT);
#ifdef __BRANCHED_PATH__
shader_merge_closures(kg, &sd);
shader_merge_closures(&sd);
#endif
/* blurring of bsdf after bounces, for rays that have a small likelihood
@ -291,7 +291,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
#ifdef __VOLUME__
/* enter/exit volume */
if(label & LABEL_TRANSMIT)
kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
#endif
}
#ifdef __VOLUME__
@ -308,7 +308,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ra
#endif
/* enter/exit volume */
kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
}
#endif
else {
@ -411,7 +411,7 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn
#ifdef __VOLUME__
/* enter/exit volume */
if(label & LABEL_TRANSMIT)
kernel_volume_enter_exit(kg, sd, &state->volume_shader);
kernel_volume_stack_enter_exit(kg, sd, state->volume_stack);
#endif
return true;
}
@ -429,7 +429,7 @@ ccl_device_inline bool kernel_path_integrate_lighting(KernelGlobals *kg, RNG *rn
#endif
/* enter/exit volume */
kernel_volume_enter_exit(kg, sd, &state->volume_shader);
kernel_volume_stack_enter_exit(kg, sd, state->volume_stack);
return true;
}
#endif
@ -515,10 +515,10 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
#ifdef __VOLUME__
/* volume attenuation */
if(state.volume_shader != SHADER_NO_ID) {
if(state.volume_stack[0].shader != SHADER_NO_ID) {
Ray segment_ray = ray;
segment_ray.t = (hit)? isect.t: FLT_MAX;
throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);
throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray);
}
#endif
@ -769,7 +769,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
#ifdef __VOLUME__
/* enter/exit volume */
if(label & LABEL_TRANSMIT)
kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
#endif
}
@ -787,7 +787,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
#endif
/* enter/exit volume */
kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
}
#endif
else {
@ -957,7 +957,7 @@ ccl_device_noinline void kernel_branched_path_integrate_lighting(KernelGlobals *
#ifdef __VOLUME__
/* enter/exit volume */
if(label & LABEL_TRANSMIT)
kernel_volume_enter_exit(kg, sd, &ps.volume_shader);
kernel_volume_stack_enter_exit(kg, sd, ps.volume_stack);
#endif
kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,
@ -1019,10 +1019,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __VOLUME__
/* volume attenuation */
if(state.volume_shader != SHADER_NO_ID) {
if(state.volume_stack[0].shader != SHADER_NO_ID) {
Ray segment_ray = ray;
segment_ray.t = (hit)? isect.t: FLT_MAX;
throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray, state.volume_shader);
throughput *= kernel_volume_get_shadow_attenuation(kg, &state, &segment_ray);
}
#endif
@ -1050,7 +1050,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
ShaderData sd;
shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce);
shader_eval_surface(kg, &sd, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
shader_merge_closures(kg, &sd);
shader_merge_closures(&sd);
/* holdout */
#ifdef __HOLDOUT__
@ -1198,7 +1198,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __VOLUME__
/* enter/exit volume */
kernel_volume_enter_exit(kg, &sd, &state.volume_shader);
kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
#endif
}

View File

@ -16,20 +16,6 @@
CCL_NAMESPACE_BEGIN
typedef struct PathState {
int flag;
int bounce;
int diffuse_bounce;
int glossy_bounce;
int transmission_bounce;
int transparent_bounce;
#ifdef __VOLUME__
int volume_shader;
#endif
} PathState;
ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state)
{
state->flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR|PATH_RAY_MIS_SKIP;
@ -40,8 +26,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg, PathState *state)
state->transparent_bounce = 0;
#ifdef __VOLUME__
/* todo: this assumes camera is always in air, need to detect when it isn't */
state->volume_shader = kernel_data.background.volume_shader;
kernel_volume_stack_init(kg, state->volume_stack);
#endif
}

View File

@ -459,6 +459,41 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s
sd->ray_dP = ray->dP;
}
/* Merging */
#if defined(__BRANCHED_PATH__) || defined(__VOLUME__)
ccl_device void shader_merge_closures(ShaderData *sd)
{
/* merge identical closures, better when we sample a single closure at a time */
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sci = &sd->closure[i];
for(int j = i + 1; j < sd->num_closure; j++) {
ShaderClosure *scj = &sd->closure[j];
#ifdef __OSL__
if(!sci->prim && !scj->prim && sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
#else
if(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
#endif
sci->weight += scj->weight;
sci->sample_weight += scj->sample_weight;
int size = sd->num_closure - (j+1);
if(size > 0) {
for(int k = 0; k < size; k++) {
scj[k] = scj[k+1];
}
}
sd->num_closure--;
j--;
}
}
}
}
#endif
/* BSDF */
#ifdef __MULTI_CLOSURE__
@ -851,9 +886,16 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
float randb, int path_flag, ShaderContext ctx)
{
#ifdef __MULTI_CLOSURE__
sd->num_closure = 0;
sd->randb_closure = randb;
#else
sd->closure.type = NBUILTIN_CLOSURES;
#endif
#ifdef __OSL__
if (kg->osl)
OSLShader::eval_surface(kg, sd, randb, path_flag, ctx);
if(kg->osl)
OSLShader::eval_surface(kg, sd, path_flag, ctx);
else
#endif
{
@ -871,9 +913,17 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
{
#ifdef __MULTI_CLOSURE__
sd->num_closure = 0;
sd->randb_closure = 0.0f;
#else
sd->closure.type = NBUILTIN_CLOSURES;
#endif
#ifdef __OSL__
if (kg->osl)
if(kg->osl) {
return OSLShader::eval_background(kg, sd, path_flag, ctx);
}
else
#endif
@ -907,6 +957,7 @@ ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int
/* Volume */
#ifdef __VOLUME__
ccl_device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
float3 omega_in, float3 omega_out)
{
@ -931,30 +982,77 @@ ccl_device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
/* Volume Evaluation */
ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
float randb, int path_flag, ShaderContext ctx)
VolumeStack *stack, float randb, int path_flag, ShaderContext ctx)
{
/* reset closures once at the start, we will be accumulating the closures
* for all volumes in the stack into a single array of closures */
#ifdef __MULTI_CLOSURE__
sd->num_closure = 0;
sd->randb_closure = randb;
#else
sd->closure.type = NBUILTIN_CLOSURES;
#endif
for(int i = 0; stack[i].shader != SHADER_NO_ID; i++) {
/* setup shaderdata from stack. it's mostly setup already in
* shader_setup_from_volume, this switching should be quick */
sd->object = stack[i].object;
sd->shader = stack[i].shader;
sd->flag &= ~(SD_SHADER_FLAGS|SD_OBJECT_FLAGS);
sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
if(sd->object != ~0) {
sd->flag |= kernel_tex_fetch(__object_flag, sd->object);
#ifdef __OBJECT_MOTION__
/* todo: this is inefficient for motion blur, we should be
* caching matrices instead of recomputing them each step */
shader_setup_object_transforms(kg, sd, sd->time);
#endif
}
/* evaluate shader */
#ifdef __SVM__
#ifdef __OSL__
if (kg->osl)
OSLShader::eval_volume(kg, sd, randb, path_flag, ctx);
else
if(kg->osl) {
OSLShader::eval_volume(kg, sd, path_flag, ctx);
}
else
#endif
svm_eval_nodes(kg, sd, SHADER_TYPE_VOLUME, randb, path_flag);
{
svm_eval_nodes(kg, sd, SHADER_TYPE_VOLUME, randb, path_flag);
}
#endif
/* merge closures to avoid exceeding number of closures limit */
if(i > 0)
shader_merge_closures(sd);
}
}
#endif
/* Displacement Evaluation */
ccl_device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx)
{
#ifdef __MULTI_CLOSURE__
sd->num_closure = 0;
sd->randb_closure = 0.0f;
#else
sd->closure.type = NBUILTIN_CLOSURES;
#endif
/* this will modify sd->P */
#ifdef __SVM__
#ifdef __OSL__
if (kg->osl)
if(kg->osl)
OSLShader::eval_displacement(kg, sd, ctx);
else
#endif
{
svm_eval_nodes(kg, sd, SHADER_TYPE_DISPLACEMENT, 0.0f, 0);
}
#endif
}
@ -984,40 +1082,5 @@ ccl_device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect
}
#endif
/* Merging */
#ifdef __BRANCHED_PATH__
ccl_device void shader_merge_closures(KernelGlobals *kg, ShaderData *sd)
{
/* merge identical closures, better when we sample a single closure at a time */
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sci = &sd->closure[i];
for(int j = i + 1; j < sd->num_closure; j++) {
ShaderClosure *scj = &sd->closure[j];
#ifdef __OSL__
if(!sci->prim && !scj->prim && sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
#else
if(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
#endif
sci->weight += scj->weight;
sci->sample_weight += scj->sample_weight;
int size = sd->num_closure - (j+1);
if(size > 0) {
for(int k = 0; k < size; k++) {
scj[k] = scj[k+1];
}
}
sd->num_closure--;
j--;
}
}
}
}
#endif
CCL_NAMESPACE_END

View File

@ -44,9 +44,8 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
float3 Pend = ray->P + ray->D*ray->t;
int bounce = state->transparent_bounce;
#ifdef __VOLUME__
int volume_shader = state->volume_shader;
PathState ps = *state;
#endif
for(;;) {
@ -74,8 +73,8 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
#ifdef __VOLUME__
/* attenuation for last line segment towards light */
if(volume_shader != SHADER_NO_ID)
throughput *= kernel_volume_get_shadow_attenuation(kg, state, ray, volume_shader);
if(ps.volume_stack[0].shader != SHADER_NO_ID)
throughput *= kernel_volume_get_shadow_attenuation(kg, &ps, ray);
#endif
*shadow *= throughput;
@ -87,10 +86,10 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
#ifdef __VOLUME__
/* attenuation between last surface and next surface */
if(volume_shader != SHADER_NO_ID) {
if(ps.volume_stack[0].shader != SHADER_NO_ID) {
Ray segment_ray = *ray;
segment_ray.t = isect.t;
throughput *= kernel_volume_get_shadow_attenuation(kg, state, &segment_ray, volume_shader);
throughput *= kernel_volume_get_shadow_attenuation(kg, &ps, &segment_ray);
}
#endif
@ -111,10 +110,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
#ifdef __VOLUME__
/* exit/enter volume */
if(sd.flag & SD_BACKFACING)
volume_shader = kernel_data.background.volume_shader;
else
volume_shader = (sd.flag & SD_HAS_VOLUME)? sd.shader: SHADER_NO_ID;
kernel_volume_stack_enter_exit(kg, &sd, ps.volume_stack);
#endif
bounce++;
@ -122,9 +118,9 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
}
}
#ifdef __VOLUME__
else if(!result && state->volume_shader != SHADER_NO_ID) {
else if(!result && state->volume_stack[0].shader != SHADER_NO_ID) {
/* apply attenuation from current volume shader */
*shadow *= kernel_volume_get_shadow_attenuation(kg, state, ray, state->volume_shader);
*shadow *= kernel_volume_get_shadow_attenuation(kg, state, ray);
}
#endif
#endif

View File

@ -48,6 +48,8 @@ CCL_NAMESPACE_BEGIN
#define SHADER_NO_ID -1
#define VOLUME_STACK_SIZE 16
/* device capabilities */
#ifdef __KERNEL_CPU__
#define __KERNEL_SHADING__
@ -511,10 +513,14 @@ enum ShaderDataFlag {
SD_HOMOGENEOUS_VOLUME = 8192, /* has homogeneous volume */
SD_HAS_BSSRDF_BUMP = 16384, /* bssrdf normal uses bump */
SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME|SD_HAS_ONLY_VOLUME|SD_HOMOGENEOUS_VOLUME|SD_HAS_BSSRDF_BUMP),
/* object flags */
SD_HOLDOUT_MASK = 32768, /* holdout for camera rays */
SD_OBJECT_MOTION = 65536, /* has object motion blur */
SD_TRANSFORM_APPLIED = 131072 /* vertices have transform applied */
SD_TRANSFORM_APPLIED = 131072, /* vertices have transform applied */
SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED)
};
struct KernelGlobals;
@ -599,6 +605,29 @@ typedef struct ShaderData {
#endif
} ShaderData;
/* Path State */
#ifdef __VOLUME__
typedef struct VolumeStack {
int object;
int shader;
} VolumeStack;
#endif
typedef struct PathState {
int flag;
int bounce;
int diffuse_bounce;
int glossy_bounce;
int transmission_bounce;
int transparent_bounce;
#ifdef __VOLUME__
VolumeStack volume_stack[VOLUME_STACK_SIZE];
#endif
} PathState;
/* Constant Kernel Data
*
* These structs are passed from CPU to various devices, and the struct layout

View File

@ -64,11 +64,11 @@ ccl_device float3 volume_shader_get_absorption_coefficient(ShaderData *sd)
}
/* evaluate shader to get extinction coefficient at P */
ccl_device float3 volume_extinction_sample(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx, float3 P)
ccl_device float3 volume_extinction_sample(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack, int path_flag, ShaderContext ctx, float3 P)
{
sd->P = P;
shader_eval_volume(kg, sd, 0.0f, path_flag, ctx);
shader_eval_volume(kg, sd, stack, 0.0f, path_flag, ctx);
return volume_shader_get_extinction_coefficient(sd);
}
@ -82,10 +82,10 @@ ccl_device float3 volume_color_attenuation(float3 sigma, float t)
/* get the volume attenuation over line segment defined by segment_ray, with the
* assumption that there are surfaces blocking light between the endpoints */
ccl_device float3 kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathState *state, Ray *segment_ray, int shader)
ccl_device float3 kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathState *state, Ray *segment_ray)
{
ShaderData sd;
shader_setup_from_volume(kg, &sd, segment_ray, shader, state->bounce);
shader_setup_from_volume(kg, &sd, segment_ray, state->volume_stack[0].shader, state->bounce);
/* do we have a volume shader? */
if(!(sd.flag & SD_HAS_VOLUME))
@ -101,7 +101,7 @@ ccl_device float3 kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathSt
* the extinction coefficient for the entire line segment */
/* todo: could this use sigma_t_cache? */
float3 sigma_t = volume_extinction_sample(kg, &sd, path_flag, ctx, segment_ray->P);
float3 sigma_t = volume_extinction_sample(kg, &sd, state->volume_stack, path_flag, ctx, segment_ray->P);
attenuation = volume_color_attenuation(sigma_t, segment_ray->t);
//}
@ -111,13 +111,62 @@ ccl_device float3 kernel_volume_get_shadow_attenuation(KernelGlobals *kg, PathSt
/* Volume Stack */
/* todo: this assumes no overlapping volumes, needs to become a stack */
ccl_device void kernel_volume_enter_exit(KernelGlobals *kg, ShaderData *sd, int *volume_shader)
ccl_device void kernel_volume_stack_init(KernelGlobals *kg, VolumeStack *stack)
{
if(sd->flag & SD_BACKFACING)
*volume_shader = kernel_data.background.volume_shader;
else
*volume_shader = (sd->flag & SD_HAS_VOLUME)? sd->shader: SHADER_NO_ID;
/* todo: this assumes camera is always in air, need to detect when it isn't */
if(kernel_data.background.volume_shader == SHADER_NO_ID) {
stack[0].shader = SHADER_NO_ID;
}
else {
stack[0].shader = kernel_data.background.volume_shader;
stack[0].object = ~0;
stack[1].shader = SHADER_NO_ID;
}
}
ccl_device void kernel_volume_stack_enter_exit(KernelGlobals *kg, ShaderData *sd, VolumeStack *stack)
{
/* todo: we should have some way for objects to indicate if they want the
* world shader to work inside them. excluding it by default is problematic
* because non-volume objects can't be assumed to be closed manifolds */
if(!(sd->flag & SD_HAS_VOLUME))
return;
if(sd->flag & SD_BACKFACING) {
/* exit volume object: remove from stack */
for(int i = 0; stack[i].shader != SHADER_NO_ID; i++) {
if(stack[i].object == sd->object) {
/* shift back next stack entries */
do {
stack[i] = stack[i+1];
i++;
}
while(stack[i].shader != SHADER_NO_ID);
return;
}
}
}
else {
/* enter volume object: add to stack */
int i;
for(i = 0; stack[i].shader != SHADER_NO_ID; i++) {
/* already in the stack? then we have nothing to do */
if(stack[i].object == sd->object)
return;
}
/* if we exceed the stack limit, ignore */
if(i >= VOLUME_STACK_SIZE-1)
return;
/* add to the end of the stack */
stack[i].shader = sd->shader;
stack[i].object = sd->object;
stack[i+1].shader = SHADER_NO_ID;
}
}
CCL_NAMESPACE_END

View File

@ -299,7 +299,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
}
}
void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
{
/* setup shader globals from shader data */
OSLThreadData *tdata = kg->osl_tdata;
@ -315,9 +315,6 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int
ss->execute(*octx, *(kg->osl->surface_state[shader]), *globals);
/* flatten closure tree */
sd->num_closure = 0;
sd->randb_closure = randb;
if (globals->Ci)
flatten_surface_closure_tree(sd, path_flag, globals->Ci);
}
@ -440,7 +437,7 @@ static void flatten_volume_closure_tree(ShaderData *sd,
}
}
void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx)
void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
{
/* setup shader globals from shader data */
OSLThreadData *tdata = kg->osl_tdata;
@ -456,9 +453,6 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int
ss->execute(*octx, *(kg->osl->volume_state[shader]), *globals);
/* flatten closure tree */
sd->num_closure = 0;
sd->randb_closure = randb;
if (globals->Ci)
flatten_volume_closure_tree(sd, globals->Ci);
}

View File

@ -53,9 +53,9 @@ public:
static void thread_free(KernelGlobals *kg);
/* eval */
static void eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx);
static void eval_surface(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx);
static float3 eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx);
static void eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag, ShaderContext ctx);
static void eval_volume(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx);
static void eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx);
/* sample & eval */

View File

@ -188,13 +188,6 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
float closure_weight = 1.0f;
int offset = sd->shader & SHADER_MASK;
#ifdef __MULTI_CLOSURE__
sd->num_closure = 0;
sd->randb_closure = randb;
#else
sd->closure.type = NBUILTIN_CLOSURES;
#endif
while(1) {
uint4 node = read_node(kg, &offset);