Cycles: add additive AO support through Fast GI settings
Add a Fast GI Method, either Replace for the existing behavior, or Add to add ambient occlusion like the old world settings. This replaces the old Ambient Occlusion settings in the world properties.
This commit is contained in:
parent
eb1fed9d60
commit
75704091fc
|
@ -125,6 +125,11 @@ enum_texture_limit = (
|
|||
('8192', "8192", "Limit texture size to 8192 pixels", 7),
|
||||
)
|
||||
|
||||
enum_fast_gi_method = (
|
||||
('REPLACE', "Replace", "Replace global illumination with ambient occlusion after a specified number of bounces"),
|
||||
('ADD', "Add", "Add ambient occlusion to diffuse surfaces"),
|
||||
)
|
||||
|
||||
# NOTE: Identifiers are expected to be an upper case version of identifiers from `Pass::get_type_enum()`
|
||||
enum_view3d_shading_render_pass = (
|
||||
('', "General", ""),
|
||||
|
@ -724,6 +729,14 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||
description="Approximate diffuse indirect light with background tinted ambient occlusion. This provides fast alternative to full global illumination, for interactive viewport rendering or final renders with reduced quality",
|
||||
default=False,
|
||||
)
|
||||
|
||||
fast_gi_method: EnumProperty(
|
||||
name="Fast GI Method",
|
||||
default='REPLACE',
|
||||
description="Fast GI approximation method",
|
||||
items=enum_fast_gi_method
|
||||
)
|
||||
|
||||
ao_bounces: IntProperty(
|
||||
name="AO Bounces",
|
||||
default=1,
|
||||
|
|
|
@ -465,8 +465,7 @@ class CYCLES_RENDER_PT_light_paths_fast_gi(CyclesButtonsPanel, Panel):
|
|||
layout.active = cscene.use_fast_gi
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "ao_bounces", text="Viewport Bounces")
|
||||
col.prop(cscene, "ao_bounces_render", text="Render Bounces")
|
||||
col.prop(cscene, "fast_gi_method", text="Method")
|
||||
|
||||
if world:
|
||||
light = world.light_settings
|
||||
|
@ -474,6 +473,11 @@ class CYCLES_RENDER_PT_light_paths_fast_gi(CyclesButtonsPanel, Panel):
|
|||
col.prop(light, "ao_factor", text="AO Factor")
|
||||
col.prop(light, "distance", text="AO Distance")
|
||||
|
||||
if cscene.fast_gi_method == 'REPLACE':
|
||||
col = layout.column(align=True)
|
||||
col.prop(cscene, "ao_bounces", text="Viewport Bounces")
|
||||
col.prop(cscene, "ao_bounces_render", text="Render Bounces")
|
||||
|
||||
|
||||
class CYCLES_RENDER_PT_motion_blur(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Motion Blur"
|
||||
|
|
|
@ -1375,6 +1375,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
|||
{
|
||||
Background *background = scene->background;
|
||||
Integrator *integrator = scene->integrator;
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
|
||||
BL::World b_world = b_scene.world();
|
||||
|
||||
|
@ -1466,14 +1467,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
|||
graph->connect(background->output("Background"), out->input("Surface"));
|
||||
}
|
||||
|
||||
/* Visibility */
|
||||
if (b_world) {
|
||||
/* AO */
|
||||
BL::WorldLighting b_light = b_world.light_settings();
|
||||
|
||||
integrator->set_ao_factor(b_light.ao_factor());
|
||||
integrator->set_ao_distance(b_light.distance());
|
||||
|
||||
/* visibility */
|
||||
PointerRNA cvisibility = RNA_pointer_get(&b_world.ptr, "cycles_visibility");
|
||||
uint visibility = 0;
|
||||
|
||||
|
@ -1485,16 +1480,38 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d,
|
|||
|
||||
background->set_visibility(visibility);
|
||||
}
|
||||
else {
|
||||
integrator->set_ao_factor(1.0f);
|
||||
integrator->set_ao_distance(10.0f);
|
||||
}
|
||||
|
||||
shader->set_graph(graph);
|
||||
shader->tag_update(scene);
|
||||
}
|
||||
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
/* Fast GI */
|
||||
if (b_world) {
|
||||
BL::WorldLighting b_light = b_world.light_settings();
|
||||
enum { FAST_GI_METHOD_REPLACE = 0, FAST_GI_METHOD_ADD = 1, FAST_GI_METHOD_NUM };
|
||||
|
||||
const bool use_fast_gi = get_boolean(cscene, "use_fast_gi");
|
||||
if (use_fast_gi) {
|
||||
const int fast_gi_method = get_enum(
|
||||
cscene, "fast_gi_method", FAST_GI_METHOD_NUM, FAST_GI_METHOD_REPLACE);
|
||||
integrator->set_ao_factor((fast_gi_method == FAST_GI_METHOD_REPLACE) ? b_light.ao_factor() :
|
||||
0.0f);
|
||||
integrator->set_ao_additive_factor(
|
||||
(fast_gi_method == FAST_GI_METHOD_ADD) ? b_light.ao_factor() : 0.0f);
|
||||
}
|
||||
else {
|
||||
integrator->set_ao_factor(0.0f);
|
||||
integrator->set_ao_additive_factor(0.0f);
|
||||
}
|
||||
|
||||
integrator->set_ao_distance(b_light.distance());
|
||||
}
|
||||
else {
|
||||
integrator->set_ao_factor(0.0f);
|
||||
integrator->set_ao_additive_factor(0.0f);
|
||||
integrator->set_ao_distance(10.0f);
|
||||
}
|
||||
|
||||
background->set_transparent(b_scene.render().film_transparent());
|
||||
|
||||
if (background->get_transparent()) {
|
||||
|
|
|
@ -1082,7 +1082,7 @@ bool PathTraceWorkGPU::kernel_creates_shadow_paths(DeviceKernel kernel)
|
|||
|
||||
bool PathTraceWorkGPU::kernel_creates_ao_paths(DeviceKernel kernel)
|
||||
{
|
||||
return (device_scene_->data.film.pass_ao != PASS_UNUSED) &&
|
||||
return (device_scene_->data.kernel_features & KERNEL_FEATURE_AO) &&
|
||||
(kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
|
||||
kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE);
|
||||
}
|
||||
|
|
|
@ -325,17 +325,25 @@ ccl_device_forceinline bool integrate_surface_volume_only_bounce(IntegratorState
|
|||
#endif
|
||||
|
||||
#if defined(__AO__)
|
||||
ccl_device_forceinline void integrate_surface_ao_pass(
|
||||
KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private const ShaderData *ccl_restrict sd,
|
||||
ccl_private const RNGState *ccl_restrict rng_state,
|
||||
ccl_global float *ccl_restrict render_buffer)
|
||||
ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg,
|
||||
IntegratorState state,
|
||||
ccl_private const ShaderData *ccl_restrict sd,
|
||||
ccl_private const RNGState *ccl_restrict
|
||||
rng_state,
|
||||
ccl_global float *ccl_restrict render_buffer)
|
||||
{
|
||||
if (!(kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) &&
|
||||
!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_CAMERA)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float bsdf_u, bsdf_v;
|
||||
path_state_rng_2D(kg, rng_state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
|
||||
const float3 ao_N = shader_bsdf_ao_normal(kg, sd);
|
||||
float3 ao_N;
|
||||
const float3 ao_weight = shader_bsdf_ao(
|
||||
kg, sd, kernel_data.integrator.ao_additive_factor, &ao_N);
|
||||
|
||||
float3 ao_D;
|
||||
float ao_pdf;
|
||||
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
|
||||
|
@ -379,6 +387,10 @@ ccl_device_forceinline void integrate_surface_ao_pass(
|
|||
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, bounce) = bounce;
|
||||
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, transparent_bounce) = transparent_bounce;
|
||||
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, throughput) = throughput;
|
||||
|
||||
if (kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) {
|
||||
INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, unshadowed_throughput) = ao_weight;
|
||||
}
|
||||
}
|
||||
#endif /* defined(__AO__) */
|
||||
|
||||
|
@ -487,10 +499,9 @@ ccl_device bool integrate_surface(KernelGlobals kg,
|
|||
|
||||
#if defined(__AO__)
|
||||
/* Ambient occlusion pass. */
|
||||
if ((kernel_data.film.pass_ao != PASS_UNUSED) &&
|
||||
(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_CAMERA)) {
|
||||
if (kernel_data.kernel_features & KERNEL_FEATURE_AO) {
|
||||
PROFILING_EVENT(PROFILING_SHADE_SURFACE_AO);
|
||||
integrate_surface_ao_pass(kg, state, &sd, &rng_state, render_buffer);
|
||||
integrate_surface_ao(kg, state, &sd, &rng_state, render_buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -42,7 +42,10 @@ KERNEL_STRUCT_MEMBER(shadow_path, uint32_t, flag, KERNEL_FEATURE_PATH_TRACING)
|
|||
/* Throughput. */
|
||||
KERNEL_STRUCT_MEMBER(shadow_path, float3, throughput, KERNEL_FEATURE_PATH_TRACING)
|
||||
/* Throughput for shadow pass. */
|
||||
KERNEL_STRUCT_MEMBER(shadow_path, float3, unshadowed_throughput, KERNEL_FEATURE_SHADOW_PASS)
|
||||
KERNEL_STRUCT_MEMBER(shadow_path,
|
||||
float3,
|
||||
unshadowed_throughput,
|
||||
KERNEL_FEATURE_SHADOW_PASS | KERNEL_FEATURE_AO_ADDITIVE)
|
||||
/* Ratio of throughput to distinguish diffuse and glossy render passes. */
|
||||
KERNEL_STRUCT_MEMBER(shadow_path, float3, diffuse_glossy_ratio, KERNEL_FEATURE_LIGHT_PASSES)
|
||||
/* Number of intersections found by ray-tracing. */
|
||||
|
|
|
@ -410,7 +410,13 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg,
|
|||
|
||||
/* Ambient occlusion. */
|
||||
if (path_flag & PATH_RAY_SHADOW_FOR_AO) {
|
||||
kernel_write_pass_float3(buffer + kernel_data.film.pass_ao, contribution);
|
||||
if ((kernel_data.kernel_features & KERNEL_FEATURE_AO_PASS) && (path_flag & PATH_RAY_CAMERA)) {
|
||||
kernel_write_pass_float3(buffer + kernel_data.film.pass_ao, contribution);
|
||||
}
|
||||
if (kernel_data.kernel_features & KERNEL_FEATURE_AO_ADDITIVE) {
|
||||
const float3 ao_weight = INTEGRATOR_STATE(state, shadow_path, unshadowed_throughput);
|
||||
kernel_accum_combined_pass(kg, path_flag, sample, contribution * ao_weight, buffer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -457,19 +457,26 @@ ccl_device float3 shader_bsdf_average_normal(KernelGlobals kg, ccl_private const
|
|||
return (is_zero(N)) ? sd->N : normalize(N);
|
||||
}
|
||||
|
||||
ccl_device float3 shader_bsdf_ao_normal(KernelGlobals kg, ccl_private const ShaderData *sd)
|
||||
ccl_device float3 shader_bsdf_ao(KernelGlobals kg,
|
||||
ccl_private const ShaderData *sd,
|
||||
const float ao_factor,
|
||||
ccl_private float3 *N_)
|
||||
{
|
||||
float3 eval = zero_float3();
|
||||
float3 N = zero_float3();
|
||||
|
||||
for (int i = 0; i < sd->num_closure; i++) {
|
||||
ccl_private const ShaderClosure *sc = &sd->closure[i];
|
||||
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
|
||||
ccl_private const DiffuseBsdf *bsdf = (ccl_private const DiffuseBsdf *)sc;
|
||||
eval += sc->weight * ao_factor;
|
||||
N += bsdf->N * fabsf(average(sc->weight));
|
||||
}
|
||||
}
|
||||
|
||||
return (is_zero(N)) ? sd->N : normalize(N);
|
||||
*N_ = (is_zero(N)) ? sd->N : normalize(N);
|
||||
return eval;
|
||||
}
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
|
|
|
@ -1147,6 +1147,7 @@ typedef struct KernelIntegrator {
|
|||
int ao_bounces;
|
||||
float ao_bounces_distance;
|
||||
float ao_bounces_factor;
|
||||
float ao_additive_factor;
|
||||
|
||||
/* transparent */
|
||||
int transparent_min_bounce;
|
||||
|
@ -1179,7 +1180,7 @@ typedef struct KernelIntegrator {
|
|||
int has_shadow_catcher;
|
||||
|
||||
/* padding */
|
||||
int pad1, pad2;
|
||||
int pad1;
|
||||
} KernelIntegrator;
|
||||
static_assert_align(KernelIntegrator, 16);
|
||||
|
||||
|
@ -1561,6 +1562,11 @@ enum KernelFeatureFlag : unsigned int {
|
|||
|
||||
/* Shadow render pass. */
|
||||
KERNEL_FEATURE_SHADOW_PASS = (1U << 24U),
|
||||
|
||||
/* AO. */
|
||||
KERNEL_FEATURE_AO_PASS = (1U << 25U),
|
||||
KERNEL_FEATURE_AO_ADDITIVE = (1U << 26U),
|
||||
KERNEL_FEATURE_AO = (KERNEL_FEATURE_AO_PASS | KERNEL_FEATURE_AO_ADDITIVE),
|
||||
};
|
||||
|
||||
/* Shader node feature mask, to specialize shader evaluation for kernels. */
|
||||
|
|
|
@ -680,6 +680,10 @@ uint Film::get_kernel_features(const Scene *scene) const
|
|||
kernel_features |= KERNEL_FEATURE_SHADOW_PASS;
|
||||
}
|
||||
}
|
||||
|
||||
if (pass_type == PASS_AO) {
|
||||
kernel_features |= KERNEL_FEATURE_AO_PASS;
|
||||
}
|
||||
}
|
||||
|
||||
return kernel_features;
|
||||
|
|
|
@ -55,6 +55,7 @@ NODE_DEFINE(Integrator)
|
|||
SOCKET_INT(ao_bounces, "AO Bounces", 0);
|
||||
SOCKET_FLOAT(ao_factor, "AO Factor", 0.0f);
|
||||
SOCKET_FLOAT(ao_distance, "AO Distance", FLT_MAX);
|
||||
SOCKET_FLOAT(ao_additive_factor, "AO Additive Factor", 0.0f);
|
||||
|
||||
SOCKET_INT(volume_max_steps, "Volume Max Steps", 1024);
|
||||
SOCKET_FLOAT(volume_step_rate, "Volume Step Rate", 1.0f);
|
||||
|
@ -159,6 +160,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
|
|||
kintegrator->ao_bounces = ao_bounces;
|
||||
kintegrator->ao_bounces_distance = ao_distance;
|
||||
kintegrator->ao_bounces_factor = ao_factor;
|
||||
kintegrator->ao_additive_factor = ao_additive_factor;
|
||||
|
||||
/* Transparent Shadows
|
||||
* We only need to enable transparent shadows, if we actually have
|
||||
|
@ -268,6 +270,17 @@ void Integrator::tag_update(Scene *scene, uint32_t flag)
|
|||
}
|
||||
}
|
||||
|
||||
uint Integrator::get_kernel_features(const Scene *scene) const
|
||||
{
|
||||
uint kernel_features = 0;
|
||||
|
||||
if (ao_additive_factor != 0.0f) {
|
||||
kernel_features |= KERNEL_FEATURE_AO_ADDITIVE;
|
||||
}
|
||||
|
||||
return kernel_features;
|
||||
}
|
||||
|
||||
AdaptiveSampling Integrator::get_adaptive_sampling() const
|
||||
{
|
||||
AdaptiveSampling adaptive_sampling;
|
||||
|
|
|
@ -47,6 +47,7 @@ class Integrator : public Node {
|
|||
NODE_SOCKET_API(int, ao_bounces)
|
||||
NODE_SOCKET_API(float, ao_factor)
|
||||
NODE_SOCKET_API(float, ao_distance)
|
||||
NODE_SOCKET_API(float, ao_additive_factor)
|
||||
|
||||
NODE_SOCKET_API(int, volume_max_steps)
|
||||
NODE_SOCKET_API(float, volume_step_rate)
|
||||
|
@ -101,6 +102,8 @@ class Integrator : public Node {
|
|||
|
||||
void tag_update(Scene *scene, uint32_t flag);
|
||||
|
||||
uint get_kernel_features(const Scene *scene) const;
|
||||
|
||||
AdaptiveSampling get_adaptive_sampling() const;
|
||||
DenoiseParams get_denoise_params() const;
|
||||
};
|
||||
|
|
|
@ -522,6 +522,7 @@ void Scene::update_kernel_features()
|
|||
}
|
||||
|
||||
kernel_features |= film->get_kernel_features(this);
|
||||
kernel_features |= integrator->get_kernel_features(this);
|
||||
|
||||
dscene.data.kernel_features = kernel_features;
|
||||
|
||||
|
|
|
@ -128,6 +128,7 @@ static void rna_def_lighting(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "aodist");
|
||||
RNA_def_property_range(prop, 0, FLT_MAX);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Distance", "Length of rays, defines how far away other faces give occlusion effect");
|
||||
RNA_def_property_update(prop, 0, "rna_World_update");
|
||||
|
|
Loading…
Reference in New Issue