diff options
Diffstat (limited to 'intern/cycles/kernel/svm/displace.h')
-rw-r--r-- | intern/cycles/kernel/svm/displace.h | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/intern/cycles/kernel/svm/displace.h b/intern/cycles/kernel/svm/displace.h new file mode 100644 index 00000000000..cea1436f36d --- /dev/null +++ b/intern/cycles/kernel/svm/displace.h @@ -0,0 +1,180 @@ +/* + * Copyright 2011-2013 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. + */ + +#pragma once + +#include "kernel/sample/mapping.h" + +CCL_NAMESPACE_BEGIN + +/* Bump Node */ + +ccl_device_noinline void svm_node_set_bump(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + uint4 node) +{ +#ifdef __RAY_DIFFERENTIALS__ + /* get normal input */ + uint normal_offset, scale_offset, invert, use_object_space; + svm_unpack_node_uchar4(node.y, &normal_offset, &scale_offset, &invert, &use_object_space); + + float3 normal_in = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N; + + float3 dPdx = sd->dP.dx; + float3 dPdy = sd->dP.dy; + + if (use_object_space) { + object_inverse_normal_transform(kg, sd, &normal_in); + object_inverse_dir_transform(kg, sd, &dPdx); + object_inverse_dir_transform(kg, sd, &dPdy); + } + + /* get surface tangents from normal */ + float3 Rx = cross(dPdy, normal_in); + float3 Ry = cross(normal_in, dPdx); + + /* get bump values */ + uint c_offset, x_offset, y_offset, strength_offset; + svm_unpack_node_uchar4(node.z, &c_offset, &x_offset, &y_offset, &strength_offset); + + float h_c = stack_load_float(stack, c_offset); + float h_x = stack_load_float(stack, x_offset); + float h_y = stack_load_float(stack, y_offset); + + /* compute surface gradient and determinant */ + float det = dot(dPdx, Rx); + float3 surfgrad = (h_x - h_c) * Rx + (h_y - h_c) * Ry; + + float absdet = fabsf(det); + + float strength = stack_load_float(stack, strength_offset); + float scale = stack_load_float(stack, scale_offset); + + if (invert) + scale *= -1.0f; + + strength = max(strength, 0.0f); + + /* compute and output perturbed normal */ + float3 normal_out = safe_normalize(absdet * normal_in - scale * signf(det) * surfgrad); + if (is_zero(normal_out)) { + normal_out = normal_in; + } + else { + normal_out = normalize(strength * normal_out + (1.0f - strength) * normal_in); + } + + if (use_object_space) { + object_normal_transform(kg, sd, &normal_out); + } + + normal_out = ensure_valid_reflection(sd->Ng, sd->I, normal_out); + + stack_store_float3(stack, node.w, normal_out); +#endif +} + +/* Displacement Node */ + +ccl_device void svm_node_set_displacement(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + uint fac_offset) +{ + float3 dP = stack_load_float3(stack, fac_offset); + sd->P += dP; +} + +ccl_device_noinline void svm_node_displacement(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + uint4 node) +{ + uint height_offset, midlevel_offset, scale_offset, normal_offset; + svm_unpack_node_uchar4(node.y, &height_offset, &midlevel_offset, &scale_offset, &normal_offset); + + float height = stack_load_float(stack, height_offset); + float midlevel = stack_load_float(stack, midlevel_offset); + float scale = stack_load_float(stack, scale_offset); + float3 normal = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N; + uint space = node.w; + + float3 dP = normal; + + if (space == NODE_NORMAL_MAP_OBJECT) { + /* Object space. */ + object_inverse_normal_transform(kg, sd, &dP); + dP *= (height - midlevel) * scale; + object_dir_transform(kg, sd, &dP); + } + else { + /* World space. */ + dP *= (height - midlevel) * scale; + } + + stack_store_float3(stack, node.z, dP); +} + +ccl_device_noinline int svm_node_vector_displacement( + KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset) +{ + uint4 data_node = read_node(kg, &offset); + uint space = data_node.x; + + uint vector_offset, midlevel_offset, scale_offset, displacement_offset; + svm_unpack_node_uchar4( + node.y, &vector_offset, &midlevel_offset, &scale_offset, &displacement_offset); + + float3 vector = stack_load_float3(stack, vector_offset); + float midlevel = stack_load_float(stack, midlevel_offset); + float scale = stack_load_float(stack, scale_offset); + float3 dP = (vector - make_float3(midlevel, midlevel, midlevel)) * scale; + + if (space == NODE_NORMAL_MAP_TANGENT) { + /* Tangent space. */ + float3 normal = sd->N; + object_inverse_normal_transform(kg, sd, &normal); + + const AttributeDescriptor attr = find_attribute(kg, sd, node.z); + float3 tangent; + if (attr.offset != ATTR_STD_NOT_FOUND) { + tangent = primitive_surface_attribute_float3(kg, sd, attr, NULL, NULL); + } + else { + tangent = normalize(sd->dPdu); + } + + float3 bitangent = normalize(cross(normal, tangent)); + const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w); + if (attr_sign.offset != ATTR_STD_NOT_FOUND) { + float sign = primitive_surface_attribute_float(kg, sd, attr_sign, NULL, NULL); + bitangent *= sign; + } + + dP = tangent * dP.x + normal * dP.y + bitangent * dP.z; + } + + if (space != NODE_NORMAL_MAP_WORLD) { + /* Tangent or object space. */ + object_dir_transform(kg, sd, &dP); + } + + stack_store_float3(stack, displacement_offset, dP); + return offset; +} + +CCL_NAMESPACE_END |