From 22abc63f676dc7681ee8f734cbc96a7279172d24 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 28 Feb 2012 16:45:08 +0000 Subject: Cycles: ambient occlusion support, with AO factor and distance, and a render pass. http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/World#Ambient_Occlusion http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Passes#Lighting_Passes --- intern/cycles/blender/addon/ui.py | 54 +++++++++++++++++++++---------- intern/cycles/blender/blender_session.cpp | 3 +- intern/cycles/blender/blender_shader.cpp | 14 ++++++++ intern/cycles/kernel/kernel_accumulate.h | 22 +++++++++++++ intern/cycles/kernel/kernel_passes.h | 2 ++ intern/cycles/kernel/kernel_path.h | 53 +++++++++++++++++++++++++----- intern/cycles/kernel/kernel_types.h | 18 ++++++++--- intern/cycles/render/background.cpp | 11 ++++++- intern/cycles/render/background.h | 3 ++ intern/cycles/render/film.cpp | 7 ++++ intern/cycles/render/integrator.cpp | 3 ++ 11 files changed, 158 insertions(+), 32 deletions(-) (limited to 'intern') diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index e006238a70d..faf057e13cc 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -196,6 +196,7 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel): col.prop(rl, "use_pass_material_index") col.prop(rl, "use_pass_emit") col.prop(rl, "use_pass_environment") + col.prop(rl, "use_pass_ambient_occlusion") col = split.column() col.label() @@ -483,48 +484,67 @@ class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel): if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'): layout.prop(world, "horizon_color", text="Color") - -class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel): - bl_label = "Settings" +class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel): + bl_label = "Volume" bl_context = "world" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): - return context.world and CyclesButtonsPanel.poll(context) + # world = context.world + # world and world.node_tree and CyclesButtonsPanel.poll(context) + return False def draw(self, context): layout = self.layout + layout.active = False world = context.world - cworld = world.cycles + panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume') - col = layout.column() +class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel): + bl_label = "Ambient Occlusion" + bl_context = "world" - col.prop(cworld, "sample_as_light") - row = col.row() - row.active = cworld.sample_as_light - row.prop(cworld, "sample_map_resolution") + @classmethod + def poll(cls, context): + return context.world and CyclesButtonsPanel.poll(context) + def draw_header(self, context): + light = context.world.light_settings + self.layout.prop(light, "use_ambient_occlusion", text="") -class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel): - bl_label = "Volume" + def draw(self, context): + layout = self.layout + light = context.world.light_settings + + layout.active = light.use_ambient_occlusion + + split = layout.split() + split.prop(light, "ao_factor", text="Factor") + split.prop(light, "distance", text="Distance") + +class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel): + bl_label = "Settings" bl_context = "world" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): - # world = context.world - # world and world.node_tree and CyclesButtonsPanel.poll(context) - return False + return context.world and CyclesButtonsPanel.poll(context) def draw(self, context): layout = self.layout - layout.active = False world = context.world - panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume') + cworld = world.cycles + col = layout.column() + + col.prop(cworld, "sample_as_light") + row = col.row() + row.active = cworld.sample_as_light + row.prop(cworld, "sample_map_resolution") class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel): bl_label = "Surface" diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index cc6ba073188..7f666706470 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -158,10 +158,11 @@ static PassType get_pass_type(BL::RenderPass b_pass) return PASS_EMISSION; case BL::RenderPass::type_ENVIRONMENT: return PASS_BACKGROUND; + case BL::RenderPass::type_AO: + return PASS_AO; case BL::RenderPass::type_DIFFUSE: case BL::RenderPass::type_SHADOW: - case BL::RenderPass::type_AO: case BL::RenderPass::type_COLOR: case BL::RenderPass::type_REFRACTION: case BL::RenderPass::type_SPECULAR: diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 5310e35dc25..a88bcaf3ace 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -696,6 +696,20 @@ void BlenderSync::sync_world() graph->connect(closure->output("Background"), out->input("Surface")); } + /* AO */ + if(b_world) { + BL::WorldLighting b_light = b_world.light_settings(); + + if(b_light.use_ambient_occlusion()) { + background->ao_factor = b_light.ao_factor(); + background->ao_distance = b_light.distance(); + } + else { + background->ao_factor = 0.0f; + background->ao_distance = 0.0f; + } + } + shader->set_graph(graph); shader->tag_update(scene); } diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index e71fad58c96..7d9aaf81906 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -135,6 +135,7 @@ __device_inline void path_radiance_init(PathRadiance *L, int use_light_pass) L->emission = make_float3(0.0f, 0.0f, 0.0f); L->background = make_float3(0.0f, 0.0f, 0.0f); + L->ao = make_float3(0.0f, 0.0f, 0.0f); } else L->emission = make_float3(0.0f, 0.0f, 0.0f); @@ -199,6 +200,27 @@ __device_inline void path_radiance_accum_emission(PathRadiance *L, float3 throug #endif } +__device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput, float3 bsdf, float3 ao, int bounce) +{ +#ifdef __PASSES__ + if(L->use_light_pass) { + if(bounce == 0) { + /* directly visible lighting */ + L->direct_diffuse += throughput*bsdf*ao; + L->ao += throughput*ao; + } + else { + /* indirectly visible lighting after BSDF bounce */ + L->indirect += throughput*bsdf*ao; + } + } + else + L->emission += throughput*bsdf*ao; +#else + *L += throughput*bsdf*ao; +#endif +} + __device_inline void path_radiance_accum_light(PathRadiance *L, float3 throughput, BsdfEval *bsdf_eval, int bounce) { #ifdef __PASSES__ diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index a1b3b0e9038..44e06be8c16 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -123,6 +123,8 @@ __device_inline void kernel_write_light_passes(KernelGlobals *kg, __global float kernel_write_pass_float3(buffer + kernel_data.film.pass_emission, sample, L->emission); if(flag & PASS_BACKGROUND) kernel_write_pass_float3(buffer + kernel_data.film.pass_background, sample, L->background); + if(flag & PASS_AO) + kernel_write_pass_float3(buffer + kernel_data.film.pass_ao, sample, L->ao); if(flag & PASS_DIFFUSE_COLOR) kernel_write_pass_float3(buffer + kernel_data.film.pass_diffuse_color, sample, L->color_diffuse); diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 05ee3212b4c..154add55004 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -145,12 +145,15 @@ __device_inline float path_state_terminate_probability(KernelGlobals *kg, PathSt return average(throughput); } -__device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, Intersection *isect, BsdfEval *L_light) +__device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ray, float3 *shadow) { if(ray->t == 0.0f) return false; - bool result = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, isect); + Intersection isect; + bool result = scene_intersect(kg, ray, PATH_RAY_SHADOW_OPAQUE, &isect); + + *shadow = make_float3(1.0f, 1.0f, 1.0f); #ifdef __TRANSPARENT_SHADOWS__ if(result && kernel_data.integrator.transparent_shadows) { @@ -162,7 +165,7 @@ __device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ra also note that for this to work correct, multi close sampling must be used, since we don't pass a random number to shader_eval_surface */ - if(shader_transparent_shadow(kg, isect)) { + if(shader_transparent_shadow(kg, &isect)) { float3 throughput = make_float3(1.0f, 1.0f, 1.0f); float3 Pend = ray->P + ray->D*ray->t; int bounce = state->transparent_bounce; @@ -184,16 +187,16 @@ __device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ra #endif } - if(!scene_intersect(kg, ray, PATH_RAY_SHADOW_TRANSPARENT, isect)) { - bsdf_eval_mul(L_light, throughput); + if(!scene_intersect(kg, ray, PATH_RAY_SHADOW_TRANSPARENT, &isect)) { + *shadow *= throughput; return false; } - if(!shader_transparent_shadow(kg, isect)) + if(!shader_transparent_shadow(kg, &isect)) return true; ShaderData sd; - shader_setup_from_ray(kg, &sd, isect, ray); + shader_setup_from_ray(kg, &sd, &isect, ray); shader_eval_surface(kg, &sd, 0.0f, PATH_RAY_SHADOW); throughput *= shader_bsdf_transparency(kg, &sd); @@ -285,6 +288,35 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R throughput /= probability; + +#ifdef __AO__ + /* ambient occlusion */ + if(kernel_data.integrator.use_ambient_occlusion) { + /* todo: solve correlation */ + float bsdf_u = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_U); + float bsdf_v = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_V); + + float3 ao_D; + float ao_pdf; + + sample_cos_hemisphere(sd.N, bsdf_u, bsdf_v, &ao_D, &ao_pdf); + + if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) { + Ray light_ray; + float3 ao_shadow; + + light_ray.P = ray_offset(sd.P, sd.Ng); + light_ray.D = ao_D; + light_ray.t = kernel_data.background.ao_distance; + + if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow)) { + float3 ao_bsdf = shader_bsdf_diffuse(kg, &sd)*kernel_data.background.ao_factor; + path_radiance_accum_ao(&L, throughput, ao_bsdf, ao_shadow, state.bounce); + } + } + } +#endif + #ifdef __EMISSION__ if(kernel_data.integrator.use_direct_light) { /* sample illumination from lights to find path contribution */ @@ -307,8 +339,13 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R #endif if(direct_emission(kg, &sd, i, light_t, light_o, light_u, light_v, &light_ray, &L_light)) { /* trace shadow ray */ - if(!shadow_blocked(kg, &state, &light_ray, &isect, &L_light)) + float3 shadow; + + if(!shadow_blocked(kg, &state, &light_ray, &shadow)) { + /* accumulate */ + bsdf_eval_mul(&L_light, shadow); path_radiance_accum_light(&L, throughput, &L_light, state.bounce); + } } #ifdef __MULTI_LIGHT__ } diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 61335d5f9fa..e5e03cedc18 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -72,6 +72,7 @@ CCL_NAMESPACE_BEGIN #define __TRANSPARENT_SHADOWS__ #define __PASSES__ #define __BACKGROUND_MIS__ +#define __AO__ #endif //#define __MULTI_LIGHT__ @@ -172,7 +173,8 @@ typedef enum PassType { PASS_GLOSSY_DIRECT = 16384, PASS_TRANSMISSION_DIRECT = 32768, PASS_EMISSION = 65536, - PASS_BACKGROUND = 131072 + PASS_BACKGROUND = 131072, + PASS_AO = 262144 } PassType; #define PASS_ALL (~0) @@ -186,6 +188,7 @@ typedef struct PathRadiance { float3 emission; float3 background; + float3 ao; float3 indirect; float3 direct_throughput; @@ -237,7 +240,8 @@ typedef enum LightType { LIGHT_POINT, LIGHT_DISTANT, LIGHT_BACKGROUND, - LIGHT_AREA + LIGHT_AREA, + LIGHT_AO } LightType; /* Camera Type */ @@ -458,7 +462,7 @@ typedef struct KernelFilm { int pass_emission; int pass_background; - int pass_pad1; + int pass_ao; int pass_pad2; } KernelFilm; @@ -466,7 +470,10 @@ typedef struct KernelBackground { /* only shader index */ int shader; int transparent; - int pad1, pad2; + + /* ambient occlusion */ + float ao_factor; + float ao_distance; } KernelBackground; typedef struct KernelSunSky { @@ -482,6 +489,7 @@ typedef struct KernelSunSky { typedef struct KernelIntegrator { /* emission */ int use_direct_light; + int use_ambient_occlusion; int num_distribution; int num_all_lights; float pdf_triangles; @@ -509,7 +517,7 @@ typedef struct KernelIntegrator { /* render layer */ int layer_flag; - int pad1, pad2, pad3; + int pad1, pad2; } KernelIntegrator; typedef struct KernelBVH { diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp index bf4131b6d38..c5b003fe6c5 100644 --- a/intern/cycles/render/background.cpp +++ b/intern/cycles/render/background.cpp @@ -31,6 +31,9 @@ CCL_NAMESPACE_BEGIN Background::Background() { + ao_factor = 0.0f; + ao_distance = FLT_MAX; + transparent = false; need_update = true; } @@ -48,6 +51,10 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene /* set shader index and transparent option */ KernelBackground *kbackground = &dscene->data.background; + + kbackground->ao_factor = ao_factor; + kbackground->ao_distance = ao_distance; + kbackground->transparent = transparent; kbackground->shader = scene->shader_manager->get_shader_id(scene->default_background); @@ -60,7 +67,9 @@ void Background::device_free(Device *device, DeviceScene *dscene) bool Background::modified(const Background& background) { - return !(transparent == background.transparent); + return !(transparent == background.transparent && + ao_factor == background.ao_factor && + ao_distance == background.ao_distance); } void Background::tag_update(Scene *scene) diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h index 16d2ccb6caa..40dacd9d6b1 100644 --- a/intern/cycles/render/background.h +++ b/intern/cycles/render/background.h @@ -29,6 +29,9 @@ class Scene; class Background { public: + float ao_factor; + float ao_distance; + bool transparent; bool need_update; diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index 376e9d6d0ca..daadb6c04c8 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -111,6 +111,10 @@ void Pass::add(PassType type, vector& passes) pass.components = 4; pass.exposure = true; break; + case PASS_AO: + pass.components = 4; + pass.exposure = true; + break; } passes.push_back(pass); @@ -224,6 +228,9 @@ void Film::device_update(Device *device, DeviceScene *dscene) case PASS_BACKGROUND: kfilm->pass_background = kfilm->pass_stride; kfilm->use_light_pass = 1; + case PASS_AO: + kfilm->pass_ao = kfilm->pass_stride; + kfilm->use_light_pass = 1; case PASS_NONE: break; } diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 47059a0a009..ff2afc7119b 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -83,6 +83,9 @@ void Integrator::device_update(Device *device, DeviceScene *dscene) kintegrator->seed = hash_int(seed); kintegrator->layer_flag = layer_flag << PATH_RAY_LAYER_SHIFT; + kintegrator->use_ambient_occlusion = + ((dscene->data.film.pass_flag & PASS_AO) || dscene->data.background.ao_factor != 0.0f); + /* sobol directions table */ int dimensions = PRNG_BASE_NUM + (max_bounce + transparent_max_bounce + 2)*PRNG_BOUNCE_NUM; uint *directions = dscene->sobol_directions.resize(SOBOL_BITS*dimensions); -- cgit v1.2.3