225 lines
7.5 KiB
C++
225 lines
7.5 KiB
C++
/* 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<typename Float3Type>
|
|
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<Float3Type>;
|
|
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<typename Float3Type>
|
|
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<Float3Type>;
|
|
|
|
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<Float3Type>) {
|
|
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<Float3Type>(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<FloatType>(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<Float3Type>) {
|
|
dual2 f = primitive_surface_attribute<dual2>(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<float2>(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<Float3Type>) {
|
|
dual4 f = primitive_surface_attribute<dual4>(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<float4>(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<Float3Type>(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<float3>(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<dual3>(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<float>(value));
|
|
}
|
|
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
|
|
stack_store_float3(stack, node.out_offset, volume_attribute_value<float3>(value));
|
|
}
|
|
else {
|
|
stack_store_float(stack, node.out_offset, volume_attribute_alpha(value));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
CCL_NAMESPACE_END
|