Cycles: Fix nan in decomposed transform for degenerated input
The decomposed transform would have consists of nan values if the input transform had zero scale. Now the decomposition will check for zero scale, and if it is detected then the result will be ensured to be finite. Additionally, rotation value will be copied from previous/next time step to help avoiding obscure interpolation. The latter step can become more comprehensive than the current simple implementation. Differential Revision: https://developer.blender.org/D8450
This commit is contained in:
parent
7f6530e5bd
commit
51af20b856
|
@ -112,3 +112,4 @@ set_source_files_properties(util_avxf_avx_test.cpp PROPERTIES COMPILE_FLAGS "${C
|
|||
CYCLES_TEST(util_avxf_avx "cycles_util;bf_intern_numaapi;${OPENIMAGEIO_LIBRARIES};${BOOST_LIBRARIES}")
|
||||
set_source_files_properties(util_avxf_avx2_test.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_KERNEL_FLAGS}")
|
||||
CYCLES_TEST(util_avxf_avx2 "cycles_util;bf_intern_numaapi;${OPENIMAGEIO_LIBRARIES};${BOOST_LIBRARIES}")
|
||||
CYCLES_TEST(util_transform "cycles_util;${OPENIMAGEIO_LIBRARIES};${BOOST_LIBRARIES}")
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2011-2020 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.
|
||||
*/
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "util/util_transform.h"
|
||||
#include "util/util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
TEST(transform_motion_decompose, Degenerated)
|
||||
{
|
||||
// Simple case: single degenerated matrix.
|
||||
{
|
||||
vector<Transform> motion = {transform_scale(0.0f, 0.0f, 0.0f)};
|
||||
vector<DecomposedTransform> decomp(motion.size());
|
||||
transform_motion_decompose(decomp.data(), motion.data(), motion.size());
|
||||
EXPECT_TRUE(transform_decomposed_isfinite_safe(&decomp[0]));
|
||||
}
|
||||
|
||||
// Copy from previous to current.
|
||||
{
|
||||
vector<Transform> motion = {transform_rotate(M_PI_4_F, make_float3(1.0f, 1.0f, 1.0f)),
|
||||
transform_scale(0.0f, 0.0f, 0.0f)};
|
||||
vector<DecomposedTransform> decomp(motion.size());
|
||||
transform_motion_decompose(decomp.data(), motion.data(), motion.size());
|
||||
EXPECT_NEAR(len(decomp[1].x - decomp[0].x), 0.0f, 1e-6f);
|
||||
}
|
||||
|
||||
// Copy from next to current.
|
||||
{
|
||||
vector<Transform> motion = {transform_scale(0.0f, 0.0f, 0.0f),
|
||||
transform_rotate(M_PI_4_F, make_float3(1.0f, 1.0f, 1.0f))};
|
||||
vector<DecomposedTransform> decomp(motion.size());
|
||||
transform_motion_decompose(decomp.data(), motion.data(), motion.size());
|
||||
EXPECT_NEAR(len(decomp[0].x - decomp[1].x), 0.0f, 1e-6f);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
|
@ -269,17 +269,17 @@ static void transform_decompose(DecomposedTransform *decomp, const Transform *tf
|
|||
/* extract scale and shear first */
|
||||
float3 scale, shear;
|
||||
scale.x = len(colx);
|
||||
colx /= scale.x;
|
||||
colx = safe_divide_float3_float(colx, scale.x);
|
||||
shear.z = dot(colx, coly);
|
||||
coly -= shear.z * colx;
|
||||
scale.y = len(coly);
|
||||
coly /= scale.y;
|
||||
coly = safe_divide_float3_float(coly, scale.y);
|
||||
shear.y = dot(colx, colz);
|
||||
colz -= shear.y * colx;
|
||||
shear.x = dot(coly, colz);
|
||||
colz -= shear.x * coly;
|
||||
scale.z = len(colz);
|
||||
colz /= scale.z;
|
||||
colz = safe_divide_float3_float(colz, scale.z);
|
||||
|
||||
transform_set_column(&M, 0, colx);
|
||||
transform_set_column(&M, 1, coly);
|
||||
|
@ -300,6 +300,7 @@ static void transform_decompose(DecomposedTransform *decomp, const Transform *tf
|
|||
|
||||
void transform_motion_decompose(DecomposedTransform *decomp, const Transform *motion, size_t size)
|
||||
{
|
||||
/* Decompose and correct rotation. */
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
transform_decompose(decomp + i, motion + i);
|
||||
|
||||
|
@ -310,6 +311,27 @@ void transform_motion_decompose(DecomposedTransform *decomp, const Transform *mo
|
|||
decomp[i].x = -decomp[i].x;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy rotation to decomposed transform where scale is degenerate. This avoids weird object
|
||||
* rotation interpolation when the scale goes to 0 for a time step.
|
||||
*
|
||||
* Note that this is very simple and naive implementation, which only deals with degenerated
|
||||
* scale happening only on one frame. It is possible to improve it further by interpolating
|
||||
* rotation into s degenerated range using rotation from timesteps from adjacent non-degenerated
|
||||
* time steps. */
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
const float3 scale = make_float3(decomp[i].y.w, decomp[i].z.w, decomp[i].w.w);
|
||||
if (!is_zero(scale)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
decomp[i].x = decomp[i - 1].x;
|
||||
}
|
||||
else if (i < size - 1) {
|
||||
decomp[i].x = decomp[i + 1].x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Transform transform_from_viewplane(BoundBox2D &viewplane)
|
||||
|
|
Loading…
Reference in New Issue