diff options
34 files changed, 402 insertions, 161 deletions
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index dc28bc647b5..922ea9d9d7f 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -271,6 +271,40 @@ def custom_bake_remap(scene): scene.render.bake.use_pass_indirect = False +def ambient_occlusion_node_relink(material, nodetree, traversed): + if nodetree in traversed: + return + traversed.add(nodetree) + + for node in nodetree.nodes: + if node.bl_idname == 'ShaderNodeAmbientOcclusion': + node.samples = 1 + node.only_local = False + node.inputs['Distance'].default_value = 0.0 + elif node.bl_idname == 'ShaderNodeGroup': + ambient_occlusion_node_relink(material, node.node_tree, traversed) + + # Gather links to replace + ao_links = [] + for link in nodetree.links: + if link.from_node.bl_idname == 'ShaderNodeAmbientOcclusion': + ao_links.append(link) + + # Replace links + for link in ao_links: + from_node = link.from_node + to_socket = link.to_socket + + nodetree.links.remove(link) + nodetree.links.new(from_node.outputs['Color'], to_socket) + +def ambient_occlusion_nodes_relink(): + traversed = set() + for material in bpy.data.materials: + if check_is_new_shading_material(material): + ambient_occlusion_node_relink(material, material.node_tree, traversed) + + @persistent def do_versions(self): if bpy.context.user_preferences.version <= (2, 78, 1): @@ -428,11 +462,14 @@ def do_versions(self): # Switch to squared roughness convention square_roughness_nodes_insert() - for world in bpy.data.worlds: - cworld = world.cycles - # World MIS - if not cworld.is_property_set("sampling_method"): - if cworld.get("sample_as_light", False): - cworld.sampling_method = 'MANUAL' - else: - cworld.sampling_method = 'NONE' + if bpy.data.version <= (2, 79, 4): + for world in bpy.data.worlds: + cworld = world.cycles + # World MIS + if not cworld.is_property_set("sampling_method"): + if cworld.get("sample_as_light", False): + cworld.sampling_method = 'MANUAL' + else: + cworld.sampling_method = 'NONE' + + ambient_occlusion_nodes_relink() diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 9896dd1d94f..89612b74c39 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -558,7 +558,12 @@ static ShaderNode *add_node(Scene *scene, node = new EmissionNode(); } else if(b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) { - node = new AmbientOcclusionNode(); + BL::ShaderNodeAmbientOcclusion b_ao_node(b_node); + AmbientOcclusionNode *ao = new AmbientOcclusionNode(); + ao->samples = b_ao_node.samples(); + ao->inside = b_ao_node.inside(); + ao->only_local = b_ao_node.only_local(); + node = ao; } else if(b_node.is_a(&RNA_ShaderNodeVolumeScatter)) { node = new ScatterVolumeNode(); diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index b1956bfb13a..c2688cd71f7 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -160,6 +160,7 @@ set(SRC_CLOSURE_HEADERS set(SRC_SVM_HEADERS svm/svm.h + svm/svm_ao.h svm/svm_attribute.h svm/svm_bevel.h svm/svm_blackbody.h diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index d3e0b25a200..de1503e5564 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -203,7 +203,7 @@ ccl_device_intersect bool scene_intersect(KernelGlobals *kg, #ifdef __BVH_LOCAL__ /* Note: ray is passed by value to work around a possible CUDA compiler bug. */ -ccl_device_intersect void scene_intersect_local(KernelGlobals *kg, +ccl_device_intersect bool scene_intersect_local(KernelGlobals *kg, const Ray ray, LocalIntersection *local_isect, int local_object, diff --git a/intern/cycles/kernel/bvh/bvh_local.h b/intern/cycles/kernel/bvh/bvh_local.h index 9292cc76a5c..6356c197dd1 100644 --- a/intern/cycles/kernel/bvh/bvh_local.h +++ b/intern/cycles/kernel/bvh/bvh_local.h @@ -41,7 +41,7 @@ ccl_device #else ccl_device_inline #endif -void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, +bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, const Ray *ray, LocalIntersection *local_isect, int local_object, @@ -70,7 +70,11 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, int object = OBJECT_NONE; float isect_t = ray->t; - local_isect->num_hits = 0; + if(local_isect) { + local_isect->num_hits = 0; + } + + kernel_assert((local_isect == NULL) == (max_hits == 0)); const int object_flag = kernel_tex_fetch(__object_flag, local_object); if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { @@ -194,16 +198,18 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* intersect ray against primitive */ for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - triangle_intersect_local(kg, - local_isect, - P, - dir, - object, - local_object, - prim_addr, - isect_t, - lcg_state, - max_hits); + if(triangle_intersect_local(kg, + local_isect, + P, + dir, + object, + local_object, + prim_addr, + isect_t, + lcg_state, + max_hits)) { + return true; + } } break; } @@ -212,17 +218,19 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* intersect ray against primitive */ for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - motion_triangle_intersect_local(kg, - local_isect, - P, - dir, - ray->time, - object, - local_object, - prim_addr, - isect_t, - lcg_state, - max_hits); + if(motion_triangle_intersect_local(kg, + local_isect, + P, + dir, + ray->time, + object, + local_object, + prim_addr, + isect_t, + lcg_state, + max_hits)) { + return true; + } } break; } @@ -234,9 +242,11 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, } } while(node_addr != ENTRYPOINT_SENTINEL); } while(node_addr != ENTRYPOINT_SENTINEL); + + return false; } -ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, +ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, const Ray *ray, LocalIntersection *local_isect, int local_object, @@ -262,6 +272,7 @@ ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, max_hits); } kernel_assert(!"Should not happen"); + return false; } #undef BVH_FUNCTION_NAME diff --git a/intern/cycles/kernel/bvh/qbvh_local.h b/intern/cycles/kernel/bvh/qbvh_local.h index 2386fa1a1e8..0dc0575556c 100644 --- a/intern/cycles/kernel/bvh/qbvh_local.h +++ b/intern/cycles/kernel/bvh/qbvh_local.h @@ -29,7 +29,7 @@ # define NODE_INTERSECT qbvh_aligned_node_intersect #endif -ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, +ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, LocalIntersection *local_isect, int local_object, @@ -59,7 +59,11 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, int object = OBJECT_NONE; float isect_t = ray->t; - local_isect->num_hits = 0; + if(local_isect) { + local_isect->num_hits = 0; + } + + kernel_assert((local_isect == NULL) == (max_hits == 0)); const int object_flag = kernel_tex_fetch(__object_flag, local_object); if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { @@ -81,7 +85,7 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #ifndef __KERNEL_SSE41__ if(!isfinite(P.x)) { - return; + return false; } #endif @@ -250,16 +254,18 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Intersect ray against primitive, */ for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - triangle_intersect_local(kg, - local_isect, - P, - dir, - object, - local_object, - prim_addr, - isect_t, - lcg_state, - max_hits); + if(triangle_intersect_local(kg, + local_isect, + P, + dir, + object, + local_object, + prim_addr, + isect_t, + lcg_state, + max_hits)) { + return true; + } } break; } @@ -268,17 +274,19 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Intersect ray against primitive. */ for(; prim_addr < prim_addr2; prim_addr++) { kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - motion_triangle_intersect_local(kg, - local_isect, - P, - dir, - ray->time, - object, - local_object, - prim_addr, - isect_t, - lcg_state, - max_hits); + if(motion_triangle_intersect_local(kg, + local_isect, + P, + dir, + ray->time, + object, + local_object, + prim_addr, + isect_t, + lcg_state, + max_hits)) { + return true; + } } break; } @@ -289,6 +297,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, } } while(node_addr != ENTRYPOINT_SENTINEL); } while(node_addr != ENTRYPOINT_SENTINEL); + + return false; } #undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h index 542843edc84..ec7bfad7349 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h @@ -218,9 +218,10 @@ ccl_device_inline bool motion_triangle_intersect( /* Special ray intersection routines for local intersections. In that case we * only want to intersect with primitives in the same object, and if case of * multiple hits we pick a single random primitive as the intersection point. + * Returns whether traversal should be stopped. */ #ifdef __BVH_LOCAL__ -ccl_device_inline void motion_triangle_intersect_local( +ccl_device_inline bool motion_triangle_intersect_local( KernelGlobals *kg, LocalIntersection *local_isect, float3 P, @@ -237,7 +238,7 @@ ccl_device_inline void motion_triangle_intersect_local( * already know we are only intersecting the right object. */ if(object == OBJECT_NONE) { if(kernel_tex_fetch(__prim_object, prim_addr) != local_object) { - return; + return false; } } @@ -258,7 +259,12 @@ ccl_device_inline void motion_triangle_intersect_local( #endif &u, &v, &t)) { - return; + return false; + } + + /* If no actual hit information is requested, just return here. */ + if(max_hits == 0) { + return true; } int hit; @@ -266,7 +272,7 @@ ccl_device_inline void motion_triangle_intersect_local( /* Record up to max_hits intersections. */ for(int i = min(max_hits, local_isect->num_hits) - 1; i >= 0; --i) { if(local_isect->hits[i].t == t) { - return; + return false; } } @@ -282,13 +288,13 @@ ccl_device_inline void motion_triangle_intersect_local( hit = lcg_step_uint(lcg_state) % local_isect->num_hits; if(hit >= max_hits) - return; + return false; } } else { /* Record closest intersection only. */ if(local_isect->num_hits && t > local_isect->hits[0].t) { - return; + return false; } hit = 0; @@ -307,6 +313,8 @@ ccl_device_inline void motion_triangle_intersect_local( /* Record geometric normal. */ local_isect->Ng[hit] = normalize(cross(verts[1] - verts[0], verts[2] - verts[0])); + + return false; } #endif /* __BVH_LOCAL__ */ diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index a3b23115ae4..a2b1e050e58 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -73,10 +73,11 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, /* Special ray intersection routines for local intersection. In that case we * only want to intersect with primitives in the same object, and if case of * multiple hits we pick a single random primitive as the intersection point. + * Returns whether traversal should be stopped. */ #ifdef __BVH_LOCAL__ -ccl_device_inline void triangle_intersect_local( +ccl_device_inline bool triangle_intersect_local( KernelGlobals *kg, LocalIntersection *local_isect, float3 P, @@ -92,7 +93,7 @@ ccl_device_inline void triangle_intersect_local( * already know we are only intersecting the right object. */ if(object == OBJECT_NONE) { if(kernel_tex_fetch(__prim_object, prim_addr) != local_object) { - return; + return false; } } @@ -115,7 +116,12 @@ ccl_device_inline void triangle_intersect_local( #endif &u, &v, &t)) { - return; + return false; + } + + /* If no actual hit information is requested, just return here. */ + if(max_hits == 0) { + return true; } int hit; @@ -123,7 +129,7 @@ ccl_device_inline void triangle_intersect_local( /* Record up to max_hits intersections. */ for(int i = min(max_hits, local_isect->num_hits) - 1; i >= 0; --i) { if(local_isect->hits[i].t == t) { - return; + return false; } } @@ -138,13 +144,13 @@ ccl_device_inline void triangle_intersect_local( hit = lcg_step_uint(lcg_state) % local_isect->num_hits; if(hit >= max_hits) - return; + return false; } } else { /* Record closest intersection only. */ if(local_isect->num_hits && t > local_isect->hits[0].t) { - return; + return false; } hit = 0; @@ -167,6 +173,8 @@ ccl_device_inline void triangle_intersect_local( tri_c = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex+2)); #endif local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a)); + + return false; } #endif /* __BVH_LOCAL__ */ diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index b0f53aef2d5..d79b556c2ce 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -491,7 +491,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #ifdef __AO__ /* ambient occlusion */ - if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) { + if(kernel_data.integrator.use_ambient_occlusion) { kernel_path_ao(kg, sd, emission_sd, L, state, throughput, make_float3(0.0f, 0.0f, 0.0f)); } #endif /* __AO__ */ @@ -661,7 +661,7 @@ ccl_device_forceinline void kernel_path_integrate( #ifdef __AO__ /* ambient occlusion */ - if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { + if(kernel_data.integrator.use_ambient_occlusion) { kernel_path_ao(kg, &sd, emission_sd, L, state, throughput, shader_bsdf_alpha(kg, &sd)); } #endif /* __AO__ */ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index 66f67c3e2c4..80fcf5b0565 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -526,7 +526,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg, #ifdef __AO__ /* ambient occlusion */ - if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { + if(kernel_data.integrator.use_ambient_occlusion) { kernel_branched_path_ao(kg, &sd, emission_sd, L, &state, throughput); } #endif /* __AO__ */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 937a50cba8b..b83460b3ffb 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -914,10 +914,6 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac eval += sc->weight*ao_factor; N += bsdf->N*fabsf(average(sc->weight)); } - else if(CLOSURE_IS_AMBIENT_OCCLUSION(sc->type)) { - eval += sc->weight; - N += sd->N*fabsf(average(sc->weight)); - } } *N_ = (is_zero(N))? sd->N : normalize(N); diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 8df7c369799..c2a65dc9999 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -881,8 +881,6 @@ enum ShaderDataFlag { SD_EXTINCTION = (1 << 6), /* Shader has have volume phase (scatter) closure. */ SD_SCATTER = (1 << 7), - /* Shader has AO closure. */ - SD_AO = (1 << 8), /* Shader has transparent closure. */ SD_TRANSPARENT = (1 << 9), /* BSDF requires LCG for evaluation. */ @@ -895,7 +893,6 @@ enum ShaderDataFlag { SD_HOLDOUT | SD_EXTINCTION | SD_SCATTER | - SD_AO | SD_BSDF_NEEDS_LCG), /* Shader flags. */ diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp index 8fff19407d9..30a9e84c399 100644 --- a/intern/cycles/kernel/osl/background.cpp +++ b/intern/cycles/kernel/osl/background.cpp @@ -74,21 +74,6 @@ public: } }; -/// ambient occlusion closure -/// -/// We only have a ambient occlusion closure for the shaders -/// to return a color in ambient occlusion shaders. No methods, -/// only the weight is taking into account -/// -class AmbientOcclusionClosure : public CClosurePrimitive { -public: - void setup(ShaderData *sd, int /* path_flag */, float3 weight) - { - closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_AMBIENT_OCCLUSION_ID, weight); - sd->flag |= SD_AO; - } -}; - ClosureParam *closure_background_params() { static ClosureParam params[] = { @@ -110,16 +95,5 @@ ClosureParam *closure_holdout_params() CCLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure) -ClosureParam *closure_ambient_occlusion_params() -{ - static ClosureParam params[] = { - CLOSURE_STRING_KEYPARAM(AmbientOcclusionClosure, label, "label"), - CLOSURE_FINISH_PARAM(AmbientOcclusionClosure) - }; - return params; -} - -CCLOSURE_PREPARE(closure_ambient_occlusion_prepare, AmbientOcclusionClosure) - CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index ee16ddaf0fd..6a1e52d7d16 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -310,8 +310,6 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) closure_background_params(), closure_background_prepare); register_closure(ss, "holdout", id++, closure_holdout_params(), closure_holdout_prepare); - register_closure(ss, "ambient_occlusion", id++, - closure_ambient_occlusion_params(), closure_ambient_occlusion_prepare); register_closure(ss, "diffuse_ramp", id++, closure_bsdf_diffuse_ramp_params(), closure_bsdf_diffuse_ramp_prepare); register_closure(ss, "phong_ramp", id++, diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index dca7e74f154..68dfa9a4650 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -45,7 +45,6 @@ CCL_NAMESPACE_BEGIN OSL::ClosureParam *closure_emission_params(); OSL::ClosureParam *closure_background_params(); OSL::ClosureParam *closure_holdout_params(); -OSL::ClosureParam *closure_ambient_occlusion_params(); OSL::ClosureParam *closure_bsdf_diffuse_ramp_params(); OSL::ClosureParam *closure_bsdf_phong_ramp_params(); OSL::ClosureParam *closure_bsdf_transparent_params(); @@ -65,7 +64,6 @@ OSL::ClosureParam *closure_bsdf_principled_clearcoat_params(); void closure_emission_prepare(OSL::RendererServices *, int id, void *data); void closure_background_prepare(OSL::RendererServices *, int id, void *data); void closure_holdout_prepare(OSL::RendererServices *, int id, void *data); -void closure_ambient_occlusion_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_diffuse_ramp_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_transparent_prepare(OSL::RendererServices *, int id, void *data); diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 1aca54d2ad5..4b7a4cb34b7 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -125,6 +125,7 @@ ustring OSLRenderServices::u_u("u"); ustring OSLRenderServices::u_v("v"); ustring OSLRenderServices::u_empty; ustring OSLRenderServices::u_at_bevel("@bevel"); +ustring OSLRenderServices::u_at_ao("@ao"); OSLRenderServices::OSLRenderServices() { @@ -957,6 +958,25 @@ bool OSLRenderServices::texture(ustring filename, status = true; } } + else if(filename == u_at_ao) { + /* AO shader hack. */ + PathState *state = sd->osl_path_state; + int num_samples = (int)s; + float radius = t; + float3 N = make_float3(dsdx, dtdx, dsdy); + int flags = 0; + if((int)dtdy) { + flags |= NODE_AO_INSIDE; + } + if((int)options.sblur) { + flags |= NODE_AO_ONLY_LOCAL; + } + if((int)options.tblur) { + flags |= NODE_AO_GLOBAL_RADIUS; + } + result[0] = svm_ao(kg, sd, N, state, radius, num_samples, flags); + status = true; + } else if(filename[1] == 'l') { /* IES light. */ int slot = atoi(filename.c_str() + 2); diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index d96048e26f2..1a40e2ece2b 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -182,6 +182,7 @@ public: static ustring u_v; static ustring u_empty; static ustring u_at_bevel; + static ustring u_at_ao; private: KernelGlobals *kernel_globals; diff --git a/intern/cycles/kernel/shaders/node_ambient_occlusion.osl b/intern/cycles/kernel/shaders/node_ambient_occlusion.osl index 5f056122bbe..d7ffa3c1606 100644 --- a/intern/cycles/kernel/shaders/node_ambient_occlusion.osl +++ b/intern/cycles/kernel/shaders/node_ambient_occlusion.osl @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 Blender Foundation + * Copyright 2011-2018 Blender Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,19 @@ #include "stdosl.h" shader node_ambient_occlusion( - normal NormalIn = N, - color Color = 0.8, - output closure color AO = 0) + color ColorIn = color(0.8, 0.8, 0.8), + int samples = 8, + float Distance = 1.0, + normal Normal = N, + int inside = 0, + int only_local = 1, + output color ColorOut = color(0.8, 0.8, 0.8), + output float AO = 1.0) { - AO = Color * ambient_occlusion(); + int global_radius = (Distance == 0.0 && !isconnected(Distance)); + + /* Abuse texture call with special @ao token. */ + AO = texture("@ao", samples, Distance, Normal[0], Normal[1], Normal[2], inside, "sblur", only_local, "tblur", global_radius); + ColorOut = ColorIn * AO; } diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h index 88919f47c7a..f14eecec2f2 100644 --- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h +++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h @@ -149,7 +149,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( #ifdef __AO__ if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) { /* ambient occlusion */ - if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) { + if(kernel_data.integrator.use_ambient_occlusion) { enqueue_flag = 1; } } diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index ce2affe96c8..10d5fe0e42b 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -144,6 +144,7 @@ CCL_NAMESPACE_END #include "kernel/svm/svm_color_util.h" #include "kernel/svm/svm_math_util.h" +#include "kernel/svm/svm_ao.h" #include "kernel/svm/svm_attribute.h" #include "kernel/svm/svm_gradient.h" #include "kernel/svm/svm_blackbody.h" @@ -324,9 +325,6 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a case NODE_CLOSURE_HOLDOUT: svm_node_closure_holdout(sd, stack, node); break; - case NODE_CLOSURE_AMBIENT_OCCLUSION: - svm_node_closure_ambient_occlusion(sd, stack, node); - break; case NODE_FRESNEL: svm_node_fresnel(sd, stack, node.y, node.z, node.w); break; @@ -480,6 +478,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a case NODE_BEVEL: svm_node_bevel(kg, sd, state, stack, node); break; + case NODE_AMBIENT_OCCLUSION: + svm_node_ao(kg, sd, state, stack, node); + break; # endif /* __SHADER_RAYTRACE__ */ #endif /* NODES_GROUP(NODE_GROUP_LEVEL_3) */ case NODE_END: diff --git a/intern/cycles/kernel/svm/svm_ao.h b/intern/cycles/kernel/svm/svm_ao.h new file mode 100644 index 00000000000..3f761627e2c --- /dev/null +++ b/intern/cycles/kernel/svm/svm_ao.h @@ -0,0 +1,111 @@ +/* +* Copyright 2011-2018 Blender Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +CCL_NAMESPACE_BEGIN + +ccl_device_noinline float svm_ao(KernelGlobals *kg, + ShaderData *sd, + float3 N, + ccl_addr_space PathState *state, + float max_dist, + int num_samples, + int flags) +{ + if(flags & NODE_AO_GLOBAL_RADIUS) { + max_dist = kernel_data.background.ao_distance; + } + + /* Early out if no sampling needed. */ + if(max_dist <= 0.0f || num_samples < 1 || sd->object == OBJECT_NONE) { + return 0.0f; + } + + if(flags & NODE_AO_INSIDE) { + N = -N; + } + + float3 T, B; + make_orthonormals(N, &T, &B); + + int unoccluded = 0; + for(int sample = 0; sample < num_samples; sample++) { + float disk_u, disk_v; + path_branched_rng_2D(kg, state->rng_hash, state, sample, num_samples, + PRNG_BEVEL_U, &disk_u, &disk_v); + + float2 d = concentric_sample_disk(disk_u, disk_v); + float3 D = make_float3(d.x, d.y, safe_sqrtf(1.0f - dot(d, d))); + + /* Create ray. */ + Ray ray; + ray.P = ray_offset(sd->P, N); + ray.D = D.x*T + D.y*B + D.z*N; + ray.t = max_dist; + ray.time = sd->time; + + if(flags & NODE_AO_ONLY_LOCAL) { + if(!scene_intersect_local(kg, + ray, + NULL, + sd->object, + NULL, + 0)) { + unoccluded++; + } + } + else { + Intersection isect; + if(!scene_intersect(kg, + ray, + PATH_RAY_SHADOW_OPAQUE, + &isect, + NULL, + 0.0f, 0.0f)) { + unoccluded++; + } + } + } + + return ((float) unoccluded) / num_samples; +} + +ccl_device void svm_node_ao(KernelGlobals *kg, + ShaderData *sd, + ccl_addr_space PathState *state, + float *stack, + uint4 node) +{ + uint flags, dist_offset, normal_offset, out_ao_offset; + decode_node_uchar4(node.y, &flags, &dist_offset, &normal_offset, &out_ao_offset); + + uint color_offset, out_color_offset, samples; + decode_node_uchar4(node.z, &color_offset, &out_color_offset, &samples, NULL); + + float dist = stack_load_float_default(stack, dist_offset, node.w); + float3 normal = stack_valid(normal_offset)? stack_load_float3(stack, normal_offset): sd->N; + float ao = svm_ao(kg, sd, normal, state, dist, samples, flags); + + if (stack_valid(out_ao_offset)) { + stack_store_float(stack, out_ao_offset, ao); + } + + if (stack_valid(out_color_offset)) { + float3 color = stack_load_float3(stack, color_offset); + stack_store_float3(stack, out_color_offset, ao * color); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 76464e37c66..f5b316c67da 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -996,24 +996,6 @@ ccl_device void svm_node_closure_holdout(ShaderData *sd, float *stack, uint4 nod sd->flag |= SD_HOLDOUT; } -ccl_device void svm_node_closure_ambient_occlusion(ShaderData *sd, float *stack, uint4 node) -{ - uint mix_weight_offset = node.y; - - if(stack_valid(mix_weight_offset)) { - float mix_weight = stack_load_float(stack, mix_weight_offset); - - if(mix_weight == 0.0f) - return; - - closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_AMBIENT_OCCLUSION_ID, sd->svm_closure_weight * mix_weight); - } - else - closure_alloc(sd, sizeof(ShaderClosure), CLOSURE_AMBIENT_OCCLUSION_ID, sd->svm_closure_weight); - - sd->flag |= SD_AO; -} - /* Closure Nodes */ ccl_device_inline void svm_node_closure_store_weight(ShaderData *sd, float3 weight) diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index ac24d23ecd2..54db18cd7bb 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -124,7 +124,7 @@ typedef enum ShaderNodeType { NODE_PARTICLE_INFO, NODE_TEX_BRICK, NODE_CLOSURE_SET_NORMAL, - NODE_CLOSURE_AMBIENT_OCCLUSION, + NODE_AMBIENT_OCCLUSION, NODE_TANGENT, NODE_NORMAL_MAP, NODE_HAIR_INFO, @@ -386,6 +386,12 @@ typedef enum NodeTexVoxelSpace { NODE_TEX_VOXEL_SPACE_WORLD = 1, } NodeTexVoxelSpace; +typedef enum NodeAO { + NODE_AO_ONLY_LOCAL = (1 << 0), + NODE_AO_INSIDE = (1 << 1), + NODE_AO_GLOBAL_RADIUS = (1 << 2), +} NodeAO; + typedef enum ShaderType { SHADER_TYPE_SURFACE, SHADER_TYPE_VOLUME, @@ -456,7 +462,6 @@ typedef enum ClosureType { /* Other */ CLOSURE_HOLDOUT_ID, - CLOSURE_AMBIENT_OCCLUSION_ID, /* Volume */ CLOSURE_VOLUME_ID, @@ -491,7 +496,6 @@ typedef enum ClosureType { #define CLOSURE_IS_VOLUME_SCATTER(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) #define CLOSURE_IS_VOLUME_ABSORPTION(type) (type == CLOSURE_VOLUME_ABSORPTION_ID) #define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID) -#define CLOSURE_IS_AMBIENT_OCCLUSION(type) (type == CLOSURE_AMBIENT_OCCLUSION_ID) #define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID) #define CLOSURE_IS_GLASS(type) (type >= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID && type <= CLOSURE_BSDF_SHARP_GLASS_ID) #define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID) diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 0f2581b2a2e..680174f6d98 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -2795,11 +2795,17 @@ NODE_DEFINE(AmbientOcclusionNode) { NodeType* type = NodeType::add("ambient_occlusion", create, NodeType::SHADER); - SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL); + SOCKET_INT(samples, "Samples", 8); + SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f)); - SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + SOCKET_IN_FLOAT(distance, "Distance", 1.0f); + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); - SOCKET_OUT_CLOSURE(AO, "AO"); + SOCKET_BOOLEAN(inside, "Inside", false); + SOCKET_BOOLEAN(only_local, "Only Local", true); + + SOCKET_OUT_COLOR(color, "Color"); + SOCKET_OUT_FLOAT(ao, "AO"); return type; } @@ -2812,17 +2818,33 @@ AmbientOcclusionNode::AmbientOcclusionNode() void AmbientOcclusionNode::compile(SVMCompiler& compiler) { ShaderInput *color_in = input("Color"); + ShaderInput *distance_in = input("Distance"); + ShaderInput *normal_in = input("Normal"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *ao_out = output("AO"); - if(color_in->link) - compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in)); - else - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color); + int flags = (inside? NODE_AO_INSIDE : 0) | (only_local? NODE_AO_ONLY_LOCAL : 0); - compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset()); + if (!distance_in->link && distance == 0.0f) { + flags |= NODE_AO_GLOBAL_RADIUS; + } + + compiler.add_node(NODE_AMBIENT_OCCLUSION, + compiler.encode_uchar4(flags, + compiler.stack_assign_if_linked(distance_in), + compiler.stack_assign_if_linked(normal_in), + compiler.stack_assign(ao_out)), + compiler.encode_uchar4(compiler.stack_assign(color_in), + compiler.stack_assign(color_out), + samples), + __float_as_uint(distance)); } void AmbientOcclusionNode::compile(OSLCompiler& compiler) { + compiler.parameter(this, "samples"); + compiler.parameter(this, "inside"); + compiler.parameter(this, "only_local"); compiler.add(this, "node_ambient_occlusion"); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 35a7df690c3..be52cf40a17 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -538,12 +538,16 @@ public: SHADER_NODE_CLASS(AmbientOcclusionNode) bool has_spatial_varying() { return true; } - virtual int get_group() { return NODE_GROUP_LEVEL_1; } - virtual ClosureType get_closure_type() { return CLOSURE_AMBIENT_OCCLUSION_ID; } + virtual int get_group() { return NODE_GROUP_LEVEL_3; } + virtual bool has_raytrace() { return true; } - float3 normal_osl; float3 color; - float surface_mix_weight; + float distance; + float3 normal; + int samples; + + bool only_local; + bool inside; }; class VolumeNode : public ShaderNode { diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 60a8471ca3b..3826b2b10de 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -208,6 +208,7 @@ shader_node_categories = [ NodeItem("ShaderNodeNewGeometry"), NodeItem("ShaderNodeWireframe"), NodeItem("ShaderNodeBevel"), + NodeItem("ShaderNodeAmbientOcclusion"), NodeItem("ShaderNodeObjectInfo"), NodeItem("ShaderNodeHairInfo"), NodeItem("ShaderNodeParticleInfo"), @@ -240,7 +241,6 @@ shader_node_categories = [ NodeItem("ShaderNodeEmission", poll=object_shader_nodes_poll), NodeItem("ShaderNodeBsdfHair", poll=object_shader_nodes_poll), NodeItem("ShaderNodeBackground", poll=world_shader_nodes_poll), - NodeItem("ShaderNodeAmbientOcclusion", poll=object_shader_nodes_poll), NodeItem("ShaderNodeHoldout", poll=object_shader_nodes_poll), NodeItem("ShaderNodeVolumeAbsorption"), NodeItem("ShaderNodeVolumeScatter"), diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index b5d906b2968..a3da6d5016e 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -28,7 +28,7 @@ * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 279 -#define BLENDER_SUBVERSION 4 +#define BLENDER_SUBVERSION 5 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index e1b91726821..6d352bd7b13 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1753,7 +1753,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - { + if (!MAIN_VERSION_ATLEAST(bmain, 279, 4)) { /* Fix for invalid state of screen due to bug in older versions. */ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 63bd305c13d..fff6c5d9f2c 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1168,6 +1168,13 @@ static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), Pointe uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE); } +static void node_shader_buts_ambient_occlusion(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "inside", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "only_local", 0, NULL, ICON_NONE); +} + /* only once called */ static void node_shader_set_butfunc(bNodeType *ntype) { @@ -1311,6 +1318,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_BEVEL: ntype->draw_buttons = node_shader_buts_bevel; break; + case SH_NODE_AMBIENT_OCCLUSION: + ntype->draw_buttons = node_shader_buts_ambient_occlusion; + break; } } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index ba8f33f75be..ce9e82b34f8 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2785,9 +2785,10 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out ve node_bsdf_diffuse(color, 0.0, N, result); } -void node_ambient_occlusion(vec4 color, out vec4 result) +void node_ambient_occlusion(vec4 color, float distance, vec3 normal, out vec4 result_color, out float result_ao) { - result = color; + result_color = color; + result_ao = 1.0; } /* emission */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6aa87cdbde2..3cbcc86a692 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1045,6 +1045,9 @@ typedef struct NodeSunBeams { #define SHD_SPACE_BLENDER_OBJECT 3 #define SHD_SPACE_BLENDER_WORLD 4 +#define SHD_AO_INSIDE 1 +#define SHD_AO_LOCAL 2 + /* math node clamp */ #define SHD_MATH_CLAMP 1 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 9bb5117cba3..1c7875873c2 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4484,6 +4484,27 @@ static void def_sh_bevel(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_Node_update"); } +static void def_sh_ambient_occlusion(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "samples", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "custom1"); + RNA_def_property_range(prop, 1, 128); + RNA_def_property_ui_text(prop, "Samples", "Number of rays to trace per shader evaluation"); + RNA_def_property_update(prop, 0, "rna_Node_update"); + + prop = RNA_def_property(srna, "inside", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_AO_INSIDE); + RNA_def_property_ui_text(prop, "Inside", "Trace rays towards the inside of the object"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "only_local", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_AO_LOCAL); + RNA_def_property_ui_text(prop, "Only Local", "Only consider the object itself when computing AO"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_sh_subsurface(StructRNA *srna) { static const EnumPropertyItem prop_subsurface_falloff_items[] = { diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 5864b3deb39..5217c7dc6e7 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -75,7 +75,7 @@ DefNode( ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LA DefNode( ShaderNode, SH_NODE_MIX_SHADER, 0, "MIX_SHADER", MixShader, "Mix Shader", "" ) DefNode( ShaderNode, SH_NODE_ADD_SHADER, 0, "ADD_SHADER", AddShader, "Add Shader", "" ) DefNode( ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "ATTRIBUTE", Attribute, "Attribute", "" ) -DefNode( ShaderNode, SH_NODE_AMBIENT_OCCLUSION, 0, "AMBIENT_OCCLUSION", AmbientOcclusion, "Ambient Occlusion", "" ) +DefNode( ShaderNode, SH_NODE_AMBIENT_OCCLUSION, def_sh_ambient_occlusion,"AMBIENT_OCCLUSION", AmbientOcclusion, "Ambient Occlusion", "" ) DefNode( ShaderNode, SH_NODE_BACKGROUND, 0, "BACKGROUND", Background, "Background", "" ) DefNode( ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "" ) DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "" ) diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c index f0a0b70eecb..cad0fcaa14f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c +++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c @@ -31,11 +31,14 @@ static bNodeSocketTemplate sh_node_ambient_occlusion_in[] = { { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 0, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, { -1, 0, "" } }; static bNodeSocketTemplate sh_node_ambient_occlusion_out[] = { - { SOCK_SHADER, 0, N_("AO")}, + { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 0, N_("AO"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { -1, 0, "" } }; @@ -44,15 +47,21 @@ static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat, bNode *UNUSED(nod return GPU_stack_link(mat, "node_ambient_occlusion", in, out, GPU_builtin(GPU_VIEW_NORMAL)); } +static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *node) +{ + node->custom1 = 8; /* samples */ + node->custom2 = SHD_AO_LOCAL; +} + /* node type definition */ void register_node_type_sh_ambient_occlusion(void) { static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_SHADER, 0); + sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT, 0); node_type_compatibility(&ntype, NODE_NEW_SHADING); node_type_socket_templates(&ntype, sh_node_ambient_occlusion_in, sh_node_ambient_occlusion_out); - node_type_init(&ntype, NULL); + node_type_init(&ntype, node_shader_init_ambient_occlusion); node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_ambient_occlusion); |