Shaders: Add Filter Width input to Bump node

This makes it possible to restore previous Blender 4.3 behavior of bump
mapping, where the large filter width was sometimes (ab)used to get a bevel
like effect on stepwise textures.

For bump from the displacement socket, filter width remains fixed at 0.1.

Ref #133991, #135841

Pull Request: https://projects.blender.org/blender/blender/pulls/136465
This commit is contained in:
Brecht Van Lommel
2025-03-24 15:53:35 +01:00
parent 68974ce26b
commit 5ce239cc22
31 changed files with 358 additions and 194 deletions
+2 -4
View File
@@ -242,10 +242,8 @@ ccl_device_inline float3 motion_triangle_smooth_normal(KernelGlobals kg,
motion_triangle_normals(kg, object, tri_vindex, numsteps, numverts, step, t, n);
const float3 N = safe_normalize(triangle_interpolate(u, v, n[0], n[1], n[2]));
N_x = safe_normalize(
triangle_interpolate(u + du.dx * BUMP_DX, v + dv.dx * BUMP_DX, n[0], n[1], n[2]));
N_y = safe_normalize(
triangle_interpolate(u + du.dy * BUMP_DY, v + dv.dy * BUMP_DY, n[0], n[1], n[2]));
N_x = safe_normalize(triangle_interpolate(u + du.dx, v + dv.dx, n[0], n[1], n[2]));
N_y = safe_normalize(triangle_interpolate(u + du.dy, v + dv.dy, n[0], n[1], n[2]));
N_x = is_zero(N_x) ? Ng : N_x;
N_y = is_zero(N_y) ? Ng : N_y;
+2 -2
View File
@@ -139,8 +139,8 @@ ccl_device_inline float3 triangle_smooth_normal(KernelGlobals kg,
const float3 n2 = kernel_data_fetch(tri_vnormal, tri_vindex.z);
const float3 N = safe_normalize(triangle_interpolate(u, v, n0, n1, n2));
N_x = safe_normalize(triangle_interpolate(u + du.dx * BUMP_DX, v + dv.dx * BUMP_DX, n0, n1, n2));
N_y = safe_normalize(triangle_interpolate(u + du.dy * BUMP_DY, v + dv.dy * BUMP_DY, n0, n1, n2));
N_x = safe_normalize(triangle_interpolate(u + du.dx, v + dv.dx, n0, n1, n2));
N_y = safe_normalize(triangle_interpolate(u + du.dy, v + dv.dy, n0, n1, n2));
N_x = is_zero(N_x) ? Ng : N_x;
N_y = is_zero(N_y) ? Ng : N_y;
@@ -5,6 +5,7 @@
#include "stdcycles.h"
shader node_attribute(string bump_offset = "center",
float bump_filter_width = BUMP_FILTER_WIDTH,
string name = "",
output point Vector = point(0.0, 0.0, 0.0),
output color Color = 0.0,
@@ -19,15 +20,15 @@ shader node_attribute(string bump_offset = "center",
Alpha = data[3];
if (bump_offset == "dx") {
Color += Dx(Color) * BUMP_DX;
Vector += Dx(Vector) * BUMP_DX;
Fac += Dx(Fac) * BUMP_DX;
Alpha += Dx(Alpha) * BUMP_DX;
Color += Dx(Color) * bump_filter_width;
Vector += Dx(Vector) * bump_filter_width;
Fac += Dx(Fac) * bump_filter_width;
Alpha += Dx(Alpha) * bump_filter_width;
}
else if (bump_offset == "dy") {
Color += Dy(Color) * BUMP_DY;
Vector += Dy(Vector) * BUMP_DY;
Fac += Dy(Fac) * BUMP_DY;
Alpha += Dy(Alpha) * BUMP_DY;
Color += Dy(Color) * bump_filter_width;
Vector += Dy(Vector) * bump_filter_width;
Fac += Dy(Fac) * bump_filter_width;
Alpha += Dy(Alpha) * bump_filter_width;
}
}
@@ -12,6 +12,7 @@ surface node_bump(int invert = 0,
normal NormalIn = N,
float Strength = 0.1,
float Distance = 1.0,
float FilterWidth = BUMP_FILTER_WIDTH,
float SampleCenter = 0.0,
float SampleX = 0.0,
float SampleY = 0.0,
@@ -45,7 +46,7 @@ surface node_bump(int invert = 0,
dist *= -1.0;
/* compute and output perturbed normal */
NormalOut = normalize(BUMP_DX * absdet * Normal - dist * sign(det) * surfgrad);
NormalOut = normalize(FilterWidth * absdet * Normal - dist * sign(det) * surfgrad);
NormalOut = normalize(strength * NormalOut + (1.0 - strength) * Normal);
if (use_object_space) {
@@ -5,6 +5,7 @@
#include "stdcycles.h"
shader node_geometry(string bump_offset = "center",
float bump_filter_width = BUMP_FILTER_WIDTH,
output point Position = point(0.0, 0.0, 0.0),
output normal Normal = normal(0.0, 0.0, 0.0),
@@ -24,12 +25,12 @@ shader node_geometry(string bump_offset = "center",
Backfacing = backfacing();
if (bump_offset == "dx") {
Position += Dx(Position) * BUMP_DX;
Parametric += Dx(Parametric) * BUMP_DX;
Position += Dx(Position) * bump_filter_width;
Parametric += Dx(Parametric) * bump_filter_width;
}
else if (bump_offset == "dy") {
Position += Dy(Position) * BUMP_DY;
Parametric += Dy(Parametric) * BUMP_DY;
Position += Dy(Position) * bump_filter_width;
Parametric += Dy(Parametric) * bump_filter_width;
}
point generated;
@@ -52,10 +53,10 @@ shader node_geometry(string bump_offset = "center",
getattribute("geom:pointiness", Pointiness);
if (bump_offset == "dx") {
Pointiness += Dx(Pointiness) * BUMP_DX;
Pointiness += Dx(Pointiness) * bump_filter_width;
}
else if (bump_offset == "dy") {
Pointiness += Dy(Pointiness) * BUMP_DY;
Pointiness += Dy(Pointiness) * bump_filter_width;
}
getattribute("geom:random_per_island", RandomPerIsland);
@@ -10,6 +10,7 @@ shader node_texture_coordinate(
int from_dupli = 0,
int use_transform = 0,
string bump_offset = "center",
float bump_filter_width = BUMP_FILTER_WIDTH,
matrix object_itfm = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
output point Generated = point(0.0, 0.0, 0.0),
@@ -74,28 +75,26 @@ shader node_texture_coordinate(
if (bump_offset == "dx") {
if (!from_dupli) {
Generated += Dx(Generated) * BUMP_DX;
UV += Dx(UV) * BUMP_DX;
Generated += Dx(Generated) * bump_filter_width;
UV += Dx(UV) * bump_filter_width;
}
Object += Dx(Object) * BUMP_DX;
Camera += Dx(Camera) * BUMP_DX;
Window += Dx(Window) * BUMP_DX;
Object += Dx(Object) * bump_filter_width;
Camera += Dx(Camera) * bump_filter_width;
Window += Dx(Window) * bump_filter_width;
if (getattribute("geom:bump_map_normal", Normal)) {
/* A scaling of `BUMP_DX` is already applied when computing the derivatives, no additional
* scaling is needed here. */
Normal = normalize(Normal + Dx(Normal));
Normal = normalize(Normal + Dx(Normal) * bump_filter_width);
}
}
else if (bump_offset == "dy") {
if (!from_dupli) {
Generated += Dy(Generated) * BUMP_DY;
UV += Dy(UV) * BUMP_DY;
Generated += Dy(Generated) * bump_filter_width;
UV += Dy(UV) * bump_filter_width;
}
Object += Dy(Object) * BUMP_DY;
Camera += Dy(Camera) * BUMP_DY;
Window += Dy(Window) * BUMP_DY;
Object += Dy(Object) * bump_filter_width;
Camera += Dy(Camera) * bump_filter_width;
Window += Dy(Window) * bump_filter_width;
if (getattribute("geom:bump_map_normal", Normal)) {
Normal = normalize(Normal + Dy(Normal));
Normal = normalize(Normal + Dy(Normal) * bump_filter_width);
}
}
@@ -7,6 +7,7 @@
shader node_uv_map(int from_dupli = 0,
string attribute = "",
string bump_offset = "center",
float bump_filter_width = BUMP_FILTER_WIDTH,
output point UV = point(0.0, 0.0, 0.0))
{
if (from_dupli) {
@@ -21,12 +22,12 @@ shader node_uv_map(int from_dupli = 0,
if (bump_offset == "dx") {
if (!from_dupli) {
UV += Dx(UV) * BUMP_DX;
UV += Dx(UV) * bump_filter_width;
}
}
else if (bump_offset == "dy") {
if (!from_dupli) {
UV += Dy(UV) * BUMP_DY;
UV += Dy(UV) * bump_filter_width;
}
}
}
@@ -5,6 +5,7 @@
#include "stdcycles.h"
shader node_vertex_color(string bump_offset = "center",
float bump_filter_width = BUMP_FILTER_WIDTH,
string layer_name = "",
output color Color = 0.0,
output float Alpha = 0.0)
@@ -24,12 +25,12 @@ shader node_vertex_color(string bump_offset = "center",
Alpha = vertex_color[3];
if (bump_offset == "dx") {
Color += Dx(Color) * BUMP_DX;
Alpha += Dx(Alpha) * BUMP_DX;
Color += Dx(Color) * bump_filter_width;
Alpha += Dx(Alpha) * bump_filter_width;
}
else if (bump_offset == "dy") {
Color += Dy(Color) * BUMP_DY;
Alpha += Dy(Alpha) * BUMP_DY;
Color += Dy(Color) * bump_filter_width;
Alpha += Dy(Alpha) * bump_filter_width;
}
}
else {
@@ -6,15 +6,16 @@
#include "stdcycles.h"
shader node_wireframe(string bump_offset = "center",
float bump_filter_width = BUMP_FILTER_WIDTH,
int use_pixel_size = 0,
float Size = 0.01,
output float Fac = 0.0)
{
if (bump_offset == "dx") {
P += Dx(P) * BUMP_DX;
P += Dx(P) * bump_filter_width;
}
else if (bump_offset == "dy") {
P += Dy(P) * BUMP_DY;
P += Dy(P) * bump_filter_width;
}
Fac = wireframe("triangles", Size, use_pixel_size);
+2 -4
View File
@@ -13,10 +13,8 @@
// Constants
#define FLT_MAX 3.402823466e+38 // max value
/* Offset of coordinates for evaluating bump node. Unit in pixel.
* NOTE: keep the same as SVM. */
#define BUMP_DX 0.1
#define BUMP_DY BUMP_DX
/* Default offset of coordinates for evaluating bump node. Unit in pixel. */
#define BUMP_FILTER_WIDTH 0.1
// Declaration of built-in functions and closures, stdosl.h does not make
// these available so we have to redefine them.
+23 -18
View File
@@ -25,8 +25,9 @@ ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals kg,
ccl_private NodeAttributeOutputType *type,
ccl_private uint *out_offset)
{
*out_offset = node.z;
*type = (NodeAttributeOutputType)node.w;
uint type_value;
svm_unpack_node_uchar2(node.z, out_offset, &type_value);
*type = (NodeAttributeOutputType)type_value;
AttributeDescriptor desc;
@@ -35,14 +36,14 @@ ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals kg,
if (desc.offset == ATTR_STD_NOT_FOUND) {
desc = attribute_not_found();
desc.offset = 0;
desc.type = (NodeAttributeType)node.w;
desc.type = (NodeAttributeType)type_value;
}
}
else {
/* background */
desc = attribute_not_found();
desc.offset = 0;
desc.type = (NodeAttributeType)node.w;
desc.type = (NodeAttributeType)type_value;
}
return desc;
@@ -158,15 +159,17 @@ ccl_device_noinline void svm_node_attr(KernelGlobals kg,
}
/* Position offsetted in x direction. */
ccl_device_forceinline float3 svm_node_bump_P_dx(const ccl_private ShaderData *sd)
ccl_device_forceinline float3 svm_node_bump_P_dx(const ccl_private ShaderData *sd,
const float bump_filter_width)
{
return sd->P + differential_from_compact(sd->Ng, sd->dP).dx * BUMP_DX;
return sd->P + differential_from_compact(sd->Ng, sd->dP).dx * bump_filter_width;
}
/* Position offsetted in y direction. */
ccl_device_forceinline float3 svm_node_bump_P_dy(const ccl_private ShaderData *sd)
ccl_device_forceinline float3 svm_node_bump_P_dy(const ccl_private ShaderData *sd,
const float bump_filter_width)
{
return sd->P + differential_from_compact(sd->Ng, sd->dP).dy * BUMP_DY;
return sd->P + differential_from_compact(sd->Ng, sd->dP).dy * bump_filter_width;
}
/* Evaluate attributes at a position shifted in x direction. */
@@ -178,6 +181,7 @@ ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg,
NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
uint out_offset = 0;
const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
const float bump_filter_width = __uint_as_float(node.w);
#ifdef __VOLUME__
/* Volume */
@@ -197,7 +201,7 @@ ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg,
if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
/* No generated attribute, fall back to object coordinates. */
float3 f_x = svm_node_bump_P_dx(sd);
float3 f_x = svm_node_bump_P_dx(sd, bump_filter_width);
if (sd->object != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &f_x);
}
@@ -217,7 +221,7 @@ ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg,
if (desc.type == NODE_ATTR_FLOAT) {
float dfdx;
const float f = primitive_surface_attribute_float(kg, sd, desc, &dfdx, nullptr);
const float f_x = f + dfdx * BUMP_DX;
const float f_x = f + dfdx * bump_filter_width;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f_x);
}
@@ -231,7 +235,7 @@ ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg,
else if (desc.type == NODE_ATTR_FLOAT2) {
float2 dfdx;
const float2 f = primitive_surface_attribute_float2(kg, sd, desc, &dfdx, nullptr);
const float2 f_x = f + dfdx * BUMP_DX;
const float2 f_x = f + dfdx * bump_filter_width;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f_x.x);
}
@@ -245,7 +249,7 @@ ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg,
else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
float4 dfdx;
const float4 f = primitive_surface_attribute_float4(kg, sd, desc, &dfdx, nullptr);
const float4 f_x = f + dfdx * BUMP_DX;
const float4 f_x = f + dfdx * bump_filter_width;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(make_float3(f_x)));
}
@@ -259,7 +263,7 @@ ccl_device_noinline void svm_node_attr_bump_dx(KernelGlobals kg,
else {
float3 dfdx;
const float3 f = primitive_surface_attribute_float3(kg, sd, desc, &dfdx, nullptr);
const float3 f_x = f + dfdx * BUMP_DX;
const float3 f_x = f + dfdx * bump_filter_width;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(f_x));
}
@@ -281,6 +285,7 @@ ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg,
NodeAttributeOutputType type = NODE_ATTR_OUTPUT_FLOAT;
uint out_offset = 0;
const AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
const float bump_filter_width = __uint_as_float(node.w);
#ifdef __VOLUME__
/* Volume */
@@ -300,7 +305,7 @@ ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg,
if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
/* No generated attribute, fall back to object coordinates. */
float3 f_y = svm_node_bump_P_dy(sd);
float3 f_y = svm_node_bump_P_dy(sd, bump_filter_width);
if (sd->object != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &f_y);
}
@@ -320,7 +325,7 @@ ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg,
if (desc.type == NODE_ATTR_FLOAT) {
float dfdy;
const float f = primitive_surface_attribute_float(kg, sd, desc, nullptr, &dfdy);
const float f_y = f + dfdy * BUMP_DY;
const float f_y = f + dfdy * bump_filter_width;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f_y);
}
@@ -334,7 +339,7 @@ ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg,
else if (desc.type == NODE_ATTR_FLOAT2) {
float2 dfdy;
const float2 f = primitive_surface_attribute_float2(kg, sd, desc, nullptr, &dfdy);
const float2 f_y = f + dfdy * BUMP_DY;
const float2 f_y = f + dfdy * bump_filter_width;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, f_y.x);
}
@@ -348,7 +353,7 @@ ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg,
else if (desc.type == NODE_ATTR_FLOAT4 || desc.type == NODE_ATTR_RGBA) {
float4 dfdy;
const float4 f = primitive_surface_attribute_float4(kg, sd, desc, nullptr, &dfdy);
const float4 f_y = f + dfdy * BUMP_DY;
const float4 f_y = f + dfdy * bump_filter_width;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(make_float3(f_y)));
}
@@ -362,7 +367,7 @@ ccl_device_noinline void svm_node_attr_bump_dy(KernelGlobals kg,
else {
float3 dfdy;
const float3 f = primitive_surface_attribute_float3(kg, sd, desc, nullptr, &dfdy);
const float3 f_y = f + dfdy * BUMP_DY;
const float3 f_y = f + dfdy * bump_filter_width;
if (type == NODE_ATTR_OUTPUT_FLOAT) {
stack_store_float(stack, out_offset, average(f_y));
}
+15 -12
View File
@@ -16,15 +16,17 @@ CCL_NAMESPACE_BEGIN
/* Bump Node */
template<uint node_feature_mask>
ccl_device_noinline void svm_node_set_bump(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint4 node)
ccl_device_noinline int svm_node_set_bump(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint4 node,
int offset)
{
uint out_offset;
uint bump_state_offset;
uint dummy;
svm_unpack_node_uchar4(node.w, &out_offset, &bump_state_offset, &dummy, &dummy);
svm_unpack_node_uchar2(node.w, &out_offset, &bump_state_offset);
const uint4 data_node = read_node(kg, &offset);
const float bump_filter_width = __uint_as_float(data_node.x);
#ifdef __RAY_DIFFERENTIALS__
IF_KERNEL_NODES_FEATURE(BUMP)
@@ -87,14 +89,13 @@ ccl_device_noinline void svm_node_set_bump(KernelGlobals kg,
strength = max(strength, 0.0f);
/* Compute and output perturbed normal.
* dP'dx = dPdx + scale * (h_x - h_c) / BUMP_DX * normal
* dP'dy = dPdy + scale * (h_y - h_c) / BUMP_DY * normal
* dP'dx = dPdx + scale * (h_x - h_c) / filter_width * normal
* dP'dy = dPdy + scale * (h_y - h_c) / filter_width * normal
* N' = cross(dP'dx, dP'dy)
* = cross(dPdx, dPdy) - scale * ((h_y - h_c) / BUMP_DY * Ry + (h_x - h_c) / BUMP_DX * Rx)
* ≈ det * normal_in - scale * surfgrad / BUMP_DX
* = cross(dPdx, dPdy) - scale * ((h_y - h_c) / filter_width * Ry + (h_x - h_c) /
* filter_width * Rx) ≈ det * normal_in - scale * surfgrad / filter_width
*/
kernel_assert(BUMP_DX == BUMP_DY);
float3 normal_out = safe_normalize(BUMP_DX * absdet * normal_in -
float3 normal_out = safe_normalize(bump_filter_width * absdet * normal_in -
scale * signf(det) * surfgrad);
if (is_zero(normal_out)) {
normal_out = normal_in;
@@ -113,6 +114,8 @@ ccl_device_noinline void svm_node_set_bump(KernelGlobals kg,
stack_store_float3(stack, out_offset, zero_float3());
}
#endif
return offset;
}
/* Displacement Node */
+10 -8
View File
@@ -56,18 +56,19 @@ ccl_device_noinline void svm_node_geometry_bump_dx(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint type,
const uint out_offset)
const uint out_offset,
const float bump_filter_width)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
switch (type) {
case NODE_GEOM_P:
data = svm_node_bump_P_dx(sd);
data = svm_node_bump_P_dx(sd, bump_filter_width);
break;
case NODE_GEOM_uv: {
const float u_x = sd->u + sd->du.dx * BUMP_DX;
const float v_x = sd->v + sd->dv.dx * BUMP_DX;
const float u_x = sd->u + sd->du.dx * bump_filter_width;
const float v_x = sd->v + sd->dv.dx * bump_filter_width;
data = make_float3(1.0f - u_x - v_x, u_x, 0.0f);
break;
}
@@ -86,18 +87,19 @@ ccl_device_noinline void svm_node_geometry_bump_dy(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint type,
const uint out_offset)
const uint out_offset,
const float bump_filter_width)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
switch (type) {
case NODE_GEOM_P:
data = svm_node_bump_P_dy(sd);
data = svm_node_bump_P_dy(sd, bump_filter_width);
break;
case NODE_GEOM_uv: {
const float u_y = sd->u + sd->du.dy * BUMP_DY;
const float v_y = sd->v + sd->dv.dy * BUMP_DY;
const float u_y = sd->u + sd->du.dy * bump_filter_width;
const float v_y = sd->v + sd->dv.dy * bump_filter_width;
data = make_float3(1.0f - u_y - v_y, u_y, 0.0f);
break;
}
+6 -6
View File
@@ -189,18 +189,18 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
svm_node_attr<node_feature_mask>(kg, sd, stack, node);
break;
SVM_CASE(NODE_VERTEX_COLOR)
svm_node_vertex_color(kg, sd, stack, node.y, node.z, node.w);
svm_node_vertex_color(kg, sd, stack, node);
break;
SVM_CASE(NODE_GEOMETRY_BUMP_DX)
IF_KERNEL_NODES_FEATURE(BUMP)
{
svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z);
svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z, __uint_as_float(node.w));
}
break;
SVM_CASE(NODE_GEOMETRY_BUMP_DY)
IF_KERNEL_NODES_FEATURE(BUMP)
{
svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z);
svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z, __uint_as_float(node.w));
}
break;
SVM_CASE(NODE_SET_DISPLACEMENT)
@@ -222,7 +222,7 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
offset = svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, offset);
break;
SVM_CASE(NODE_SET_BUMP)
svm_node_set_bump<node_feature_mask>(kg, sd, stack, node);
offset = svm_node_set_bump<node_feature_mask>(kg, sd, stack, node, offset);
break;
SVM_CASE(NODE_ATTR_BUMP_DX)
IF_KERNEL_NODES_FEATURE(BUMP)
@@ -239,13 +239,13 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
SVM_CASE(NODE_VERTEX_COLOR_BUMP_DX)
IF_KERNEL_NODES_FEATURE(BUMP)
{
svm_node_vertex_color_bump_dx(kg, sd, stack, node.y, node.z, node.w);
svm_node_vertex_color_bump_dx(kg, sd, stack, node);
}
break;
SVM_CASE(NODE_VERTEX_COLOR_BUMP_DY)
IF_KERNEL_NODES_FEATURE(BUMP)
{
svm_node_vertex_color_bump_dy(kg, sd, stack, node.y, node.z, node.w);
svm_node_vertex_color_bump_dy(kg, sd, stack, node);
}
break;
SVM_CASE(NODE_TEX_COORD_BUMP_DX)
+27 -18
View File
@@ -11,7 +11,9 @@
#include "kernel/geom/primitive.h"
#include "kernel/svm/attribute.h"
#include "kernel/svm/types.h"
#include "kernel/svm/util.h"
#include "util/math_base.h"
CCL_NAMESPACE_BEGIN
@@ -29,9 +31,10 @@ ccl_device_noinline int svm_node_tex_coord(KernelGlobals kg,
const uint out_offset = node.z;
switch ((NodeTexCoord)type) {
case NODE_TEXCO_OBJECT: {
case NODE_TEXCO_OBJECT:
case NODE_TEXCO_OBJECT_WITH_TRANSFORM: {
data = sd->P;
if (node.w == 0) {
if (type == NODE_TEXCO_OBJECT) {
if (sd->object != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &data);
}
@@ -149,11 +152,13 @@ ccl_device_noinline int svm_node_tex_coord_bump_dx(KernelGlobals kg,
float3 data = zero_float3();
const uint type = node.y;
const uint out_offset = node.z;
const float bump_filter_width = __uint_as_float(node.w);
switch ((NodeTexCoord)type) {
case NODE_TEXCO_OBJECT: {
data = svm_node_bump_P_dx(sd);
if (node.w == 0) {
case NODE_TEXCO_OBJECT:
case NODE_TEXCO_OBJECT_WITH_TRANSFORM: {
data = svm_node_bump_P_dx(sd, bump_filter_width);
if (type == NODE_TEXCO_OBJECT) {
if (sd->object != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &data);
}
@@ -169,17 +174,18 @@ ccl_device_noinline int svm_node_tex_coord_bump_dx(KernelGlobals kg,
}
case NODE_TEXCO_NORMAL: {
data = texco_normal_from_uv(
kg, sd, sd->u + sd->du.dx * BUMP_DX, sd->v + sd->dv.dx * BUMP_DX);
kg, sd, sd->u + sd->du.dx * bump_filter_width, sd->v + sd->dv.dx * bump_filter_width);
break;
}
case NODE_TEXCO_CAMERA: {
const Transform tfm = kernel_data.cam.worldtocamera;
if (sd->object != OBJECT_NONE) {
data = transform_point(&tfm, svm_node_bump_P_dx(sd));
data = transform_point(&tfm, svm_node_bump_P_dx(sd, bump_filter_width));
}
else {
data = transform_point(&tfm, svm_node_bump_P_dx(sd) + camera_position(kg));
data = transform_point(&tfm,
svm_node_bump_P_dx(sd, bump_filter_width) + camera_position(kg));
}
break;
}
@@ -190,7 +196,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dx(KernelGlobals kg,
data = camera_world_to_ndc(kg, sd, sd->ray_P);
}
else {
data = camera_world_to_ndc(kg, sd, svm_node_bump_P_dx(sd));
data = camera_world_to_ndc(kg, sd, svm_node_bump_P_dx(sd, bump_filter_width));
}
data.z = 0.0f;
break;
@@ -213,7 +219,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dx(KernelGlobals kg,
break;
}
case NODE_TEXCO_VOLUME_GENERATED: {
data = svm_node_bump_P_dx(sd);
data = svm_node_bump_P_dx(sd, bump_filter_width);
# ifdef __VOLUME__
if (sd->object != OBJECT_NONE) {
@@ -242,11 +248,13 @@ ccl_device_noinline int svm_node_tex_coord_bump_dy(KernelGlobals kg,
float3 data = zero_float3();
const uint type = node.y;
const uint out_offset = node.z;
const float bump_filter_width = __uint_as_float(node.w);
switch ((NodeTexCoord)type) {
case NODE_TEXCO_OBJECT: {
data = svm_node_bump_P_dy(sd);
if (node.w == 0) {
case NODE_TEXCO_OBJECT:
case NODE_TEXCO_OBJECT_WITH_TRANSFORM: {
data = svm_node_bump_P_dy(sd, bump_filter_width);
if (type == NODE_TEXCO_OBJECT) {
if (sd->object != OBJECT_NONE) {
object_inverse_position_transform(kg, sd, &data);
}
@@ -262,17 +270,18 @@ ccl_device_noinline int svm_node_tex_coord_bump_dy(KernelGlobals kg,
}
case NODE_TEXCO_NORMAL: {
data = texco_normal_from_uv(
kg, sd, sd->u + sd->du.dy * BUMP_DY, sd->v + sd->dv.dy * BUMP_DY);
kg, sd, sd->u + sd->du.dy * bump_filter_width, sd->v + sd->dv.dy * bump_filter_width);
break;
}
case NODE_TEXCO_CAMERA: {
const Transform tfm = kernel_data.cam.worldtocamera;
if (sd->object != OBJECT_NONE) {
data = transform_point(&tfm, svm_node_bump_P_dy(sd));
data = transform_point(&tfm, svm_node_bump_P_dy(sd, bump_filter_width));
}
else {
data = transform_point(&tfm, svm_node_bump_P_dy(sd) + camera_position(kg));
data = transform_point(&tfm,
svm_node_bump_P_dy(sd, bump_filter_width) + camera_position(kg));
}
break;
}
@@ -283,7 +292,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dy(KernelGlobals kg,
data = camera_world_to_ndc(kg, sd, sd->ray_P);
}
else {
data = camera_world_to_ndc(kg, sd, svm_node_bump_P_dy(sd));
data = camera_world_to_ndc(kg, sd, svm_node_bump_P_dy(sd, bump_filter_width));
}
data.z = 0.0f;
break;
@@ -306,7 +315,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dy(KernelGlobals kg,
break;
}
case NODE_TEXCO_VOLUME_GENERATED: {
data = svm_node_bump_P_dy(sd);
data = svm_node_bump_P_dy(sd, bump_filter_width);
# ifdef __VOLUME__
if (sd->object != OBJECT_NONE) {
+1 -3
View File
@@ -112,6 +112,7 @@ enum NodeLightFalloff {
enum NodeTexCoord {
NODE_TEXCO_NORMAL,
NODE_TEXCO_OBJECT,
NODE_TEXCO_OBJECT_WITH_TRANSFORM,
NODE_TEXCO_CAMERA,
NODE_TEXCO_WINDOW,
NODE_TEXCO_REFLECTION,
@@ -518,8 +519,5 @@ enum ClosureType {
#define CLOSURE_WEIGHT_CUTOFF 1e-5f
/* Treat closure as singular if the squared roughness is below this threshold. */
#define BSDF_ROUGHNESS_SQ_THRESH 2e-10f
/* Offset of coordinates for evaluating bump node. Unit in pixel. */
#define BUMP_DX 0.1f
#define BUMP_DY BUMP_DX
CCL_NAMESPACE_END
+25 -13
View File
@@ -7,16 +7,20 @@
#include "kernel/geom/attribute.h"
#include "kernel/geom/primitive.h"
#include "kernel/svm/util.h"
#include "util/math_base.h"
CCL_NAMESPACE_BEGIN
ccl_device_noinline void svm_node_vertex_color(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint layer_id,
const uint color_offset,
const uint alpha_offset)
const uint4 node)
{
uint layer_id;
uint color_offset;
uint alpha_offset;
svm_unpack_node_uchar3(node.y, &layer_id, &color_offset, &alpha_offset);
const AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
if (descriptor.offset != ATTR_STD_NOT_FOUND) {
if (descriptor.type == NODE_ATTR_FLOAT4 || descriptor.type == NODE_ATTR_RGBA) {
@@ -41,23 +45,27 @@ ccl_device_noinline void svm_node_vertex_color(KernelGlobals kg,
ccl_device_noinline void svm_node_vertex_color_bump_dx(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint layer_id,
const uint color_offset,
const uint alpha_offset)
const uint4 node)
{
uint layer_id;
uint color_offset;
uint alpha_offset;
svm_unpack_node_uchar3(node.y, &layer_id, &color_offset, &alpha_offset);
const float bump_filter_width = __uint_as_float(node.z);
const AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
if (descriptor.offset != ATTR_STD_NOT_FOUND) {
if (descriptor.type == NODE_ATTR_FLOAT4 || descriptor.type == NODE_ATTR_RGBA) {
float4 dfdx;
float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, &dfdx, nullptr);
vertex_color += dfdx * BUMP_DX;
vertex_color += dfdx * bump_filter_width;
stack_store_float3(stack, color_offset, make_float3(vertex_color));
stack_store_float(stack, alpha_offset, vertex_color.w);
}
else {
float3 dfdx;
float3 vertex_color = primitive_surface_attribute_float3(kg, sd, descriptor, &dfdx, nullptr);
vertex_color += dfdx * BUMP_DX;
vertex_color += dfdx * bump_filter_width;
stack_store_float3(stack, color_offset, vertex_color);
stack_store_float(stack, alpha_offset, 1.0f);
}
@@ -71,23 +79,27 @@ ccl_device_noinline void svm_node_vertex_color_bump_dx(KernelGlobals kg,
ccl_device_noinline void svm_node_vertex_color_bump_dy(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private float *stack,
const uint layer_id,
const uint color_offset,
const uint alpha_offset)
const uint4 node)
{
uint layer_id;
uint color_offset;
uint alpha_offset;
svm_unpack_node_uchar3(node.y, &layer_id, &color_offset, &alpha_offset);
const float bump_filter_width = __uint_as_float(node.z);
const AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
if (descriptor.offset != ATTR_STD_NOT_FOUND) {
if (descriptor.type == NODE_ATTR_FLOAT4 || descriptor.type == NODE_ATTR_RGBA) {
float4 dfdy;
float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, nullptr, &dfdy);
vertex_color += dfdy * BUMP_DY;
vertex_color += dfdy * bump_filter_width;
stack_store_float3(stack, color_offset, make_float3(vertex_color));
stack_store_float(stack, alpha_offset, vertex_color.w);
}
else {
float3 dfdy;
float3 vertex_color = primitive_surface_attribute_float3(kg, sd, descriptor, nullptr, &dfdy);
vertex_color += dfdy * BUMP_DY;
vertex_color += dfdy * bump_filter_width;
stack_store_float3(stack, color_offset, vertex_color);
stack_store_float(stack, alpha_offset, 1.0f);
}
+6 -4
View File
@@ -12,6 +12,7 @@
#include "kernel/geom/triangle.h"
#include "kernel/svm/util.h"
#include "kernel/util/differential.h"
#include "util/math_base.h"
CCL_NAMESPACE_BEGIN
@@ -84,10 +85,11 @@ ccl_device_noinline void svm_node_wireframe(KernelGlobals kg,
const uint4 node)
{
const uint in_size = node.y;
const uint out_fac = node.z;
const float bump_filter_width = __uint_as_float(node.z);
uint use_pixel_size;
uint bump_offset;
svm_unpack_node_uchar2(node.w, &use_pixel_size, &bump_offset);
uint out_fac;
svm_unpack_node_uchar3(node.w, &use_pixel_size, &bump_offset, &out_fac);
/* Input Data */
const float size = stack_load_float(stack, in_size);
@@ -98,10 +100,10 @@ ccl_device_noinline void svm_node_wireframe(KernelGlobals kg,
float3 P = sd->P;
if (bump_offset == NODE_BUMP_OFFSET_DX) {
P += dP.dx * BUMP_DX;
P += dP.dx * bump_filter_width;
}
else if (bump_offset == NODE_BUMP_OFFSET_DY) {
P += dP.dy * BUMP_DY;
P += dP.dy * bump_filter_width;
}
const float f = wireframe(kg, sd, dP, size, pixel_size, &P);
+13 -5
View File
@@ -924,6 +924,7 @@ void ShaderGraph::refine_bump_nodes()
ShaderNode *node = nodes[i];
if (node->special_type == SHADER_SPECIAL_TYPE_BUMP && node->input("Height")->link) {
BumpNode *bump = static_cast<BumpNode *>(node);
ShaderInput *bump_input = node->input("Height");
ShaderNodeSet nodes_bump;
@@ -941,12 +942,15 @@ void ShaderGraph::refine_bump_nodes()
* that any texture coordinates are shifted by dx/dy when sampling. */
for (ShaderNode *node : nodes_bump) {
node->bump = SHADER_BUMP_CENTER;
node->bump_filter_width = bump->get_filter_width();
}
for (const NodePair &pair : nodes_dx) {
pair.second->bump = SHADER_BUMP_DX;
pair.second->bump_filter_width = bump->get_filter_width();
}
for (const NodePair &pair : nodes_dy) {
pair.second->bump = SHADER_BUMP_DY;
pair.second->bump_filter_width = bump->get_filter_width();
}
ShaderOutput *out = bump_input->link;
@@ -992,6 +996,11 @@ void ShaderGraph::bump_from_displacement(bool use_object_space)
ShaderNodeSet nodes_displace;
find_dependencies(nodes_displace, displacement_in);
/* Add bump node. */
BumpNode *bump = create_node<BumpNode>();
bump->set_use_object_space(use_object_space);
bump->set_distance(1.0f);
/* copy nodes for 3 bump samples */
ShaderNodeMap nodes_center;
ShaderNodeMap nodes_dx;
@@ -1005,12 +1014,15 @@ void ShaderGraph::bump_from_displacement(bool use_object_space)
* that any texture coordinates are shifted by dx/dy when sampling */
for (const NodePair &pair : nodes_center) {
pair.second->bump = SHADER_BUMP_CENTER;
pair.second->bump_filter_width = bump->get_filter_width();
}
for (const NodePair &pair : nodes_dx) {
pair.second->bump = SHADER_BUMP_DX;
pair.second->bump_filter_width = bump->get_filter_width();
}
for (const NodePair &pair : nodes_dy) {
pair.second->bump = SHADER_BUMP_DY;
pair.second->bump_filter_width = bump->get_filter_width();
}
/* add set normal node and connect the bump normal output to the set normal
@@ -1019,11 +1031,7 @@ void ShaderGraph::bump_from_displacement(bool use_object_space)
* overwrite the shader normal */
ShaderNode *set_normal = create_node<SetNormalNode>();
/* add bump node and connect copied graphs to it */
BumpNode *bump = create_node<BumpNode>();
bump->set_use_object_space(use_object_space);
bump->set_distance(1.0f);
/* Connect copied graphs to bump node. */
ShaderOutput *out = displacement_in->link;
ShaderOutput *out_center = nodes_center[out->parent]->output(out->name());
ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
+1
View File
@@ -212,6 +212,7 @@ class ShaderNode : public Node {
int id = -1;
/* for bump mapping utility */
ShaderBump bump = SHADER_BUMP_NONE;
float bump_filter_width = 0.0f;
/* special node type */
ShaderNodeSpecialType special_type = SHADER_SPECIAL_TYPE_NONE;
+111 -34
View File
@@ -3,6 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 */
#include "scene/shader_nodes.h"
#include "kernel/svm/types.h"
#include "scene/colorspace.h"
#include "scene/constant_fold.h"
#include "scene/film.h"
@@ -20,6 +21,7 @@
#include "util/color.h"
#include "util/log.h"
#include "util/math_base.h"
#include "util/transform.h"
#include "kernel/svm/color_util.h"
@@ -3948,32 +3950,38 @@ void GeometryNode::compile(SVMCompiler &compiler)
out = output("Position");
if (!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
compiler.add_node(
geom_node, NODE_GEOM_P, compiler.stack_assign(out), __float_as_uint(bump_filter_width));
}
out = output("Normal");
if (!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_N, compiler.stack_assign(out));
compiler.add_node(
geom_node, NODE_GEOM_N, compiler.stack_assign(out), __float_as_uint(bump_filter_width));
}
out = output("Tangent");
if (!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_T, compiler.stack_assign(out));
compiler.add_node(
geom_node, NODE_GEOM_T, compiler.stack_assign(out), __float_as_uint(bump_filter_width));
}
out = output("True Normal");
if (!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_Ng, compiler.stack_assign(out));
compiler.add_node(
geom_node, NODE_GEOM_Ng, compiler.stack_assign(out), __float_as_uint(bump_filter_width));
}
out = output("Incoming");
if (!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
compiler.add_node(
geom_node, NODE_GEOM_I, compiler.stack_assign(out), __float_as_uint(bump_filter_width));
}
out = output("Parametric");
if (!out->links.empty()) {
compiler.add_node(geom_node, NODE_GEOM_uv, compiler.stack_assign(out));
compiler.add_node(
geom_node, NODE_GEOM_uv, compiler.stack_assign(out), __float_as_uint(bump_filter_width));
}
out = output("Backfacing");
@@ -3984,8 +3992,10 @@ void GeometryNode::compile(SVMCompiler &compiler)
out = output("Pointiness");
if (!out->links.empty()) {
if (compiler.output_type() != SHADER_TYPE_VOLUME) {
compiler.add_node(
attr_node, ATTR_STD_POINTINESS, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT);
compiler.add_node(attr_node,
ATTR_STD_POINTINESS,
compiler.encode_uchar4(compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT),
__float_as_uint(bump_filter_width));
}
else {
compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
@@ -3997,8 +4007,8 @@ void GeometryNode::compile(SVMCompiler &compiler)
if (compiler.output_type() != SHADER_TYPE_VOLUME) {
compiler.add_node(attr_node,
ATTR_STD_RANDOM_PER_ISLAND,
compiler.stack_assign(out),
NODE_ATTR_OUTPUT_FLOAT);
compiler.encode_uchar4(compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT),
__float_as_uint(bump_filter_width));
}
else {
compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
@@ -4017,6 +4027,7 @@ void GeometryNode::compile(OSLCompiler &compiler)
else {
compiler.parameter("bump_offset", "center");
}
compiler.parameter("bump_filter_width", bump_filter_width);
compiler.add(this, "node_geometry");
}
@@ -4089,41 +4100,65 @@ void TextureCoordinateNode::compile(SVMCompiler &compiler)
out = output("Generated");
if (!out->links.empty()) {
if (compiler.background) {
compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
compiler.add_node(
geom_node, NODE_GEOM_P, compiler.stack_assign(out), __float_as_uint(bump_filter_width));
}
else {
if (from_dupli) {
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, compiler.stack_assign(out));
compiler.add_node(texco_node,
NODE_TEXCO_DUPLI_GENERATED,
compiler.stack_assign(out),
__float_as_uint(bump_filter_width));
}
else if (compiler.output_type() == SHADER_TYPE_VOLUME) {
compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, compiler.stack_assign(out));
compiler.add_node(texco_node,
NODE_TEXCO_VOLUME_GENERATED,
compiler.stack_assign(out),
__float_as_uint(bump_filter_width));
}
else {
const int attr = compiler.attribute(ATTR_STD_GENERATED);
compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
compiler.add_node(
attr_node,
attr,
compiler.encode_uchar4(compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3),
__float_as_uint(bump_filter_width));
}
}
}
out = output("Normal");
if (!out->links.empty()) {
compiler.add_node(texco_node, NODE_TEXCO_NORMAL, compiler.stack_assign(out));
compiler.add_node(texco_node,
NODE_TEXCO_NORMAL,
compiler.stack_assign(out),
__float_as_uint(bump_filter_width));
}
out = output("UV");
if (!out->links.empty()) {
if (from_dupli) {
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
compiler.add_node(texco_node,
NODE_TEXCO_DUPLI_UV,
compiler.stack_assign(out),
__float_as_uint(bump_filter_width));
}
else {
const int attr = compiler.attribute(ATTR_STD_UV);
compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
compiler.add_node(
attr_node,
attr,
compiler.encode_uchar4(compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3),
__float_as_uint(bump_filter_width));
}
}
out = output("Object");
if (!out->links.empty()) {
compiler.add_node(texco_node, NODE_TEXCO_OBJECT, compiler.stack_assign(out), use_transform);
compiler.add_node(texco_node,
(use_transform) ? NODE_TEXCO_OBJECT_WITH_TRANSFORM : NODE_TEXCO_OBJECT,
compiler.stack_assign(out),
__float_as_uint(bump_filter_width));
if (use_transform) {
const Transform ob_itfm = transform_inverse(ob_tfm);
compiler.add_node(ob_itfm.x);
@@ -4134,21 +4169,31 @@ void TextureCoordinateNode::compile(SVMCompiler &compiler)
out = output("Camera");
if (!out->links.empty()) {
compiler.add_node(texco_node, NODE_TEXCO_CAMERA, compiler.stack_assign(out));
compiler.add_node(texco_node,
NODE_TEXCO_CAMERA,
compiler.stack_assign(out),
__float_as_uint(bump_filter_width));
}
out = output("Window");
if (!out->links.empty()) {
compiler.add_node(texco_node, NODE_TEXCO_WINDOW, compiler.stack_assign(out));
compiler.add_node(texco_node,
NODE_TEXCO_WINDOW,
compiler.stack_assign(out),
__float_as_uint(bump_filter_width));
}
out = output("Reflection");
if (!out->links.empty()) {
if (compiler.background) {
compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
compiler.add_node(
geom_node, NODE_GEOM_I, compiler.stack_assign(out), __float_as_uint(bump_filter_width));
}
else {
compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, compiler.stack_assign(out));
compiler.add_node(texco_node,
NODE_TEXCO_REFLECTION,
compiler.stack_assign(out),
__float_as_uint(bump_filter_width));
}
}
}
@@ -4164,6 +4209,7 @@ void TextureCoordinateNode::compile(OSLCompiler &compiler)
else {
compiler.parameter("bump_offset", "center");
}
compiler.parameter("bump_filter_width", bump_filter_width);
if (compiler.background) {
compiler.parameter("is_background", true);
@@ -4232,7 +4278,10 @@ void UVMapNode::compile(SVMCompiler &compiler)
if (!out->links.empty()) {
if (from_dupli) {
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
compiler.add_node(texco_node,
NODE_TEXCO_DUPLI_UV,
compiler.stack_assign(out),
__float_as_uint(bump_filter_width));
}
else {
if (!attribute.empty()) {
@@ -4242,7 +4291,11 @@ void UVMapNode::compile(SVMCompiler &compiler)
attr = compiler.attribute(ATTR_STD_UV);
}
compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3);
compiler.add_node(
attr_node,
attr,
compiler.encode_uchar4(compiler.stack_assign(out), NODE_ATTR_OUTPUT_FLOAT3),
__float_as_uint(bump_filter_width));
}
}
}
@@ -4258,6 +4311,7 @@ void UVMapNode::compile(OSLCompiler &compiler)
else {
compiler.parameter("bump_offset", "center");
}
compiler.parameter("bump_filter_width", bump_filter_width);
compiler.parameter(this, "from_dupli");
compiler.parameter(this, "attribute");
@@ -4857,8 +4911,11 @@ void VertexColorNode::compile(SVMCompiler &compiler)
node = NODE_VERTEX_COLOR;
}
compiler.add_node(
node, layer_id, compiler.stack_assign(color_out), compiler.stack_assign(alpha_out));
compiler.add_node(node,
compiler.encode_uchar4(layer_id,
compiler.stack_assign(color_out),
compiler.stack_assign(alpha_out)),
__float_as_uint(bump_filter_width));
}
void VertexColorNode::compile(OSLCompiler &compiler)
@@ -4872,6 +4929,7 @@ void VertexColorNode::compile(OSLCompiler &compiler)
else {
compiler.parameter("bump_offset", "center");
}
compiler.parameter("bump_filter_width", bump_filter_width);
if (layer_name.empty()) {
compiler.parameter("layer_name", ustring("geom:vertex_color"));
@@ -6052,21 +6110,34 @@ void AttributeNode::compile(SVMCompiler &compiler)
if (!color_out->links.empty() || !vector_out->links.empty()) {
if (!color_out->links.empty()) {
compiler.add_node(
attr_node, attr, compiler.stack_assign(color_out), NODE_ATTR_OUTPUT_FLOAT3);
attr_node,
attr,
compiler.encode_uchar4(compiler.stack_assign(color_out), NODE_ATTR_OUTPUT_FLOAT3),
__float_as_uint(bump_filter_width));
}
if (!vector_out->links.empty()) {
compiler.add_node(
attr_node, attr, compiler.stack_assign(vector_out), NODE_ATTR_OUTPUT_FLOAT3);
attr_node,
attr,
compiler.encode_uchar4(compiler.stack_assign(vector_out), NODE_ATTR_OUTPUT_FLOAT3),
__float_as_uint(bump_filter_width));
}
}
if (!fac_out->links.empty()) {
compiler.add_node(attr_node, attr, compiler.stack_assign(fac_out), NODE_ATTR_OUTPUT_FLOAT);
compiler.add_node(
attr_node,
attr,
compiler.encode_uchar4(compiler.stack_assign(fac_out), NODE_ATTR_OUTPUT_FLOAT),
__float_as_uint(bump_filter_width));
}
if (!alpha_out->links.empty()) {
compiler.add_node(
attr_node, attr, compiler.stack_assign(alpha_out), NODE_ATTR_OUTPUT_FLOAT_ALPHA);
attr_node,
attr,
compiler.encode_uchar4(compiler.stack_assign(alpha_out), NODE_ATTR_OUTPUT_FLOAT_ALPHA),
__float_as_uint(bump_filter_width));
}
}
@@ -6081,6 +6152,7 @@ void AttributeNode::compile(OSLCompiler &compiler)
else {
compiler.parameter("bump_offset", "center");
}
compiler.parameter("bump_filter_width", bump_filter_width);
if (Attribute::name_standard(attribute.c_str()) != ATTR_STD_NONE) {
compiler.parameter("name", (string("geom:") + attribute.c_str()).c_str());
@@ -6234,10 +6306,11 @@ void WireframeNode::compile(SVMCompiler &compiler)
else if (bump == SHADER_BUMP_DY) {
bump_offset = NODE_BUMP_OFFSET_DY;
}
compiler.add_node(NODE_WIREFRAME,
compiler.stack_assign(size_in),
compiler.stack_assign(fac_out),
compiler.encode_uchar4(use_pixel_size, bump_offset, 0, 0));
compiler.add_node(
NODE_WIREFRAME,
compiler.stack_assign(size_in),
__float_as_uint(bump_filter_width),
compiler.encode_uchar4(use_pixel_size, bump_offset, compiler.stack_assign(fac_out), 0));
}
void WireframeNode::compile(OSLCompiler &compiler)
@@ -6251,6 +6324,8 @@ void WireframeNode::compile(OSLCompiler &compiler)
else {
compiler.parameter("bump_offset", "center");
}
compiler.parameter("bump_filter_width", bump_filter_width);
compiler.parameter(this, "use_pixel_size");
compiler.add(this, "node_wireframe");
}
@@ -6976,6 +7051,7 @@ NODE_DEFINE(BumpNode)
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
SOCKET_IN_FLOAT(distance, "Distance", 0.1f);
SOCKET_IN_FLOAT(filter_width, "Filter Width", 0.1f);
SOCKET_OUT_NORMAL(normal, "Normal");
@@ -7009,6 +7085,7 @@ void BumpNode::compile(SVMCompiler &compiler)
compiler.stack_assign(dy_in),
compiler.stack_assign(strength_in)),
compiler.encode_uchar4(compiler.stack_assign(normal_out), compiler.get_bump_state_offset()));
compiler.add_node(__float_as_uint(filter_width));
}
void BumpNode::compile(OSLCompiler &compiler)
+1
View File
@@ -1480,6 +1480,7 @@ class BumpNode : public ShaderNode {
NODE_SOCKET_API(bool, invert)
NODE_SOCKET_API(bool, use_object_space)
NODE_SOCKET_API(float, height)
NODE_SOCKET_API(float, filter_width)
NODE_SOCKET_API(float, sample_center)
NODE_SOCKET_API(float, sample_x)
NODE_SOCKET_API(float, sample_y)
@@ -1287,6 +1287,21 @@ static void do_version_color_to_float_conversion(bNodeTree *node_tree)
}
}
static void do_version_bump_filter_width(bNodeTree *node_tree)
{
LISTBASE_FOREACH_MUTABLE (bNode *, node, &node_tree->nodes) {
if (node->type_legacy != SH_NODE_BUMP) {
continue;
}
bNodeSocket *filter_width_input = blender::bke::node_find_socket(
node, SOCK_IN, "Filter Width");
if (filter_width_input) {
*version_cycles_node_socket_float_value(filter_width_input) = 1.0f;
}
}
}
static void do_version_viewer_shortcut(bNodeTree *node_tree)
{
LISTBASE_FOREACH_MUTABLE (bNode *, node, &node_tree->nodes) {
@@ -1636,6 +1651,9 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
if (ntree->type == NTREE_COMPOSIT) {
do_version_color_to_float_conversion(ntree);
}
else if (ntree->type == NTREE_SHADER) {
do_version_bump_filter_width(ntree);
}
}
FOREACH_NODETREE_END;
}
@@ -621,8 +621,12 @@ vec2 bsdf_lut(float cos_theta, float roughness, float ior, bool do_multiscatter)
vec3 displacement_bump()
{
# if defined(GPU_FRAGMENT_SHADER) && !defined(MAT_GEOM_CURVES)
/* This is the filter width for automatic displacement + bump mapping, which is fixed.
* NOTE: keep the same as default bump node filter width. */
const float bump_filter_width = 0.1;
vec2 dHd;
dF_branch(dot(nodetree_displacement(), g_data.N + dF_impl(g_data.N)), dHd);
dF_branch(dot(nodetree_displacement(), g_data.N + dF_impl(g_data.N)), bump_filter_width, dHd);
vec3 dPdx = dFdx(g_data.P);
vec3 dPdy = dFdy(g_data.P);
@@ -637,9 +641,7 @@ vec3 displacement_bump()
vec3 surfgrad = dHd.x * Rx + dHd.y * Ry;
float facing = FrontFacing ? 1.0 : -1.0;
/* NOTE: keep the same as defined `BUMP_DX`. */
const float bump_dx = 0.1;
return normalize(bump_dx * abs(det) * g_data.N - facing * sign(det) * surfgrad);
return normalize(bump_filter_width * abs(det) * g_data.N - facing * sign(det) * surfgrad);
# else
return g_data.N;
# endif
+1 -1
View File
@@ -186,7 +186,7 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *r_
* The given function should return a float.
* The result will be a vec2 containing dFdx and dFdy result of that function.
*/
GPUNodeLink *GPU_differentiate_float_function(const char *function_name);
GPUNodeLink *GPU_differentiate_float_function(const char *function_name, const float filter_width);
bool GPU_link(GPUMaterial *mat, const char *name, ...);
bool GPU_stack_link(GPUMaterial *mat,
+7 -3
View File
@@ -151,7 +151,10 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
case GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN:
input->source = GPU_SOURCE_FUNCTION_CALL;
/* NOTE(@fclem): End of function call is the return variable set during codegen. */
SNPRINTF(input->function_call, "dF_branch_incomplete(%s(), ", link->function_name);
SNPRINTF(input->function_call,
"dF_branch_incomplete(%s(), %g, ",
link->differentiate_float.function_name,
link->differentiate_float.filter_width);
break;
default:
break;
@@ -638,11 +641,12 @@ GPUNodeLink *GPU_uniform(const float *num)
return link;
}
GPUNodeLink *GPU_differentiate_float_function(const char *function_name)
GPUNodeLink *GPU_differentiate_float_function(const char *function_name, const float filter_width)
{
GPUNodeLink *link = gpu_node_link_create();
link->link_type = GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN;
link->function_name = function_name;
link->differentiate_float.function_name = function_name;
link->differentiate_float.filter_width = filter_width;
return link;
}
+4 -1
View File
@@ -97,7 +97,10 @@ struct GPUNodeLink {
/* GPU_NODE_LINK_IMAGE_BLENDER */
GPUMaterialTexture *texture;
/* GPU_NODE_LINK_DIFFERENTIATE_FLOAT_FN */
const char *function_name;
struct {
const char *function_name;
float filter_width;
} differentiate_float;
};
};
@@ -322,8 +322,8 @@ GlobalData g_data;
/* Stubs. */
# define dF_impl(a) (vec3(0.0))
# define dF_branch(a, b) (b = vec2(0.0))
# define dF_branch_incomplete(a, b) (b = vec2(0.0))
# define dF_branch(a, b, c) (c = vec2(0.0))
# define dF_branch_incomplete(a, b, c) (c = vec2(0.0))
#elif defined(GPU_FAST_DERIVATIVE) /* TODO(@fclem): User Option? */
/* Fast derivatives */
@@ -334,33 +334,33 @@ vec3 dF_impl(vec3 v)
void dF_branch(float fn, out vec2 result)
{
/* NOTE: this function is currently unused, once it is used we need to check if `BUMP_DX/BUMP_DY`
* needs to be applied. */
/* NOTE: this function is currently unused, once it is used we need to check if
* `g_derivative_filter_width` needs to be applied. */
result.x = dFdx(fn);
result.y = dFdy(fn);
}
#else
/* Offset of coordinates for evaluating bump node. Unit in pixel. */
# define BUMP_DX 0.1
# define BUMP_DY BUMP_DX
/* Offset of coordinates for evaluating bump node. Unit in pixel. */
float g_derivative_filter_width = 0.0;
/* Precise derivatives */
int g_derivative_flag = 0;
vec3 dF_impl(vec3 v)
{
if (g_derivative_flag > 0) {
return dFdx(v) * BUMP_DX;
return dFdx(v) * g_derivative_filter_width;
}
else if (g_derivative_flag < 0) {
return dFdy(v) * BUMP_DY;
return dFdy(v) * g_derivative_filter_width;
}
return vec3(0.0);
}
# define dF_branch(fn, result) \
# define dF_branch(fn, filter_width, result) \
if (true) { \
g_derivative_filter_width = filter_width; \
g_derivative_flag = 1; \
result.x = (fn); \
g_derivative_flag = -1; \
@@ -370,8 +370,9 @@ vec3 dF_impl(vec3 v)
}
/* Used when the non-offset value is already computed elsewhere */
# define dF_branch_incomplete(fn, result) \
# define dF_branch_incomplete(fn, filter_width, result) \
if (true) { \
g_derivative_filter_width = filter_width; \
g_derivative_flag = 1; \
result.x = (fn); \
g_derivative_flag = -1; \
@@ -18,6 +18,7 @@ void differentiate_texco(vec4 v, out vec3 df)
void node_bump(float strength,
float dist,
float height,
float filter_width,
vec3 N,
vec2 height_xy,
float invert,
@@ -42,9 +43,7 @@ void node_bump(float strength,
strength = max(strength, 0.0);
/* NOTE: keep the same as defined `BUMP_DX`. */
const float bump_dx = 0.1;
result = normalize(bump_dx * abs(det) * N - dist * sign(det) * surfgrad);
result = normalize(filter_width * abs(det) * N - dist * sign(det) * surfgrad);
result = normalize(mix(N, result, strength));
#else
result = N;
@@ -32,7 +32,21 @@ static void node_declare(NodeDeclarationBuilder &b)
.max(1000.0f)
.description(
"Multiplier for the height value to control the overall distance for bump mapping");
b.add_input<decl::Float>("Height").default_value(1.0f).min(-1000.0f).max(1000.0f).hide_value();
b.add_input<decl::Float>("Filter Width")
.default_value(0.1f)
.min(0.001)
.max(10.0f)
.subtype(PROP_PIXEL)
.description(
"Filter width in pixels, used to compute the bump mapping direction. For most textures "
"the default value of 0.1 enables subpixel filtering for stable results. For stepwise "
"textures a larger filter width can be used to get a bevel like effect on the edges");
b.add_input<decl::Float>("Height")
.default_value(1.0f)
.min(-1000.0f)
.max(1000.0f)
.hide_value()
.description("Height above surface. Connect the height map texture to this input");
b.add_input<decl::Vector>("Normal").min(-1.0f).max(1.0f).hide_value();
b.add_output<decl::Vector>("Normal");
}
@@ -61,6 +75,7 @@ static int gpu_shader_bump(GPUMaterial *mat,
GPU_link(mat, "world_normals_get", &in[3].link);
}
const float filter_width = in[4].vec[0];
const char *height_function = GPU_material_split_sub_function(mat, GPU_FLOAT, &in[2].link);
/* TODO (Miguel Pozo):
@@ -71,7 +86,7 @@ static int gpu_shader_bump(GPUMaterial *mat,
* A better option would be to add a "value" input socket (in this case the height) to the
* differentiate node, but currently this kind of intermediate nodes are pruned in the
* code generation process (see #104265), so we need to fix that first. */
GPUNodeLink *dheight = GPU_differentiate_float_function(height_function);
GPUNodeLink *dheight = GPU_differentiate_float_function(height_function, filter_width);
float invert = (node->custom1) ? -1.0 : 1.0;
+4 -1
View File
@@ -254,9 +254,12 @@ def main():
# OSL tests:
# Blackbody is slightly different between SVM and OSL.
# Microfacet hair renders slightly differently, and fails on Windows and Linux with OSL
#
# both_displacement.blend has slight differences between Linux and other platforms.
test_dir_name = Path(args.testdir).name
if (test_dir_name in {'motion_blur', 'integrator'}) or ((args.osl) and (test_dir_name in {'shader', 'hair'})):
if (test_dir_name in {'motion_blur', 'integrator', "displacement"}) or \
((args.osl) and (test_dir_name in {'shader', 'hair'})):
report.set_fail_threshold(0.032)
# Layer mixing is different between SVM and OSL, so a few tests have