2011-04-27 11:58:34 +00:00
|
|
|
/*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Copyright 2011-2013 Blender Foundation
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* 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
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* 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
|
2014-12-25 01:50:24 +00:00
|
|
|
* limitations under the License.
|
2011-04-27 11:58:34 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
/* Texture Coordinate Node */
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
ccl_device void svm_node_tex_coord(
|
|
|
|
KernelGlobals *kg, ShaderData *sd, int path_flag, float *stack, uint4 node, int *offset)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
float3 data;
|
|
|
|
uint type = node.y;
|
|
|
|
uint out_offset = node.z;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case NODE_TEXCO_OBJECT: {
|
|
|
|
data = sd->P;
|
|
|
|
if (node.w == 0) {
|
|
|
|
if (sd->object != OBJECT_NONE) {
|
|
|
|
object_inverse_position_transform(kg, sd, &data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Transform tfm;
|
|
|
|
tfm.x = read_node_float(kg, offset);
|
|
|
|
tfm.y = read_node_float(kg, offset);
|
|
|
|
tfm.z = read_node_float(kg, offset);
|
|
|
|
data = transform_point(&tfm, data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_NORMAL: {
|
|
|
|
data = sd->N;
|
|
|
|
object_inverse_normal_transform(kg, sd, &data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_CAMERA: {
|
|
|
|
Transform tfm = kernel_data.cam.worldtocamera;
|
|
|
|
|
|
|
|
if (sd->object != OBJECT_NONE)
|
|
|
|
data = transform_point(&tfm, sd->P);
|
|
|
|
else
|
|
|
|
data = transform_point(&tfm, sd->P + camera_position(kg));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_WINDOW: {
|
|
|
|
if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
|
|
|
|
kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
|
|
|
|
data = camera_world_to_ndc(kg, sd, sd->ray_P);
|
|
|
|
else
|
|
|
|
data = camera_world_to_ndc(kg, sd, sd->P);
|
|
|
|
data.z = 0.0f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_REFLECTION: {
|
|
|
|
if (sd->object != OBJECT_NONE)
|
|
|
|
data = 2.0f * dot(sd->N, sd->I) * sd->N - sd->I;
|
|
|
|
else
|
|
|
|
data = sd->I;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_DUPLI_GENERATED: {
|
|
|
|
data = object_dupli_generated(kg, sd->object);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_DUPLI_UV: {
|
|
|
|
data = object_dupli_uv(kg, sd->object);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_VOLUME_GENERATED: {
|
|
|
|
data = sd->P;
|
2013-12-31 16:33:55 +00:00
|
|
|
|
2014-03-29 12:03:48 +00:00
|
|
|
#ifdef __VOLUME__
|
2019-04-17 04:17:24 +00:00
|
|
|
if (sd->object != OBJECT_NONE)
|
|
|
|
data = volume_normalized_position(kg, sd, data);
|
2014-03-29 12:03:48 +00:00
|
|
|
#endif
|
2019-04-17 04:17:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
stack_store_float3(stack, out_offset, data);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
ccl_device void svm_node_tex_coord_bump_dx(
|
|
|
|
KernelGlobals *kg, ShaderData *sd, int path_flag, float *stack, uint4 node, int *offset)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
2019-04-17 04:17:24 +00:00
|
|
|
float3 data;
|
|
|
|
uint type = node.y;
|
|
|
|
uint out_offset = node.z;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case NODE_TEXCO_OBJECT: {
|
|
|
|
data = sd->P + sd->dP.dx;
|
|
|
|
if (node.w == 0) {
|
|
|
|
if (sd->object != OBJECT_NONE) {
|
|
|
|
object_inverse_position_transform(kg, sd, &data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Transform tfm;
|
|
|
|
tfm.x = read_node_float(kg, offset);
|
|
|
|
tfm.y = read_node_float(kg, offset);
|
|
|
|
tfm.z = read_node_float(kg, offset);
|
|
|
|
data = transform_point(&tfm, data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_NORMAL: {
|
|
|
|
data = sd->N;
|
|
|
|
object_inverse_normal_transform(kg, sd, &data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_CAMERA: {
|
|
|
|
Transform tfm = kernel_data.cam.worldtocamera;
|
|
|
|
|
|
|
|
if (sd->object != OBJECT_NONE)
|
|
|
|
data = transform_point(&tfm, sd->P + sd->dP.dx);
|
|
|
|
else
|
|
|
|
data = transform_point(&tfm, sd->P + sd->dP.dx + camera_position(kg));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_WINDOW: {
|
|
|
|
if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
|
|
|
|
kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
|
|
|
|
data = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dx);
|
|
|
|
else
|
|
|
|
data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx);
|
|
|
|
data.z = 0.0f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_REFLECTION: {
|
|
|
|
if (sd->object != OBJECT_NONE)
|
|
|
|
data = 2.0f * dot(sd->N, sd->I) * sd->N - sd->I;
|
|
|
|
else
|
|
|
|
data = sd->I;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_DUPLI_GENERATED: {
|
|
|
|
data = object_dupli_generated(kg, sd->object);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_DUPLI_UV: {
|
|
|
|
data = object_dupli_uv(kg, sd->object);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_VOLUME_GENERATED: {
|
|
|
|
data = sd->P + sd->dP.dx;
|
|
|
|
|
|
|
|
# ifdef __VOLUME__
|
|
|
|
if (sd->object != OBJECT_NONE)
|
|
|
|
data = volume_normalized_position(kg, sd, data);
|
|
|
|
# endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stack_store_float3(stack, out_offset, data);
|
2011-04-27 11:58:34 +00:00
|
|
|
#else
|
2019-04-17 04:17:24 +00:00
|
|
|
svm_node_tex_coord(kg, sd, path_flag, stack, node, offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
ccl_device void svm_node_tex_coord_bump_dy(
|
|
|
|
KernelGlobals *kg, ShaderData *sd, int path_flag, float *stack, uint4 node, int *offset)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
2019-04-17 04:17:24 +00:00
|
|
|
float3 data;
|
|
|
|
uint type = node.y;
|
|
|
|
uint out_offset = node.z;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case NODE_TEXCO_OBJECT: {
|
|
|
|
data = sd->P + sd->dP.dy;
|
|
|
|
if (node.w == 0) {
|
|
|
|
if (sd->object != OBJECT_NONE) {
|
|
|
|
object_inverse_position_transform(kg, sd, &data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Transform tfm;
|
|
|
|
tfm.x = read_node_float(kg, offset);
|
|
|
|
tfm.y = read_node_float(kg, offset);
|
|
|
|
tfm.z = read_node_float(kg, offset);
|
|
|
|
data = transform_point(&tfm, data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_NORMAL: {
|
|
|
|
data = sd->N;
|
|
|
|
object_inverse_normal_transform(kg, sd, &data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_CAMERA: {
|
|
|
|
Transform tfm = kernel_data.cam.worldtocamera;
|
|
|
|
|
|
|
|
if (sd->object != OBJECT_NONE)
|
|
|
|
data = transform_point(&tfm, sd->P + sd->dP.dy);
|
|
|
|
else
|
|
|
|
data = transform_point(&tfm, sd->P + sd->dP.dy + camera_position(kg));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_WINDOW: {
|
|
|
|
if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
|
|
|
|
kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
|
|
|
|
data = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dy);
|
|
|
|
else
|
|
|
|
data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy);
|
|
|
|
data.z = 0.0f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_REFLECTION: {
|
|
|
|
if (sd->object != OBJECT_NONE)
|
|
|
|
data = 2.0f * dot(sd->N, sd->I) * sd->N - sd->I;
|
|
|
|
else
|
|
|
|
data = sd->I;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_DUPLI_GENERATED: {
|
|
|
|
data = object_dupli_generated(kg, sd->object);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_DUPLI_UV: {
|
|
|
|
data = object_dupli_uv(kg, sd->object);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NODE_TEXCO_VOLUME_GENERATED: {
|
|
|
|
data = sd->P + sd->dP.dy;
|
|
|
|
|
|
|
|
# ifdef __VOLUME__
|
|
|
|
if (sd->object != OBJECT_NONE)
|
|
|
|
data = volume_normalized_position(kg, sd, data);
|
|
|
|
# endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stack_store_float3(stack, out_offset, data);
|
2011-04-27 11:58:34 +00:00
|
|
|
#else
|
2019-04-17 04:17:24 +00:00
|
|
|
svm_node_tex_coord(kg, sd, path_flag, stack, node, offset);
|
2011-04-27 11:58:34 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
2012-11-06 19:59:02 +00:00
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
uint color_offset, strength_offset, normal_offset, space;
|
|
|
|
decode_node_uchar4(node.y, &color_offset, &strength_offset, &normal_offset, &space);
|
|
|
|
|
|
|
|
float3 color = stack_load_float3(stack, color_offset);
|
|
|
|
color = 2.0f * make_float3(color.x - 0.5f, color.y - 0.5f, color.z - 0.5f);
|
|
|
|
|
|
|
|
bool is_backfacing = (sd->flag & SD_BACKFACING) != 0;
|
|
|
|
float3 N;
|
|
|
|
|
|
|
|
if (space == NODE_NORMAL_MAP_TANGENT) {
|
|
|
|
/* tangent space */
|
|
|
|
if (sd->object == OBJECT_NONE) {
|
|
|
|
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* first try to get tangent attribute */
|
|
|
|
const AttributeDescriptor attr = find_attribute(kg, sd, node.z);
|
|
|
|
const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w);
|
|
|
|
const AttributeDescriptor attr_normal = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL);
|
|
|
|
|
|
|
|
if (attr.offset == ATTR_STD_NOT_FOUND || attr_sign.offset == ATTR_STD_NOT_FOUND ||
|
|
|
|
attr_normal.offset == ATTR_STD_NOT_FOUND) {
|
|
|
|
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get _unnormalized_ interpolated normal and tangent */
|
|
|
|
float3 tangent = primitive_surface_attribute_float3(kg, sd, attr, NULL, NULL);
|
|
|
|
float sign = primitive_surface_attribute_float(kg, sd, attr_sign, NULL, NULL);
|
|
|
|
float3 normal;
|
|
|
|
|
|
|
|
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
|
|
|
normal = primitive_surface_attribute_float3(kg, sd, attr_normal, NULL, NULL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
normal = sd->Ng;
|
|
|
|
|
|
|
|
/* the normal is already inverted, which is too soon for the math here */
|
|
|
|
if (is_backfacing) {
|
|
|
|
normal = -normal;
|
|
|
|
}
|
|
|
|
|
|
|
|
object_inverse_normal_transform(kg, sd, &normal);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* apply normal map */
|
|
|
|
float3 B = sign * cross(normal, tangent);
|
|
|
|
N = safe_normalize(color.x * tangent + color.y * B + color.z * normal);
|
|
|
|
|
|
|
|
/* transform to world space */
|
|
|
|
object_normal_transform(kg, sd, &N);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* strange blender convention */
|
|
|
|
if (space == NODE_NORMAL_MAP_BLENDER_OBJECT || space == NODE_NORMAL_MAP_BLENDER_WORLD) {
|
|
|
|
color.y = -color.y;
|
|
|
|
color.z = -color.z;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* object, world space */
|
|
|
|
N = color;
|
|
|
|
|
|
|
|
if (space == NODE_NORMAL_MAP_OBJECT || space == NODE_NORMAL_MAP_BLENDER_OBJECT)
|
|
|
|
object_normal_transform(kg, sd, &N);
|
|
|
|
else
|
|
|
|
N = safe_normalize(N);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* invert normal for backfacing polygons */
|
|
|
|
if (is_backfacing) {
|
|
|
|
N = -N;
|
|
|
|
}
|
|
|
|
|
|
|
|
float strength = stack_load_float(stack, strength_offset);
|
|
|
|
|
|
|
|
if (strength != 1.0f) {
|
|
|
|
strength = max(strength, 0.0f);
|
|
|
|
N = safe_normalize(sd->N + (N - sd->N) * strength);
|
|
|
|
}
|
|
|
|
|
|
|
|
N = ensure_valid_reflection(sd->Ng, sd->I, N);
|
|
|
|
|
|
|
|
if (is_zero(N)) {
|
|
|
|
N = sd->N;
|
|
|
|
}
|
|
|
|
|
|
|
|
stack_store_float3(stack, normal_offset, N);
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
2012-11-06 19:59:02 +00:00
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
uint tangent_offset, direction_type, axis;
|
|
|
|
decode_node_uchar4(node.y, &tangent_offset, &direction_type, &axis, NULL);
|
|
|
|
|
|
|
|
float3 tangent;
|
|
|
|
float3 attribute_value;
|
|
|
|
const AttributeDescriptor desc = find_attribute(kg, sd, node.z);
|
|
|
|
if (desc.offset != ATTR_STD_NOT_FOUND) {
|
|
|
|
if (desc.type == NODE_ATTR_FLOAT2) {
|
|
|
|
float2 value = primitive_surface_attribute_float2(kg, sd, desc, NULL, NULL);
|
|
|
|
attribute_value.x = value.x;
|
|
|
|
attribute_value.y = value.y;
|
|
|
|
attribute_value.z = 0.0f;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
attribute_value = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (direction_type == NODE_TANGENT_UVMAP) {
|
|
|
|
/* UV map */
|
|
|
|
if (desc.offset == ATTR_STD_NOT_FOUND)
|
|
|
|
tangent = make_float3(0.0f, 0.0f, 0.0f);
|
|
|
|
else
|
|
|
|
tangent = attribute_value;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* radial */
|
|
|
|
float3 generated;
|
|
|
|
|
|
|
|
if (desc.offset == ATTR_STD_NOT_FOUND)
|
|
|
|
generated = sd->P;
|
|
|
|
else
|
|
|
|
generated = attribute_value;
|
|
|
|
|
|
|
|
if (axis == NODE_TANGENT_AXIS_X)
|
|
|
|
tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));
|
|
|
|
else if (axis == NODE_TANGENT_AXIS_Y)
|
|
|
|
tangent = make_float3(-(generated.z - 0.5f), 0.0f, (generated.x - 0.5f));
|
|
|
|
else
|
|
|
|
tangent = make_float3(-(generated.y - 0.5f), (generated.x - 0.5f), 0.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
object_normal_transform(kg, sd, &tangent);
|
|
|
|
tangent = cross(sd->N, normalize(cross(tangent, sd->N)));
|
|
|
|
stack_store_float3(stack, tangent_offset, tangent);
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_END
|