Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic animation import in glTF #46

Merged
merged 3 commits into from
Aug 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/changelog-plugins.dox
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ namespace Magnum {

@subsection changelog-plugins-latest-new New features

- Initial support for animation data import in
@ref Trade::TinyGltfImporter "TinyGltfImporter"
- Minimal support for the [KHR_materials_pbrSpecularGlossiness](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness)
extension in @ref Trade::TinyGltfImporter "TinyGltfImporter"
- The top-level `tinygltf::Model` structure is now exposed through
Expand Down
58 changes: 58 additions & 0 deletions package/archlinux/PKGBUILD-clang-addesssanitizer
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Author: mosra <[email protected]>
pkgname=magnum-plugins
pkgver=dev.clang.addresssanitizer
pkgrel=1
pkgdesc="Plugins for the Magnum C++11/C++14 graphics engine (clang-addresssanitizer build)"
arch=('i686' 'x86_64')
url="http://magnum.graphics"
license=('MIT')
depends=('magnum' 'ninja' 'qt4' 'devil' 'freetype2' 'harfbuzz' 'libjpeg' 'libpng' 'assimp')
makedepends=('cmake' 'clang')
options=(!strip)
provides=('magnum-plugins-git')

_rootdir=$startdir/../../

build() {
mkdir -p "$_rootdir/build-clang-addresssanitizer"
cd "$_rootdir/build-clang-addresssanitizer"

cmake .. \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_CXX_FLAGS="-fsanitize=address" \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX=/usr \
-DBUILD_TESTS=ON \
-DBUILD_GL_TESTS=ON \
-DWITH_ASSIMPIMPORTER=ON \
-DWITH_COLLADAIMPORTER=ON \
-DWITH_DDSIMPORTER=ON \
-DWITH_DEVILIMAGEIMPORTER=ON \
-DWITH_DRFLACAUDIOIMPORTER=ON \
-DWITH_DRWAVAUDIOIMPORTER=ON \
-DWITH_FREETYPEFONT=ON \
-DWITH_HARFBUZZFONT=ON \
-DWITH_JPEGIMPORTER=ON \
-DWITH_MINIEXRIMAGECONVERTER=ON \
-DWITH_OPENGEXIMPORTER=ON \
-DWITH_PNGIMAGECONVERTER=ON \
-DWITH_PNGIMPORTER=ON \
-DWITH_STANFORDIMPORTER=ON \
-DWITH_STBIMAGECONVERTER=ON \
-DWITH_STBIMAGEIMPORTER=ON \
-DWITH_STBTRUETYPEFONT=ON \
-DWITH_STBVORBISAUDIOIMPORTER=ON \
-DWITH_TINYGLTFIMPORTER=ON \
-G Ninja
ninja
}

check() {
cd "$_rootdir/build-clang-addresssanitizer"
CORRADE_TEST_COLOR=ON ctest --output-on-failure
}

package() {
cd "$_rootdir/build-clang-addresssanitizer"
DESTDIR="$pkgdir/" ninja install
}
6 changes: 6 additions & 0 deletions src/MagnumPlugins/TinyGltfImporter/Test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ corrade_add_test(TinyGltfImporterTest
FILES
empty.gltf
empty.glb
animation.gltf
animation.glb
animation.bin
animation-embedded.gltf
animation-embedded.glb
animation-wrong.gltf
camera.gltf
camera.glb
# external-data.* packed via a resource
Expand Down
206 changes: 206 additions & 0 deletions src/MagnumPlugins/TinyGltfImporter/Test/TinyGltfImporterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <Magnum/Math/Quaternion.h>
#include <Magnum/Trade/AbstractImporter.h>
#include <Magnum/Trade/AbstractMaterialData.h>
#include <Magnum/Trade/AnimationData.h>
#include <Magnum/Trade/CameraData.h>
#include <Magnum/Trade/ImageData.h>
#include <Magnum/Trade/LightData.h>
Expand All @@ -58,6 +59,14 @@ struct TinyGltfImporterTest: TestSuite::Tester {
void openError();
void openFileError();

void animation();
void animationWrongTimeType();
void animationWrongInterpolationType();
void animationWrongTranslationType();
void animationWrongRotationType();
void animationWrongScalingType();
void animationUnsupportedPath();

void camera();

void light();
Expand Down Expand Up @@ -144,6 +153,16 @@ TinyGltfImporterTest::TinyGltfImporterTest() {
&TinyGltfImporterTest::openFileError},
Containers::arraySize(OpenErrorData));

addInstancedTests({&TinyGltfImporterTest::animation},
Containers::arraySize(MultiFileData));

addTests({&TinyGltfImporterTest::animationWrongTimeType,
&TinyGltfImporterTest::animationWrongInterpolationType,
&TinyGltfImporterTest::animationWrongTranslationType,
&TinyGltfImporterTest::animationWrongRotationType,
&TinyGltfImporterTest::animationWrongScalingType,
&TinyGltfImporterTest::animationUnsupportedPath});

addInstancedTests({&TinyGltfImporterTest::camera,

&TinyGltfImporterTest::light,
Expand Down Expand Up @@ -234,6 +253,193 @@ void TinyGltfImporterTest::openFileError() {
CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::openFile(): cannot open file nope" + std::string{data.suffix} + "\n");
}

void TinyGltfImporterTest::animation() {
auto&& data = MultiFileData[testCaseInstanceId()];
setTestCaseDescription(data.name);

std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation" + std::string{data.suffix})));

CORRADE_COMPARE(importer->animationCount(), 2);

/* Empty animation */
{
CORRADE_COMPARE(importer->animationName(0), "empty");
CORRADE_COMPARE(importer->animationForName("empty"), 0);

auto animation = importer->animation(0);
CORRADE_VERIFY(animation);
CORRADE_VERIFY(animation->data().empty());
CORRADE_COMPARE(animation->trackCount(), 0);

/* Translation/rotation/scaling animation */
} {
CORRADE_COMPARE(importer->animationName(1), "TRS animation");
CORRADE_COMPARE(importer->animationForName("TRS animation"), 1);

auto animation = importer->animation(1);
CORRADE_VERIFY(animation);
CORRADE_VERIFY(animation->importerState());
/* Two rotation keys, four translation and scaling keys with common
time track */
CORRADE_COMPARE(animation->data().size(),
2*(sizeof(Float) + sizeof(Quaternion)) +
4*(sizeof(Float) + 2*sizeof(Vector3)));
CORRADE_COMPARE(animation->trackCount(), 3);

/* Rotation, linearly interpolated */
CORRADE_COMPARE(animation->trackType(0), AnimationTrackType::Quaternion);
CORRADE_COMPARE(animation->trackResultType(0), AnimationTrackType::Quaternion);
CORRADE_COMPARE(animation->trackTarget(0), AnimationTrackTarget::Rotation3D);
CORRADE_COMPARE(animation->trackTargetId(0), 1337);
Animation::TrackView<Float, Quaternion> rotation = animation->track<Quaternion>(0);
CORRADE_COMPARE(rotation.interpolation(), Animation::Interpolation::Linear);
CORRADE_COMPARE(rotation.before(), Animation::Extrapolation::Constant);
CORRADE_COMPARE(rotation.after(), Animation::Extrapolation::Constant);
const Float rotationKeys[]{
1.25f,
2.50f
};
const Quaternion rotationValues[]{
Quaternion::rotation(0.0_degf, Vector3::xAxis()),
Quaternion::rotation(180.0_degf, Vector3::xAxis())
};
CORRADE_COMPARE_AS(rotation.keys(), (Containers::StridedArrayView<const Float>{rotationKeys}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(rotation.values(), (Containers::StridedArrayView<const Quaternion>{rotationValues}), TestSuite::Compare::Container);
CORRADE_COMPARE(rotation.at(1.875f), Quaternion::rotation(90.0_degf, Vector3::xAxis()));

const Float translationScalingKeys[]{
0.0f,
1.25f,
2.5f,
3.75f
};

/* Translation, constant interpolated, sharing keys with scaling */
CORRADE_COMPARE(animation->trackType(1), AnimationTrackType::Vector3);
CORRADE_COMPARE(animation->trackResultType(1), AnimationTrackType::Vector3);
CORRADE_COMPARE(animation->trackTarget(1), AnimationTrackTarget::Translation3D);
CORRADE_COMPARE(animation->trackTargetId(1), 42);
Animation::TrackView<Float, Vector3> translation = animation->track<Vector3>(1);
CORRADE_COMPARE(translation.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(translation.before(), Animation::Extrapolation::Constant);
CORRADE_COMPARE(translation.after(), Animation::Extrapolation::Constant);
const Vector3 translationData[]{
Vector3::yAxis(0.0f),
Vector3::yAxis(2.5f),
Vector3::yAxis(2.5f),
Vector3::yAxis(0.0f)
};
CORRADE_COMPARE_AS(translation.keys(), (Containers::StridedArrayView<const Float>{translationScalingKeys}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(translation.values(), (Containers::StridedArrayView<const Vector3>{translationData}), TestSuite::Compare::Container);
CORRADE_COMPARE(translation.at(1.5f), Vector3::yAxis(2.5f));

/* Scaling, linearly interpolated, sharing keys with translation */
CORRADE_COMPARE(animation->trackType(2), AnimationTrackType::Vector3);
CORRADE_COMPARE(animation->trackResultType(2), AnimationTrackType::Vector3);
CORRADE_COMPARE(animation->trackTarget(2), AnimationTrackTarget::Scaling3D);
CORRADE_COMPARE(animation->trackTargetId(2), 12);
Animation::TrackView<Float, Vector3> scaling = animation->track<Vector3>(2);
CORRADE_COMPARE(scaling.interpolation(), Animation::Interpolation::Linear);
CORRADE_COMPARE(scaling.before(), Animation::Extrapolation::Constant);
CORRADE_COMPARE(scaling.after(), Animation::Extrapolation::Constant);
const Vector3 scalingData[]{
Vector3{1.0f},
Vector3::zScale(5.0f),
Vector3::zScale(6.0f),
Vector3(1.0f),
};
CORRADE_COMPARE_AS(scaling.keys(), (Containers::StridedArrayView<const Float>{translationScalingKeys}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scaling.values(), (Containers::StridedArrayView<const Vector3>{scalingData}), TestSuite::Compare::Container);
CORRADE_COMPARE(scaling.at(1.5f), Vector3::zScale(5.2f));
}
}

void TinyGltfImporterTest::animationWrongTimeType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(0), "wrong time type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(0));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): time track has unexpected type 4/5126\n");
}

void TinyGltfImporterTest::animationWrongInterpolationType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(1), "wrong interpolation type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(1));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): unsupported interpolation QUADRATIC\n");
}

void TinyGltfImporterTest::animationWrongTranslationType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(2), "wrong translation type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(2));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): translation track has unexpected type 4/5126\n");
}

void TinyGltfImporterTest::animationWrongRotationType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(3), "wrong rotation type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(3));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): rotation track has unexpected type 65/5126\n");
}

void TinyGltfImporterTest::animationWrongScalingType() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(4), "wrong scaling type");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(4));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): scaling track has unexpected type 4/5126\n");
}

void TinyGltfImporterTest::animationUnsupportedPath() {
std::unique_ptr<AbstractImporter> importer = _manager.instantiate("TinyGltfImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(TINYGLTFIMPORTER_TEST_DIR,
"animation-wrong.gltf")));

CORRADE_COMPARE(importer->animationCount(), 6);
CORRADE_COMPARE(importer->animationName(5), "unsupported path");

std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!importer->animation(5));
CORRADE_COMPARE(out.str(), "Trade::TinyGltfImporter::animation(): unsupported track target color\n");
}

void TinyGltfImporterTest::camera() {
auto&& data = SingleFileData[testCaseInstanceId()];
setTestCaseDescription(data.name);
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"asset":{"version":"2.0"},"animations":[{"name":"empty","channels":[],"samplers":[]},{"name":"TRS animation","channels":[{"sampler":0,"target":{"node":1337,"path":"rotation"}},{"sampler":1,"target":{"node":42,"path":"translation"}},{"sampler":2,"target":{"node":12,"path":"scale"}}],"samplers":[{"input":0,"interpolation":"LINEAR","output":1},{"input":2,"interpolation":"STEP","output":3},{"input":2,"interpolation":"LINEAR","output":4}]}],"accessors":[{"bufferView":0,"byteOffset":0,"componentType":5126,"count":2,"type":"SCALAR"},{"bufferView":1,"byteOffset":0,"componentType":5126,"count":2,"type":"VEC4"},{"bufferView":0,"byteOffset":8,"componentType":5126,"count":4,"type":"SCALAR"},{"bufferView":2,"byteOffset":0,"componentType":5126,"count":4,"type":"VEC3"},{"bufferView":3,"byteOffset":0,"componentType":5126,"count":4,"type":"VEC3"}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":24},{"buffer":0,"byteOffset":24,"byteLength":32},{"buffer":0,"byteOffset":56,"byteLength":48},{"buffer":0,"byteOffset":104,"byteLength":48}],"buffers":[{"byteLength":152,"uri":"data:application/octet-stream;base64,AACgPwAAIEAAAAAAAACgPwAAIEAAAHBAAAAAAAAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAIA/AACAPwAAoEAAAIA/AACAPwAAwEAAAIA/AACAPwAAgD8="}]}
Loading