From ebd431d58080a300b266ffec4e87c0e1f457bfd8 Mon Sep 17 00:00:00 2001 From: Weizhen Huang Date: Tue, 6 Jun 2023 13:19:28 +0200 Subject: [PATCH] Fix wrong normal transformation in Vector Transform shader node Normals do not transform the same way as vectors do, see https://www.pbr-book.org/3ed-2018/Geometry_and_Transformations/Applying_Transformations --- intern/cycles/kernel/svm/vector_transform.h | 79 ++++++++++++++------- 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/intern/cycles/kernel/svm/vector_transform.h b/intern/cycles/kernel/svm/vector_transform.h index 2c69e6c7b63..3eb2f7a5207 100644 --- a/intern/cycles/kernel/svm/vector_transform.h +++ b/intern/cycles/kernel/svm/vector_transform.h @@ -26,23 +26,31 @@ ccl_device_noinline void svm_node_vector_transform(KernelGlobals kg, Transform tfm; bool is_object = (sd->object != OBJECT_NONE); - bool is_direction = (type == NODE_VECTOR_TRANSFORM_TYPE_VECTOR || - type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL); + bool is_normal = (type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL); + bool is_direction = (type == NODE_VECTOR_TRANSFORM_TYPE_VECTOR); /* From world */ if (from == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD) { if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) { - tfm = kernel_data.cam.worldtocamera; - if (is_direction) - in = transform_direction(&tfm, in); - else - in = transform_point(&tfm, in); + if (is_normal) { + tfm = kernel_data.cam.cameratoworld; + in = normalize(transform_direction_transposed(&tfm, in)); + } + else { + tfm = kernel_data.cam.worldtocamera; + in = is_direction ? transform_direction(&tfm, in) : transform_point(&tfm, in); + } } else if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) { - if (is_direction) + if (is_normal) { + object_inverse_normal_transform(kg, sd, &in); + } + else if (is_direction) { object_inverse_dir_transform(kg, sd, &in); - else + } + else { object_inverse_position_transform(kg, sd, &in); + } } } @@ -51,17 +59,25 @@ ccl_device_noinline void svm_node_vector_transform(KernelGlobals kg, if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD || to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT) { - tfm = kernel_data.cam.cameratoworld; - if (is_direction) - in = transform_direction(&tfm, in); - else - in = transform_point(&tfm, in); + if (is_normal) { + tfm = kernel_data.cam.worldtocamera; + in = normalize(transform_direction_transposed(&tfm, in)); + } + else { + tfm = kernel_data.cam.cameratoworld; + in = is_direction ? transform_direction(&tfm, in) : transform_point(&tfm, in); + } } if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT && is_object) { - if (is_direction) + if (is_normal) { + object_inverse_normal_transform(kg, sd, &in); + } + else if (is_direction) { object_inverse_dir_transform(kg, sd, &in); - else + } + else { object_inverse_position_transform(kg, sd, &in); + } } } @@ -71,24 +87,33 @@ ccl_device_noinline void svm_node_vector_transform(KernelGlobals kg, to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) && is_object) { - if (is_direction) + if (is_normal) { + object_normal_transform(kg, sd, &in); + } + else if (is_direction) { object_dir_transform(kg, sd, &in); - else + } + else { object_position_transform(kg, sd, &in); + } } if (to == NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA) { - tfm = kernel_data.cam.worldtocamera; - if (is_direction) - in = transform_direction(&tfm, in); - else - in = transform_point(&tfm, in); + if (is_normal) { + tfm = kernel_data.cam.cameratoworld; + in = normalize(transform_direction_transposed(&tfm, in)); + } + else { + tfm = kernel_data.cam.worldtocamera; + if (is_direction) { + in = transform_direction(&tfm, in); + } + else { + in = transform_point(&tfm, in); + } + } } } - /* Normalize Normal */ - if (type == NODE_VECTOR_TRANSFORM_TYPE_NORMAL) - in = normalize(in); - /* Output */ if (stack_valid(vector_out)) { stack_store_float3(stack, vector_out, in);