Cycles: Ray Portal BSDF

Transport rays that enter to another location in the scene, with
specified ray position and normal. This may be used to render portals
for visual effects, and other production rendering tricks.

This acts much like a Transparent BSDF. Render passes are passed
through, and this is affected by light path max transparent bounces.

Pull Request: https://projects.blender.org/blender/blender/pulls/114386
This commit is contained in:
David Murmann 2024-04-29 12:37:51 +02:00 committed by Brecht Van Lommel
parent 12f0f56350
commit ee51f643b0
32 changed files with 330 additions and 9 deletions

@ -667,6 +667,9 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
node = graph->create_node<TransparentBsdfNode>();
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfRayPortal)) {
node = graph->create_node<RayPortalBsdfNode>();
}
else if (b_node.is_a(&RNA_ShaderNodeBsdfSheen)) {
BL::ShaderNodeBsdfSheen b_sheen_node(b_node);
SheenBsdfNode *sheen = graph->create_node<SheenBsdfNode>();

@ -129,6 +129,7 @@ set(SRC_KERNEL_CLOSURE_HEADERS
closure/bsdf_microfacet.h
closure/bsdf_oren_nayar.h
closure/bsdf_phong_ramp.h
closure/bsdf_ray_portal.h
closure/bsdf_sheen.h
closure/bsdf_toon.h
closure/bsdf_transparent.h

@ -13,6 +13,7 @@
#include "kernel/closure/bsdf_microfacet.h"
#include "kernel/closure/bsdf_sheen.h"
#include "kernel/closure/bsdf_transparent.h"
#include "kernel/closure/bsdf_ray_portal.h"
#include "kernel/closure/bsdf_ashikhmin_shirley.h"
#include "kernel/closure/bsdf_toon.h"
#include "kernel/closure/bsdf_hair.h"
@ -157,6 +158,10 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
*sampled_roughness = zero_float2();
*eta = 1.0f;
break;
case CLOSURE_BSDF_RAY_PORTAL_ID:
/* ray portals are not handled by the BSDF code, we should never get here */
kernel_assert(false);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:
@ -289,6 +294,7 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
*eta = 1.0f;
break;
case CLOSURE_BSDF_TRANSPARENT_ID:
case CLOSURE_BSDF_RAY_PORTAL_ID:
*roughness = zero_float2();
*eta = 1.0f;
break;
@ -389,6 +395,9 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
case CLOSURE_BSDF_TRANSPARENT_ID:
label = LABEL_TRANSMIT | LABEL_TRANSPARENT;
break;
case CLOSURE_BSDF_RAY_PORTAL_ID:
label = LABEL_TRANSMIT | LABEL_RAY_PORTAL;
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
@ -488,6 +497,9 @@ ccl_device_inline
case CLOSURE_BSDF_TRANSPARENT_ID:
eval = bsdf_transparent_eval(sc, sd->wi, wo, pdf);
break;
case CLOSURE_BSDF_RAY_PORTAL_ID:
eval = bsdf_ray_portal_eval(sc, sd->wi, wo, pdf);
break;
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID:

@ -0,0 +1,53 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: Apache-2.0 */
#pragma once
CCL_NAMESPACE_BEGIN
typedef struct RayPortalClosure {
SHADER_CLOSURE_BASE;
float3 P;
float3 D;
} RayPortalClosure;
static_assert(sizeof(ShaderClosure) >= sizeof(RayPortalClosure), "RayPortalClosure is too large!");
ccl_device void bsdf_ray_portal_setup(ccl_private ShaderData *sd,
const Spectrum weight,
uint32_t path_flag,
float3 position,
float3 direction)
{
/* Check cutoff weight. */
float sample_weight = fabsf(average(weight));
if (!(sample_weight >= CLOSURE_WEIGHT_CUTOFF)) {
return;
}
sd->closure_transparent_extinction += weight;
sd->flag |= SD_BSDF | SD_RAY_PORTAL;
ccl_private RayPortalClosure *pc = (ccl_private RayPortalClosure *)closure_alloc(
sd, sizeof(RayPortalClosure), CLOSURE_BSDF_RAY_PORTAL_ID, weight);
if (pc) {
pc->sample_weight = sample_weight;
pc->N = sd->N;
pc->P = position;
pc->D = direction;
}
}
ccl_device Spectrum bsdf_ray_portal_eval(ccl_private const ShaderClosure *sc,
const float3 wi,
const float3 wo,
ccl_private float *pdf)
{
*pdf = 0.0f;
return zero_spectrum();
}
CCL_NAMESPACE_END

@ -19,9 +19,9 @@ ccl_device void bsdf_transparent_setup(ccl_private ShaderData *sd,
return;
}
if (sd->flag & SD_TRANSPARENT) {
sd->closure_transparent_extinction += weight;
sd->closure_transparent_extinction += weight;
if (sd->flag & SD_TRANSPARENT) {
/* Add weight to existing transparent BSDF. */
for (int i = 0; i < sd->num_closure; i++) {
ccl_private ShaderClosure *sc = &sd->closure[i];
@ -35,7 +35,6 @@ ccl_device void bsdf_transparent_setup(ccl_private ShaderData *sd,
}
else {
sd->flag |= SD_BSDF | SD_TRANSPARENT;
sd->closure_transparent_extinction = weight;
if (path_flag & PATH_RAY_TERMINATE) {
/* In this case the number of closures is set to zero to disable

@ -68,7 +68,8 @@ ccl_device_inline void film_write_data_passes(KernelGlobals kg,
}
}
if (!(sd->flag & SD_TRANSPARENT) || kernel_data.film.pass_alpha_threshold == 0.0f ||
if (!(sd->flag & (SD_TRANSPARENT | SD_RAY_PORTAL)) ||
kernel_data.film.pass_alpha_threshold == 0.0f ||
average(surface_shader_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold)
{
if (flag & PASSMASK(NORMAL)) {

@ -107,7 +107,7 @@ ccl_device_inline void path_state_next(KernelGlobals kg,
/* ray through transparent keeps same flags from previous ray and is
* not counted as a regular bounce, transparent has separate max */
if (label & LABEL_TRANSPARENT) {
if (label & (LABEL_TRANSPARENT | LABEL_RAY_PORTAL)) {
uint32_t transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce) + 1;
flag |= PATH_RAY_TRANSPARENT;
@ -115,6 +115,10 @@ ccl_device_inline void path_state_next(KernelGlobals kg,
flag |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE;
}
if (shader_flag & SD_RAY_PORTAL) {
flag |= PATH_RAY_MIS_SKIP;
}
INTEGRATOR_STATE_WRITE(state, path, flag) = flag;
INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = transparent_bounce;
/* Random number generator next bounce. */

@ -51,6 +51,11 @@ ccl_device_inline Spectrum integrate_transparent_surface_shadow(KernelGlobals kg
shadow_volume_stack_enter_exit(kg, state, shadow_sd);
# endif
/* Disable transparent shadows for ray portals */
if (shadow_sd->flag & SD_RAY_PORTAL) {
return zero_spectrum();
}
/* Compute transparency from closures. */
return surface_shader_transparency(kg, shadow_sd);
}

@ -146,6 +146,50 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
kg, state, L, mis_weight, render_buffer, object_lightgroup(kg, sd->object));
}
ccl_device int integrate_surface_ray_portal(KernelGlobals kg,
IntegratorState state,
ccl_private ShaderData *sd,
ccl_private const ShaderClosure *sc)
{
ccl_private const RayPortalClosure *pc = (ccl_private const RayPortalClosure *)sc;
float sum_sample_weight = 0.0f;
for (int i = 0; i < sd->num_closure; i++) {
ccl_private const ShaderClosure *sc = &sd->closure[i];
if (CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) {
sum_sample_weight += sc->sample_weight;
}
}
if (sum_sample_weight <= 0.0f) {
return LABEL_NONE;
}
if (len_squared(sd->P - pc->P) > 1e-9f) {
/* if the ray origin is changed, unset the current object,
* so we can potentially hit the same polygon again */
INTEGRATOR_STATE_WRITE(state, isect, object) = OBJECT_NONE;
INTEGRATOR_STATE_WRITE(state, ray, P) = pc->P;
}
else {
INTEGRATOR_STATE_WRITE(state, ray, P) = integrate_surface_ray_offset(kg, sd, pc->P, pc->D);
}
INTEGRATOR_STATE_WRITE(state, ray, D) = pc->D;
INTEGRATOR_STATE_WRITE(state, ray, tmin) = 0.0f;
INTEGRATOR_STATE_WRITE(state, ray, tmax) = FLT_MAX;
#ifdef __RAY_DIFFERENTIALS__
INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
#endif
const float pick_pdf = pc->sample_weight / sum_sample_weight;
INTEGRATOR_STATE_WRITE(state, path, throughput) *= pc->weight / pick_pdf;
int label = LABEL_TRANSMIT | LABEL_RAY_PORTAL;
path_state_next(kg, state, label, sd->flag);
return label;
}
/* Branch off a shadow path and initialize common part of it.
* THe common is between the surface shading and configuration of a special shadow ray for the
* shadow linking. */
@ -400,6 +444,9 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
return subsurface_bounce(kg, state, sd, sc);
}
#endif
if (CLOSURE_IS_RAY_PORTAL(sc->type)) {
return integrate_surface_ray_portal(kg, state, sd, sc);
}
/* BSDF closure, sample direction. */
float bsdf_pdf = 0.0f, unguided_bsdf_pdf = 0.0f;

@ -953,7 +953,7 @@ ccl_device Spectrum surface_shader_transparency(KernelGlobals kg, ccl_private co
if (sd->flag & SD_HAS_ONLY_VOLUME) {
return one_spectrum();
}
else if (sd->flag & SD_TRANSPARENT) {
else if (sd->flag & (SD_TRANSPARENT | SD_RAY_PORTAL)) {
return sd->closure_transparent_extinction;
}
else {
@ -1174,6 +1174,7 @@ ccl_device void surface_shader_eval(KernelGlobals kg,
sd->num_closure = 0;
sd->num_closure_left = max_closures;
sd->closure_transparent_extinction = zero_spectrum();
#ifdef __OSL__
if (kernel_data.kernel_features & KERNEL_FEATURE_OSL) {

@ -197,6 +197,17 @@ ccl_device void osl_closure_transparent_setup(KernelGlobals kg,
bsdf_transparent_setup(sd, rgb_to_spectrum(weight), path_flag);
}
ccl_device void osl_closure_ray_portal_bsdf_setup(KernelGlobals kg,
ccl_private ShaderData *sd,
uint32_t path_flag,
float3 weight,
ccl_private const RayPortalBSDFClosure *closure,
float3 *layer_albedo)
{
bsdf_ray_portal_setup(
sd, rgb_to_spectrum(weight), path_flag, closure->position, closure->direction);
}
/* MaterialX closures */
ccl_device void osl_closure_dielectric_bsdf_setup(KernelGlobals kg,
ccl_private ShaderData *sd,

@ -40,6 +40,11 @@ OSL_CLOSURE_STRUCT_END(Refraction, refraction)
OSL_CLOSURE_STRUCT_BEGIN(Transparent, transparent)
OSL_CLOSURE_STRUCT_END(Transparent, transparent)
OSL_CLOSURE_STRUCT_BEGIN(RayPortalBSDF, ray_portal_bsdf)
OSL_CLOSURE_STRUCT_MEMBER(RayPortalBSDF, VECTOR, packed_float3, position, NULL)
OSL_CLOSURE_STRUCT_MEMBER(RayPortalBSDF, VECTOR, packed_float3, direction, NULL)
OSL_CLOSURE_STRUCT_END(RayPortalBSDF, ray_portal_bsdf)
OSL_CLOSURE_STRUCT_BEGIN(DielectricBSDF, dielectric_bsdf)
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, VECTOR, packed_float3, N, NULL)
OSL_CLOSURE_STRUCT_MEMBER(DielectricBSDF, VECTOR, packed_float3, T, NULL)

@ -69,6 +69,7 @@ set(SRC_OSL
node_output_surface.osl
node_output_volume.osl
node_particle_info.osl
node_ray_portal_bsdf.osl
node_refraction_bsdf.osl
node_rgb_curves.osl
node_rgb_ramp.osl

@ -0,0 +1,13 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#include "stdcycles.h"
shader node_ray_portal_bsdf(color Color = 0.8,
vector Position = vector(0.0, 0.0, 0.0),
vector Direction = vector(0.0, 0.0, 0.0),
output closure color BSDF = 0)
{
BSDF = Color * ray_portal_bsdf(Position, Direction);
}

@ -63,4 +63,7 @@ closure color hair_huang(normal N,
closure color henyey_greenstein(float g) BUILTIN;
closure color absorption() BUILTIN;
// Ray Portal
closure color ray_portal_bsdf(vector position, vector direction) BUILTIN;
#endif /* CCL_STDOSL_H */

@ -454,6 +454,17 @@ ccl_device
bsdf_transparent_setup(sd, weight, path_flag);
break;
}
case CLOSURE_BSDF_RAY_PORTAL_ID: {
Spectrum weight = closure_weight * mix_weight;
float3 position = stack_load_float3(stack, data_node.y);
float3 direction = stack_load_float3(stack, data_node.z);
if (is_zero(direction)) {
direction = -sd->wi;
}
bsdf_ray_portal_setup(sd, weight, path_flag, position, direction);
break;
}
case CLOSURE_BSDF_MICROFACET_GGX_ID:
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:

@ -448,6 +448,7 @@ typedef enum ClosureType {
CLOSURE_BSDF_HAIR_HUANG_ID,
/* Special cases */
CLOSURE_BSDF_RAY_PORTAL_ID,
CLOSURE_BSDF_TRANSPARENT_ID,
/* BSSRDF */
@ -478,7 +479,8 @@ typedef enum ClosureType {
#define CLOSURE_IS_BSDF_TRANSMISSION(type) \
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
#define CLOSURE_IS_BSDF_SINGULAR(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
#define CLOSURE_IS_BSDF_SINGULAR(type) \
(type == CLOSURE_BSDF_TRANSPARENT_ID || type == CLOSURE_BSDF_RAY_PORTAL_ID)
#define CLOSURE_IS_BSDF_TRANSPARENT(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
#define CLOSURE_IS_BSDF_MULTISCATTER(type) \
(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID || \
@ -506,6 +508,7 @@ typedef enum ClosureType {
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && \
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID)
#define CLOSURE_IS_RAY_PORTAL(type) (type == CLOSURE_BSDF_RAY_PORTAL_ID)
#define CLOSURE_WEIGHT_CUTOFF 1e-5f
/* Treat closure as singular if the squared roughness is below this threshold. */

@ -364,6 +364,7 @@ typedef enum ClosureLabel {
LABEL_VOLUME_SCATTER = 64,
LABEL_TRANSMIT_TRANSPARENT = 128,
LABEL_SUBSURFACE_SCATTER = 256,
LABEL_RAY_PORTAL = 512,
} ClosureLabel;
/* Render Passes */
@ -835,9 +836,12 @@ enum ShaderDataFlag {
SD_BSDF_NEEDS_LCG = (1 << 10),
/* BSDF has a transmissive component. */
SD_BSDF_HAS_TRANSMISSION = (1 << 11),
/* Shader has ray portal closure. */
SD_RAY_PORTAL = (1 << 12),
SD_CLOSURE_FLAGS = (SD_EMISSION | SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSSRDF | SD_HOLDOUT |
SD_EXTINCTION | SD_SCATTER | SD_BSDF_NEEDS_LCG | SD_BSDF_HAS_TRANSMISSION),
SD_EXTINCTION | SD_SCATTER | SD_BSDF_NEEDS_LCG | SD_BSDF_HAS_TRANSMISSION |
SD_RAY_PORTAL),
/* Shader flags. */

@ -2879,6 +2879,38 @@ void TransparentBsdfNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_transparent_bsdf");
}
/* Ray Portal BSDF Closure */
NODE_DEFINE(RayPortalBsdfNode)
{
NodeType *type = NodeType::add("ray_portal_bsdf", create, NodeType::SHADER);
SOCKET_IN_COLOR(color, "Color", one_float3());
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_IN_VECTOR(position, "Position", zero_float3(), SocketType::LINK_POSITION);
SOCKET_IN_VECTOR(direction, "Direction", zero_float3());
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
}
RayPortalBsdfNode::RayPortalBsdfNode() : BsdfNode(get_node_type())
{
closure = CLOSURE_BSDF_RAY_PORTAL_ID;
}
void RayPortalBsdfNode::compile(SVMCompiler &compiler)
{
BsdfNode::compile(compiler, NULL, NULL, input("Position"), input("Direction"));
}
void RayPortalBsdfNode::compile(OSLCompiler &compiler)
{
compiler.add(this, "node_ray_portal_bsdf");
}
/* Subsurface Scattering Closure */
NODE_DEFINE(SubsurfaceScatteringNode)

@ -562,6 +562,19 @@ class TransparentBsdfNode : public BsdfNode {
}
};
class RayPortalBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(RayPortalBsdfNode)
NODE_SOCKET_API(float3, position)
NODE_SOCKET_API(float3, direction)
bool has_surface_transparent()
{
return true;
}
};
class SheenBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(SheenBsdfNode)

@ -184,6 +184,11 @@ class NODE_MT_category_shader_shader(Menu):
layout,
"ShaderNodeVolumePrincipled"
)
node_add_menu.add_node_type(
layout,
"ShaderNodeBsdfRayPortal",
poll=object_not_eevee_shader_nodes_poll(context),
)
node_add_menu.add_node_type(
layout,
"ShaderNodeBsdfRefraction",

@ -917,6 +917,7 @@ void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index
#define SH_NODE_COMBINE_COLOR 711
#define SH_NODE_SEPARATE_COLOR 712
#define SH_NODE_MIX 713
#define SH_NODE_BSDF_RAY_PORTAL 714
/** \} */

@ -567,6 +567,8 @@ static const char *node_get_static_idname(int type, int treetype)
return "ShaderNodeBsdfTranslucent";
case SH_NODE_BSDF_TRANSPARENT:
return "ShaderNodeBsdfTransparent";
case SH_NODE_BSDF_RAY_PORTAL:
return "ShaderNodeBsdfRayPortal";
case /*SH_NODE_BSDF_VELVET*/ 139:
return "ShaderNodeBsdfVelvet";
case /*SH_NODE_VOLUME_TRANSPARENT*/ 161:

@ -569,6 +569,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_particle_info.glsl
shaders/material/gpu_shader_material_point_info.glsl
shaders/material/gpu_shader_material_principled.glsl
shaders/material/gpu_shader_material_ray_portal.glsl
shaders/material/gpu_shader_material_refraction.glsl
shaders/material/gpu_shader_material_rgb_to_bw.glsl
shaders/material/gpu_shader_material_separate_color.glsl

@ -0,0 +1,14 @@
/* SPDX-FileCopyrightText: 2019-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
void node_bsdf_ray_portal(
vec4 color, vec3 position, vec3 direction, float weight, out Closure result)
{
ClosureTransparency transparency_data;
transparency_data.weight = weight;
transparency_data.transmittance = color.rgb;
transparency_data.holdout = 0.0;
result = closure_eval(transparency_data);
}

@ -68,6 +68,7 @@ DefNode(ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSD
DefNode(ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "Glossy refraction with sharp or microfacet distribution, typically used for materials that transmit light")
DefNode(ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "Lambertian diffuse transmission")
DefNode(ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "Transparency without refraction, passing straight through the surface as if there were no geometry")
DefNode(ShaderNode, SH_NODE_BSDF_RAY_PORTAL, 0, "BSDF_RAY_PORTAL", BsdfRayPortal, "Ray Portal BSDF", "Continue tracing from an arbitrary new position and in a new direction")
DefNode(ShaderNode, SH_NODE_BSDF_SHEEN, def_sheen, "BSDF_SHEEN", BsdfSheen, "Sheen BSDF", "Reflection for materials such as cloth.\nTypically mixed with other shaders (such as a Diffuse Shader) and is not particularly useful on its own")
DefNode(ShaderNode, SH_NODE_BSDF_TOON, def_toon, "BSDF_TOON", BsdfToon, "Toon BSDF", "Diffuse and Glossy shaders with cartoon light effects")
DefNode(ShaderNode, SH_NODE_BSDF_HAIR, def_hair, "BSDF_HAIR", BsdfHair, "Hair BSDF", "Reflection and transmission shaders optimized for hair rendering")

@ -37,6 +37,7 @@ set(SRC
nodes/node_shader_bsdf_hair.cc
nodes/node_shader_bsdf_hair_principled.cc
nodes/node_shader_bsdf_principled.cc
nodes/node_shader_bsdf_ray_portal.cc
nodes/node_shader_bsdf_refraction.cc
nodes/node_shader_bsdf_sheen.cc
nodes/node_shader_bsdf_toon.cc

@ -25,6 +25,7 @@ void register_shader_nodes()
register_node_type_sh_bsdf_hair_principled();
register_node_type_sh_bsdf_hair();
register_node_type_sh_bsdf_principled();
register_node_type_sh_bsdf_ray_portal();
register_node_type_sh_bsdf_refraction();
register_node_type_sh_bsdf_toon();
register_node_type_sh_bsdf_translucent();

@ -21,6 +21,7 @@ void register_node_type_sh_bsdf_glossy();
void register_node_type_sh_bsdf_hair_principled();
void register_node_type_sh_bsdf_hair();
void register_node_type_sh_bsdf_principled();
void register_node_type_sh_bsdf_ray_portal();
void register_node_type_sh_bsdf_refraction();
void register_node_type_sh_bsdf_toon();
void register_node_type_sh_bsdf_translucent();

@ -922,6 +922,7 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
case SH_NODE_BSDF_HAIR_PRINCIPLED:
case SH_NODE_BSDF_HAIR:
case SH_NODE_BSDF_PRINCIPLED:
case SH_NODE_BSDF_RAY_PORTAL:
case SH_NODE_BSDF_REFRACTION:
case SH_NODE_BSDF_TOON:
case SH_NODE_BSDF_TRANSLUCENT:
@ -979,6 +980,7 @@ static bool closure_node_filter(const bNode *node)
case SH_NODE_BSDF_HAIR_PRINCIPLED:
case SH_NODE_BSDF_HAIR:
case SH_NODE_BSDF_PRINCIPLED:
case SH_NODE_BSDF_RAY_PORTAL:
case SH_NODE_BSDF_REFRACTION:
case SH_NODE_BSDF_TOON:
case SH_NODE_BSDF_TRANSLUCENT:

@ -0,0 +1,70 @@
/* SPDX-FileCopyrightText: 2005 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "node_shader_util.hh"
#include "BLI_math_vector.h"
namespace blender::nodes::node_shader_bsdf_ray_portal_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_input<decl::Vector>("Position").hide_value();
b.add_input<decl::Vector>("Direction").hide_value();
b.add_input<decl::Float>("Weight").unavailable();
b.add_output<decl::Shader>("BSDF");
}
static int node_shader_gpu_bsdf_ray_portal(GPUMaterial *mat,
bNode *node,
bNodeExecData * /*execdata*/,
GPUNodeStack *in,
GPUNodeStack *out)
{
if (in[0].link || !is_zero_v3(in[0].vec)) {
GPU_material_flag_set(mat, GPU_MATFLAG_TRANSPARENT);
}
return GPU_stack_link(mat, node, "node_bsdf_ray_portal", in, out);
}
NODE_SHADER_MATERIALX_BEGIN
#ifdef WITH_MATERIALX
{
switch (to_type_) {
case NodeItem::Type::BSDF: {
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
/* Returning diffuse node as BSDF component */
return create_node("oren_nayar_diffuse_bsdf", NodeItem::Type::BSDF, {{"color", color}});
}
case NodeItem::Type::SurfaceOpacity: {
NodeItem color = get_input_value("Color", NodeItem::Type::Color3);
/* Returning: 1 - <average of color components> */
return val(1.0f) - color.dotproduct(val(1.0f / 3.0f));
}
default:
break;
}
return empty();
}
#endif
NODE_SHADER_MATERIALX_END
} // namespace blender::nodes::node_shader_bsdf_ray_portal_cc
/* node type definition */
void register_node_type_sh_bsdf_ray_portal()
{
namespace file_ns = blender::nodes::node_shader_bsdf_ray_portal_cc;
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_BSDF_RAY_PORTAL, "Ray Portal BSDF", NODE_CLASS_SHADER);
ntype.add_ui_poll = object_shader_nodes_poll;
ntype.declare = file_ns::node_declare;
ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_ray_portal;
ntype.materialx_fn = file_ns::node_shader_materialx;
nodeRegisterType(&ntype);
}

@ -1 +1 @@
Subproject commit 07eb1ed864d9fd6006dc24c7b2dcb05f58ddd945
Subproject commit 4f37cd18510607d2a5e97699a4aaae6d8738c0ba