From 5445dda2956d64385b20874592b3305b7056505a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 27 Jan 2010 21:40:08 +0000 Subject: [PATCH] Ambient Occlusion split up into: Ambient occlusion: multiplied with direct lighting by default, add is also still available and more blending methods might be added if they are useful. This is fundamentally a non physical effect. Environment lighting: always added as you would expect (though you can subtract by specifying negative energy). This can be just white or take colors or textures from the world. Indirect lighting: only supported for AAO at the moment (and is still too approximate), and also is always added. A factor is available to specify how much is added, though value 1.0 is correct. Also: * Material ambient value now defaults to 1.0. * Added Environment, Indirect and Emit pass. * "Both" blending method is no longer available. * Attenuation, sampling parameters are still shared, some could be split up, though if they are different this would affect performance. --- release/scripts/ui/properties_render.py | 12 +- release/scripts/ui/properties_world.py | 127 +++++++++------ source/blender/blenkernel/BKE_blender.h | 2 +- source/blender/blenkernel/intern/material.c | 2 +- source/blender/blenkernel/intern/world.c | 3 + source/blender/blenloader/intern/readfile.c | 30 ++++ source/blender/makesdna/DNA_scene_types.h | 36 ++--- source/blender/makesdna/DNA_world_types.h | 11 +- source/blender/makesrna/intern/rna_render.c | 2 + source/blender/makesrna/intern/rna_scene.c | 36 +++++ source/blender/makesrna/intern/rna_world.c | 132 +++++++++------- .../render/extern/include/RE_shader_ext.h | 5 +- .../render/intern/include/render_types.h | 1 + .../render/intern/include/rendercore.h | 2 +- .../render/intern/source/convertblender.c | 12 +- .../blender/render/intern/source/occlusion.c | 79 +++++++--- .../blender/render/intern/source/pipeline.c | 33 ++++ .../blender/render/intern/source/rayshade.c | 102 ++++++------- .../blender/render/intern/source/rendercore.c | 23 ++- .../blender/render/intern/source/shadeinput.c | 6 +- .../render/intern/source/shadeoutput.c | 144 ++++++++++-------- source/blender/render/intern/source/strand.c | 8 + source/blender/render/intern/source/zbuf.c | 27 ++++ 23 files changed, 559 insertions(+), 276 deletions(-) diff --git a/release/scripts/ui/properties_render.py b/release/scripts/ui/properties_render.py index 90f54851020..d837f5f1b79 100644 --- a/release/scripts/ui/properties_render.py +++ b/release/scripts/ui/properties_render.py @@ -137,11 +137,11 @@ class RENDER_PT_layers(RenderButtonsPanel): col.prop(rl, "pass_uv") col.prop(rl, "pass_mist") col.prop(rl, "pass_object_index") + col.prop(rl, "pass_color") if wide_ui: col = split.column() col.label() - col.prop(rl, "pass_color") col.prop(rl, "pass_diffuse") row = col.row() row.prop(rl, "pass_specular") @@ -150,16 +150,24 @@ class RENDER_PT_layers(RenderButtonsPanel): row.prop(rl, "pass_shadow") row.prop(rl, "pass_shadow_exclude", text="", icon='X') row = col.row() + row.prop(rl, "pass_emit") + row.prop(rl, "pass_emit_exclude", text="", icon='X') + row = col.row() row.prop(rl, "pass_ao") row.prop(rl, "pass_ao_exclude", text="", icon='X') row = col.row() + row.prop(rl, "pass_environment") + row.prop(rl, "pass_environment_exclude", text="", icon='X') + row = col.row() + row.prop(rl, "pass_indirect") + row.prop(rl, "pass_indirect_exclude", text="", icon='X') + row = col.row() row.prop(rl, "pass_reflection") row.prop(rl, "pass_reflection_exclude", text="", icon='X') row = col.row() row.prop(rl, "pass_refraction") row.prop(rl, "pass_refraction_exclude", text="", icon='X') - class RENDER_PT_shading(RenderButtonsPanel): bl_label = "Shading" COMPAT_ENGINES = {'BLENDER_RENDER'} diff --git a/release/scripts/ui/properties_world.py b/release/scripts/ui/properties_world.py index c4eaa049ce6..2633aeb6cc9 100644 --- a/release/scripts/ui/properties_world.py +++ b/release/scripts/ui/properties_world.py @@ -105,6 +105,7 @@ class WORLD_PT_world(WorldButtonsPanel): class WORLD_PT_mist(WorldButtonsPanel): bl_label = "Mist" + bl_default_closed = True COMPAT_ENGINES = {'BLENDER_RENDER'} def draw_header(self, context): @@ -135,6 +136,7 @@ class WORLD_PT_mist(WorldButtonsPanel): class WORLD_PT_stars(WorldButtonsPanel): bl_label = "Stars" + bl_default_closed = True COMPAT_ENGINES = {'BLENDER_RENDER'} def draw_header(self, context): @@ -166,77 +168,110 @@ class WORLD_PT_ambient_occlusion(WorldButtonsPanel): COMPAT_ENGINES = {'BLENDER_RENDER'} def draw_header(self, context): - world = context.world - - self.layout.prop(world.ambient_occlusion, "enabled", text="") + light = context.world.lighting + self.layout.prop(light, "use_ambient_occlusion", text="") def draw(self, context): layout = self.layout - wide_ui = context.region.width > narrowui - ao = context.world.ambient_occlusion + light = context.world.lighting - layout.active = ao.enabled + layout.active = light.use_ambient_occlusion - layout.prop(ao, "gather_method", expand=True) + split = layout.split() + split.prop(light, "ao_factor", text="Factor") + split.prop(light, "ao_blend_mode", text="") + +class WORLD_PT_environment_lighting(WorldButtonsPanel): + bl_label = "Environment Lighting" + COMPAT_ENGINES = {'BLENDER_RENDER'} + + def draw_header(self, context): + light = context.world.lighting + self.layout.prop(light, "use_environment_lighting", text="") + + def draw(self, context): + layout = self.layout + light = context.world.lighting + + layout.active = light.use_environment_lighting + + split = layout.split() + split.prop(light, "environment_energy", text="Energy") + split.prop(light, "environment_color", text="") + +class WORLD_PT_indirect_lighting(WorldButtonsPanel): + bl_label = "Indirect Lighting" + COMPAT_ENGINES = {'BLENDER_RENDER'} + + def draw_header(self, context): + light = context.world.lighting + self.layout.prop(light, "use_indirect_lighting", text="") + + def draw(self, context): + layout = self.layout + light = context.world.lighting + + layout.active = light.use_indirect_lighting + + split = layout.split() + split.prop(light, "indirect_factor", text="Factor") + split.prop(light, "indirect_bounces", text="Bounces") + +class WORLD_PT_gather(WorldButtonsPanel): + bl_label = "Gather" + COMPAT_ENGINES = {'BLENDER_RENDER'} + + def draw(self, context): + layout = self.layout + light = context.world.lighting + + layout.active = light.use_ambient_occlusion or light.use_environment_lighting or light.use_indirect_lighting + + layout.prop(light, "gather_method", expand=True) split = layout.split() col = split.column() col.label(text="Attenuation:") - if ao.gather_method == 'RAYTRACE': - col.prop(ao, "distance") - col.prop(ao, "falloff") + if light.gather_method == 'RAYTRACE': + col.prop(light, "distance") + col.prop(light, "falloff") sub = col.row() - sub.active = ao.falloff - sub.prop(ao, "falloff_strength", text="Strength") + sub.active = light.falloff + sub.prop(light, "falloff_strength", text="Strength") - if ao.gather_method == 'RAYTRACE': - if wide_ui: - col = split.column() + if light.gather_method == 'RAYTRACE': + col = split.column() col.label(text="Sampling:") - col.prop(ao, "sample_method", text="") + col.prop(light, "sample_method", text="") sub = col.column() - sub.prop(ao, "samples") + sub.prop(light, "samples") - if ao.sample_method == 'ADAPTIVE_QMC': - sub.prop(ao, "threshold") - sub.prop(ao, "adapt_to_speed", slider=True) - elif ao.sample_method == 'CONSTANT_JITTERED': - sub.prop(ao, "bias") + if light.sample_method == 'ADAPTIVE_QMC': + sub.prop(light, "threshold") + sub.prop(light, "adapt_to_speed", slider=True) + elif light.sample_method == 'CONSTANT_JITTERED': + sub.prop(light, "bias") - if ao.gather_method == 'APPROXIMATE': - if wide_ui: - col = split.column() + if light.gather_method == 'APPROXIMATE': + col = split.column() col.label(text="Sampling:") - col.prop(ao, "passes") - col.prop(ao, "error_tolerance", text="Error") - col.prop(ao, "pixel_cache") - col.prop(ao, "correction") - - col = layout.column() - col.label(text="Influence:") - - col.row().prop(ao, "blend_mode", expand=True) - - split = layout.split() - - col = split.column() - col.prop(ao, "energy") - col.prop(ao, "indirect_energy") - - if wide_ui: - col = split.column() - col.prop(ao, "color") - col.prop(ao, "indirect_bounces") + col.prop(light, "passes") + col.prop(light, "error_tolerance", text="Error") + col.prop(light, "pixel_cache") + col.prop(light, "correction") bpy.types.register(WORLD_PT_context_world) bpy.types.register(WORLD_PT_preview) bpy.types.register(WORLD_PT_world) bpy.types.register(WORLD_PT_ambient_occlusion) +bpy.types.register(WORLD_PT_environment_lighting) +bpy.types.register(WORLD_PT_indirect_lighting) +bpy.types.register(WORLD_PT_gather) bpy.types.register(WORLD_PT_mist) bpy.types.register(WORLD_PT_stars) -bpy.types.register(WORLD_PT_custom_props) \ No newline at end of file +bpy.types.register(WORLD_PT_custom_props) diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 37b98565ea3..45df0913079 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -43,7 +43,7 @@ struct bContext; struct ReportList; #define BLENDER_VERSION 250 -#define BLENDER_SUBVERSION 14 +#define BLENDER_SUBVERSION 15 #define BLENDER_MINVERSION 250 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 3567c061f04..2d4ff857b2a 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -112,7 +112,7 @@ void init_material(Material *ma) ma->specr= ma->specg= ma->specb= 1.0; ma->mirr= ma->mirg= ma->mirb= 1.0; ma->spectra= 1.0; - ma->amb= 0.5; + ma->amb= 1.0; ma->alpha= 1.0; ma->spec= ma->hasize= 0.5; ma->har= 50; diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index b5f8bc81b81..0b49808bf15 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -102,6 +102,9 @@ World *add_world(char *name) wrld->aodist= 10.0f; wrld->aosamp= 5; wrld->aoenergy= 1.0f; + wrld->ao_env_energy= 1.0f; + wrld->ao_indirect_energy= 1.0f; + wrld->ao_indirect_bounces= 1; wrld->aobias= 0.05f; wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY; wrld->ao_approx_error= 0.25f; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c3457adc288..84b27ad44eb 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -10604,6 +10604,36 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } + if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 15)) { + World *wo; + Material *ma; + + /* ambient default from 0.5f to 1.0f */ + for(ma= main->mat.first; ma; ma=ma->id.next) + ma->amb *= 2.0f; + + for(wo= main->world.first; wo; wo=wo->id.next) { + /* ao splitting into ao/env/indirect */ + wo->ao_env_energy= wo->aoenergy; + wo->aoenergy= 1.0f; + + if(wo->ao_indirect_bounces == 0) + wo->ao_indirect_bounces= 1; + else + wo->mode |= WO_INDIRECT_LIGHT; + + if(wo->aomix == WO_AOSUB) + wo->ao_env_energy= -wo->ao_env_energy; + else if(wo->aomix == WO_AOADDSUB) + wo->mode |= WO_AMB_OCC; + + wo->aomix= WO_AOMUL; + + /* ambient default from 0.5f to 1.0f */ + mul_v3_fl(&wo->ambr, 0.5f); + wo->ao_env_energy *= 0.5f; + } + } /* put 2.50 compatibility code here until next subversion bump */ //{ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 4caae9e1dfc..636596f7af7 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -170,23 +170,25 @@ typedef struct SceneRenderLayer { #define SCE_LAY_NEG_ZMASK 0x80000 /* srl->passflag */ -#define SCE_PASS_COMBINED 1 -#define SCE_PASS_Z 2 -#define SCE_PASS_RGBA 4 -#define SCE_PASS_DIFFUSE 8 -#define SCE_PASS_SPEC 16 -#define SCE_PASS_SHADOW 32 -#define SCE_PASS_AO 64 -#define SCE_PASS_REFLECT 128 -#define SCE_PASS_NORMAL 256 -#define SCE_PASS_VECTOR 512 -#define SCE_PASS_REFRACT 1024 -#define SCE_PASS_INDEXOB 2048 -#define SCE_PASS_UV 4096 -#define SCE_PASS_RADIO 8192 /* Radio removed, can use for new GI? */ -#define SCE_PASS_MIST 16384 - -#define SCE_PASS_RAYHITS 32768 +#define SCE_PASS_COMBINED 1 +#define SCE_PASS_Z 2 +#define SCE_PASS_RGBA 4 +#define SCE_PASS_DIFFUSE 8 +#define SCE_PASS_SPEC 16 +#define SCE_PASS_SHADOW 32 +#define SCE_PASS_AO 64 +#define SCE_PASS_REFLECT 128 +#define SCE_PASS_NORMAL 256 +#define SCE_PASS_VECTOR 512 +#define SCE_PASS_REFRACT 1024 +#define SCE_PASS_INDEXOB 2048 +#define SCE_PASS_UV 4096 +#define SCE_PASS_RADIO 8192 /* Radio removed, can use for new GI? */ +#define SCE_PASS_MIST 16384 +#define SCE_PASS_RAYHITS 32768 +#define SCE_PASS_EMIT 65536 +#define SCE_PASS_ENVIRONMENT 131072 +#define SCE_PASS_INDIRECT 262144 /* note, srl->passflag is treestore element 'nr' in outliner, short still... */ diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h index 9b3f78caee0..b79bc766d17 100644 --- a/source/blender/makesdna/DNA_world_types.h +++ b/source/blender/makesdna/DNA_world_types.h @@ -107,7 +107,7 @@ typedef struct World { short aomode, aosamp, aomix, aocolor; float ao_adapt_thresh, ao_adapt_speed_fac; float ao_approx_error, ao_approx_correction; - float ao_indirect_energy; + float ao_indirect_energy, ao_env_energy, ao_pad2; short ao_indirect_bounces, ao_pad; short ao_samp_method, ao_gather_method, ao_approx_passes; @@ -142,13 +142,16 @@ typedef struct World { #define WO_STARS 2 #define WO_DOF 4 #define WO_ACTIVITY_CULLING 8 -#define WO_AMB_OCC 16 +#define WO_ENV_LIGHT 16 #define WO_DBVT_CULLING 32 +#define WO_AMB_OCC 64 +#define WO_INDIRECT_LIGHT 128 /* aomix */ #define WO_AOADD 0 -#define WO_AOSUB 1 -#define WO_AOADDSUB 2 +#define WO_AOSUB 1 /* deprecated */ +#define WO_AOADDSUB 2 /* deprecated */ +#define WO_AOMUL 3 /* ao_samp_method - methods for sampling the AO hemi */ #define WO_AOSAMP_CONSTANT 0 diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 8212423acd5..85fd33f6c63 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -369,6 +369,8 @@ static void rna_def_render_pass(BlenderRNA *brna) {SCE_PASS_INDEXOB, "OBJECT_INDEX", 0, "Object Index", ""}, {SCE_PASS_UV, "UV", 0, "UV", ""}, {SCE_PASS_MIST, "MIST", 0, "Mist", ""}, + {SCE_PASS_EMIT, "EMIT", 0, "Emit", ""}, + {SCE_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "RenderPass", NULL); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 7e4fc9aa9e0..3f79a06566d 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1142,6 +1142,24 @@ void rna_def_render_layer_common(StructRNA *srna, int scene) if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update"); else RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop= RNA_def_property(srna, "pass_emit", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_EMIT); + RNA_def_property_ui_text(prop, "Emit", "Deliver emission pass."); + if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update"); + else RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + prop= RNA_def_property(srna, "pass_environment", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_ENVIRONMENT); + RNA_def_property_ui_text(prop, "Environment", "Deliver environment lighting pass."); + if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update"); + else RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + prop= RNA_def_property(srna, "pass_indirect", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_INDIRECT); + RNA_def_property_ui_text(prop, "Indirect", "Deliver indirect lighting pass."); + if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update"); + else RNA_def_property_clear_flag(prop, PROP_EDITABLE); + prop= RNA_def_property(srna, "pass_specular_exclude", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_SPEC); RNA_def_property_ui_text(prop, "Specular Exclude", "Exclude specular pass from combined."); @@ -1171,6 +1189,24 @@ void rna_def_render_layer_common(StructRNA *srna, int scene) RNA_def_property_ui_text(prop, "Refraction Exclude", "Exclude raytraced refraction pass from combined."); if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update"); else RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + prop= RNA_def_property(srna, "pass_emit_exclude", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_EMIT); + RNA_def_property_ui_text(prop, "Emit Exclude", "Exclude emission pass from combined."); + if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update"); + else RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + prop= RNA_def_property(srna, "pass_environment_exclude", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_ENVIRONMENT); + RNA_def_property_ui_text(prop, "Environment Exclude", "Exclude environment pass from combined."); + if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update"); + else RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + prop= RNA_def_property(srna, "pass_indirect_exclude", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "pass_xor", SCE_PASS_INDIRECT); + RNA_def_property_ui_text(prop, "Indirect Exclude", "Exclude indirect pass from combined."); + if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, "rna_SceneRenderLayer_pass_update"); + else RNA_def_property_clear_flag(prop, PROP_EDITABLE); } static void rna_def_scene_game_data(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index 4046fc266da..c2af18193b2 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -45,9 +45,9 @@ #include "WM_api.h" #include "WM_types.h" -static PointerRNA rna_World_ambient_occlusion_get(PointerRNA *ptr) +static PointerRNA rna_World_lighting_get(PointerRNA *ptr) { - return rna_pointer_inherit_refine(ptr, &RNA_WorldAmbientOcclusion, ptr->id.data); + return rna_pointer_inherit_refine(ptr, &RNA_WorldLighting, ptr->id.data); } static PointerRNA rna_World_stars_get(PointerRNA *ptr) @@ -182,15 +182,14 @@ static void rna_def_world_mtex(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_World_update"); } -static void rna_def_ambient_occlusion(BlenderRNA *brna) +static void rna_def_lighting(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; static EnumPropertyItem blend_mode_items[] = { + {WO_AOMUL, "MULTIPLY", 0, "Multiply", "Multiply direct lighting with ambient occlusion, darkening the result."}, {WO_AOADD, "ADD", 0, "Add", "Add light and shadow."}, - {WO_AOSUB, "SUBTRACT", 0, "Subtract", "Subtract light and shadow (needs a normal light to make anything visible.)"}, - {WO_AOADDSUB, "BOTH", 0, "Both", "Both lighten and darken."}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem prop_color_items[] = { @@ -210,14 +209,78 @@ static void rna_def_ambient_occlusion(BlenderRNA *brna) {WO_AOGATHER_APPROX, "APPROXIMATE", 0, "Approximate", "Inaccurate, but faster and without noise."}, {0, NULL, 0, NULL, NULL}}; - srna= RNA_def_struct(brna, "WorldAmbientOcclusion", NULL); + srna= RNA_def_struct(brna, "WorldLighting", NULL); RNA_def_struct_sdna(srna, "World"); RNA_def_struct_nested(brna, srna, "World"); - RNA_def_struct_ui_text(srna, "Ambient Occlusion", "Ambient occlusion settings for a World datablock."); + RNA_def_struct_ui_text(srna, "Lighting", "Lighting for a World datablock."); - prop= RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE); + /* ambient occlusion */ + prop= RNA_def_property(srna, "use_ambient_occlusion", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_AMB_OCC); - RNA_def_property_ui_text(prop, "Enabled", "Use Ambient Occlusion to add light based on distance between elements, creating the illusion of omnipresent light"); + RNA_def_property_ui_text(prop, "Use Ambient Occlusion", "Use Ambient Occlusion to add shadowing based on distance between objects."); + RNA_def_property_update(prop, 0, "rna_World_update"); + + prop= RNA_def_property(srna, "ao_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "aoenergy"); + RNA_def_property_range(prop, 0, INT_MAX); + RNA_def_property_ui_range(prop, 0, 1, 0.1, 2); + RNA_def_property_ui_text(prop, "Factor", "Factor for ambient occlusion blending blending."); + RNA_def_property_update(prop, 0, "rna_World_update"); + + prop= RNA_def_property(srna, "ao_blend_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "aomix"); + RNA_def_property_enum_items(prop, blend_mode_items); + RNA_def_property_ui_text(prop, "Blend Mode", "Defines how AO mixes with material shading."); + RNA_def_property_update(prop, 0, "rna_World_update"); + + /* environment lighting */ + prop= RNA_def_property(srna, "use_environment_lighting", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_ENV_LIGHT); + RNA_def_property_ui_text(prop, "Use Environment Lighting", "Add light coming from the environment."); + RNA_def_property_update(prop, 0, "rna_World_update"); + + prop= RNA_def_property(srna, "environment_energy", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "ao_env_energy"); + RNA_def_property_ui_range(prop, 0, FLT_MAX, 0.1, 2); + RNA_def_property_ui_text(prop, "Environment Color", "Defines the strength of environment light."); + RNA_def_property_update(prop, 0, "rna_World_update"); + + prop= RNA_def_property(srna, "environment_color", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "aocolor"); + RNA_def_property_enum_items(prop, prop_color_items); + RNA_def_property_ui_text(prop, "Environment Color", "Defines where the color of the environment light comes from."); + RNA_def_property_update(prop, 0, "rna_World_update"); + + /* indirect lighting */ + prop= RNA_def_property(srna, "use_indirect_lighting", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_INDIRECT_LIGHT); + RNA_def_property_ui_text(prop, "Use Indirect Lighting", "Add indirect light bouncing of surrounding objects."); + RNA_def_property_update(prop, 0, "rna_World_update"); + + prop= RNA_def_property(srna, "indirect_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "ao_indirect_energy"); + RNA_def_property_range(prop, 0, INT_MAX); + RNA_def_property_ui_range(prop, 0, 1, 0.1, 2); + RNA_def_property_ui_text(prop, "Indirect Factor", "Factor for how much surrounding objects contribute to light."); + RNA_def_property_update(prop, 0, "rna_World_update"); + + prop= RNA_def_property(srna, "indirect_bounces", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "ao_indirect_bounces"); + RNA_def_property_range(prop, 1, INT_MAX); + RNA_def_property_ui_text(prop, "Bounces", "Number of indirect diffuse light bounces to use for approximate ambient occlusion."); + RNA_def_property_update(prop, 0, "rna_World_update"); + + /* gathering parameters */ + prop= RNA_def_property(srna, "gather_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "ao_gather_method"); + RNA_def_property_enum_items(prop, prop_gather_method_items); + RNA_def_property_ui_text(prop, "Gather Method", ""); + RNA_def_property_update(prop, 0, "rna_World_update"); + + prop= RNA_def_property(srna, "passes", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "ao_approx_passes"); + RNA_def_property_range(prop, 0, 10); + RNA_def_property_ui_text(prop, "Passes", "Number of preprocessing passes to reduce overocclusion (for Approximate)."); RNA_def_property_update(prop, 0, "rna_World_update"); prop= RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE); @@ -230,12 +293,6 @@ static void rna_def_ambient_occlusion(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Strength", "Distance attenuation factor, the higher, the 'shorter' the shadows."); RNA_def_property_update(prop, 0, "rna_World_update"); - prop= RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "aoenergy"); - RNA_def_property_ui_range(prop, 0, 10, 0.1, 3); - RNA_def_property_ui_text(prop, "Energy", "Amount of enerygy generated by ambient occlusion."); - RNA_def_property_update(prop, 0, "rna_World_update"); - prop= RNA_def_property(srna, "bias", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "aobias"); RNA_def_property_range(prop, 0, 0.5); @@ -283,46 +340,11 @@ static void rna_def_ambient_occlusion(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Samples", "Amount of ray samples. Higher values give smoother results and longer rendering times"); RNA_def_property_update(prop, 0, "rna_World_update"); - prop= RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "aomix"); - RNA_def_property_enum_items(prop, blend_mode_items); - RNA_def_property_ui_text(prop, "Blend Mode", "Defines how AO mixes with material shading."); - RNA_def_property_update(prop, 0, "rna_World_update"); - - prop= RNA_def_property(srna, "color", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "aocolor"); - RNA_def_property_enum_items(prop, prop_color_items); - RNA_def_property_ui_text(prop, "Color", "Defines the color of the AO light"); - RNA_def_property_update(prop, 0, "rna_World_update"); - prop= RNA_def_property(srna, "sample_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "ao_samp_method"); RNA_def_property_enum_items(prop, prop_sample_method_items); RNA_def_property_ui_text(prop, "Sample Method", "Method for generating shadow samples (for Raytrace)."); RNA_def_property_update(prop, 0, "rna_World_update"); - - prop= RNA_def_property(srna, "gather_method", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "ao_gather_method"); - RNA_def_property_enum_items(prop, prop_gather_method_items); - RNA_def_property_ui_text(prop, "Gather Method", ""); - RNA_def_property_update(prop, 0, "rna_World_update"); - - prop= RNA_def_property(srna, "passes", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "ao_approx_passes"); - RNA_def_property_range(prop, 0, 10); - RNA_def_property_ui_text(prop, "Passes", "Number of preprocessing passes to reduce overocclusion (for Approximate)."); - RNA_def_property_update(prop, 0, "rna_World_update"); - - prop= RNA_def_property(srna, "indirect_energy", PROP_FLOAT, PROP_UNSIGNED); - RNA_def_property_float_sdna(prop, NULL, "ao_indirect_energy"); - RNA_def_property_ui_range(prop, 0, 10, 0.1, 3); - RNA_def_property_ui_text(prop, "Indirect", "Use approximate ambient occlusion for indirect diffuse lighting."); - RNA_def_property_update(prop, 0, "rna_World_update"); - - prop= RNA_def_property(srna, "indirect_bounces", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "ao_indirect_bounces"); - RNA_def_property_ui_text(prop, "Bounces", "Number of indirect diffuse light bounces to use for approximate ambient occlusion."); - RNA_def_property_update(prop, 0, "rna_World_update"); } static void rna_def_world_mist(BlenderRNA *brna) @@ -499,11 +521,11 @@ void RNA_def_world(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_World_update"); /* nested structs */ - prop= RNA_def_property(srna, "ambient_occlusion", PROP_POINTER, PROP_NONE); + prop= RNA_def_property(srna, "lighting", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); - RNA_def_property_struct_type(prop, "WorldAmbientOcclusion"); - RNA_def_property_pointer_funcs(prop, "rna_World_ambient_occlusion_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Ambient Occlusion", "World ambient occlusion settings."); + RNA_def_property_struct_type(prop, "WorldLighting"); + RNA_def_property_pointer_funcs(prop, "rna_World_lighting_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Lighting", "World lighting settings."); prop= RNA_def_property(srna, "mist", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); @@ -517,7 +539,7 @@ void RNA_def_world(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_World_stars_get", NULL, NULL); RNA_def_property_ui_text(prop, "Stars", "World stars settings."); - rna_def_ambient_occlusion(brna); + rna_def_lighting(brna); rna_def_world_mist(brna); rna_def_world_stars(brna); rna_def_world_mtex(brna); diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 28d88e1f8b4..a7c0f9511a5 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -49,10 +49,13 @@ typedef struct ShadeResult float combined[4]; float col[4]; float alpha, mist, z; + float emit[3]; float diff[3]; /* no ramps, shadow, etc */ float spec[3]; float shad[3]; float ao[3]; + float env[3]; + float indirect[3]; float refl[3]; float refr[3]; float nor[3]; @@ -153,7 +156,7 @@ typedef struct ShadeInput float dxstrand, dystrand; /* AO is a pre-process now */ - float ao[3], indirect[3]; + float ao[3], indirect[3], env[3]; int xs, ys; /* pixel to be rendered */ int mask; /* subsample mask */ diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index d41851db5ff..ba995621a98 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -399,6 +399,7 @@ typedef struct StrandSurface { float (*co)[3]; /* for occlusion caching */ float (*ao)[3]; + float (*env)[3]; float (*indirect)[3]; /* for speedvectors */ float (*prevco)[3], (*nextco)[3]; diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index 250fbc000cb..e97ab1de9bb 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -99,7 +99,7 @@ RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi); extern void ray_shadow(ShadeInput *, LampRen *, float *); extern void ray_trace(ShadeInput *, ShadeResult *); -extern void ray_ao(ShadeInput *, float *); +extern void ray_ao(ShadeInput *, float *, float *); extern void init_jitter_plane(LampRen *lar); extern void init_ao_sphere(struct World *wrld); extern void init_render_qmcsampler(Render *re); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 63782223c33..a8afc40f04d 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1701,7 +1701,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem if(re->r.mode & R_SPEED) dosurfacecache= 1; - else if((re->wrld.mode & WO_AMB_OCC) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)) + else if((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && (re->wrld.ao_gather_method == WO_AOGATHER_APPROX)) if(ma->amb != 0.0f) dosurfacecache= 1; @@ -3811,7 +3811,7 @@ void init_render_world(Render *re) while(re->wrld.aosamp*re->wrld.aosamp < re->osa) re->wrld.aosamp++; if(!(re->r.mode & R_RAYTRACE) && (re->wrld.ao_gather_method == WO_AOGATHER_RAYTRACE)) - re->wrld.mode &= ~WO_AMB_OCC; + re->wrld.mode &= ~(WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT); } else { memset(&re->wrld, 0, sizeof(World)); @@ -4849,7 +4849,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) if(re->r.mode & R_RAYTRACE) { init_render_qmcsampler(re); - if(re->wrld.mode & WO_AMB_OCC) + if(re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT) init_ao_sphere(&re->wrld); } @@ -4925,7 +4925,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view) project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0, 1); /* Occlusion */ - if((re->wrld.mode & WO_AMB_OCC) && !re->test_break(re->tbh)) + if((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh)) if(re->wrld.ao_gather_method == WO_AOGATHER_APPROX) if(re->r.renderer==R_INTERN) if(re->r.mode & R_SHADOW) @@ -5537,7 +5537,7 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob) if(re->r.mode & R_RAYTRACE) { init_render_qmcsampler(re); - if(re->wrld.mode & WO_AMB_OCC) + if(re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT) init_ao_sphere(&re->wrld); } @@ -5569,7 +5569,7 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob) makeraytree(re); /* occlusion */ - if((re->wrld.mode & WO_AMB_OCC) && !re->test_break(re->tbh)) + if((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh)) if(re->wrld.ao_gather_method == WO_AOGATHER_APPROX) if(re->r.mode & R_SHADOW) make_occ_tree(re); diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index 40fcc2b399a..d06339f75cc 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -64,7 +64,7 @@ #define CACHE_STEP 3 typedef struct OcclusionCacheSample { - float co[3], n[3], ao[3], indirect[3], intensity, dist2; + float co[3], n[3], ao[3], env[3], indirect[3], intensity, dist2; int x, y, filled; } OcclusionCacheSample; @@ -120,6 +120,7 @@ typedef struct OcclusionThread { Render *re; StrandSurface *mesh; float (*faceao)[3]; + float (*faceenv)[3]; float (*faceindirect)[3]; int begin, end; int thread; @@ -1375,19 +1376,19 @@ static void occ_compute_passes(Render *re, OcclusionTree *tree, int totpass) MEM_freeN(occ); } -static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, float *co, float *n, int thread, int onlyshadow, float *ao, float *indirect) +static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, float *co, float *n, int thread, int onlyshadow, float *ao, float *env, float *indirect) { float nn[3], bn[3], fac, occ, occlusion, correction, rad[3]; - int aocolor; + int envcolor; - aocolor= re->wrld.aocolor; + envcolor= re->wrld.aocolor; if(onlyshadow) - aocolor= WO_AOPLAIN; + envcolor= WO_AOPLAIN; VECCOPY(nn, n); negate_v3(nn); - occ_lookup(tree, thread, exclude, co, nn, &occ, (tree->doindirect)? rad: NULL, (aocolor)? bn: NULL); + occ_lookup(tree, thread, exclude, co, nn, &occ, (tree->doindirect)? rad: NULL, (env && envcolor)? bn: NULL); correction= re->wrld.ao_approx_correction; @@ -1396,13 +1397,20 @@ static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, f if(correction != 0.0f) occlusion += correction*exp(-occ); - if(aocolor) { + if(env) { /* sky shading using bent normal */ - if(ELEM(aocolor, WO_AOSKYCOL, WO_AOSKYTEX)) { + if(ELEM(envcolor, WO_AOSKYCOL, WO_AOSKYTEX)) { fac= 0.5*(1.0f+bn[0]*re->grvec[0]+ bn[1]*re->grvec[1]+ bn[2]*re->grvec[2]); - ao[0]= (1.0f-fac)*re->wrld.horr + fac*re->wrld.zenr; - ao[1]= (1.0f-fac)*re->wrld.horg + fac*re->wrld.zeng; - ao[2]= (1.0f-fac)*re->wrld.horb + fac*re->wrld.zenb; + env[0]= (1.0f-fac)*re->wrld.horr + fac*re->wrld.zenr; + env[1]= (1.0f-fac)*re->wrld.horg + fac*re->wrld.zeng; + env[2]= (1.0f-fac)*re->wrld.horb + fac*re->wrld.zenb; + + mul_v3_fl(env, occlusion); + } + else { + env[0]= occlusion; + env[1]= occlusion; + env[2]= occlusion; } #if 0 else { /* WO_AOSKYTEX */ @@ -1416,10 +1424,9 @@ static void sample_occ_tree(Render *re, OcclusionTree *tree, OccFace *exclude, f shadeSkyView(ao, co, bn, dxyview); } #endif - - mul_v3_fl(ao, occlusion); } - else { + + if(ao) { ao[0]= occlusion; ao[1]= occlusion; ao[2]= occlusion; @@ -1447,7 +1454,7 @@ static OcclusionCacheSample *find_occ_sample(OcclusionCache *cache, int x, int y return &cache->sample[y*cache->w + x]; } -static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int y, int thread, float *ao, float *indirect) +static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int y, int thread, float *ao, float *env, float *indirect) { OcclusionCache *cache; OcclusionCacheSample *samples[4], *sample; @@ -1468,6 +1475,7 @@ static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int dist2= INPR(d, d); if(dist2 < 0.5f*sample->dist2 && INPR(sample->n, n) > 0.98f) { VECCOPY(ao, sample->ao); + VECCOPY(env, sample->env); VECCOPY(indirect, sample->indirect); return 1; } @@ -1495,6 +1503,7 @@ static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int /* compute weighted interpolation between samples */ zero_v3(ao); + zero_v3(env); zero_v3(indirect); totw= 0.0f; @@ -1522,12 +1531,14 @@ static int sample_occ_cache(OcclusionTree *tree, float *co, float *n, int x, int totw += w; madd_v3_v3fl(ao, samples[i]->ao, w); + madd_v3_v3fl(env, samples[i]->env, w); madd_v3_v3fl(indirect, samples[i]->indirect, w); } if(totw >= 0.9f) { totw= 1.0f/totw; mul_v3_fl(ao, totw); + mul_v3_fl(env, totw); mul_v3_fl(indirect, totw); return 1; } @@ -1553,16 +1564,21 @@ static void sample_occ_surface(ShadeInput *shi) interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co); zero_v3(shi->ao); + zero_v3(shi->env); zero_v3(shi->indirect); madd_v3_v3fl(shi->ao, mesh->ao[face[0]], w[0]); + madd_v3_v3fl(shi->env, mesh->env[face[0]], w[0]); madd_v3_v3fl(shi->indirect, mesh->indirect[face[0]], w[0]); madd_v3_v3fl(shi->ao, mesh->ao[face[1]], w[1]); + madd_v3_v3fl(shi->env, mesh->env[face[1]], w[1]); madd_v3_v3fl(shi->indirect, mesh->indirect[face[1]], w[1]); madd_v3_v3fl(shi->ao, mesh->ao[face[2]], w[2]); + madd_v3_v3fl(shi->env, mesh->env[face[2]], w[2]); madd_v3_v3fl(shi->indirect, mesh->indirect[face[2]], w[2]); if(face[3]) { madd_v3_v3fl(shi->ao, mesh->ao[face[3]], w[3]); + madd_v3_v3fl(shi->env, mesh->env[face[3]], w[3]); madd_v3_v3fl(shi->indirect, mesh->indirect[face[3]], w[3]); } } @@ -1570,6 +1586,7 @@ static void sample_occ_surface(ShadeInput *shi) shi->ao[0]= 1.0f; shi->ao[1]= 1.0f; shi->ao[2]= 1.0f; + zero_v3(shi->env); zero_v3(shi->indirect); } } @@ -1581,7 +1598,7 @@ static void *exec_strandsurface_sample(void *data) OcclusionThread *othread= (OcclusionThread*)data; Render *re= othread->re; StrandSurface *mesh= othread->mesh; - float ao[3], indirect[3], co[3], n[3], *co1, *co2, *co3, *co4; + float ao[3], env[3], indirect[3], co[3], n[3], *co1, *co2, *co3, *co4; int a, *face; for(a=othread->begin; aend; a++) { @@ -1602,8 +1619,9 @@ static void *exec_strandsurface_sample(void *data) } negate_v3(n); - sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, ao, indirect); + sample_occ_tree(re, re->occlusiontree, NULL, co, n, othread->thread, 0, ao, env, indirect); VECCOPY(othread->faceao[a], ao); + VECCOPY(othread->faceenv[a], env); VECCOPY(othread->faceindirect[a], indirect); } @@ -1616,7 +1634,7 @@ void make_occ_tree(Render *re) OcclusionTree *tree; StrandSurface *mesh; ListBase threads; - float ao[3], indirect[3], (*faceao)[3], (*faceindirect)[3]; + float ao[3], env[3], indirect[3], (*faceao)[3], (*faceenv)[3], (*faceindirect)[3]; int a, totface, totthread, *face, *count; /* ugly, needed for occ_face */ @@ -1630,7 +1648,7 @@ void make_occ_tree(Render *re) if(tree) { if(re->wrld.ao_approx_passes > 0) occ_compute_passes(re, tree, re->wrld.ao_approx_passes); - if(tree->doindirect && re->wrld.ao_indirect_bounces > 1) + if(tree->doindirect && (re->wrld.mode & WO_INDIRECT_LIGHT)) occ_compute_bounces(re, tree, re->wrld.ao_indirect_bounces); for(mesh=re->strandsurface.first; mesh; mesh=mesh->next) { @@ -1639,6 +1657,7 @@ void make_occ_tree(Render *re) count= MEM_callocN(sizeof(int)*mesh->totvert, "OcclusionCount"); faceao= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceAO"); + faceenv= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceEnv"); faceindirect= MEM_callocN(sizeof(float)*3*mesh->totface, "StrandSurfFaceIndirect"); totthread= (mesh->totface > 10000)? re->r.threads: 1; @@ -1646,6 +1665,7 @@ void make_occ_tree(Render *re) for(a=0; aface[a]; VECCOPY(ao, faceao[a]); + VECCOPY(env, faceenv[a]); VECCOPY(indirect, faceindirect[a]); VECADD(mesh->ao[face[0]], mesh->ao[face[0]], ao); + VECADD(mesh->env[face[0]], mesh->env[face[0]], env); VECADD(mesh->indirect[face[0]], mesh->indirect[face[0]], indirect); count[face[0]]++; VECADD(mesh->ao[face[1]], mesh->ao[face[1]], ao); + VECADD(mesh->env[face[1]], mesh->env[face[1]], env); VECADD(mesh->indirect[face[1]], mesh->indirect[face[1]], indirect); count[face[1]]++; VECADD(mesh->ao[face[2]], mesh->ao[face[2]], ao); + VECADD(mesh->env[face[2]], mesh->env[face[2]], env); VECADD(mesh->indirect[face[2]], mesh->indirect[face[2]], indirect); count[face[2]]++; if(face[3]) { VECADD(mesh->ao[face[3]], mesh->ao[face[3]], ao); + VECADD(mesh->env[face[3]], mesh->env[face[3]], env); VECADD(mesh->indirect[face[3]], mesh->indirect[face[3]], indirect); count[face[3]]++; } @@ -1691,12 +1716,14 @@ void make_occ_tree(Render *re) for(a=0; atotvert; a++) { if(count[a]) { mul_v3_fl(mesh->ao[a], 1.0f/count[a]); + mul_v3_fl(mesh->env[a], 1.0f/count[a]); mul_v3_fl(mesh->indirect[a], 1.0f/count[a]); } } MEM_freeN(count); MEM_freeN(faceao); + MEM_freeN(faceenv); MEM_freeN(faceindirect); } } @@ -1723,12 +1750,12 @@ void sample_occ(Render *re, ShadeInput *shi) sample_occ_surface(shi); } /* try to get result from the cache if possible */ - else if(shi->depth!=0 || !sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao, shi->indirect)) { + else if(shi->depth!=0 || !sample_occ_cache(tree, shi->co, shi->vno, shi->xs, shi->ys, shi->thread, shi->ao, shi->env, shi->indirect)) { /* no luck, let's sample the occlusion */ exclude.obi= shi->obi - re->objectinstance; exclude.facenr= shi->vlr->index; onlyshadow= (shi->mat->mode & MA_ONLYSHADOW); - sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->indirect); + sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect); /* fill result into sample, each time */ if(tree->cache) { @@ -1739,8 +1766,10 @@ void sample_occ(Render *re, ShadeInput *shi) VECCOPY(sample->co, shi->co); VECCOPY(sample->n, shi->vno); VECCOPY(sample->ao, shi->ao); + VECCOPY(sample->env, shi->env); VECCOPY(sample->indirect, shi->indirect); sample->intensity= MAX3(sample->ao[0], sample->ao[1], sample->ao[2]); + sample->intensity= MAX2(sample->intensity, MAX3(sample->env[0], sample->env[1], sample->env[2])); sample->intensity= MAX2(sample->intensity, MAX3(sample->indirect[0], sample->indirect[1], sample->indirect[2])); sample->dist2= INPR(shi->dxco, shi->dxco) + INPR(shi->dyco, shi->dyco); sample->filled= 1; @@ -1753,6 +1782,10 @@ void sample_occ(Render *re, ShadeInput *shi) shi->ao[1]= 1.0f; shi->ao[2]= 1.0f; + shi->env[0]= 0.0f; + shi->env[1]= 0.0f; + shi->env[2]= 0.0f; + shi->indirect[0]= 0.0f; shi->indirect[1]= 0.0f; shi->indirect[2]= 0.0f; @@ -1823,13 +1856,15 @@ void cache_occ_samples(Render *re, RenderPart *pa, ShadeSample *ssamp) onlyshadow= (shi->mat->mode & MA_ONLYSHADOW); exclude.obi= shi->obi - re->objectinstance; exclude.facenr= shi->vlr->index; - sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->indirect); + sample_occ_tree(re, tree, &exclude, shi->co, shi->vno, shi->thread, onlyshadow, shi->ao, shi->env, shi->indirect); VECCOPY(sample->co, shi->co); VECCOPY(sample->n, shi->vno); VECCOPY(sample->ao, shi->ao); + VECCOPY(sample->env, shi->env); VECCOPY(sample->indirect, shi->indirect); sample->intensity= MAX3(sample->ao[0], sample->ao[1], sample->ao[2]); + sample->intensity= MAX2(sample->intensity, MAX3(sample->env[0], sample->env[1], sample->env[2])); sample->intensity= MAX2(sample->intensity, MAX3(sample->indirect[0], sample->indirect[1], sample->indirect[2])); sample->dist2= INPR(shi->dxco, shi->dxco) + INPR(shi->dyco, shi->dyco); sample->x= shi->xs; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index ff7d0d90a06..eaafeec3a8a 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -309,6 +309,12 @@ static char *get_pass_name(int passtype, int channel) if(channel==2) return "Color.B"; return "Color.A"; } + if(passtype == SCE_PASS_EMIT) { + if(channel==-1) return "Emit"; + if(channel==0) return "Emit.R"; + if(channel==1) return "Emit.G"; + return "Emit.B"; + } if(passtype == SCE_PASS_DIFFUSE) { if(channel==-1) return "Diffuse"; if(channel==0) return "Diffuse.R"; @@ -333,6 +339,18 @@ static char *get_pass_name(int passtype, int channel) if(channel==1) return "AO.G"; return "AO.B"; } + if(passtype == SCE_PASS_ENVIRONMENT) { + if(channel==-1) return "Environment"; + if(channel==0) return "Environment.R"; + if(channel==1) return "Environment.G"; + return "Environment.B"; + } + if(passtype == SCE_PASS_INDIRECT) { + if(channel==-1) return "Indirect"; + if(channel==0) return "Indirect.R"; + if(channel==1) return "Indirect.G"; + return "Indirect.B"; + } if(passtype == SCE_PASS_REFLECT) { if(channel==-1) return "Reflect"; if(channel==0) return "Reflect.R"; @@ -390,6 +408,9 @@ static int passtype_from_name(char *str) if(strcmp(str, "Color")==0) return SCE_PASS_RGBA; + if(strcmp(str, "Emit")==0) + return SCE_PASS_EMIT; + if(strcmp(str, "Diffuse")==0) return SCE_PASS_DIFFUSE; @@ -402,6 +423,12 @@ static int passtype_from_name(char *str) if(strcmp(str, "AO")==0) return SCE_PASS_AO; + if(strcmp(str, "Environment")==0) + return SCE_PASS_ENVIRONMENT; + + if(strcmp(str, "Indirect")==0) + return SCE_PASS_INDIRECT; + if(strcmp(str, "Reflect")==0) return SCE_PASS_REFLECT; @@ -572,12 +599,18 @@ static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int render_layer_add_pass(rr, rl, 3, SCE_PASS_UV); if(srl->passflag & SCE_PASS_RGBA) render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA); + if(srl->passflag & SCE_PASS_EMIT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT); if(srl->passflag & SCE_PASS_DIFFUSE) render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE); if(srl->passflag & SCE_PASS_SPEC) render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC); if(srl->passflag & SCE_PASS_AO) render_layer_add_pass(rr, rl, 3, SCE_PASS_AO); + if(srl->passflag & SCE_PASS_ENVIRONMENT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT); + if(srl->passflag & SCE_PASS_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT); if(srl->passflag & SCE_PASS_SHADOW) render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW); if(srl->passflag & SCE_PASS_REFLECT) diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 5bdc1276a91..d35521e92ac 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -1829,7 +1829,7 @@ static float *sphere_sampler(int type, int resol, int thread, int xs, int ys) } } -static void ray_ao_qmc(ShadeInput *shi, float *shadfac) +static void ray_ao_qmc(ShadeInput *shi, float *ao, float *env) { Isect isec; RayHint point_hint; @@ -1845,8 +1845,8 @@ static void ray_ao_qmc(ShadeInput *shi, float *shadfac) int samples=0; int max_samples = R.wrld.aosamp*R.wrld.aosamp; - float dxyview[3], skyadded=0, div; - int aocolor; + float dxyview[3], skyadded=0; + int envcolor; RE_RC_INIT(isec, *shi); isec.orig.ob = shi->obi; @@ -1866,15 +1866,15 @@ static void ray_ao_qmc(ShadeInput *shi, float *shadfac) RE_rayobject_hint_bb( R.raytree, &point_hint, isec.start, isec.start ); isec.hint = &point_hint; - - shadfac[0]= shadfac[1]= shadfac[2]= 0.0f; + zero_v3(ao); + zero_v3(env); /* prevent sky colors to be added for only shadow (shadow becomes alpha) */ - aocolor= R.wrld.aocolor; + envcolor= R.wrld.aocolor; if(shi->mat->mode & MA_ONLYSHADOW) - aocolor= WO_AOPLAIN; + envcolor= WO_AOPLAIN; - if(aocolor == WO_AOSKYTEX) { + if(envcolor == WO_AOSKYTEX) { dxyview[0]= 1.0f/(float)R.wrld.aosamp; dxyview[1]= 1.0f/(float)R.wrld.aosamp; dxyview[2]= 0.0f; @@ -1927,7 +1927,7 @@ static void ray_ao_qmc(ShadeInput *shi, float *shadfac) if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac); else fac+= 1.0f; } - else if(aocolor!=WO_AOPLAIN) { + else if(envcolor!=WO_AOPLAIN) { float skycol[4]; float skyfac, view[3]; @@ -1936,18 +1936,18 @@ static void ray_ao_qmc(ShadeInput *shi, float *shadfac) view[2]= -dir[2]; normalize_v3(view); - if(aocolor==WO_AOSKYCOL) { + if(envcolor==WO_AOSKYCOL) { skyfac= 0.5*(1.0f+view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]); - shadfac[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr; - shadfac[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng; - shadfac[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb; + env[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr; + env[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng; + env[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb; } else { /* WO_AOSKYTEX */ shadeSkyView(skycol, isec.start, view, dxyview, shi->thread); shadeSunView(skycol, shi->view); - shadfac[0]+= skycol[0]; - shadfac[1]+= skycol[1]; - shadfac[2]+= skycol[2]; + env[0]+= skycol[0]; + env[1]+= skycol[1]; + env[2]+= skycol[2]; } skyadded++; } @@ -1965,29 +1965,27 @@ static void ray_ao_qmc(ShadeInput *shi, float *shadfac) } } - if(aocolor!=WO_AOPLAIN && skyadded) { - div= (1.0f - fac/(float)samples)/((float)skyadded); - - shadfac[0]*= div; // average color times distances/hits formula - shadfac[1]*= div; // average color times distances/hits formula - shadfac[2]*= div; // average color times distances/hits formula - } else { - shadfac[0]= shadfac[1]= shadfac[2]= 1.0f - fac/(float)samples; - } + /* average color times distances/hits formula */ + ao[0]= ao[1]= ao[2]= 1.0f - fac/(float)samples; + + if(envcolor!=WO_AOPLAIN && skyadded) + mul_v3_fl(env, (1.0f - fac/(float)samples)/((float)skyadded)); + else + copy_v3_v3(env, ao); if (qsa) release_thread_qmcsampler(&R, shi->thread, qsa); } /* extern call from shade_lamp_loop, ambient occlusion calculus */ -static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac) +static void ray_ao_spheresamp(ShadeInput *shi, float *ao, float *env) { Isect isec; RayHint point_hint; - float *vec, *nrm, div, bias, sh=0.0f; + float *vec, *nrm, bias, sh=0.0f; float maxdist = R.wrld.aodist; float dxyview[3]; - int j= -1, tot, actual=0, skyadded=0, aocolor, resol= R.wrld.aosamp; + int j= -1, tot, actual=0, skyadded=0, envcolor, resol= R.wrld.aosamp; RE_RC_INIT(isec, *shi); isec.orig.ob = shi->obi; @@ -2007,7 +2005,8 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac) RE_rayobject_hint_bb( R.raytree, &point_hint, isec.start, isec.start ); isec.hint = &point_hint; - shadfac[0]= shadfac[1]= shadfac[2]= 0.0f; + zero_v3(ao); + zero_v3(env); /* bias prevents smoothed faces to appear flat */ if(shi->vlr->flag & R_SMOOTH) { @@ -2020,9 +2019,9 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac) } /* prevent sky colors to be added for only shadow (shadow becomes alpha) */ - aocolor= R.wrld.aocolor; + envcolor= R.wrld.aocolor; if(shi->mat->mode & MA_ONLYSHADOW) - aocolor= WO_AOPLAIN; + envcolor= WO_AOPLAIN; if(resol>32) resol= 32; @@ -2031,7 +2030,7 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac) // warning: since we use full sphere now, and dotproduct is below, we do twice as much tot= 2*resol*resol; - if(aocolor == WO_AOSKYTEX) { + if(envcolor == WO_AOSKYTEX) { dxyview[0]= 1.0f/(float)resol; dxyview[1]= 1.0f/(float)resol; dxyview[2]= 0.0f; @@ -2063,7 +2062,7 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac) if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac); else sh+= 1.0f; } - else if(aocolor!=WO_AOPLAIN) { + else if(envcolor!=WO_AOPLAIN) { float skycol[4]; float fac, view[3]; @@ -2072,18 +2071,18 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac) view[2]= -vec[2]; normalize_v3(view); - if(aocolor==WO_AOSKYCOL) { + if(envcolor==WO_AOSKYCOL) { fac= 0.5*(1.0f+view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]); - shadfac[0]+= (1.0f-fac)*R.wrld.horr + fac*R.wrld.zenr; - shadfac[1]+= (1.0f-fac)*R.wrld.horg + fac*R.wrld.zeng; - shadfac[2]+= (1.0f-fac)*R.wrld.horb + fac*R.wrld.zenb; + env[0]+= (1.0f-fac)*R.wrld.horr + fac*R.wrld.zenr; + env[1]+= (1.0f-fac)*R.wrld.horg + fac*R.wrld.zeng; + env[2]+= (1.0f-fac)*R.wrld.horb + fac*R.wrld.zenb; } else { /* WO_AOSKYTEX */ shadeSkyView(skycol, isec.start, view, dxyview, shi->thread); shadeSunView(skycol, shi->view); - shadfac[0]+= skycol[0]; - shadfac[1]+= skycol[1]; - shadfac[2]+= skycol[2]; + env[0]+= skycol[0]; + env[1]+= skycol[1]; + env[2]+= skycol[2]; } skyadded++; } @@ -2095,28 +2094,25 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *shadfac) if(actual==0) sh= 1.0f; else sh = 1.0f - sh/((float)actual); - if(aocolor!=WO_AOPLAIN && skyadded) { - div= sh/((float)skyadded); - - shadfac[0]*= div; // average color times distances/hits formula - shadfac[1]*= div; // average color times distances/hits formula - shadfac[2]*= div; // average color times distances/hits formula - } - else { - shadfac[0]= shadfac[1]= shadfac[2]= sh; - } + /* average color times distances/hits formula */ + ao[0]= ao[1]= ao[2]= sh; + + if(envcolor!=WO_AOPLAIN && skyadded) + mul_v3_fl(env, sh/((float)skyadded)); + else + copy_v3_v3(env, ao); } -void ray_ao(ShadeInput *shi, float *shadfac) +void ray_ao(ShadeInput *shi, float *ao, float *env) { /* Unfortunately, the unusual way that the sphere sampler calculates roughly twice as many * samples as are actually traced, and skips them based on bias and OSA settings makes it very difficult * to reuse code between these two functions. This is the easiest way I can think of to do it * --broken */ if (ELEM(R.wrld.ao_samp_method, WO_AOSAMP_HAMMERSLEY, WO_AOSAMP_HALTON)) - ray_ao_qmc(shi, shadfac); + ray_ao_qmc(shi, ao, env); else if (R.wrld.ao_samp_method == WO_AOSAMP_CONSTANT) - ray_ao_spheresamp(shi, shadfac); + ray_ao_spheresamp(shi, ao, env); } static void ray_shadow_jittered_coords(ShadeInput *shi, int max, float jitco[RE_MAX_OSA][3], int *totjitco) diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index e99d2bfa0f6..dec826faa65 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -459,6 +459,9 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, col= shr->col; pixsize= 4; break; + case SCE_PASS_EMIT: + col= shr->emit; + break; case SCE_PASS_DIFFUSE: col= shr->diff; break; @@ -471,6 +474,12 @@ static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, case SCE_PASS_AO: col= shr->ao; break; + case SCE_PASS_ENVIRONMENT: + col= shr->env; + break; + case SCE_PASS_INDIRECT: + col= shr->indirect; + break; case SCE_PASS_REFLECT: col= shr->refl; break; @@ -557,6 +566,9 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult col= shr->col; pixsize= 4; break; + case SCE_PASS_EMIT: + col= shr->emit; + break; case SCE_PASS_DIFFUSE: col= shr->diff; break; @@ -569,6 +581,12 @@ static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult case SCE_PASS_AO: col= shr->ao; break; + case SCE_PASS_ENVIRONMENT: + col= shr->env; + break; + case SCE_PASS_INDIRECT: + col= shr->indirect; + break; case SCE_PASS_REFLECT: col= shr->refl; break; @@ -2117,10 +2135,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int quad, int if(bs->type==RE_BAKE_AO) { ambient_occlusion(shi); - if(R.r.bake_flag & R_BAKE_NORMALIZE) - VECCOPY(shr.combined, shi->ao) - else - ambient_occlusion_to_diffuse(shi, shr.combined); + VECCOPY(shr.combined, shi->ao) } else { if (bs->type==RE_BAKE_SHADOW) /* Why do shadows set the color anyhow?, ignore material color for baking */ diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index fd1e27ab28a..38241878300 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -1319,11 +1319,11 @@ void shade_samples_do_AO(ShadeSample *ssamp) if(!(R.r.mode & R_RAYTRACE) && !(R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) return; - if(R.wrld.mode & WO_AMB_OCC) { + if(R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) { shi= &ssamp->shi[0]; - if(((shi->passflag & SCE_PASS_COMBINED) && (shi->combinedflag & SCE_PASS_AO)) - || (shi->passflag & SCE_PASS_AO)) + if(((shi->passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) + || (shi->passflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) for(sample=0, shi= ssamp->shi; sampletot; shi++, sample++) if(!(shi->mode & MA_SHLESS)) ambient_occlusion(shi); /* stores in shi->ao[] */ diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index e9386bb0d94..4192966b1fa 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -1013,41 +1013,69 @@ void ambient_occlusion(ShadeInput *shi) if((R.wrld.ao_gather_method == WO_AOGATHER_APPROX) && shi->mat->amb!=0.0f) sample_occ(&R, shi); else if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) - ray_ao(shi, shi->ao); + ray_ao(shi, shi->ao, shi->env); else shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f; } /* wrld mode was checked for */ -void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff) +static void ambient_occlusion_apply(ShadeInput *shi, ShadeResult *shr) { - if((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX) { - if(shi->amb!=0.0f) { - float f= R.wrld.aoenergy*shi->amb; + float f= R.wrld.aoenergy; + float tmp[3], tmpspec[3]; - if (R.wrld.aomix==WO_AOADDSUB) { - diff[0] = 2.0f*shi->ao[0]-1.0f; - diff[1] = 2.0f*shi->ao[1]-1.0f; - diff[2] = 2.0f*shi->ao[2]-1.0f; - } - else if (R.wrld.aomix==WO_AOSUB) { - diff[0] = shi->ao[0]-1.0f; - diff[1] = shi->ao[1]-1.0f; - diff[2] = shi->ao[2]-1.0f; - } - else { - VECCOPY(diff, shi->ao); - } - - VECMUL(diff, f); - madd_v3_v3fl(diff, shi->indirect, R.wrld.ao_indirect_energy*shi->amb); - } - else - diff[0]= diff[1]= diff[2]= 0.0f; + if(!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) + return; + if(f == 0.0f) + return; + + if(R.wrld.aomix==WO_AOADD) { + shr->combined[0] += shi->ao[0]*shi->r*shi->refl*f; + shr->combined[1] += shi->ao[1]*shi->g*shi->refl*f; + shr->combined[2] += shi->ao[2]*shi->b*shi->refl*f; } - else - diff[0]= diff[1]= diff[2]= 0.0f; + else if(R.wrld.aomix==WO_AOMUL) { + mul_v3_v3v3(tmp, shr->combined, shi->ao); + mul_v3_v3v3(tmpspec, shr->spec, shi->ao); + + if(f == 1.0f) { + copy_v3_v3(shr->combined, tmp); + copy_v3_v3(shr->spec, tmpspec); + } + else { + interp_v3_v3v3(shr->combined, shr->combined, tmp, f); + interp_v3_v3v3(shr->spec, shr->spec, tmpspec, f); + } + } +} + +static void environment_lighting_apply(ShadeInput *shi, ShadeResult *shr) +{ + float f= R.wrld.ao_env_energy*shi->amb; + + if(!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) + return; + if(f == 0.0f) + return; + + shr->combined[0] += shi->env[0]*shi->r*shi->refl*f; + shr->combined[1] += shi->env[1]*shi->g*shi->refl*f; + shr->combined[2] += shi->env[2]*shi->b*shi->refl*f; +} + +static void indirect_lighting_apply(ShadeInput *shi, ShadeResult *shr) +{ + float f= R.wrld.ao_indirect_energy; + + if(!((R.r.mode & R_RAYTRACE) || R.wrld.ao_gather_method == WO_AOGATHER_APPROX)) + return; + if(f == 0.0f) + return; + + shr->combined[0] += shi->indirect[0]*shi->r*shi->refl*f; + shr->combined[1] += shi->indirect[1]*shi->g*shi->refl*f; + shr->combined[2] += shi->indirect[2]*shi->b*shi->refl*f; } /* result written in shadfac */ @@ -1510,7 +1538,7 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr) } /* quite disputable this... also note it doesn't mirror-raytrace */ - if((R.wrld.mode & WO_AMB_OCC) && shi->amb!=0.0f) { + if((R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && shi->amb!=0.0f) { float f; f= 1.0f - shi->ao[0]; @@ -1520,12 +1548,8 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr) shr->alpha += f; shr->alpha *= f; } - else if(R.wrld.aomix==WO_AOSUB) { - shr->alpha += f; - } - else { + else if(R.wrld.aomix==WO_AOMUL) { shr->alpha *= f; - shr->alpha += f; } } } @@ -1600,25 +1624,26 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) } if( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { // vertexcolor light - shr->diff[0]= shi->r*(shi->emit+shi->vcol[0]); - shr->diff[1]= shi->g*(shi->emit+shi->vcol[1]); - shr->diff[2]= shi->b*(shi->emit+shi->vcol[2]); + shr->emit[0]= shi->r*(shi->emit+shi->vcol[0]); + shr->emit[1]= shi->g*(shi->emit+shi->vcol[1]); + shr->emit[2]= shi->b*(shi->emit+shi->vcol[2]); } else { - shr->diff[0]= shi->r*shi->emit; - shr->diff[1]= shi->g*shi->emit; - shr->diff[2]= shi->b*shi->emit; + shr->emit[0]= shi->r*shi->emit; + shr->emit[1]= shi->g*shi->emit; + shr->emit[2]= shi->b*shi->emit; } - VECCOPY(shr->shad, shr->diff); /* AO pass */ - if(R.wrld.mode & WO_AMB_OCC) { - if(((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & SCE_PASS_AO)) - || (passflag & SCE_PASS_AO)) { + if(R.wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) { + if(((passflag & SCE_PASS_COMBINED) && (shi->combinedflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) + || (passflag & (SCE_PASS_AO|SCE_PASS_ENVIRONMENT|SCE_PASS_INDIRECT))) { /* AO was calculated for scanline already */ if(shi->depth) ambient_occlusion(shi); VECCOPY(shr->ao, shi->ao); + VECCOPY(shr->env, shi->env); // XXX multiply + VECCOPY(shr->indirect, shi->indirect); // XXX multiply } } @@ -1727,6 +1752,19 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) /* from now stuff everything in shr->combined: ambient, AO, radio, ramps, exposure */ if(!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) { + /* add AO in combined? */ + if(R.wrld.mode & WO_AMB_OCC) + if(shi->combinedflag & SCE_PASS_AO) + ambient_occlusion_apply(shi, shr); + + if(R.wrld.mode & WO_ENV_LIGHT) + if(shi->combinedflag & SCE_PASS_ENVIRONMENT) + environment_lighting_apply(shi, shr); + + if(R.wrld.mode & WO_INDIRECT_LIGHT) + if(shi->combinedflag & SCE_PASS_INDIRECT) + indirect_lighting_apply(shi, shr); + shr->combined[0]+= shi->ambr; shr->combined[1]+= shi->ambg; shr->combined[2]+= shi->ambb; @@ -1738,22 +1776,6 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) shr->combined[2]+= shi->b*shi->amb*shi->rad[2]; }*/ - /* add AO in combined? */ - if(R.wrld.mode & WO_AMB_OCC) { - if(shi->combinedflag & SCE_PASS_AO) { - float aodiff[3]; - ambient_occlusion_to_diffuse(shi, aodiff); - - shr->combined[0] += shi->r*aodiff[0]; - shr->combined[1] += shi->g*aodiff[1]; - shr->combined[2] += shi->b*aodiff[2]; - - if (shr->combined[0] < 0.f) shr->combined[0]= 0.f; - if (shr->combined[1] < 0.f) shr->combined[1]= 0.f; - if (shr->combined[2] < 0.f) shr->combined[2]= 0.f; - } - } - if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi); } @@ -1775,10 +1797,12 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr) } - /* and add spec */ + /* and add emit and spec */ + if(shi->combinedflag & SCE_PASS_EMIT) + VECADD(shr->combined, shr->combined, shr->emit); if(shi->combinedflag & SCE_PASS_SPEC) VECADD(shr->combined, shr->combined, shr->spec); - + /* modulate by the object color */ if((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) { if(!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) { diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c index 2b1c121539e..279d53d050c 100644 --- a/source/blender/render/intern/source/strand.c +++ b/source/blender/render/intern/source/strand.c @@ -222,6 +222,8 @@ void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, Sha interpolate_vec3(shr1->nor, shr2->nor, t, negt, shr->nor); normalize_v3(shr->nor); } + if(addpassflag & SCE_PASS_EMIT) + interpolate_vec3(shr1->emit, shr2->emit, t, negt, shr->emit); if(addpassflag & SCE_PASS_DIFFUSE) interpolate_vec3(shr1->diff, shr2->diff, t, negt, shr->diff); if(addpassflag & SCE_PASS_SPEC) @@ -230,6 +232,10 @@ void interpolate_shade_result(ShadeResult *shr1, ShadeResult *shr2, float t, Sha interpolate_vec3(shr1->shad, shr2->shad, t, negt, shr->shad); if(addpassflag & SCE_PASS_AO) interpolate_vec3(shr1->ao, shr2->ao, t, negt, shr->ao); + if(addpassflag & SCE_PASS_ENVIRONMENT) + interpolate_vec3(shr1->env, shr2->env, t, negt, shr->env); + if(addpassflag & SCE_PASS_INDIRECT) + interpolate_vec3(shr1->indirect, shr2->indirect, t, negt, shr->indirect); if(addpassflag & SCE_PASS_REFLECT) interpolate_vec3(shr1->refl, shr2->refl, t, negt, shr->refl); if(addpassflag & SCE_PASS_REFRACT) @@ -963,6 +969,7 @@ StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm, mesh->totface= totface; mesh->face= MEM_callocN(sizeof(int)*4*mesh->totface, "StrandSurfFaces"); mesh->ao= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfAO"); + mesh->env= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfEnv"); mesh->indirect= MEM_callocN(sizeof(float)*3*mesh->totvert, "StrandSurfIndirect"); BLI_addtail(&re->strandsurface, mesh); } @@ -1002,6 +1009,7 @@ void free_strand_surface(Render *re) if(mesh->prevco) MEM_freeN(mesh->prevco); if(mesh->nextco) MEM_freeN(mesh->nextco); if(mesh->ao) MEM_freeN(mesh->ao); + if(mesh->env) MEM_freeN(mesh->env); if(mesh->indirect) MEM_freeN(mesh->indirect); if(mesh->face) MEM_freeN(mesh->face); } diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index ac3474e51e5..484dbdd37a3 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -3516,6 +3516,9 @@ void merge_transp_passes(RenderLayer *rl, ShadeResult *shr) col= shr->col; pixsize= 4; break; + case SCE_PASS_EMIT: + col= shr->emit; + break; case SCE_PASS_DIFFUSE: col= shr->diff; break; @@ -3528,6 +3531,12 @@ void merge_transp_passes(RenderLayer *rl, ShadeResult *shr) case SCE_PASS_AO: col= shr->ao; break; + case SCE_PASS_ENVIRONMENT: + col= shr->env; + break; + case SCE_PASS_INDIRECT: + col= shr->indirect; + break; case SCE_PASS_REFLECT: col= shr->refl; break; @@ -3615,6 +3624,9 @@ void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alph fp= rpass->rect + 4*offset; addAlphaOverFloat(fp, shr->col); break; + case SCE_PASS_EMIT: + col= shr->emit; + break; case SCE_PASS_DIFFUSE: col= shr->diff; break; @@ -3627,6 +3639,12 @@ void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alph case SCE_PASS_AO: col= shr->ao; break; + case SCE_PASS_ENVIRONMENT: + col= shr->env; + break; + case SCE_PASS_INDIRECT: + col= shr->indirect; + break; case SCE_PASS_REFLECT: col= shr->refl; break; @@ -3851,6 +3869,9 @@ static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassf if(addpassflag & SCE_PASS_NORMAL) addvecmul(samp_shr->nor, shr->nor, fac); + if(addpassflag & SCE_PASS_EMIT) + addvecmul(samp_shr->emit, shr->emit, fac); + if(addpassflag & SCE_PASS_DIFFUSE) addvecmul(samp_shr->diff, shr->diff, fac); @@ -3863,6 +3884,12 @@ static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassf if(addpassflag & SCE_PASS_AO) addvecmul(samp_shr->ao, shr->ao, fac); + if(addpassflag & SCE_PASS_ENVIRONMENT) + addvecmul(samp_shr->env, shr->env, fac); + + if(addpassflag & SCE_PASS_INDIRECT) + addvecmul(samp_shr->indirect, shr->indirect, fac); + if(addpassflag & SCE_PASS_REFLECT) addvecmul(samp_shr->refl, shr->refl, fac);