Cycles: change Ambient Occlusion shader to output colors.

This means the shader can now be used for procedural texturing. New
settings on the node are Samples, Inside, Local Only and Distance.

Original patch by Lukas with further changes by Brecht.

Differential Revision: https://developer.blender.org/D3479
This commit is contained in:
Lukas Stockner 2018-06-15 11:03:29 +02:00 committed by Brecht Van Lommel
parent 2b9edbc98b
commit 799779d432
Notes: blender-bot 2023-02-13 23:39:48 +01:00
Referenced by issue #77106, Crash when baking diffuse map. (EXCEPTION_ACCESS_VIOLATION)
34 changed files with 403 additions and 162 deletions

View File

@ -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()

View File

@ -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();

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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);

View File

@ -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. */

View File

@ -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

View File

@ -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++,

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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_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_INT(samples, "Samples", 8);
SOCKET_OUT_CLOSURE(AO, "AO");
SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
SOCKET_IN_FLOAT(distance, "Distance", 1.0f);
SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
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");
}

View File

@ -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 {

View File

@ -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"),

View File

@ -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

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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

View File

@ -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[] = {

View File

@ -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", "" )

View File

@ -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);