/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "kernel/globals.h" #include "kernel/geom/attribute.h" #include "kernel/geom/object.h" #include "kernel/geom/primitive.h" #include "kernel/geom/volume.h" #include "kernel/svm/node_types.h" #include "kernel/svm/util.h" CCL_NAMESPACE_BEGIN /* Attribute Node */ ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals kg, ccl_private ShaderData *sd, const ccl_global SVMNodeAttr &ccl_restrict node, ccl_private NodeAttributeOutputType *type) { *type = node.output_type; AttributeDescriptor desc; if (sd->object != OBJECT_NONE) { desc = find_attribute(kg, sd, node.attr); if (!is_attribute_found(desc)) { desc = attribute_not_found(); desc.type = (NodeAttributeType)node.output_type; } } else { /* background */ desc = attribute_not_found(); desc.type = (NodeAttributeType)node.output_type; } return desc; } /* Store attribute to the stack. Float3Type is float3 or dual3. */ template ccl_device_inline void svm_node_attr_store(const NodeAttributeOutputType type, ccl_private float *stack, const uint out_offset, const ccl_private Float3Type &f) { using FloatType = dual_scalar_t; if (type == NODE_ATTR_OUTPUT_FLOAT3) { stack_store(stack, out_offset, f); } else { stack_store(stack, out_offset, FloatType(average(f))); } } /* Core surface attribute evaluation, returning Float3Type = float3 or dual3. * Fetches the attribute, applies output type conversion (float3 or scalar-as-float3), * and computes derivatives when Float3Type is a dual type. */ template ccl_device_inline Float3Type svm_node_attr_surface_eval(KernelGlobals kg, ccl_private ShaderData *sd, const ccl_global SVMNodeAttr &ccl_restrict node, const NodeAttributeOutputType type, const AttributeDescriptor desc) { using FloatType = dual_scalar_t; if (sd->type == PRIMITIVE_LAMP && node.attr == ATTR_STD_UV) { Float3Type uv(make_float3(1.0f - sd->u - sd->v, sd->u, 0.0f)); if constexpr (is_dual_v) { uv.dx = make_float3(-sd->du.dx - sd->dv.dx, sd->du.dx, 0.0f); uv.dy = make_float3(-sd->du.dy - sd->dv.dy, sd->du.dy, 0.0f); } return uv; } if (node.attr == ATTR_STD_GENERATED && !is_attribute_found(desc)) { Float3Type f = shading_position(sd); object_inverse_position_transform_if_object(kg, sd, &f); return f; } /* Surface attribute fetch with output type conversion. */ if (desc.type == NODE_ATTR_FLOAT) { FloatType f = primitive_surface_attribute(kg, sd, desc); if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) { return make_float3(FloatType(1.0f)); } return make_float3(f, f, f); } if (desc.type == NODE_ATTR_FLOAT2) { if constexpr (is_dual_v) { dual2 f = primitive_surface_attribute(kg, sd, desc); if (type == NODE_ATTR_OUTPUT_FLOAT) { return make_float3(f.x()); } if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) { return make_float3(FloatType(1.0f)); } return make_float3(f); } else { float2 f = primitive_surface_attribute(kg, sd, desc); if (type == NODE_ATTR_OUTPUT_FLOAT) { return make_float3(f.x); } if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) { return make_float3(FloatType(1.0f)); } return make_float3(f); } } if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) { if constexpr (is_dual_v) { dual4 f = primitive_surface_attribute(kg, sd, desc); if (type == NODE_ATTR_OUTPUT_FLOAT) { return make_float3(average(make_float3(f))); } if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) { return make_float3(f.w()); } return make_float3(f); } else { float4 f = primitive_surface_attribute(kg, sd, desc); if (type == NODE_ATTR_OUTPUT_FLOAT) { return make_float3(average(make_float3(f))); } if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) { return make_float3(f.w); } return make_float3(f); } } Float3Type f = primitive_surface_attribute(kg, sd, desc); if (type == NODE_ATTR_OUTPUT_FLOAT) { return make_float3(average(f)); } if (type == NODE_ATTR_OUTPUT_FLOAT_ALPHA) { return make_float3(FloatType(1.0f)); } return f; } /* Surface attribute node. */ ccl_device_noinline void svm_node_attr_surface(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *ccl_restrict stack, const ccl_global SVMNodeAttr &ccl_restrict node) { NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT; const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type); float3 data = svm_node_attr_surface_eval(kg, sd, node, type, desc); svm_node_attr_store(type, stack, node.out_offset, data); } /* Evaluate surface attributes with derivatives and optional bump offset. * Used for derivative tracking and bump mapping. */ ccl_device_noinline void svm_node_attr_derivative(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *ccl_restrict stack, const ccl_global SVMNodeAttr &ccl_restrict node) { NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT; const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type); dual3 data = svm_node_attr_surface_eval(kg, sd, node, type, desc); if (node.bump_offset == NODE_BUMP_OFFSET_DX) { data.val += data.dx * node.bump_filter_width; } else if (node.bump_offset == NODE_BUMP_OFFSET_DY) { data.val += data.dy * node.bump_filter_width; } if (node.store_derivatives) { svm_node_attr_store(type, stack, node.out_offset, data); } else { svm_node_attr_store(type, stack, node.out_offset, float3(data.val)); } } #ifdef __VOLUME__ /* Volume attribute node. Volumes have no derivatives or bump. */ ccl_device_noinline void svm_node_attr_volume(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *ccl_restrict stack, const ccl_global SVMNodeAttr &ccl_restrict node) { kernel_assert(primitive_is_volume_attribute(sd)); NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT; const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type); const bool stochastic_sample = __float_as_uint(node.bump_filter_width); const float4 value = volume_attribute_float4(kg, sd, desc, stochastic_sample); if (type == NODE_ATTR_OUTPUT_FLOAT) { stack_store_float(stack, node.out_offset, volume_attribute_value(value)); } else if (type == NODE_ATTR_OUTPUT_FLOAT3) { stack_store_float3(stack, node.out_offset, volume_attribute_value(value)); } else { stack_store_float(stack, node.out_offset, volume_attribute_alpha(value)); } } #endif CCL_NAMESPACE_END