mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Fix 'Held' interpolation of timesamples value.
This commit is contained in:
@@ -1168,16 +1168,24 @@ struct TypedTimeSamples {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto it = std::lower_bound(
|
||||
// Held = nerarest preceding value for a gien time.
|
||||
// example:
|
||||
// input = 0.0: 100, 1.0: 200
|
||||
//
|
||||
// t -1.0 => 100(time 0.0)
|
||||
// t 0.0 => 100(time 0.0)
|
||||
// t 0.1 => 100(time 0.0)
|
||||
// t 0.9 => 100(time 0.0)
|
||||
// t 1.0 => 200(time 1.0)
|
||||
//
|
||||
// This can be achieved by using upper_bound, and subtract 1 from the found position.
|
||||
auto it = std::upper_bound(
|
||||
_samples.begin(), _samples.end(), t,
|
||||
[](const Sample &a, double tval) { return a.t < tval; });
|
||||
[](double tval, const Sample &a) { return tval < a.t; });
|
||||
|
||||
if (it == _samples.end()) {
|
||||
// ???
|
||||
return false;
|
||||
}
|
||||
const auto it_minus_1 = (it == _samples.begin()) ? _samples.begin() : (it - 1);
|
||||
|
||||
(*dst) = it->value;
|
||||
(*dst) = it_minus_1->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,12 +50,24 @@ bool PrimVar::get_interpolated_value(const double t, const value::TimeSampleInte
|
||||
(*dst) = samples[0].value;
|
||||
return true;
|
||||
} else {
|
||||
// TODO: Unify code in prim-types.hh
|
||||
auto it = std::lower_bound(
|
||||
samples.begin(), samples.end(), t,
|
||||
[](const value::TimeSamples::Sample &a, double tval) { return a.t < tval; });
|
||||
|
||||
if (tinterp == value::TimeSampleInterpolationType::Linear) {
|
||||
if (tinterp == value::TimeSampleInterpolationType::Held || !value::IsLerpSupportedType(_value.type_id())) {
|
||||
|
||||
auto it = std::upper_bound(
|
||||
samples.begin(), samples.end(), t,
|
||||
[](double tval, const value::TimeSamples::Sample &a) { return tval < a.t; });
|
||||
|
||||
const auto it_minus_1 = (it == samples.begin()) ? samples.begin() : (it - 1);
|
||||
|
||||
(*dst) = it_minus_1->value;
|
||||
return true;
|
||||
|
||||
} else { // Lerp
|
||||
|
||||
// TODO: Unify code in prim-types.hh
|
||||
auto it = std::lower_bound(
|
||||
samples.begin(), samples.end(), t,
|
||||
[](const value::TimeSamples::Sample &a, double tval) { return a.t < tval; });
|
||||
|
||||
const auto it_minus_1 = (it == samples.begin()) ? samples.begin() : (it - 1);
|
||||
|
||||
@@ -86,18 +98,15 @@ bool PrimVar::get_interpolated_value(const double t, const value::TimeSampleInte
|
||||
|
||||
bool ret = value::Lerp(p0, p1, dt, dst);
|
||||
return ret;
|
||||
} else {
|
||||
if (it == samples.end()) {
|
||||
// ???
|
||||
return false;
|
||||
}
|
||||
|
||||
(*dst) = it->value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_default()) {
|
||||
(*dst) = _value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -295,6 +295,7 @@ struct PrimVar {
|
||||
|
||||
if (auto pv = get_default_value<T>()) {
|
||||
(*v) = pv.value();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_ts.empty()) {
|
||||
@@ -302,7 +303,18 @@ struct PrimVar {
|
||||
}
|
||||
}
|
||||
|
||||
return _ts.get(v, t, tinterp);
|
||||
if (has_timesamples()) {
|
||||
return _ts.get(v, t, tinterp);
|
||||
}
|
||||
|
||||
if (has_default()) {
|
||||
if (auto pv = get_default_value<T>()) {
|
||||
(*v) = pv.value();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t num_timesamples() const {
|
||||
|
||||
@@ -2412,16 +2412,13 @@ struct TimeSamples {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = std::lower_bound(
|
||||
auto it = std::upper_bound(
|
||||
_samples.begin(), _samples.end(), t,
|
||||
[](const Sample &a, double tval) { return a.t < tval; });
|
||||
[](double tval, const Sample &a) { return tval < a.t; });
|
||||
|
||||
if (it == _samples.end()) {
|
||||
// ???
|
||||
return false;
|
||||
}
|
||||
const auto it_minus_1 = (it == _samples.begin()) ? _samples.begin() : (it - 1);
|
||||
|
||||
const value::Value &v = it->value;
|
||||
const value::Value &v = it_minus_1->value;
|
||||
|
||||
if (const T *pv = v.as<T>()) {
|
||||
(*dst) = *pv;
|
||||
@@ -2468,11 +2465,11 @@ struct TimeSamples {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto it = std::lower_bound(
|
||||
_samples.begin(), _samples.end(), t,
|
||||
[](const Sample &a, double tval) { return a.t < tval; });
|
||||
|
||||
if (interp == TimeSampleInterpolationType::Linear) {
|
||||
auto it = std::lower_bound(
|
||||
_samples.begin(), _samples.end(), t,
|
||||
[](const Sample &a, double tval) { return a.t < tval; });
|
||||
|
||||
|
||||
// MS STL does not allow seek vector iterator before begin
|
||||
// Issue #110
|
||||
@@ -2514,17 +2511,20 @@ struct TimeSamples {
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
if (it == _samples.end()) {
|
||||
// ???
|
||||
return false;
|
||||
}
|
||||
// Held
|
||||
auto it = std::upper_bound(
|
||||
_samples.begin(), _samples.end(), t,
|
||||
[](double tval, const Sample &a) { return tval < a.t; });
|
||||
|
||||
const auto it_minus_1 = (it == _samples.begin()) ? _samples.begin() : (it - 1);
|
||||
|
||||
const value::Value &v = it_minus_1->value;
|
||||
|
||||
const value::Value &v = it->value;
|
||||
if (const T *pv = v.as<T>()) {
|
||||
(*dst) = *pv;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ set(TEST_SOURCES
|
||||
unit-xform.cc
|
||||
unit-math.cc
|
||||
unit-ioutil.cc
|
||||
unit-timesamples.cc
|
||||
)
|
||||
|
||||
if (TINYUSDZ_WITH_PXR_COMPAT_API)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "unit-math.h"
|
||||
#include "unit-ioutil.h"
|
||||
#include "unit-strutil.h"
|
||||
#include "unit-timesamples.h"
|
||||
|
||||
#if defined(TINYUSDZ_WITH_PXR_COMPAT_API)
|
||||
#include "unit-pxr-compat-api.h"
|
||||
@@ -35,6 +36,7 @@ TEST_LIST = {
|
||||
{ "pathutil_test", pathutil_test },
|
||||
{ "ioutil_test", ioutil_test },
|
||||
{ "strutil_test", strutil_test },
|
||||
{ "timesamples_test", timesamples_test },
|
||||
#if defined(TINYUSDZ_WITH_PXR_COMPAT_API)
|
||||
{ "pxr_compat_api_test", pxr_compat_api_test },
|
||||
#endif
|
||||
|
||||
114
tests/unit/unit-timesamples.cc
Normal file
114
tests/unit/unit-timesamples.cc
Normal file
@@ -0,0 +1,114 @@
|
||||
#ifdef _MSC_VER
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#define TEST_NO_MAIN
|
||||
#include "acutest.h"
|
||||
|
||||
#include "unit-timesamples.h"
|
||||
#include "prim-types.hh"
|
||||
#include "math-util.inc"
|
||||
|
||||
using namespace tinyusdz;
|
||||
|
||||
void timesamples_test(void) {
|
||||
|
||||
{
|
||||
value::token tok1("bora");
|
||||
value::token tok2("muda");
|
||||
|
||||
Animatable<value::token> toks;
|
||||
toks.add_sample(0, tok1);
|
||||
toks.add_sample(10, tok2);
|
||||
|
||||
{
|
||||
value::token tok;
|
||||
TEST_CHECK(toks.get(value::TimeCode::Default(), &tok));
|
||||
// return the value of the first item(= timecode 0)
|
||||
TEST_CHECK(tok.str() == "bora");
|
||||
}
|
||||
|
||||
// Held interpolation
|
||||
{
|
||||
value::token tok;
|
||||
TEST_CHECK(toks.get(0.0, &tok));
|
||||
TEST_CHECK(tok.str() == "bora");
|
||||
|
||||
TEST_CHECK(toks.get(-1.0, &tok));
|
||||
TEST_CHECK(tok.str() == "bora");
|
||||
|
||||
TEST_CHECK(toks.get(1.0, &tok));
|
||||
TEST_CHECK(tok.str() == "bora");
|
||||
|
||||
TEST_CHECK(toks.get(10.0, &tok));
|
||||
TEST_CHECK(tok.str() == "muda");
|
||||
|
||||
TEST_CHECK(toks.get(1000.0, &tok));
|
||||
TEST_CHECK(tok.str() == "muda");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Animatable<float> samples;
|
||||
samples.add_sample(0, 0.0f);
|
||||
samples.add_sample(1, 10.0f);
|
||||
|
||||
{
|
||||
float f;
|
||||
TEST_CHECK(samples.get(value::TimeCode::Default(), &f));
|
||||
// return the value of the first item(= timecode 0)
|
||||
TEST_CHECK(math::is_close(f, 0.0f));
|
||||
}
|
||||
|
||||
// Linear interpolation
|
||||
{
|
||||
float f;
|
||||
TEST_CHECK(samples.get(0.0, &f));
|
||||
TEST_CHECK(math::is_close(f, 0.0f));
|
||||
|
||||
TEST_CHECK(samples.get(0.5, &f));
|
||||
TEST_CHECK(math::is_close(f, 5.0f));
|
||||
|
||||
TEST_CHECK(samples.get(1.0, &f));
|
||||
TEST_CHECK(math::is_close(f, 10.0f));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
primvar::PrimVar pbar;
|
||||
value::TimeSamples ts;
|
||||
ts.add_sample(0, value::Value(0.0f));
|
||||
ts.add_sample(1, value::Value(10.0f));
|
||||
pbar.set_timesamples(ts);
|
||||
pbar.set_value(2000.0f); // default value
|
||||
|
||||
{
|
||||
float f;
|
||||
TEST_CHECK(pbar.get_interpolated_value(value::TimeCode::Default(), value::TimeSampleInterpolationType::Held, &f));
|
||||
// return the value of the first item(= timecode 0)
|
||||
TEST_CHECK(math::is_close(f, 2000.0f));
|
||||
}
|
||||
|
||||
// Linear interpolation
|
||||
{
|
||||
float f;
|
||||
TEST_CHECK(pbar.get_interpolated_value(-10.0, value::TimeSampleInterpolationType::Linear, &f));
|
||||
TEST_CHECK(math::is_close(f, 0.0f));
|
||||
|
||||
TEST_CHECK(pbar.get_interpolated_value(0.0, value::TimeSampleInterpolationType::Linear, &f));
|
||||
TEST_CHECK(math::is_close(f, 0.0f));
|
||||
|
||||
TEST_CHECK(pbar.get_interpolated_value(0.5, value::TimeSampleInterpolationType::Linear, &f));
|
||||
TEST_CHECK(math::is_close(f, 5.0f));
|
||||
|
||||
TEST_CHECK(pbar.get_interpolated_value(1.0, value::TimeSampleInterpolationType::Linear, &f));
|
||||
TEST_CHECK(math::is_close(f, 10.0f));
|
||||
|
||||
TEST_CHECK(pbar.get_interpolated_value(value::TimeCode::Default(), value::TimeSampleInterpolationType::Linear, &f));
|
||||
TEST_CHECK(math::is_close(f, 2000.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
3
tests/unit/unit-timesamples.h
Normal file
3
tests/unit/unit-timesamples.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void timesamples_test(void);
|
||||
Reference in New Issue
Block a user