* Fix missing update when editing objects with emission materials.
* Fix preview pass rendering set to 1 not showing full resolution.
* Fix CUDA runtime compiling failing due to missing cache directory.
* Use settings from first render layer for visibility and material override.

And a bunch of incomplete and still disabled code mostly related to closure
sampling.
This commit is contained in:
Brecht Van Lommel 2011-09-12 13:13:56 +00:00
parent c40492205b
commit ebc653463d
43 changed files with 1239 additions and 712 deletions

@ -207,11 +207,10 @@ option(WITH_API_INSTALL "Copy API header files into the blender install fold
# Cycles
option(WITH_CYCLES "Enable Cycles Render Engine" ON)
OPTION(WITH_CYCLES_OSL "Build with Open Shading Language support" OFF)
OPTION(WITH_CYCLES_CUDA "Build with CUDA support" OFF)
OPTION(WITH_CYCLES_CUDA "Build with CUDA binaries" OFF)
OPTION(WITH_CYCLES_BLENDER "Build Blender Python extension" ON)
OPTION(WITH_CYCLES_PARTIO "Build with Partio point cloud support (unfinished)" OFF)
OPTION(WITH_CYCLES_NETWORK "Build with network rendering support (unfinished)" OFF)
OPTION(WITH_CYCLES_MULTI "Build with network rendering support (unfinished)" OFF)
OPTION(WITH_CYCLES_TEST "Build cycles test application" OFF)
# disable for now, but plan to support on all platforms eventually

@ -41,10 +41,6 @@ if(WITH_CYCLES_NETWORK)
add_definitions(-DWITH_NETWORK)
endif()
if(WITH_CYCLES_MULTI)
add_definitions(-DWITH_MULTI)
endif()
if(WITH_CYCLES_CUDA)
add_definitions(-DWITH_CUDA_BINARIES)
endif()
@ -59,6 +55,7 @@ endif()
add_definitions(-DWITH_OPENCL)
add_definitions(-DWITH_CUDA)
add_definitions(-DWITH_MULTI)
include_directories(
${BOOST_INCLUDE_DIR}

@ -140,6 +140,42 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
sub.prop(cscene, "debug_bvh_type", text="")
sub.prop(cscene, "debug_use_spatial_splits")
class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
bl_label = "Layers"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render
# row = layout.row()
# row.template_list(rd, "layers", rd.layers, "active_index", rows=2)
# col = row.column(align=True)
# col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
# col.operator("scene.render_layer_remove", icon='ZOOMOUT', text="")
row = layout.row()
# rl = rd.layers.active
rl = rd.layers[0]
row.prop(rl, "name")
#row.prop(rd, "use_single_layer", text="", icon_only=True)
split = layout.split()
col = split.column()
col.prop(scene, "layers", text="Scene")
col = split.column()
col.prop(rl, "layers", text="Layer")
layout.separator()
layout.prop(rl, "material_override", text="Material")
class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
bl_label = "Post Processing"
bl_options = {'DEFAULT_CLOSED'}

@ -223,8 +223,12 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
vector<uint> used_shaders;
BL::Object::material_slots_iterator slot;
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
find_shader(slot->material(), used_shaders);
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
if(render_layer.material_override)
find_shader(render_layer.material_override, used_shaders);
else
find_shader(slot->material(), used_shaders);
}
if(used_shaders.size() == 0)
used_shaders.push_back(scene->default_surface);

@ -108,7 +108,7 @@ void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob,
/* Object */
void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint visibility)
{
/* light is handled separately */
if(object_is_light(b_ob)) {
@ -130,7 +130,7 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob,
object->name = b_ob.name();
object->tfm = tfm;
object->visibility = object_ray_visibility(b_ob);
object->visibility = object_ray_visibility(b_ob) & visibility;
if(b_parent.ptr.data != b_ob.ptr.data)
object->visibility &= object_ray_visibility(b_parent);
@ -147,12 +147,8 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob,
void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
{
/* layer data */
uint layer;
if(b_v3d)
layer = get_layer(b_v3d.layers());
else
layer = get_layer(b_scene.layers());
uint scene_layer = render_layer.scene_layer;
uint layer = render_layer.layer;
/* prepare for sync */
light_map.pre_sync();
@ -165,8 +161,14 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
for(b_scene.objects.begin(b_ob); b_ob != b_scene.objects.end(); ++b_ob) {
bool hide = (b_v3d)? b_ob->hide(): b_ob->hide_render();
uint ob_layer = get_layer(b_ob->layers());
if(!hide && (ob_layer & scene_layer)) {
uint visibility = PATH_RAY_ALL;
if(!(ob_layer & layer))
visibility &= ~PATH_RAY_CAMERA;
if(!hide && get_layer(b_ob->layers()) & layer) {
if(b_ob->is_duplicator()) {
/* dupli objects */
object_create_duplilist(*b_ob, b_scene);
@ -176,7 +178,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
for(b_ob->dupli_list.begin(b_dup); b_dup != b_ob->dupli_list.end(); ++b_dup) {
Transform tfm = get_transform(b_dup->matrix());
sync_object(*b_ob, b_index, b_dup->object(), tfm);
sync_object(*b_ob, b_index, b_dup->object(), tfm, visibility);
b_index++;
}
@ -185,7 +187,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
else {
/* object itself */
Transform tfm = get_transform(b_ob->matrix_world());
sync_object(*b_ob, 0, *b_ob, tfm);
sync_object(*b_ob, 0, *b_ob, tfm, visibility);
}
}
}

@ -118,6 +118,7 @@ void BlenderSync::sync_data(BL::SpaceView3D b_v3d)
{
sync_integrator();
sync_film();
sync_render_layer(b_v3d);
sync_shaders();
sync_objects(b_v3d);
}
@ -172,6 +173,29 @@ void BlenderSync::sync_film()
filter->tag_update(scene);
}
/* Render Layer */
void BlenderSync::sync_render_layer(BL::SpaceView3D b_v3d)
{
if(b_v3d) {
render_layer.scene_layer = get_layer(b_v3d.layers());
render_layer.layer = render_layer.scene_layer;
render_layer.material_override = PointerRNA_NULL;
}
else {
BL::RenderSettings r = b_scene.render();
BL::RenderSettings::layers_iterator b_rlay;
for(r.layers.begin(b_rlay); b_rlay != r.layers.end(); ++b_rlay) {
render_layer.scene_layer = get_layer(b_scene.layers());
render_layer.layer = get_layer(b_rlay->layers());
render_layer.material_override = b_rlay->material_override();
break; /* single layer for now */
}
}
}
/* Scene Parameters */
SceneParams BlenderSync::get_scene_params(BL::Scene b_scene)

@ -72,11 +72,12 @@ private:
void sync_integrator();
void sync_view();
void sync_world();
void sync_render_layer(BL::SpaceView3D b_v3d);
void sync_shaders();
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
Mesh *sync_mesh(BL::Object b_ob, bool object_updated);
void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm);
void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint visibility);
void sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm);
/* util */
@ -99,6 +100,17 @@ private:
Scene *scene;
bool preview;
struct RenderLayerInfo {
RenderLayerInfo()
: scene_layer(0), layer(0),
material_override(PointerRNA_NULL)
{}
uint scene_layer;
uint layer;
BL::Material material_override;
} render_layer;
};
CCL_NAMESPACE_END

@ -84,7 +84,7 @@ void Device::pixels_alloc(device_memory& mem)
void Device::pixels_copy_from(device_memory& mem, int y, int w, int h)
{
mem_copy_from(mem, sizeof(uchar)*4*y*w, sizeof(uchar)*4*w*h);
mem_copy_from(mem, sizeof(uint8_t)*4*y*w, sizeof(uint8_t)*4*w*h);
}
void Device::pixels_free(device_memory& mem)
@ -104,7 +104,13 @@ void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int width, in
glPixelZoom((float)width/(float)w, (float)height/(float)h);
glRasterPos2f(0, y);
glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)rgba.data_pointer);
uint8_t *pixels = (uint8_t*)rgba.data_pointer;
/* for multi devices, this assumes the ineffecient method that we allocate
all pixels on the device even though we only render to a subset */
pixels += sizeof(uint8_t)*4*y*w;
glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glRasterPos2f(0.0f, 0.0f);
glPixelZoom(1.0f, 1.0f);

@ -232,11 +232,16 @@ public:
double starttime = time_dt();
printf("Compiling CUDA kernel ...\n");
path_create_directories(cubin);
string command = string_printf("%s -arch=sm_%d%d -m%d --cubin \"%s\" --use_fast_math "
"-o \"%s\" --ptxas-options=\"-v\" --maxrregcount=%d --opencc-options -OPT:Olimit=0 -I\"%s\" -DNVCC",
nvcc.c_str(), major, minor, machine, kernel.c_str(), cubin.c_str(), maxreg, include.c_str());
system(command.c_str());
if(system(command.c_str()) == -1) {
fprintf(stderr, "Failed to execute compilation command.\n");
return "";
}
/* verify if compilation succeeded */
if(!path_exists(cubin)) {
@ -708,9 +713,13 @@ public:
cuda_push_context();
/* for multi devices, this assumes the ineffecient method that we allocate
all pixels on the device even though we only render to a subset */
size_t offset = sizeof(uint8_t)*4*y*w;
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pmem.cuPBO);
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glEnable(GL_TEXTURE_2D);
@ -729,11 +738,11 @@ public:
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glTexCoord2f((float)w/(float)width, 0);
glTexCoord2f((float)w/(float)pmem.w, 0.0f);
glVertex2f((float)width, 0.0f);
glTexCoord2f((float)w/(float)width, (float)h/(float)height);
glTexCoord2f((float)w/(float)pmem.w, (float)h/(float)pmem.h);
glVertex2f((float)width, (float)height);
glTexCoord2f(0.0f, (float)h/(float)height);
glTexCoord2f(0.0f, (float)h/(float)pmem.h);
glVertex2f(0.0f, (float)height);
glEnd();

@ -47,9 +47,6 @@ public:
MultiDevice(bool background_)
: unique_ptr(1)
{
/* enforce background for now */
background = true;
Device *device;
/* add CPU device */
@ -125,6 +122,15 @@ public:
return desc.str();
}
bool load_kernels()
{
foreach(SubDevice& sub, devices)
if(!sub.device->load_kernels())
return false;
return true;
}
void mem_alloc(device_memory& mem, MemoryType type)
{
foreach(SubDevice& sub, devices) {
@ -219,12 +225,26 @@ public:
void pixels_alloc(device_memory& mem)
{
Device::pixels_alloc(mem);
foreach(SubDevice& sub, devices) {
mem.device_pointer = 0;
sub.device->pixels_alloc(mem);
sub.ptr_map[unique_ptr] = mem.device_pointer;
}
mem.device_pointer = unique_ptr++;
}
void pixels_free(device_memory& mem)
{
Device::pixels_free(mem);
device_ptr tmp = mem.device_pointer;
foreach(SubDevice& sub, devices) {
mem.device_pointer = sub.ptr_map[tmp];
sub.device->pixels_free(mem);
sub.ptr_map.erase(sub.ptr_map.find(tmp));
}
mem.device_pointer = 0;
}
void pixels_copy_from(device_memory& mem, int y, int w, int h)
@ -248,14 +268,16 @@ public:
{
device_ptr tmp = rgba.device_pointer;
int i = 0, sub_h = h/devices.size();
int sub_height = height/devices.size();
foreach(SubDevice& sub, devices) {
int sy = y + i*sub_h;
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
int sheight = (i == (int)devices.size() - 1)? height - sub_height*i: sub_height;
/* adjust math for w/width */
rgba.device_pointer = sub.ptr_map[tmp];
sub.device->draw_pixels(rgba, sy, w, sh, width, height, transparent);
sub.device->draw_pixels(rgba, sy, w, sh, width, sheight, transparent);
i++;
}

@ -46,20 +46,29 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
return eval;
}
__device bool direct_emission(KernelGlobals *kg, ShaderData *sd, float randt, float rando,
float randu, float randv, Ray *ray, float3 *eval)
__device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
float randt, float rando, float randu, float randv, Ray *ray, float3 *eval)
{
/* sample a position on a light */
LightSample ls;
light_sample(kg, randt, randu, randv, sd->P, &ls);
#ifdef __MULTI_LIGHT__
if(lindex != -1) {
/* sample position on a specified light */
light_select(kg, lindex, randu, randv, sd->P, &ls);
}
else
#endif
{
/* sample a light and position on int */
light_sample(kg, randt, randu, randv, sd->P, &ls);
}
/* compute incoming direction and distance */
float t;
float3 omega_in = normalize_len(ls.P - sd->P, &t);
/* compute pdf */
float pdf = light_pdf(kg, &ls, -omega_in, t);
float pdf = light_sample_pdf(kg, &ls, -omega_in, t);
/* evaluate closure */
*eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -omega_in);
@ -67,6 +76,8 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, float randt, fl
if(is_zero(*eval) || pdf == 0.0f)
return false;
/* todo: use visbility flag to skip lights */
/* evaluate BSDF at shading point */
float bsdf_pdf;
float3 bsdf_eval = shader_bsdf_eval(kg, sd, omega_in, &bsdf_pdf);
@ -88,10 +99,22 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, float randt, fl
*eval *= 0.25f;
}
/* setup ray */
ray->P = ray_offset(sd->P, sd->Ng);
ray->D = ray_offset(ls.P, ls.Ng) - ray->P;
ray->D = normalize_len(ray->D, &ray->t);
#if 0
/* todo: implement this in light */
bool no_shadow = true;
if(no_shadow) {
ray->t = 0.0f;
}
else {
#endif
/* setup ray */
ray->P = ray_offset(sd->P, sd->Ng);
ray->D = ray_offset(ls.P, ls.Ng) - ray->P;
ray->D = normalize_len(ray->D, &ray->t);
#if 0
}
#endif
return true;
}

@ -20,7 +20,7 @@
#ifdef __KERNEL_CPU__
#ifdef WITH_OSL
#ifdef __OSL__
#include "osl_globals.h"
#endif
@ -43,7 +43,7 @@ typedef struct KernelGlobals {
KernelData __data;
#ifdef WITH_OSL
#ifdef __OSL__
/* On the CPU, we also have the OSL globals here. Most data structures are shared
with SVM, the difference is in the shaders and object/mesh attributes. */
OSLGlobals osl;

@ -129,7 +129,7 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra
}
}
__device float light_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
__device float light_sample_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
{
float pdf;
@ -141,5 +141,15 @@ __device float light_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
return pdf;
}
__device void light_select(KernelGlobals *kg, int index, float randu, float randv, float3 P, LightSample *ls)
{
point_light_sample(kg, index, randu, randv, P, ls);
}
__device float light_select_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
{
return point_light_pdf(kg, t);
}
CCL_NAMESPACE_END

@ -162,6 +162,86 @@ __device_inline float path_state_terminate_probability(KernelGlobals *kg, PathSt
return average(throughput);
}
#ifdef __TRANSPARENT_SHADOWS__
__device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect)
{
int prim = kernel_tex_fetch(__prim_index, isect->prim);
float4 Ns = kernel_tex_fetch(__tri_normal, prim);
int shader = __float_as_int(Ns.w);
/* todo: add shader flag to check this */
return true;
}
#endif
__device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, Intersection *isect, float3 *light_L)
{
if(ray->t == 0.0f)
return false;
bool result = scene_intersect(kg, ray, PATH_RAY_SHADOW, isect);
#ifdef __TRANSPARENT_SHADOWS__
if(result && kernel_data.integrator.transparent_shadows) {
/* transparent shadows work in such a way to try to minimize overhead
in cases where we don't need them. after a regular shadow ray is
cast we check if the hit primitive was potentially transparent, and
only in that case start marching. this gives on extra ray cast for
the cases were we do want transparency */
if(shader_transparent_shadow(kg, isect)) {
/* todo: fix double contribution from indirect for triangle lights */
/* if(kernel_data.integrator.transparent_shadows && (path_flag & PATH_RAY_TRANSPARENT)) */
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
float3 Pend = ray->P + ray->D*ray->t;
int bounce = state->transparent_bounce;
for(;;) {
if(bounce >= kernel_data.integrator.transparent_max_bounce) {
return true;
}
else if(bounce >= kernel_data.integrator.transparent_min_bounce) {
/* todo: get random number somewhere for probabilistic terminate */
#if 0
float probability = average(throughput);
float terminate = 0.0f; /* todo: get this random number */
if(terminate >= probability)
return true;
throughput /= probability;
#endif
}
/* todo: fix it so we get first hit */
if(!scene_intersect(kg, ray, PATH_RAY_SHADOW, isect)) {
*light_L *= throughput;
return false;
}
if(!shader_transparent_shadow(kg, isect))
return true;
ShaderData sd;
shader_setup_from_ray(kg, &sd, isect, ray);
shader_eval_surface(kg, &sd, 0.0f, PATH_RAY_SHADOW); /* todo: state flag? */
throughput *= shader_bsdf_transparency(kg, &sd);
ray->P = ray_offset(sd.P, -sd.Ng);
ray->t = len(Pend - ray->P);
bounce++;
}
return true;
}
}
#endif
return result;
}
__device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray ray, float3 throughput)
{
/* initialize */
@ -247,13 +327,22 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray
Ray light_ray;
float3 light_L;
/* todo: use visbility flag to skip lights */
#ifdef __MULTI_LIGHT__
/* index -1 means randomly sample from distribution */
int i = (kernel_data.integrator.num_distribution)? -1: 0;
if(direct_emission(kg, &sd, light_t, light_o, light_u, light_v, &light_ray, &light_L)) {
/* trace shadow ray */
if(!scene_intersect(kg, &light_ray, PATH_RAY_SHADOW, &isect))
L += throughput*light_L;
for(; i < kernel_data.integrator.num_all_lights; i++) {
#else
const int i = -1;
#endif
if(direct_emission(kg, &sd, i, light_t, light_o, light_u, light_v, &light_ray, &light_L)) {
/* trace shadow ray */
if(!shadow_blocked(kg, &state, &light_ray, &isect, &light_L))
L += throughput*light_L;
}
#ifdef __MULTI_LIGHT__
}
#endif
}
}
#endif

@ -26,14 +26,19 @@
*
*/
#ifdef __OSL__
#include "osl_shader.h"
#else
#include "svm/bsdf.h"
#include "svm/emissive.h"
#include "svm/volume.h"
#include "svm/svm_bsdf.h"
#include "svm/svm.h"
#ifdef WITH_OSL
#include "osl_shader.h"
#endif
CCL_NAMESPACE_BEGIN
@ -270,96 +275,201 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData
/* BSDF */
__device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
float randu, float randv, float3 *eval,
float3 *omega_in, differential3 *domega_in, float *pdf)
#ifdef __MULTI_CLOSURE__
__device_inline float3 _shader_bsdf_multi_eval(const ShaderData *sd, const float3 omega_in, float *pdf,
int skip_bsdf, float3 sum_eval, float sum_pdf, float sum_sample_weight)
{
int label;
for(int i = 0; i< sd->num_closure; i++) {
if(i == skip_bsdf)
continue;
*pdf = 0.0f;
const ShaderClosure *sc = &sd->closure[i];
#ifdef WITH_OSL
if(kg->osl.use)
label = OSLShader::bsdf_sample(sd, randu, randv, *eval, *omega_in, *domega_in, *pdf);
else
if(CLOSURE_IS_BSDF(sc->type)) {
float bsdf_pdf = 0.0f;
#ifdef __OSL__
float3 eval = OSLShader::bsdf_eval(sd, sc, omega_in, bsdf_pdf);
#else
float3 eval = svm_bsdf_eval(sd, sc, omega_in, &bsdf_pdf);
#endif
label = svm_bsdf_sample(sd, randu, randv, eval, omega_in, domega_in, pdf);
return label;
if(bsdf_pdf != 0.0f) {
sum_eval += eval*sc->weight;
sum_pdf += bsdf_pdf*sc->sample_weight;
}
sum_sample_weight += sc->sample_weight;
}
}
*pdf = sum_pdf/sum_sample_weight;
return sum_eval;
}
#endif
__device float3 shader_bsdf_eval(KernelGlobals *kg, const ShaderData *sd,
const float3 omega_in, float *pdf)
{
float3 eval;
#ifdef __MULTI_CLOSURE__
return _shader_bsdf_multi_eval(sd, omega_in, pdf, -1, make_float3(0.0f, 0.0f, 0.0f), 0.0f, 0.0f);
#else
const ShaderClosure *sc = &sd->closure;
*pdf = 0.0f;
return svm_bsdf_eval(sd, sc, omega_in, pdf)*sc->weight;
#endif
}
__device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
float randu, float randv, float3 *eval,
float3 *omega_in, differential3 *domega_in, float *pdf)
{
#ifdef __MULTI_CLOSURE__
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 += sd->closure[sampled].sample_weight;
if(r <= sum)
break;
}
}
if(sampled == sd->num_closure) {
*pdf = 0.0f;
return LABEL_NONE;
}
}
const ShaderClosure *sc = &sd->closure[sampled];
int label;
*pdf = 0.0f;
#ifdef WITH_OSL
if(kg->osl.use)
eval = OSLShader::bsdf_eval(sd, omega_in, *pdf);
else
#ifdef __OSL__
label = OSLShader::bsdf_sample(sd, sc, randu, randv, *eval, *omega_in, *domega_in, *pdf);
#else
label = svm_bsdf_sample(sd, sc, randu, randv, eval, omega_in, domega_in, pdf);
#endif
eval = svm_bsdf_eval(sd, omega_in, pdf);
return eval;
*eval *= sc->weight;
if(sd->num_closure > 1 && *pdf != 0.0f) {
float sweight = sc->sample_weight;
*eval = _shader_bsdf_multi_eval(sd, *omega_in, pdf, sampled, *eval, *pdf*sweight, sweight);
}
return label;
#else
/* sample the single closure that we picked */
*pdf = 0.0f;
int label = svm_bsdf_sample(sd, &sd->closure, randu, randv, eval, omega_in, domega_in, pdf);
*eval *= sd->closure.weight;
return label;
#endif
}
__device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness)
{
#ifdef WITH_OSL
if(!kg->osl.use)
#ifndef __OSL__
#ifdef __MULTI_CLOSURE__
for(int i = 0; i< sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_BSDF(sc->type))
svm_bsdf_blur(sc, roughness);
}
#else
svm_bsdf_blur(&sd->closure, roughness);
#endif
#endif
svm_bsdf_blur(sd, roughness);
}
__device float3 shader_bsdf_transparency(KernelGlobals *kg, ShaderData *sd)
{
#ifdef __MULTI_CLOSURE__
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i< sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID) // XXX osl
eval += sc->weight;
}
return eval;
#else
if(sd->closure.type == CLOSURE_BSDF_TRANSPARENT_ID)
return sd->closure.weight;
else
return make_float3(0.0f, 0.0f, 0.0f);
#endif
}
/* Emission */
__device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd)
{
#ifdef WITH_OSL
if(kg->osl.use) {
return OSLShader::emissive_eval(sd);
}
else
#endif
{
return svm_emissive_eval(sd);
}
}
#ifdef __MULTI_CLOSURE__
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
__device void shader_emissive_sample(KernelGlobals *kg, ShaderData *sd,
float randu, float randv, float3 *eval, float3 *I, float *pdf)
{
#ifdef WITH_OSL
if(kg->osl.use) {
OSLShader::emissive_sample(sd, randu, randv, eval, I, pdf);
}
else
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_EMISSION(sc->type)) {
#ifdef __OSL__
eval += OSLShader::emissive_eval(sd)*sc->weight;
#else
eval += svm_emissive_eval(sd, sc)*sc->weight;
#endif
{
svm_emissive_sample(sd, randu, randv, eval, I, pdf);
}
}
return eval;
#else
return svm_emissive_eval(sd, &sd->closure)*sd->closure.weight;
#endif
}
/* Holdout */
__device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
{
#ifdef WITH_OSL
if(kg->osl.use) {
return OSLShader::holdout_eval(sd);
#ifdef __MULTI_CLOSURE__
float3 weight = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i < sd->num_closure; i++) {
ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_HOLDOUT(sc->type))
weight += sc->weight;
}
else
return weight;
#else
if(sd->closure.type == CLOSURE_HOLDOUT_ID)
return make_float3(1.0f, 1.0f, 1.0f);
return make_float3(0.0f, 0.0f, 0.0f);
#endif
{
#ifdef __SVM__
if(sd->svm_closure == CLOSURE_HOLDOUT_ID)
return make_float3(1.0f, 1.0f, 1.0f);
else
#endif
return make_float3(0.0f, 0.0f, 0.0f);
}
}
/* Surface Evaluation */
@ -367,54 +477,54 @@ __device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
__device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
float randb, int path_flag)
{
#ifdef WITH_OSL
if(kg->osl.use) {
OSLShader::eval_surface(kg, sd, randb, path_flag);
}
else
#endif
{
#ifdef __SVM__
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, randb, path_flag);
#ifdef __OSL__
OSLShader::eval_surface(kg, sd, randb, path_flag);
#else
bsdf_diffuse_setup(sd, sd->N);
sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f);
#ifdef __SVM__
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, randb, path_flag);
#else
bsdf_diffuse_setup(sd, &sd->closure);
sd->closure.weight = make_float3(0.8f, 0.8f, 0.8f);
#endif
#ifdef __CAUSTICS_TRICKS__
/* caustic tricks */
if((path_flag & PATH_RAY_DIFFUSE) && (sd->flag & SD_BSDF_GLOSSY)) {
if(kernel_data.integrator.no_caustics) {
sd->flag &= ~(SD_BSDF_GLOSSY|SD_BSDF_HAS_EVAL|SD_EMISSION);
sd->svm_closure = NBUILTIN_CLOSURES;
sd->svm_closure_weight = make_float3(0.0f, 0.0f, 0.0f);
}
else if(kernel_data.integrator.blur_caustics > 0.0f)
shader_bsdf_blur(kg, sd, kernel_data.integrator.blur_caustics);
}
#endif
}
}
/* Background Evaluation */
__device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
{
#ifdef WITH_OSL
if(kg->osl.use) {
return OSLShader::eval_background(kg, sd, path_flag);
}
else
#endif
{
#ifdef __SVM__
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, 0.0f, path_flag);
#ifdef __OSL__
return OSLShader::eval_background(kg, sd, path_flag);
#else
sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f);
#ifdef __SVM__
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, 0.0f, path_flag);
#ifdef __MULTI_CLOSURE__
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i< sd->num_closure; i++) {
const ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_BACKGROUND(sc->type))
eval += sc->weight;
}
return eval;
#else
if(sd->closure.type == CLOSURE_BACKGROUND_ID)
return sd->closure.weight;
else
return make_float3(0.8f, 0.8f, 0.8f);
#endif
return sd->svm_closure_weight;
}
#else
return make_float3(0.8f, 0.8f, 0.8f);
#endif
#endif
}
/* Volume */
@ -422,15 +532,25 @@ __device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int pa
__device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
float3 omega_in, float3 omega_out)
{
#ifdef WITH_OSL
if(kg->osl.use) {
OSLShader::volume_eval_phase(sd, omega_in, omega_out);
}
else
#ifdef __MULTI_CLOSURE__
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i< sd->num_closure; i++) {
const ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_VOLUME(sc->type)) {
#ifdef __OSL__
eval += OSLShader::volume_eval_phase(sd, omega_in, omega_out);
#else
eval += volume_eval_phase(sd, sc, omega_in, omega_out);
#endif
{
return volume_eval_phase(sd, omega_in, omega_out);
}
}
return eval;
#else
return volume_eval_phase(sd, &sd->closure, omega_in, omega_out);
#endif
}
/* Volume Evaluation */
@ -438,17 +558,13 @@ __device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
__device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
float randb, int path_flag)
{
#ifdef WITH_OSL
if(kg->osl.use) {
OSLShader::eval_volume(kg, sd, randb, path_flag);
}
else
#endif
{
#ifdef __SVM__
svm_eval_nodes(kg, sd, SHADER_TYPE_VOLUME, randb, path_flag);
#ifdef __OSL__
OSLShader::eval_volume(kg, sd, randb, path_flag);
#else
svm_eval_nodes(kg, sd, SHADER_TYPE_VOLUME, randb, path_flag);
#endif
#endif
}
}
/* Displacement Evaluation */
@ -456,27 +572,21 @@ __device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
__device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd)
{
/* this will modify sd->P */
#ifdef WITH_OSL
if(kg->osl.use) {
OSLShader::eval_displacement(kg, sd);
}
else
#endif
{
#ifdef __SVM__
svm_eval_nodes(kg, sd, SHADER_TYPE_DISPLACEMENT, 0.0f, 0);
#ifdef __OSL__
OSLShader::eval_displacement(kg, sd);
#else
svm_eval_nodes(kg, sd, SHADER_TYPE_DISPLACEMENT, 0.0f, 0);
#endif
#endif
}
}
/* Free ShaderData */
__device void shader_release(KernelGlobals *kg, ShaderData *sd)
{
#ifdef WITH_OSL
if(kg->osl.use)
OSLShader::release(kg, sd);
#ifdef __OSL__
OSLShader::release(kg, sd);
#endif
}

@ -34,6 +34,9 @@ CCL_NAMESPACE_BEGIN
#define __BACKGROUND__
#define __CAUSTICS_TRICKS__
#define __VISIBILITY_FLAG__
#define __RAY_DIFFERENTIALS__
#define __CAMERA_CLIPPING__
#define __INTERSECTION_REFINE__
#ifndef __KERNEL_OPENCL__
#define __SVM__
@ -42,9 +45,13 @@ CCL_NAMESPACE_BEGIN
#define __HOLDOUT__
#endif
#define __RAY_DIFFERENTIALS__
#define __CAMERA_CLIPPING__
#define __INTERSECTION_REFINE__
#ifdef __KERNEL_CPU__
//#define __MULTI_CLOSURE__
//#define __MULTI_LIGHT__
//#define __TRANSPARENT_SHADOWS__
//#define __OSL__
#endif
//#define __SOBOL_FULL_SCREEN__
//#define __MODIFY_TP__
//#define __QBVH__
@ -179,20 +186,27 @@ typedef enum AttributeElement {
ATTR_ELEMENT_NONE
} AttributeElement;
/* OSL data */
/* Closure data */
#if !defined(__KERNEL_GPU__) && defined(WITH_OSL)
#define MAX_CLOSURE 8
#define MAX_OSL_CLOSURE 8
struct FlatClosure {
void *prim;
typedef struct ShaderClosure {
ClosureType type;
float3 weight;
float sample_weight;
};
#ifdef __MULTI_CLOSURE__
float sample_weight;
#endif
#ifdef __OSL__
void *prim;
#else
float data0;
float data1;
#endif
} ShaderClosure;
/* Shader Data
*
* Main shader state at a point on the surface or in a volume. All coordinates
@ -244,34 +258,18 @@ typedef struct ShaderData {
float3 dPdu, dPdv;
#endif
/* SVM closure data. we always sample a single closure, to get fixed
* memory usage, svm_closure_data contains closure parameters. */
ClosureType svm_closure;
float3 svm_closure_weight;
float svm_closure_data0;
float svm_closure_data1;
#if !defined(__KERNEL_GPU__) && defined(WITH_OSL)
/* OSL closure data and context. we store all closures flattened into
* lists per type, different from SVM. */
struct {
FlatClosure bsdf[MAX_OSL_CLOSURE];
FlatClosure emissive[MAX_OSL_CLOSURE];
FlatClosure volume[MAX_OSL_CLOSURE];
int num_bsdf;
int num_emissive;
int num_volume;
float bsdf_sample_sum;
float emissive_sample_sum;
float volume_sample_sum;
float3 holdout_weight;
float randb;
} osl_closure;
#ifdef __MULTI_CLOSURE__
/* Closure data, we store a fixed array of closures */
ShaderClosure closure[MAX_CLOSURE];
int num_closure;
float randb_closure;
#else
/* Closure data, with a single sampled closure for low memory usage */
ShaderClosure closure;
#endif
#ifdef __OSL__
/* OSL context */
void *osl_ctx;
#endif
} ShaderData;
@ -352,11 +350,11 @@ typedef struct KernelSunSky {
typedef struct KernelIntegrator {
/* emission */
int use_emission;
int num_triangles;
int num_distribution;
int num_lights;
int num_all_lights;
float pdf_triangles;
float pdf_lights;
float pdf_pad;
/* bounces */
int min_bounce;

@ -119,13 +119,13 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data();
if(prim) {
FlatClosure flat;
flat.prim = prim;
flat.weight = weight;
ShaderClosure sc;
sc.prim = prim;
sc.weight = weight;
switch(prim->category()) {
case ClosurePrimitive::BSDF: {
if(sd->osl_closure.num_bsdf == MAX_OSL_CLOSURE)
if(sd->num_closure == MAX_CLOSURE)
return;
OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)prim;
@ -140,7 +140,8 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
float sample_weight = fabsf(average(weight))*albedo;
float sample_sum = sd->osl_closure.bsdf_sample_sum + sample_weight;
flat.sample_weight = sample_weight;
sc.sample_weight = sample_weight;
sc.type = CLOSURE_BSDF_ID;
sd->osl_closure.bsdf_sample_sum = sample_sum;
/* scattering flags */
@ -152,29 +153,35 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
sd->flag |= SD_BSDF;
/* add */
sd->osl_closure.bsdf[sd->osl_closure.num_bsdf++] = flat;
sd->closure[sd->num_closure++] = sc;
break;
}
case ClosurePrimitive::Emissive: {
if(sd->osl_closure.num_bsdf == MAX_OSL_CLOSURE)
if(sd->num_closure == MAX_CLOSURE)
return;
/* sample weight */
float sample_weight = fabsf(average(weight));
float sample_sum = sd->osl_closure.emissive_sample_sum + sample_weight;
flat.sample_weight = sample_weight;
sc.sample_weight = sample_weight;
sc.type = CLOSURE_EMISSION_ID;
sd->osl_closure.emissive_sample_sum = sample_sum;
/* flag */
sd->flag |= SD_EMISSION;
sd->osl_closure.emissive[sd->osl_closure.num_emissive++] = flat;
sd->closure[sd->num_closure++] = sc;
break;
}
case ClosurePrimitive::Holdout:
sd->osl_closure.holdout_weight += weight;
if(sd->num_closure == MAX_CLOSURE)
return;
sc.sample_weight = 0.0f;
sc.type = CLOSURE_HOLDOUT_ID;
sd->flag |= SD_HOLDOUT;
sd->closure[sd->num_closure++] = sc;
break;
case ClosurePrimitive::BSSRDF:
case ClosurePrimitive::Debug:
@ -213,12 +220,8 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int
ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.surface_state[sd->shader]), *globals);
/* flatten closure tree */
sd->osl_closure.bsdf_sample_sum = 0.0f;
sd->osl_closure.emissive_sample_sum = 0.0f;
sd->osl_closure.num_bsdf = 0;
sd->osl_closure.num_emissive = 0;
sd->osl_closure.holdout_weight = make_float3(0.0f, 0.0f, 0.0f);
sd->osl_closure.randb = randb;
sd->num_closure = 0;
sd->randb_closure = randb;
if(globals->Ci) {
bool no_glossy = (path_flag & PATH_RAY_DIFFUSE) && kernel_data.integrator.no_caustics;
@ -292,24 +295,25 @@ static void flatten_volume_closure_tree(ShaderData *sd,
OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data();
if(prim) {
FlatClosure flat;
flat.prim = prim;
flat.weight = weight;
ShaderClosure sc;
sc.prim = prim;
sc.weight = weight;
switch(prim->category()) {
case ClosurePrimitive::Volume: {
if(sd->osl_closure.num_bsdf == MAX_OSL_CLOSURE)
if(sd->num_closure == MAX_CLOSURE)
return;
/* sample weight */
float sample_weight = fabsf(average(weight));
float sample_sum = sd->osl_closure.volume_sample_sum + sample_weight;
flat.sample_weight = sample_weight;
sc.sample_weight = sample_weight;
sc.type = CLOSURE_VOLUME_ID;
sd->osl_closure.volume_sample_sum = sample_sum;
/* add */
sd->osl_closure.volume[sd->osl_closure.num_volume++] = flat;
sd->closure[sd->num_closure++] = sc;
break;
}
case ClosurePrimitive::Holdout:
@ -389,183 +393,76 @@ void OSLShader::release(KernelGlobals *kg, const ShaderData *sd)
/* BSDF Closure */
int OSLShader::bsdf_sample(const ShaderData *sd, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)
int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)
{
OSL::BSDFClosure *sample_bsdf = NULL;
OSL::BSDFClosure *sample_bsdf = (OSL::BSDFClosure*)sc->prim;
int label = LABEL_NONE;
float r = sd->osl_closure.randb*sd->osl_closure.bsdf_sample_sum;
float sample_sum = 0.0f;
pdf = 0.0f;
if(sd->osl_closure.bsdf_sample_sum == 0.0f)
return LABEL_NONE;
/* sample BSDF closure */
ustring ulabel;
/* find a closure to sample */
for(int i = 0; i < sd->osl_closure.num_bsdf; i++) {
const FlatClosure *flat = &sd->osl_closure.bsdf[i];
sample_sum += flat->sample_weight;
ulabel = sample_bsdf->sample(TO_VEC3(sd->Ng),
TO_VEC3(sd->I), TO_VEC3(sd->dI.dx), TO_VEC3(sd->dI.dy),
randu, randv,
TO_VEC3(omega_in), TO_VEC3(domega_in.dx), TO_VEC3(domega_in.dy),
pdf, TO_COLOR3(eval));
if(r > sample_sum)
continue;
/* convert OSL label */
if(ulabel == OSL::Labels::REFLECT)
label = LABEL_REFLECT;
else if(ulabel == OSL::Labels::TRANSMIT)
label = LABEL_TRANSMIT;
else
return LABEL_NONE; /* sampling failed */
/* sample BSDF closure */
sample_bsdf = (OSL::BSDFClosure*)flat->prim;
ustring ulabel;
/* convert scattering to our bitflag label */
ustring uscattering = sample_bsdf->scattering();
ulabel = sample_bsdf->sample(TO_VEC3(sd->Ng),
TO_VEC3(sd->I), TO_VEC3(sd->dI.dx), TO_VEC3(sd->dI.dy),
randu, randv,
TO_VEC3(omega_in), TO_VEC3(domega_in.dx), TO_VEC3(domega_in.dy),
pdf, TO_COLOR3(eval));
/* convert OSL label */
if(ulabel == OSL::Labels::REFLECT)
label = LABEL_REFLECT;
else if(ulabel == OSL::Labels::TRANSMIT)
label = LABEL_TRANSMIT;
else
return LABEL_NONE; /* sampling failed */
/* convert scattering to our bitflag label */
ustring uscattering = sample_bsdf->scattering();
if(uscattering == OSL::Labels::DIFFUSE)
label |= LABEL_DIFFUSE;
else if(uscattering == OSL::Labels::GLOSSY)
label |= LABEL_GLOSSY;
else if(uscattering == OSL::Labels::SINGULAR)
label |= LABEL_SINGULAR;
else
label |= LABEL_TRANSPARENT;
/* eval + pdf */
eval *= flat->weight;
pdf *= flat->sample_weight;
break;
}
if(!sample_bsdf || pdf == 0.0f)
return LABEL_NONE;
/* add eval/pdf from other BSDF closures */
for(int i = 0; i < sd->osl_closure.num_bsdf; i++) {
const FlatClosure *flat = &sd->osl_closure.bsdf[i];
OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)flat->prim;
if(bsdf != sample_bsdf) {
OSL::Color3 bsdf_eval;
float bsdf_pdf = 0.0f;
if(dot(sd->Ng, omega_in) >= 0.0f)
bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf);
else
bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf);
if(bsdf_pdf != 0.0f) {
eval += TO_FLOAT3(bsdf_eval)*flat->weight;
pdf += bsdf_pdf*flat->sample_weight;
}
}
}
pdf *= 1.0f/(sd->osl_closure.bsdf_sample_sum);
if(uscattering == OSL::Labels::DIFFUSE)
label |= LABEL_DIFFUSE;
else if(uscattering == OSL::Labels::GLOSSY)
label |= LABEL_GLOSSY;
else if(uscattering == OSL::Labels::SINGULAR)
label |= LABEL_SINGULAR;
else
label |= LABEL_TRANSPARENT;
return label;
}
float3 OSLShader::bsdf_eval(const ShaderData *sd, const float3& omega_in, float& pdf)
float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf)
{
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)sc->prim;
OSL::Color3 bsdf_eval;
pdf = 0.0f;
for(int i = 0; i < sd->osl_closure.num_bsdf; i++) {
const FlatClosure *flat = &sd->osl_closure.bsdf[i];
OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)flat->prim;
OSL::Color3 bsdf_eval;
float bsdf_pdf = 0.0f;
if(dot(sd->Ng, omega_in) >= 0.0f)
bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf);
else
bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf);
if(bsdf_pdf != 0.0f) {
eval += TO_FLOAT3(bsdf_eval)*flat->weight;
pdf += bsdf_pdf*flat->sample_weight;
}
}
pdf *= 1.0f/sd->osl_closure.bsdf_sample_sum;
return eval;
if(dot(sd->Ng, omega_in) >= 0.0f)
bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf);
else
bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf);
return TO_FLOAT3(bsdf_eval);
}
/* Emissive Closure */
float3 OSLShader::emissive_eval(const ShaderData *sd)
float3 OSLShader::emissive_eval(const ShaderData *sd, const ShaderClosure *sc)
{
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i < sd->osl_closure.num_emissive; i++) {
const FlatClosure *flat = &sd->osl_closure.emissive[i];
OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure*)flat->prim;
OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I));
eval += TO_FLOAT3(emissive_eval)*flat->weight;
}
OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure*)sc->prim;
OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I));
eval += TO_FLOAT3(emissive_eval);
return eval;
}
void OSLShader::emissive_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *I, float *pdf)
{
float r = sd->osl_closure.randb*sd->osl_closure.emissive_sample_sum;
float sample_sum = 0.0f;
*pdf = 0.0f;
if(sd->osl_closure.emissive_sample_sum == 0.0f)
return;
/* find a closure to sample */
for(int i = 0; i < sd->osl_closure.num_emissive; i++) {
const FlatClosure *flat = &sd->osl_closure.emissive[i];
sample_sum += flat->sample_weight;
if(r <= sample_sum) {
/* sample emissive closure */
OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure*)flat->prim;
emissive->sample(TO_VEC3(sd->Ng), randu, randv, TO_VEC3(*I), *pdf);
*eval = flat->weight;
*pdf *= flat->sample_weight/sd->osl_closure.emissive_sample_sum;
return;
}
}
}
/* Volume Closure */
float3 OSLShader::volume_eval_phase(const ShaderData *sd, const float3 omega_in, const float3 omega_out)
float3 OSLShader::volume_eval_phase(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out)
{
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
for(int i = 0; i < sd->osl_closure.num_volume; i++) {
const FlatClosure *flat = &sd->osl_closure.volume[i];
OSL::VolumeClosure *volume = (OSL::VolumeClosure*)flat->prim;
OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out));
eval += TO_FLOAT3(volume_eval)*flat->weight;
}
return eval;
}
/* Holdout Closure */
float3 OSLShader::holdout_eval(const ShaderData *sd)
{
return sd->osl_closure.holdout_weight;
OSL::VolumeClosure *volume = (OSL::VolumeClosure*)sc->prim;
OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out));
return TO_FLOAT3(volume_eval)*sc->weight;
}
CCL_NAMESPACE_END

@ -46,6 +46,7 @@ namespace OSL = ::OSL;
class OSLRenderServices;
class Scene;
class ShaderClosure;
class ShaderData;
class differential3;
class KernelGlobals;
@ -66,15 +67,16 @@ public:
static void eval_displacement(KernelGlobals *kg, ShaderData *sd);
/* sample & eval */
static int bsdf_sample(const ShaderData *sd, float randu, float randv,
static int bsdf_sample(const ShaderData *sd, const ShaderClosure *sc,
float randu, float randv,
float3& eval, float3& omega_in, differential3& domega_in, float& pdf);
static float3 bsdf_eval(const ShaderData *sd, const float3& omega_in, float& pdf);
static float3 emissive_eval(const ShaderData *sd);
static void emissive_sample(const ShaderData *sd, float randu, float randv,
float3 *eval, float3 *I, float *pdf);
static float3 volume_eval_phase(const ShaderData *sd, const float3 omega_in,
const float3 omega_out);
static float3 holdout_eval(const ShaderData *sd);
static float3 bsdf_eval(const ShaderData *sd, const ShaderClosure *sc,
const float3& omega_in, float& pdf);
static float3 emissive_eval(const ShaderData *sd, const ShaderClosure *sc);
static float3 volume_eval_phase(const ShaderData *sd, const ShaderClosure *sc,
const float3 omega_in, const float3 omega_out);
/* release */
static void release(KernelGlobals *kg, const ShaderData *sd);

@ -40,24 +40,24 @@ typedef struct BsdfAshikhminVelvetClosure {
float m_invsigma2;
} BsdfAshikhminVelvetClosure;
__device void bsdf_ashikhmin_velvet_setup(ShaderData *sd, float3 N, float sigma)
__device void bsdf_ashikhmin_velvet_setup(ShaderData *sd, ShaderClosure *sc, float sigma)
{
sigma = fmaxf(sigma, 0.01f);
float m_invsigma2 = 1.0f/(sigma * sigma);
sd->svm_closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
sc->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL;
sd->svm_closure_data0 = m_invsigma2;
sc->data0 = m_invsigma2;
}
__device void bsdf_ashikhmin_velvet_blur(ShaderData *sd, float roughness)
__device void bsdf_ashikhmin_velvet_blur(ShaderClosure *sc, float roughness)
{
}
__device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float m_invsigma2 = sd->svm_closure_data0;
float m_invsigma2 = sc->data0;
float3 m_N = sd->N;
float cosNO = dot(m_N, I);
@ -89,19 +89,19 @@ __device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderData *sd, const f
return make_float3(0, 0, 0);
}
__device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float bsdf_ashikhmin_velvet_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_ashikhmin_velvet_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_ashikhmin_velvet_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_ashikhmin_velvet_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
float m_invsigma2 = sd->svm_closure_data0;
float m_invsigma2 = sc->data0;
float3 m_N = sd->N;
// we are viewing the surface from above - send a ray out with uniform

@ -41,17 +41,17 @@ typedef struct BsdfDiffuseClosure {
//float3 m_N;
} BsdfDiffuseClosure;
__device void bsdf_diffuse_setup(ShaderData *sd, float3 N)
__device void bsdf_diffuse_setup(ShaderData *sd, ShaderClosure *sc)
{
sd->svm_closure = CLOSURE_BSDF_DIFFUSE_ID;
sc->type = CLOSURE_BSDF_DIFFUSE_ID;
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL;
}
__device void bsdf_diffuse_blur(ShaderData *sd, float roughness)
__device void bsdf_diffuse_blur(ShaderClosure *sc, float roughness)
{
}
__device float3 bsdf_diffuse_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_diffuse_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float3 m_N = sd->N;
@ -60,17 +60,17 @@ __device float3 bsdf_diffuse_eval_reflect(const ShaderData *sd, const float3 I,
return make_float3(cos_pi, cos_pi, cos_pi);
}
__device float3 bsdf_diffuse_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_diffuse_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float bsdf_diffuse_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_diffuse_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_diffuse_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_diffuse_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
float3 m_N = sd->N;
@ -99,22 +99,22 @@ typedef struct BsdfTranslucentClosure {
//float3 m_N;
} BsdfTranslucentClosure;
__device void bsdf_translucent_setup(ShaderData *sd, float3 N)
__device void bsdf_translucent_setup(ShaderData *sd, ShaderClosure *sc)
{
sd->svm_closure = CLOSURE_BSDF_TRANSLUCENT_ID;
sc->type = CLOSURE_BSDF_TRANSLUCENT_ID;
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL;
}
__device void bsdf_translucent_blur(ShaderData *sd, float roughness)
__device void bsdf_translucent_blur(ShaderClosure *sc, float roughness)
{
}
__device float3 bsdf_translucent_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_translucent_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float3 bsdf_translucent_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_translucent_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float3 m_N = sd->N;
@ -123,12 +123,12 @@ __device float3 bsdf_translucent_eval_transmit(const ShaderData *sd, const float
return make_float3 (cos_pi, cos_pi, cos_pi);
}
__device float bsdf_translucent_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_translucent_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_translucent_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_translucent_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
float3 m_N = sd->N;

@ -43,34 +43,34 @@ typedef struct BsdfMicrofacetGGXClosure {
float m_eta;
} BsdfMicrofacetGGXClosure;
__device void bsdf_microfacet_ggx_setup(ShaderData *sd, float3 N, float ag, float eta, bool refractive)
__device void bsdf_microfacet_ggx_setup(ShaderData *sd, ShaderClosure *sc, float ag, float eta, bool refractive)
{
float m_ag = clamp(ag, 1e-5f, 1.0f);
float m_eta = eta;
sd->svm_closure_data0 = m_ag;
sd->svm_closure_data1 = m_eta;
sc->data0 = m_ag;
sc->data1 = m_eta;
if(refractive)
sd->svm_closure = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
sc->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
else
sd->svm_closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
sc->type = CLOSURE_BSDF_MICROFACET_GGX_ID;
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
}
__device void bsdf_microfacet_ggx_blur(ShaderData *sd, float roughness)
__device void bsdf_microfacet_ggx_blur(ShaderClosure *sc, float roughness)
{
float m_ag = sd->svm_closure_data0;
float m_ag = sc->data0;
m_ag = fmaxf(roughness, m_ag);
sd->svm_closure_data0 = m_ag;
sc->data0 = m_ag;
}
__device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float m_ag = sd->svm_closure_data0;
//float m_eta = sd->svm_closure_data1;
int m_refractive = sd->svm_closure == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
float m_ag = sc->data0;
//float m_eta = sc->data1;
int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
float3 m_N = sd->N;
if(m_refractive) return make_float3 (0, 0, 0);
@ -103,11 +103,11 @@ __device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderData *sd, const flo
return make_float3 (0, 0, 0);
}
__device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float m_ag = sd->svm_closure_data0;
float m_eta = sd->svm_closure_data1;
int m_refractive = sd->svm_closure == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
float m_ag = sc->data0;
float m_eta = sc->data1;
int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
float3 m_N = sd->N;
if(!m_refractive) return make_float3 (0, 0, 0);
@ -139,16 +139,16 @@ __device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderData *sd, const fl
return make_float3 (out, out, out);
}
__device float bsdf_microfacet_ggx_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_microfacet_ggx_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_microfacet_ggx_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_microfacet_ggx_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
float m_ag = sd->svm_closure_data0;
float m_eta = sd->svm_closure_data1;
int m_refractive = sd->svm_closure == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
float m_ag = sc->data0;
float m_eta = sc->data1;
int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
float3 m_N = sd->N;
float cosNO = dot(m_N, sd->I);
@ -268,34 +268,34 @@ typedef struct BsdfMicrofacetBeckmannClosure {
float m_eta;
} BsdfMicrofacetBeckmannClosure;
__device void bsdf_microfacet_beckmann_setup(ShaderData *sd, float3 N, float ab, float eta, bool refractive)
__device void bsdf_microfacet_beckmann_setup(ShaderData *sd, ShaderClosure *sc, float ab, float eta, bool refractive)
{
float m_ab = clamp(ab, 1e-5f, 1.0f);
float m_eta = eta;
sd->svm_closure_data0 = m_ab;
sd->svm_closure_data1 = m_eta;
sc->data0 = m_ab;
sc->data1 = m_eta;
if(refractive)
sd->svm_closure = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
else
sd->svm_closure = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
}
__device void bsdf_microfacet_beckmann_blur(ShaderData *sd, float roughness)
__device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness)
{
float m_ab = sd->svm_closure_data0;
float m_ab = sc->data0;
m_ab = fmaxf(roughness, m_ab);
sd->svm_closure_data0 = m_ab;
sc->data0 = m_ab;
}
__device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float m_ab = sd->svm_closure_data0;
//float m_eta = sd->svm_closure_data1;
int m_refractive = sd->svm_closure == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
float m_ab = sc->data0;
//float m_eta = sc->data1;
int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
float3 m_N = sd->N;
if(m_refractive) return make_float3 (0, 0, 0);
@ -330,11 +330,11 @@ __device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderData *sd, cons
return make_float3 (0, 0, 0);
}
__device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float m_ab = sd->svm_closure_data0;
float m_eta = sd->svm_closure_data1;
int m_refractive = sd->svm_closure == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
float m_ab = sc->data0;
float m_eta = sc->data1;
int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
float3 m_N = sd->N;
if(!m_refractive) return make_float3 (0, 0, 0);
@ -368,16 +368,16 @@ __device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderData *sd, con
return make_float3 (out, out, out);
}
__device float bsdf_microfacet_beckmann_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_microfacet_beckmann_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_microfacet_beckmann_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_microfacet_beckmann_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
float m_ab = sd->svm_closure_data0;
float m_eta = sd->svm_closure_data1;
int m_refractive = sd->svm_closure == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
float m_ab = sc->data0;
float m_eta = sc->data1;
int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
float3 m_N = sd->N;
float cosNO = dot(m_N, sd->I);

@ -41,34 +41,34 @@ typedef struct BsdfReflectionClosure {
//float3 m_N;
} BsdfReflectionClosure;
__device void bsdf_reflection_setup(ShaderData *sd, float3 N)
__device void bsdf_reflection_setup(ShaderData *sd, ShaderClosure *sc)
{
sd->svm_closure = CLOSURE_BSDF_REFLECTION_ID;
sc->type = CLOSURE_BSDF_REFLECTION_ID;
sd->flag |= SD_BSDF;
}
__device void bsdf_reflection_blur(ShaderData *sd, float roughness)
__device void bsdf_reflection_blur(ShaderClosure *sc, float roughness)
{
}
__device float3 bsdf_reflection_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_reflection_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float3 bsdf_reflection_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_reflection_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float bsdf_reflection_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_reflection_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_reflection_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_reflection_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
//const BsdfReflectionClosure *self = (const BsdfReflectionClosure*)sd->svm_closure_data;
//const BsdfReflectionClosure *self = (const BsdfReflectionClosure*)sc->data;
float3 m_N = sd->N;
// only one direction is possible

@ -41,36 +41,36 @@ typedef struct BsdfRefractionClosure {
float m_eta;
} BsdfRefractionClosure;
__device void bsdf_refraction_setup(ShaderData *sd, float3 N, float eta)
__device void bsdf_refraction_setup(ShaderData *sd, ShaderClosure *sc, float eta)
{
sd->svm_closure_data0 = eta;
sc->data0 = eta;
sd->svm_closure = CLOSURE_BSDF_REFRACTION_ID;
sc->type = CLOSURE_BSDF_REFRACTION_ID;
sd->flag |= SD_BSDF;
}
__device void bsdf_refraction_blur(ShaderData *sd, float roughness)
__device void bsdf_refraction_blur(ShaderClosure *sc, float roughness)
{
}
__device float3 bsdf_refraction_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_refraction_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float3 bsdf_refraction_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_refraction_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float bsdf_refraction_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_refraction_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_refraction_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_refraction_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
float m_eta = sd->svm_closure_data0;
float m_eta = sc->data0;
float3 m_N = sd->N;
float3 R, T;

@ -35,32 +35,32 @@
CCL_NAMESPACE_BEGIN
__device void bsdf_transparent_setup(ShaderData *sd)
__device void bsdf_transparent_setup(ShaderData *sd, ShaderClosure *sc)
{
sd->svm_closure = CLOSURE_BSDF_TRANSPARENT_ID;
sc->type = CLOSURE_BSDF_TRANSPARENT_ID;
sd->flag |= SD_BSDF;
}
__device void bsdf_transparent_blur(ShaderData *sd, float roughness)
__device void bsdf_transparent_blur(ShaderClosure *sc, float roughness)
{
}
__device float3 bsdf_transparent_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_transparent_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float3 bsdf_transparent_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_transparent_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float bsdf_transparent_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_transparent_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_transparent_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_transparent_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
// only one direction is possible
*omega_in = -sd->I;

@ -44,28 +44,28 @@ typedef struct BsdfWardClosure {
float m_ay;
} BsdfWardClosure;
__device void bsdf_ward_setup(ShaderData *sd, float3 N, float3 T, float ax, float ay)
__device void bsdf_ward_setup(ShaderData *sd, ShaderClosure *sc, float3 T, float ax, float ay)
{
float m_ax = clamp(ax, 1e-5f, 1.0f);
float m_ay = clamp(ay, 1e-5f, 1.0f);
sd->svm_closure_data0 = m_ax;
sd->svm_closure_data1 = m_ay;
sc->data0 = m_ax;
sc->data1 = m_ay;
sd->svm_closure = CLOSURE_BSDF_WARD_ID;
sc->type = CLOSURE_BSDF_WARD_ID;
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
}
__device void bsdf_ward_blur(ShaderData *sd, float roughness)
__device void bsdf_ward_blur(ShaderClosure *sc, float roughness)
{
sd->svm_closure_data0 = fmaxf(roughness, sd->svm_closure_data0);
sd->svm_closure_data1 = fmaxf(roughness, sd->svm_closure_data1);
sc->data0 = fmaxf(roughness, sc->data0);
sc->data1 = fmaxf(roughness, sc->data1);
}
__device float3 bsdf_ward_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_ward_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float m_ax = sd->svm_closure_data0;
float m_ay = sd->svm_closure_data1;
float m_ax = sc->data0;
float m_ay = sc->data1;
float3 m_N = sd->N;
float3 m_T = normalize(sd->dPdu);
@ -93,20 +93,20 @@ __device float3 bsdf_ward_eval_reflect(const ShaderData *sd, const float3 I, con
return make_float3 (0, 0, 0);
}
__device float3 bsdf_ward_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_ward_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float bsdf_ward_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_ward_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_ward_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_ward_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
float m_ax = sd->svm_closure_data0;
float m_ay = sd->svm_closure_data1;
float m_ax = sc->data0;
float m_ay = sc->data1;
float3 m_N = sd->N;
float3 m_T = normalize(sd->dPdu);

@ -42,26 +42,26 @@ typedef struct BsdfWestinBackscatterClosure {
float m_invroughness;
} BsdfWestinBackscatterClosure;
__device void bsdf_westin_backscatter_setup(ShaderData *sd, float3 N, float roughness)
__device void bsdf_westin_backscatter_setup(ShaderData *sd, ShaderClosure *sc, float roughness)
{
roughness = clamp(roughness, 1e-5f, 1.0f);
float m_invroughness = 1.0f/roughness;
sd->svm_closure = CLOSURE_BSDF_WESTIN_BACKSCATTER_ID;
sc->type = CLOSURE_BSDF_WESTIN_BACKSCATTER_ID;
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
sd->svm_closure_data0 = m_invroughness;
sc->data0 = m_invroughness;
}
__device void bsdf_westin_backscatter_blur(ShaderData *sd, float roughness)
__device void bsdf_westin_backscatter_blur(ShaderClosure *sc, float roughness)
{
float m_invroughness = sd->svm_closure_data0;
float m_invroughness = sc->data0;
m_invroughness = min(1.0f/roughness, m_invroughness);
sd->svm_closure_data0 = m_invroughness;
sc->data0 = m_invroughness;
}
__device float3 bsdf_westin_backscatter_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_westin_backscatter_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float m_invroughness = sd->svm_closure_data0;
float m_invroughness = sc->data0;
float3 m_N = sd->N;
// pdf is implicitly 0 (no indirect sampling)
@ -76,19 +76,19 @@ __device float3 bsdf_westin_backscatter_eval_reflect(const ShaderData *sd, const
return make_float3 (0, 0, 0);
}
__device float3 bsdf_westin_backscatter_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_westin_backscatter_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float bsdf_westin_backscatter_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_westin_backscatter_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_westin_backscatter_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_westin_backscatter_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
float m_invroughness = sd->svm_closure_data0;
float m_invroughness = sc->data0;
float3 m_N = sd->N;
float cosNO = dot(m_N, sd->I);
@ -137,20 +137,20 @@ typedef struct BsdfWestinSheenClosure {
float m_edginess;
} BsdfWestinSheenClosure;
__device void bsdf_westin_sheen_setup(ShaderData *sd, float3 N, float edginess)
__device void bsdf_westin_sheen_setup(ShaderData *sd, ShaderClosure *sc, float edginess)
{
sd->svm_closure = CLOSURE_BSDF_WESTIN_SHEEN_ID;
sc->type = CLOSURE_BSDF_WESTIN_SHEEN_ID;
sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
sd->svm_closure_data0 = edginess;
sc->data0 = edginess;
}
__device void bsdf_westin_sheen_blur(ShaderData *sd, float roughness)
__device void bsdf_westin_sheen_blur(ShaderClosure *sc, float roughness)
{
}
__device float3 bsdf_westin_sheen_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_westin_sheen_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float m_edginess = sd->svm_closure_data0;
float m_edginess = sc->data0;
float3 m_N = sd->N;
// pdf is implicitly 0 (no indirect sampling)
@ -165,19 +165,19 @@ __device float3 bsdf_westin_sheen_eval_reflect(const ShaderData *sd, const float
return make_float3 (0, 0, 0);
}
__device float3 bsdf_westin_sheen_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
__device float3 bsdf_westin_sheen_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
return make_float3(0.0f, 0.0f, 0.0f);
}
__device float bsdf_westin_sheen_albedo(const ShaderData *sd, const float3 I)
__device float bsdf_westin_sheen_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I)
{
return 1.0f;
}
__device int bsdf_westin_sheen_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
__device int bsdf_westin_sheen_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
{
float m_edginess = sd->svm_closure_data0;
float m_edginess = sc->data0;
float3 m_N = sd->N;
// we are viewing the surface from the right side - send a ray out with cosine

@ -42,23 +42,6 @@ __device float3 emissive_eval(const float3 Ng, const float3 I)
return make_float3(res, res, res);
}
__device void emissive_sample(const float3 Ng, float randu, float randv, float3 *I, float *pdf)
{
// We don't do anything sophisticated here for the step
// We just sample the whole cone uniformly to the cosine
float3 T, B;
make_orthonormals(Ng, &T, &B);
float phi = 2 * M_PI_F * randu;
float cosTheta = sqrtf(1.0f - 1.0f * randv);
float sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
*I = (cosf(phi) * sinTheta) * T +
(sinf(phi) * sinTheta) * B +
cosTheta * Ng;
*pdf = M_1_PI_F;
}
/// Return the probability distribution function in the direction I,
/// given the parameters and the light's surface normal. This MUST match
/// the PDF computed by sample().
@ -68,15 +51,9 @@ __device float emissive_pdf(const float3 Ng, const float3 I)
return (cosNO > 0.0f)? M_1_PI_F: 0.0f;
}
__device float3 svm_emissive_eval(ShaderData *sd)
__device float3 svm_emissive_eval(ShaderData *sd, ShaderClosure *sc)
{
return sd->svm_closure_weight*emissive_eval(sd->Ng, sd->I);
}
__device void svm_emissive_sample(ShaderData *sd, float randu, float randv, float3 *eval, float3 *I, float *pdf)
{
*eval = sd->svm_closure_weight;
emissive_sample(sd->Ng, randu, randv, I, pdf);
return emissive_eval(sd->Ng, sd->I);
}
CCL_NAMESPACE_END

@ -47,14 +47,14 @@ CCL_NAMESPACE_BEGIN
/* Stack */
__device float3 stack_load_float3(float *stack, uint a)
__device_inline float3 stack_load_float3(float *stack, uint a)
{
kernel_assert(a+2 < SVM_STACK_SIZE);
return make_float3(stack[a+0], stack[a+1], stack[a+2]);
}
__device void stack_store_float3(float *stack, uint a, float3 f)
__device_inline void stack_store_float3(float *stack, uint a, float3 f)
{
kernel_assert(a+2 < SVM_STACK_SIZE);
@ -63,40 +63,40 @@ __device void stack_store_float3(float *stack, uint a, float3 f)
stack[a+2] = f.z;
}
__device float stack_load_float(float *stack, uint a)
__device_inline float stack_load_float(float *stack, uint a)
{
kernel_assert(a < SVM_STACK_SIZE);
return stack[a];
}
__device float stack_load_float_default(float *stack, uint a, uint value)
__device_inline float stack_load_float_default(float *stack, uint a, uint value)
{
return (a == (uint)SVM_STACK_INVALID)? __int_as_float(value): stack_load_float(stack, a);
}
__device void stack_store_float(float *stack, uint a, float f)
__device_inline void stack_store_float(float *stack, uint a, float f)
{
kernel_assert(a < SVM_STACK_SIZE);
stack[a] = f;
}
__device bool stack_valid(uint a)
__device_inline bool stack_valid(uint a)
{
return a != (uint)SVM_STACK_INVALID;
}
/* Reading Nodes */
__device uint4 read_node(KernelGlobals *kg, int *offset)
__device_inline uint4 read_node(KernelGlobals *kg, int *offset)
{
uint4 node = kernel_tex_fetch(__svm_nodes, *offset);
(*offset)++;
return node;
}
__device float4 read_node_float(KernelGlobals *kg, int *offset)
__device_inline float4 read_node_float(KernelGlobals *kg, int *offset)
{
uint4 node = kernel_tex_fetch(__svm_nodes, *offset);
float4 f = make_float4(__int_as_float(node.x), __int_as_float(node.y), __int_as_float(node.z), __int_as_float(node.w));
@ -104,7 +104,7 @@ __device float4 read_node_float(KernelGlobals *kg, int *offset)
return f;
}
__device void decode_node_uchar4(uint i, uint *x, uint *y, uint *z, uint *w)
__device_inline void decode_node_uchar4(uint i, uint *x, uint *y, uint *z, uint *w)
{
if(x) *x = (i & 0xFF);
if(y) *y = ((i >> 8) & 0xFF);
@ -154,8 +154,12 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
float closure_weight = 1.0f;
int offset = sd->shader;
sd->svm_closure = NBUILTIN_CLOSURES;
sd->svm_closure_weight = make_float3(0.0f, 0.0f, 0.0f);
#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);
@ -169,16 +173,16 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
break;
}
case NODE_CLOSURE_BSDF:
svm_node_closure_bsdf(sd, stack, node, randb);
svm_node_closure_bsdf(kg, sd, stack, node, randb, path_flag);
break;
case NODE_CLOSURE_EMISSION:
svm_node_closure_emission(sd);
svm_node_closure_emission(sd, stack, node);
break;
case NODE_CLOSURE_BACKGROUND:
svm_node_closure_background(sd);
svm_node_closure_background(sd, node);
break;
case NODE_CLOSURE_HOLDOUT:
svm_node_closure_holdout(sd);
svm_node_closure_holdout(sd, stack, node);
break;
case NODE_CLOSURE_SET_WEIGHT:
svm_node_closure_set_weight(sd, node.y, node.z, node.w);
@ -190,7 +194,7 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
svm_node_emission_weight(kg, sd, stack, node);
break;
case NODE_MIX_CLOSURE:
svm_node_mix_closure(sd, stack, node.y, node.z, &offset, &randb);
svm_node_mix_closure(sd, stack, node, &offset, &randb);
break;
case NODE_ADD_CLOSURE:
svm_node_add_closure(sd, stack, node.y, node.z, &offset, &randb, &closure_weight);
@ -307,7 +311,9 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
break;
case NODE_END:
default:
sd->svm_closure_weight *= closure_weight;
#ifndef __MULTI_CLOSURE__
sd->closure.weight *= closure_weight;
#endif
return;
}
}

@ -29,48 +29,48 @@
CCL_NAMESPACE_BEGIN
__device int svm_bsdf_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
__device int svm_bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
{
int label;
switch(sd->svm_closure) {
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
label = bsdf_diffuse_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_diffuse_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
#ifdef __SVM__
case CLOSURE_BSDF_TRANSLUCENT_ID:
label = bsdf_translucent_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_translucent_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_REFLECTION_ID:
label = bsdf_reflection_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_reflection_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_REFRACTION_ID:
label = bsdf_refraction_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_refraction_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_TRANSPARENT_ID:
label = bsdf_transparent_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_transparent_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
label = bsdf_microfacet_ggx_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_microfacet_ggx_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
label = bsdf_microfacet_beckmann_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_microfacet_beckmann_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
#ifdef __DPDU__
case CLOSURE_BSDF_WARD_ID:
label = bsdf_ward_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_ward_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
#endif
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
label = bsdf_ashikhmin_velvet_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_ashikhmin_velvet_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
label = bsdf_westin_backscatter_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_westin_backscatter_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
case CLOSURE_BSDF_WESTIN_SHEEN_ID:
label = bsdf_westin_sheen_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
label = bsdf_westin_sheen_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
break;
#endif
default:
@ -78,53 +78,51 @@ __device int svm_bsdf_sample(const ShaderData *sd, float randu, float randv, flo
break;
}
*eval *= sd->svm_closure_weight;
return label;
}
__device float3 svm_bsdf_eval(const ShaderData *sd, const float3 omega_in, float *pdf)
__device float3 svm_bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf)
{
float3 eval;
if(dot(sd->Ng, omega_in) >= 0.0f) {
switch(sd->svm_closure) {
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
eval = bsdf_diffuse_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_diffuse_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_TRANSLUCENT_ID:
eval = bsdf_translucent_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_translucent_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_REFLECTION_ID:
eval = bsdf_reflection_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_reflection_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_REFRACTION_ID:
eval = bsdf_refraction_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_refraction_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_TRANSPARENT_ID:
eval = bsdf_transparent_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_transparent_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_microfacet_ggx_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
eval = bsdf_microfacet_beckmann_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_microfacet_beckmann_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
#ifdef __DPDU__
case CLOSURE_BSDF_WARD_ID:
eval = bsdf_ward_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_ward_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
#endif
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
eval = bsdf_ashikhmin_velvet_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_ashikhmin_velvet_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
eval = bsdf_westin_backscatter_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_westin_backscatter_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_WESTIN_SHEEN_ID:
eval = bsdf_westin_sheen_eval_reflect(sd, sd->I, omega_in, pdf);
eval = bsdf_westin_sheen_eval_reflect(sd, sc, sd->I, omega_in, pdf);
break;
default:
eval = make_float3(0.0f, 0.0f, 0.0f);
@ -132,43 +130,43 @@ __device float3 svm_bsdf_eval(const ShaderData *sd, const float3 omega_in, float
}
}
else {
switch(sd->svm_closure) {
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
eval = bsdf_diffuse_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_diffuse_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_TRANSLUCENT_ID:
eval = bsdf_translucent_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_translucent_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_REFLECTION_ID:
eval = bsdf_reflection_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_reflection_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_REFRACTION_ID:
eval = bsdf_refraction_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_refraction_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_TRANSPARENT_ID:
eval = bsdf_transparent_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_transparent_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
eval = bsdf_microfacet_ggx_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_microfacet_ggx_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
eval = bsdf_microfacet_beckmann_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_microfacet_beckmann_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
#ifdef __DPDU__
case CLOSURE_BSDF_WARD_ID:
eval = bsdf_ward_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_ward_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
#endif
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
eval = bsdf_ashikhmin_velvet_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_ashikhmin_velvet_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
eval = bsdf_westin_backscatter_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_westin_backscatter_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
case CLOSURE_BSDF_WESTIN_SHEEN_ID:
eval = bsdf_westin_sheen_eval_transmit(sd, sd->I, omega_in, pdf);
eval = bsdf_westin_sheen_eval_transmit(sd, sc, sd->I, omega_in, pdf);
break;
default:
eval = make_float3(0.0f, 0.0f, 0.0f);
@ -176,50 +174,48 @@ __device float3 svm_bsdf_eval(const ShaderData *sd, const float3 omega_in, float
}
}
eval *= sd->svm_closure_weight;
return eval;
}
__device void svm_bsdf_blur(ShaderData *sd, float roughness)
__device void svm_bsdf_blur(ShaderClosure *sc, float roughness)
{
switch(sd->svm_closure) {
switch(sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
bsdf_diffuse_blur(sd, roughness);
bsdf_diffuse_blur(sc, roughness);
break;
case CLOSURE_BSDF_TRANSLUCENT_ID:
bsdf_translucent_blur(sd, roughness);
bsdf_translucent_blur(sc, roughness);
break;
case CLOSURE_BSDF_REFLECTION_ID:
bsdf_reflection_blur(sd, roughness);
bsdf_reflection_blur(sc, roughness);
break;
case CLOSURE_BSDF_REFRACTION_ID:
bsdf_refraction_blur(sd, roughness);
bsdf_refraction_blur(sc, roughness);
break;
case CLOSURE_BSDF_TRANSPARENT_ID:
bsdf_transparent_blur(sd, roughness);
bsdf_transparent_blur(sc, roughness);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
bsdf_microfacet_ggx_blur(sd, roughness);
bsdf_microfacet_ggx_blur(sc, roughness);
break;
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
bsdf_microfacet_beckmann_blur(sd, roughness);
bsdf_microfacet_beckmann_blur(sc, roughness);
break;
#ifdef __DPDU__
case CLOSURE_BSDF_WARD_ID:
bsdf_ward_blur(sd, roughness);
bsdf_ward_blur(sc, roughness);
break;
#endif
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
bsdf_ashikhmin_velvet_blur(sd, roughness);
bsdf_ashikhmin_velvet_blur(sc, roughness);
break;
case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
bsdf_westin_backscatter_blur(sd, roughness);
bsdf_westin_backscatter_blur(sc, roughness);
break;
case CLOSURE_BSDF_WESTIN_SHEEN_ID:
bsdf_westin_sheen_blur(sd, roughness);
bsdf_westin_sheen_blur(sc, roughness);
break;
default:
break;

@ -20,28 +20,92 @@ CCL_NAMESPACE_BEGIN
/* Closure Nodes */
__device void svm_node_closure_bsdf(ShaderData *sd, float *stack, uint4 node, float randb)
__device void svm_node_glossy_setup(ShaderData *sd, ShaderClosure *sc, int type, float eta, float roughness, bool refract)
{
if(type == CLOSURE_BSDF_REFRACTION_ID) {
if(refract)
bsdf_refraction_setup(sd, sc, eta);
else
bsdf_reflection_setup(sd, sc);
}
else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) {
bsdf_microfacet_beckmann_setup(sd, sc, roughness, eta, refract);
}
else
bsdf_microfacet_ggx_setup(sd, sc, roughness, eta, refract);
}
__device_inline ShaderClosure *svm_node_closure_get(ShaderData *sd)
{
#ifdef __MULTI_CLOSURE__
ShaderClosure *sc = &sd->closure[sd->num_closure];
if(sd->num_closure < MAX_CLOSURE)
sd->num_closure++;
return sc;
#else
return &sd->closure;
#endif
}
__device_inline void svm_node_closure_set_mix_weight(ShaderClosure *sc, float mix_weight)
{
#ifdef __MULTI_CLOSURE__
sc->weight *= mix_weight;
sc->sample_weight = fabsf(average(sc->weight));
#endif
}
__device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, float randb, int path_flag)
{
uint type, param1_offset, param2_offset;
#ifdef __MULTI_CLOSURE__
uint mix_weight_offset;
decode_node_uchar4(node.y, &type, &param1_offset, &param2_offset, &mix_weight_offset);
float mix_weight = (stack_valid(mix_weight_offset)? stack_load_float(stack, mix_weight_offset): 1.0f);
if(mix_weight == 0.0f)
return;
#else
decode_node_uchar4(node.y, &type, &param1_offset, &param2_offset, NULL);
float mix_weight = 1.0f;
#endif
float param1 = (stack_valid(param1_offset))? stack_load_float(stack, param1_offset): __int_as_float(node.z);
float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __int_as_float(node.w);
switch(type) {
case CLOSURE_BSDF_DIFFUSE_ID:
bsdf_diffuse_setup(sd, sd->N);
case CLOSURE_BSDF_DIFFUSE_ID: {
ShaderClosure *sc = svm_node_closure_get(sd);
svm_node_closure_set_mix_weight(sc, mix_weight);
bsdf_diffuse_setup(sd, sc);
break;
case CLOSURE_BSDF_TRANSLUCENT_ID:
bsdf_translucent_setup(sd, sd->N);
}
case CLOSURE_BSDF_TRANSLUCENT_ID: {
ShaderClosure *sc = svm_node_closure_get(sd);
svm_node_closure_set_mix_weight(sc, mix_weight);
bsdf_translucent_setup(sd, sc);
break;
case CLOSURE_BSDF_TRANSPARENT_ID:
bsdf_transparent_setup(sd);
}
case CLOSURE_BSDF_TRANSPARENT_ID: {
ShaderClosure *sc = svm_node_closure_get(sd);
svm_node_closure_set_mix_weight(sc, mix_weight);
bsdf_transparent_setup(sd, sc);
break;
}
case CLOSURE_BSDF_REFLECTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: {
/* roughness */
#ifdef __CAUSTICS_TRICKS__
if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE))
break;
#endif
ShaderClosure *sc = svm_node_closure_get(sd);
svm_node_closure_set_mix_weight(sc, mix_weight);
/* index of refraction */
float eta = clamp(1.0f-param2, 1e-5f, 1.0f - 1e-5f);
eta = 1.0f/eta;
@ -49,26 +113,22 @@ __device void svm_node_closure_bsdf(ShaderData *sd, float *stack, uint4 node, fl
/* fresnel */
float cosNO = dot(sd->N, sd->I);
float fresnel = fresnel_dielectric_cos(cosNO, eta);
float roughness = param1;
sd->svm_closure_weight *= fresnel;
sc->weight *= fresnel;
/* setup bsdf */
if(type == CLOSURE_BSDF_REFLECTION_ID) {
bsdf_reflection_setup(sd, sd->N);
}
else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) {
float roughness = param1;
bsdf_microfacet_beckmann_setup(sd, sd->N, roughness, eta, false);
}
else {
float roughness = param1;
bsdf_microfacet_ggx_setup(sd, sd->N, roughness, eta, false);
}
svm_node_glossy_setup(sd, sc, type, eta, roughness, false);
break;
}
case CLOSURE_BSDF_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: {
#ifdef __CAUSTICS_TRICKS__
if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE))
break;
#endif
/* index of refraction */
float eta = clamp(1.0f-param2, 1e-5f, 1.0f - 1e-5f);
eta = (sd->flag & SD_BACKFACING)? eta: 1.0f/eta;
@ -76,34 +136,58 @@ __device void svm_node_closure_bsdf(ShaderData *sd, float *stack, uint4 node, fl
/* fresnel */
float cosNO = dot(sd->N, sd->I);
float fresnel = fresnel_dielectric_cos(cosNO, eta);
bool refract = (fresnel < randb);
float roughness = param1;
#ifdef __MULTI_CLOSURE__
/* reflection */
ShaderClosure *sc = svm_node_closure_get(sd);
float3 weight = sc->weight;
float sample_weight = sc->sample_weight;
svm_node_closure_set_mix_weight(sc, mix_weight*fresnel);
svm_node_glossy_setup(sd, sc, type, eta, roughness, false);
/* refraction */
sc = svm_node_closure_get(sd);
sc->weight = weight;
sc->sample_weight = sample_weight;
svm_node_closure_set_mix_weight(sc, mix_weight*(1.0f - fresnel));
svm_node_glossy_setup(sd, sc, type, eta, roughness, true);
#else
ShaderClosure *sc = svm_node_closure_get(sd);
bool refract = (randb > fresnel);
svm_node_closure_set_mix_weight(sc, mix_weight);
svm_node_glossy_setup(sd, sc, type, eta, roughness, refract);
#endif
/* setup bsdf */
if(type == CLOSURE_BSDF_REFRACTION_ID) {
if(refract)
bsdf_refraction_setup(sd, sd->N, eta);
else
bsdf_reflection_setup(sd, sd->N);
}
else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) {
float roughness = param1;
bsdf_microfacet_beckmann_setup(sd, sd->N, roughness, eta, refract);
}
else {
float roughness = param1;
bsdf_microfacet_ggx_setup(sd, sd->N, roughness, eta, refract);
}
break;
}
#ifdef __DPDU__
case CLOSURE_BSDF_WARD_ID: {
#ifdef __CAUSTICS_TRICKS__
if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE))
break;
#endif
ShaderClosure *sc = svm_node_closure_get(sd);
svm_node_closure_set_mix_weight(sc, mix_weight);
float roughness_u = param1;
float roughness_v = param2;
bsdf_ward_setup(sd, sd->N, normalize(sd->dPdu), roughness_u, roughness_v);
bsdf_ward_setup(sd, sc, normalize(sd->dPdu), roughness_u, roughness_v);
break;
}
#endif
case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: {
ShaderClosure *sc = svm_node_closure_get(sd);
svm_node_closure_set_mix_weight(sc, mix_weight);
/* sigma */
float sigma = clamp(param1, 0.0f, 1.0f);
@ -115,55 +199,107 @@ __device void svm_node_closure_bsdf(ShaderData *sd, float *stack, uint4 node, fl
float cosNO = dot(sd->N, sd->I);
float fresnel = fresnel_dielectric_cos(cosNO, eta);
sd->svm_closure_weight *= fresnel;
sc->weight *= fresnel;
bsdf_ashikhmin_velvet_setup(sd, sd->N, sigma);
bsdf_ashikhmin_velvet_setup(sd, sc, sigma);
break;
}
default:
return;
break;
}
}
__device void svm_node_closure_emission(ShaderData *sd)
__device void svm_node_closure_emission(ShaderData *sd, float *stack, uint4 node)
{
sd->svm_closure = CLOSURE_EMISSION_ID;
#ifdef __MULTI_CLOSURE__
ShaderClosure *sc = svm_node_closure_get(sd);
uint mix_weight_offset = node.y;
if(stack_valid(mix_weight_offset)) {
float mix_weight = stack_load_float(stack, mix_weight_offset);
if(mix_weight == 0.0f)
return;
sc->weight *= mix_weight;
}
#else
ShaderClosure *sc = &sd->closure;
#endif
sc->type = CLOSURE_EMISSION_ID;
sd->flag |= SD_EMISSION;
}
__device void svm_node_closure_background(ShaderData *sd)
__device void svm_node_closure_background(ShaderData *sd, uint4 node)
{
sd->svm_closure = CLOSURE_BACKGROUND_ID;
#ifdef __MULTI_CLOSURE__
ShaderClosure *sc = svm_node_closure_get(sd);
#else
ShaderClosure *sc = &sd->closure;
#endif
sc->type = CLOSURE_BACKGROUND_ID;
}
__device void svm_node_closure_holdout(ShaderData *sd)
__device void svm_node_closure_holdout(ShaderData *sd, float *stack, uint4 node)
{
sd->svm_closure = CLOSURE_HOLDOUT_ID;
#ifdef __MULTI_CLOSURE__
ShaderClosure *sc = svm_node_closure_get(sd);
uint mix_weight_offset = node.y;
if(stack_valid(mix_weight_offset)) {
float mix_weight = stack_load_float(stack, mix_weight_offset);
if(mix_weight == 0.0f)
return;
sc->weight = make_float3(mix_weight, mix_weight, mix_weight);
}
else
sc->weight = make_float3(1.0f, 1.0f, 1.0f);
sc->sample_weight = 0.0f;
#else
ShaderClosure *sc = &sd->closure;
#endif
sc->type = CLOSURE_HOLDOUT_ID;
sd->flag |= SD_HOLDOUT;
}
/* Closure Nodes */
__device_inline void svm_node_closure_store_weight(ShaderData *sd, float3 weight)
{
#ifdef __MULTI_CLOSURE__
sd->closure[sd->num_closure].weight = weight;
#else
sd->closure.weight = weight;
#endif
}
__device void svm_node_closure_set_weight(ShaderData *sd, uint r, uint g, uint b)
{
sd->svm_closure_weight.x = __int_as_float(r);
sd->svm_closure_weight.y = __int_as_float(g);
sd->svm_closure_weight.z = __int_as_float(b);
float3 weight = make_float3(__int_as_float(r), __int_as_float(g), __int_as_float(b));
svm_node_closure_store_weight(sd, weight);
}
__device void svm_node_emission_set_weight_total(KernelGlobals *kg, ShaderData *sd, uint r, uint g, uint b)
{
sd->svm_closure_weight.x = __int_as_float(r);
sd->svm_closure_weight.y = __int_as_float(g);
sd->svm_closure_weight.z = __int_as_float(b);
float3 weight = make_float3(__int_as_float(r), __int_as_float(g), __int_as_float(b));
if(sd->object != ~0)
sd->svm_closure_weight /= object_surface_area(kg, sd->object);
weight /= object_surface_area(kg, sd->object);
svm_node_closure_store_weight(sd, weight);
}
__device void svm_node_closure_weight(ShaderData *sd, float *stack, uint weight_offset)
{
sd->svm_closure_weight = stack_load_float3(stack, weight_offset);
float3 weight = stack_load_float3(stack, weight_offset);
svm_node_closure_store_weight(sd, weight);
}
__device void svm_node_emission_weight(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
@ -172,37 +308,59 @@ __device void svm_node_emission_weight(KernelGlobals *kg, ShaderData *sd, float
uint strength_offset = node.z;
uint total_power = node.w;
sd->svm_closure_weight = stack_load_float3(stack, color_offset)*stack_load_float(stack, strength_offset);
float3 weight = stack_load_float3(stack, color_offset)*stack_load_float(stack, strength_offset);
if(total_power && sd->object != ~0)
sd->svm_closure_weight /= object_surface_area(kg, sd->object);
weight /= object_surface_area(kg, sd->object);
svm_node_closure_store_weight(sd, weight);
}
__device void svm_node_mix_closure(ShaderData *sd, float *stack,
uint weight_offset, uint node_jump, int *offset, float *randb)
uint4 node, int *offset, float *randb)
{
float weight = stack_load_float(stack, weight_offset);
weight = clamp(weight, 0.0f, 1.0f);
#ifdef __MULTI_CLOSURE__
/* fetch weight from blend input, previous mix closures,
and write to stack to be used by closure nodes later */
uint weight_offset, in_weight_offset, weight1_offset, weight2_offset;
decode_node_uchar4(node.y, &weight_offset, &in_weight_offset, &weight1_offset, &weight2_offset);
float weight = stack_load_float(stack, weight_offset);
float in_weight = (stack_valid(in_weight_offset))? stack_load_float(stack, in_weight_offset): 1.0f;
if(stack_valid(weight1_offset))
stack_store_float(stack, weight1_offset, in_weight*(1.0f - weight));
if(stack_valid(weight2_offset))
stack_store_float(stack, weight2_offset, in_weight*weight);
#else
/* pick a closure and make the random number uniform over 0..1 again.
closure 1 starts on the next node, for closure 2 the start is at an
offset from the current node, so we jump */
uint weight_offset = node.y;
uint node_jump = node.z;
float weight = stack_load_float(stack, weight_offset);
weight = clamp(weight, 0.0f, 1.0f);
if(*randb < weight) {
*offset += node_jump;
*randb = *randb/weight;
}
else
*randb = (*randb - weight)/(1.0f - weight);
#endif
}
__device void svm_node_add_closure(ShaderData *sd, float *stack, uint unused,
uint node_jump, int *offset, float *randb, float *closure_weight)
{
float weight = 0.5f;
#ifdef __MULTI_CLOSURE__
/* nothing to do, handled in compiler */
#else
/* pick one of the two closures with probability 0.5. sampling quality
is not going to be great, for that we'd need to evaluate the weights
of the two closures being added */
float weight = 0.5f;
if(*randb < weight) {
*offset += node_jump;
*randb = *randb/weight;
@ -211,6 +369,7 @@ __device void svm_node_add_closure(ShaderData *sd, float *stack, uint unused,
*randb = (*randb - weight)/(1.0f - weight);
*closure_weight *= 2.0f;
#endif
}
CCL_NAMESPACE_END

@ -258,6 +258,7 @@ typedef enum ShaderType {
/* Closure */
typedef enum ClosureType {
CLOSURE_BSDF_ID,
CLOSURE_BSDF_DIFFUSE_ID,
CLOSURE_BSDF_TRANSLUCENT_ID,
CLOSURE_BSDF_REFLECTION_ID,
@ -272,16 +273,25 @@ typedef enum ClosureType {
CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
CLOSURE_BSDF_WESTIN_BACKSCATTER_ID,
CLOSURE_BSDF_WESTIN_SHEEN_ID,
CLOSURE_BSSRDF_CUBIC_ID,
CLOSURE_EMISSION_ID,
CLOSURE_DEBUG_ID,
CLOSURE_BACKGROUND_ID,
CLOSURE_HOLDOUT_ID,
CLOSURE_SUBSURFACE_ID,
CLOSURE_VOLUME_ID,
NBUILTIN_CLOSURES
} ClosureType;
/* watch this, being lazy with memory usage */
#define CLOSURE_IS_BSDF(type) (type <= CLOSURE_BSDF_WESTIN_SHEEN_ID)
#define CLOSURE_IS_VOLUME(type) (type == CLOSURE_VOLUME_ID)
#define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID)
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
#define CLOSURE_IS_BACKGROUND(type) (type == CLOSURE_BACKGROUND_ID)
CCL_NAMESPACE_END
#endif /* __SVM_TYPES_H__ */

@ -34,7 +34,7 @@ CCL_NAMESPACE_BEGIN
/* VOLUME CLOSURE */
__device float3 volume_eval_phase(ShaderData *sd, const float3 omega_in, const float3 omega_out)
__device float3 volume_eval_phase(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out)
{
return make_float3(1.0f, 1.0f, 1.0f);
}

@ -55,6 +55,9 @@ LightManager::~LightManager()
void LightManager::device_update_distribution(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
/* option to always sample all point lights */
bool multi_light = false;
/* count */
size_t num_lights = scene->lights.size();
size_t num_triangles = 0;
@ -82,7 +85,10 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
}
}
size_t num_distribution = num_triangles + num_lights;
size_t num_distribution = num_triangles;
if(!multi_light)
num_distribution += num_lights;
/* emission area */
float4 *distribution = dscene->light_distribution.resize(num_distribution + 1);
@ -137,14 +143,16 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
float trianglearea = totarea;
/* point lights */
float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
if(!multi_light) {
float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
for(size_t i = 0; i < scene->lights.size(); i++, offset++) {
distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(-i-1);
distribution[offset].z = 1.0f;
distribution[offset].w = scene->lights[i]->radius;
totarea += lightarea;
for(size_t i = 0; i < scene->lights.size(); i++, offset++) {
distribution[offset].x = totarea;
distribution[offset].y = __int_as_float(-i-1);
distribution[offset].z = 1.0f;
distribution[offset].w = scene->lights[i]->radius;
totarea += lightarea;
}
}
/* normalize cumulative distribution functions */
@ -163,28 +171,40 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
/* update device */
KernelIntegrator *kintegrator = &dscene->data.integrator;
kintegrator->use_emission = (totarea > 0.0f);
kintegrator->use_emission = (totarea > 0.0f) || (multi_light && num_lights);
if(kintegrator->use_emission) {
/* number of emissives */
kintegrator->num_triangles = num_triangles;
kintegrator->num_lights = num_lights;
kintegrator->num_distribution = num_distribution;
kintegrator->num_distribution = (totarea > 0.0f)? num_distribution: 0;
/* precompute pdfs */
kintegrator->pdf_triangles = 0.0f;
kintegrator->pdf_lights = 0.0f;
if(trianglearea > 0.0f) {
kintegrator->pdf_triangles = 1.0f/trianglearea;
if(num_lights)
kintegrator->pdf_triangles *= 0.5f;
}
if(multi_light) {
/* sample one of all triangles and all lights */
kintegrator->num_all_lights = num_lights;
if(num_lights) {
kintegrator->pdf_lights = 1.0f/num_lights;
if(trianglearea > 0.0f)
kintegrator->pdf_lights *= 0.5f;
kintegrator->pdf_triangles = 1.0f/trianglearea;
if(num_lights)
kintegrator->pdf_lights = 1.0f;
}
else {
/* sample one, with 0.5 probability of light or triangle */
kintegrator->num_all_lights = 0;
if(trianglearea > 0.0f) {
kintegrator->pdf_triangles = 1.0f/trianglearea;
if(num_lights)
kintegrator->pdf_triangles *= 0.5f;
}
if(num_lights) {
kintegrator->pdf_lights = 1.0f/num_lights;
if(trianglearea > 0.0f)
kintegrator->pdf_lights *= 0.5f;
}
}
/* CDF */

@ -21,6 +21,7 @@
#include "device.h"
#include "shader.h"
#include "light.h"
#include "mesh.h"
#include "object.h"
#include "scene.h"
@ -250,6 +251,10 @@ void Mesh::tag_update(Scene *scene, bool rebuild)
scene->mesh_manager->need_update = true;
scene->object_manager->need_update = true;
foreach(uint sindex, used_shaders)
if(scene->shaders[sindex]->has_surface_emission)
scene->light_manager->need_update = true;
}
/* Mesh Manager */

@ -1024,7 +1024,8 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *
compiler.add_node(NODE_CLOSURE_BSDF,
compiler.encode_uchar4(closure,
(param1)? param1->stack_offset: SVM_STACK_INVALID,
(param2)? param2->stack_offset: SVM_STACK_INVALID),
(param2)? param2->stack_offset: SVM_STACK_INVALID,
compiler.closure_mix_weight_offset()),
__float_as_int((param1)? param1->value.x: 0.0f),
__float_as_int((param2)? param2->value.x: 0.0f));
}
@ -1222,8 +1223,6 @@ EmissionNode::EmissionNode()
void EmissionNode::compile(SVMCompiler& compiler)
{
compiler.add_node(NODE_CLOSURE_EMISSION, CLOSURE_EMISSION_ID);
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
@ -1236,6 +1235,8 @@ void EmissionNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_EMISSION_SET_WEIGHT_TOTAL, color_in->value * strength_in->value.x);
else
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value * strength_in->value.x);
compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
}
void EmissionNode::compile(OSLCompiler& compiler)
@ -1256,8 +1257,6 @@ BackgroundNode::BackgroundNode()
void BackgroundNode::compile(SVMCompiler& compiler)
{
compiler.add_node(NODE_CLOSURE_BACKGROUND, CLOSURE_BACKGROUND_ID);
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
@ -1268,6 +1267,8 @@ void BackgroundNode::compile(SVMCompiler& compiler)
}
else
compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value*strength_in->value.x);
compiler.add_node(NODE_CLOSURE_BACKGROUND, CLOSURE_BACKGROUND_ID);
}
void BackgroundNode::compile(OSLCompiler& compiler)
@ -1285,7 +1286,7 @@ HoldoutNode::HoldoutNode()
void HoldoutNode::compile(SVMCompiler& compiler)
{
compiler.add_node(NODE_CLOSURE_HOLDOUT, CLOSURE_HOLDOUT_ID);
compiler.add_node(NODE_CLOSURE_HOLDOUT, compiler.closure_mix_weight_offset());
}
void HoldoutNode::compile(OSLCompiler& compiler)

@ -17,6 +17,7 @@
*/
#include "device.h"
#include "light.h"
#include "mesh.h"
#include "object.h"
#include "scene.h"
@ -83,8 +84,15 @@ void Object::apply_transform()
void Object::tag_update(Scene *scene)
{
if(mesh && mesh->transform_applied)
mesh->need_update = true;
if(mesh) {
if(mesh->transform_applied)
mesh->need_update = true;
foreach(uint sindex, mesh->used_shaders)
if(scene->shaders[sindex]->has_surface_emission)
scene->light_manager->need_update = true;
}
scene->mesh_manager->need_update = true;
scene->object_manager->need_update = true;
}

@ -35,7 +35,7 @@ Session::Session(const SessionParams& params_)
: params(params_),
tile_manager(params.progressive, params.passes, params.tile_size, params.min_size)
{
device_use_gl = ((params.device_type == DEVICE_CUDA || params.device_type == DEVICE_OPENCL) && !params.background);
device_use_gl = ((params.device_type != DEVICE_CPU) && !params.background);
device = Device::create(params.device_type, params.background, params.threads);
buffers = new RenderBuffers(device);

@ -58,7 +58,7 @@ public:
background = false;
output_path = "";
progressive = false;
progressive = true;
passes = INT_MAX;
tile_size = 64;
min_size = 64;

@ -105,6 +105,7 @@ SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_man
current_type = SHADER_TYPE_SURFACE;
current_shader = NULL;
background = false;
mix_weight_offset = SVM_STACK_INVALID;
}
int SVMCompiler::stack_size(ShaderSocketType type)
@ -419,6 +420,84 @@ void SVMCompiler::generate_closure(ShaderNode *node, set<ShaderNode*> done, Stac
}
}
void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done, uint in_offset)
{
/* todo: the weaks point here is that unlike the single closure sampling
we will evaluate all nodes even if they are used as input for closures
that are unused. it's not clear what would be the best way to skip such
nodes at runtime, especially if they are tangled up */
if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) {
ShaderInput *fin = node->input("Fac");
ShaderInput *cl1in = node->input("Closure1");
ShaderInput *cl2in = node->input("Closure2");
uint out1_offset = SVM_STACK_INVALID;
uint out2_offset = SVM_STACK_INVALID;
if(fin) {
/* mix closure */
set<ShaderNode*> dependencies;
find_dependencies(dependencies, done, fin);
generate_svm_nodes(dependencies, done);
stack_assign(fin);
if(cl1in->link)
out1_offset = stack_find_offset(SHADER_SOCKET_FLOAT);
if(cl2in->link)
out2_offset = stack_find_offset(SHADER_SOCKET_FLOAT);
add_node(NODE_MIX_CLOSURE,
encode_uchar4(fin->stack_offset, in_offset, out1_offset, out2_offset));
}
else {
/* add closure */
out1_offset = in_offset;
out2_offset = in_offset;
}
if(cl1in->link) {
generate_multi_closure(cl1in->link->parent, done, out1_offset);
if(fin)
active_stack.users[out1_offset]--;
}
if(cl2in->link) {
generate_multi_closure(cl2in->link->parent, done, out2_offset);
if(fin)
active_stack.users[out2_offset]--;
}
}
else {
/* execute dependencies for closure */
foreach(ShaderInput *in, node->inputs) {
if(!node_skip_input(node, in) && in->link) {
set<ShaderNode*> dependencies;
find_dependencies(dependencies, done, in);
generate_svm_nodes(dependencies, done);
}
}
mix_weight_offset = in_offset;
/* compile closure itself */
node->compile(*this);
stack_clear_users(node, done);
stack_clear_temporary(node);
mix_weight_offset = SVM_STACK_INVALID;
if(node->name == ustring("emission"))
current_shader->has_surface_emission = true;
/* end node is added outside of this */
}
}
void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
{
/* Converting a shader graph into svm_nodes that can be executed
@ -464,21 +543,35 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
}
if(clin->link) {
bool generate = false;
if(type == SHADER_TYPE_SURFACE) {
/* generate surface shader */
generate_closure(clin->link->parent, set<ShaderNode*>(), Stack());
generate = true;
shader->has_surface = true;
}
else if(type == SHADER_TYPE_VOLUME) {
/* generate volume shader */
generate_closure(clin->link->parent, set<ShaderNode*>(), Stack());
generate = true;
shader->has_volume = true;
}
else if(type == SHADER_TYPE_DISPLACEMENT) {
/* generate displacement shader */
generate_closure(clin->link->parent, set<ShaderNode*>(), Stack());
generate = true;
shader->has_displacement = true;
}
if(generate) {
set<ShaderNode*> done;
bool multi_closure = false; /* __MULTI_CLOSURE__ */
if(multi_closure) {
generate_multi_closure(clin->link->parent, done, SVM_STACK_INVALID);
}
else {
Stack stack;
generate_closure(clin->link->parent, done, stack);
}
}
}
/* compile output node */

@ -24,6 +24,7 @@
#include "shader.h"
#include "util_set.h"
#include "util_string.h"
CCL_NAMESPACE_BEGIN
@ -65,6 +66,7 @@ public:
uint attribute(ustring name);
uint attribute(Attribute::Standard std);
uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0);
uint closure_mix_weight_offset() { return mix_weight_offset; }
ShaderType output_type() { return current_type; }
@ -75,6 +77,8 @@ public:
protected:
struct Stack {
Stack() { memset(users, 0, sizeof(users)); }
int users[SVM_STACK_SIZE];
};
@ -88,6 +92,7 @@ protected:
void find_dependencies(set<ShaderNode*>& dependencies, const set<ShaderNode*>& done, ShaderInput *input);
void generate_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNode*>& done);
void generate_closure(ShaderNode *node, set<ShaderNode*> done, Stack stack);
void generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done, uint in_offset);
void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
@ -96,6 +101,7 @@ protected:
Shader *current_shader;
Stack active_stack;
int max_stack_use;
uint mix_weight_offset;
};
CCL_NAMESPACE_END

@ -96,7 +96,7 @@ void TileManager::set_tiles()
bool TileManager::done()
{
return (state.pass+1 >= passes);
return (state.pass+1 >= passes && state.resolution == 1);
}
bool TileManager::next()

@ -109,11 +109,16 @@ string path_files_md5_hash(const string& dir)
return hash.get_hex();
}
void path_create_directories(const string& path)
{
boost::filesystem::create_directories(path_dirname(path));
}
bool path_write_binary(const string& path, const vector<uint8_t>& binary)
{
/* write binary file from memory */
boost::filesystem::create_directories(path_dirname(path));
path_create_directories(path);
/* write binary file from memory */
FILE *f = fopen(path.c_str(), "wb");
if(!f)

@ -42,6 +42,7 @@ string path_escape(const string& path);
bool path_exists(const string& path);
string path_files_md5_hash(const string& dir);
void path_create_directories(const string& path);
bool path_write_binary(const string& path, const vector<uint8_t>& binary);
bool path_read_binary(const string& path, vector<uint8_t>& binary);