From 28fa02157452ba4d6109718fda598d44112261fb Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 11 Dec 2024 14:17:30 +0000 Subject: [PATCH 01/14] Added vsg::CameraSampler class --- include/vsg/all.h | 1 + include/vsg/animation/CameraSampler.h | 120 ++++++++++++ include/vsg/core/ConstVisitor.h | 4 + include/vsg/core/Visitor.h | 4 + src/vsg/CMakeLists.txt | 1 + src/vsg/animation/CameraSampler.cpp | 255 +++++++++++++++++++++++++ src/vsg/animation/TransformSampler.cpp | 5 +- src/vsg/core/ConstVisitor.cpp | 8 + src/vsg/core/Visitor.cpp | 8 + 9 files changed, 402 insertions(+), 4 deletions(-) create mode 100644 include/vsg/animation/CameraSampler.h create mode 100644 src/vsg/animation/CameraSampler.cpp diff --git a/include/vsg/all.h b/include/vsg/all.h index 0bcc75651..c6a7a32fb 100644 --- a/include/vsg/all.h +++ b/include/vsg/all.h @@ -86,6 +86,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include #include #include #include diff --git a/include/vsg/animation/CameraSampler.h b/include/vsg/animation/CameraSampler.h new file mode 100644 index 000000000..7e84db849 --- /dev/null +++ b/include/vsg/animation/CameraSampler.h @@ -0,0 +1,120 @@ +#pragma once + +/* + +Copyright(c) 2024 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include +#include + +namespace vsg +{ + + class VSG_DECLSPEC CameraKeyframes : public Inherit + { + public: + CameraKeyframes(); + + /// name of node + std::string name; + + /// position key frames + std::vector origins; + + /// position key frames + std::vector positions; + + /// rotation key frames + std::vector rotations; + + /// field of view key frames + std::vector projections; + + void clear() + { + origins.clear(); + positions.clear(); + rotations.clear(); + projections.clear(); + } + + void add(double time, const dvec3& origin, const dvec3& position, const dquat& rotation, const dvec3& projection) + { + origins.push_back(VectorKey{time, origin}); + positions.push_back(VectorKey{time, position}); + rotations.push_back(QuatKey{time, rotation}); + projections.push_back(VectorKey{time, projection}); + } + + void add(double time, const dvec3& position, const dquat& rotation, const dvec3& projection) + { + positions.push_back(VectorKey{time, position}); + rotations.push_back(QuatKey{time, rotation}); + projections.push_back(VectorKey{time, projection}); + } + + void add(double time, const dvec3& origin, const dvec3& position, const dquat& rotation) + { + origins.push_back(VectorKey{time, origin}); + positions.push_back(VectorKey{time, position}); + rotations.push_back(QuatKey{time, rotation}); + } + + void add(double time, const dvec3& position, const dquat& rotation) + { + positions.push_back(VectorKey{time, position}); + rotations.push_back(QuatKey{time, rotation}); + } + + void read(Input& input) override; + void write(Output& output) const override; + }; + VSG_type_name(vsg::CameraKeyframes); + + /// Animation sampler for sampling position, rotation and scale keyframes for setting camera view and project matrices. + class VSG_DECLSPEC CameraSampler : public Inherit + { + public: + CameraSampler(); + CameraSampler(const CameraSampler& rhs, const CopyOp& copyop = {}); + + ref_ptr keyframes; + ref_ptr object; + + // updated using keyFrames + dvec3 origin; + dvec3 position; + dquat rotation; + dvec3 projection; + + void update(double time) override; + double maxTime() const override; + + inline dmat4 transform() const { return translate(position) * vsg::rotate(rotation); } + + public: + ref_ptr clone(const CopyOp& copyop = {}) const override { return CameraSampler::create(*this, copyop); } + int compare(const Object& rhs) const override; + + void read(Input& input) override; + void write(Output& output) const override; + + void apply(mat4Value& mat) override; + void apply(dmat4Value& mat) override; + void apply(LookAt& lookAt) override; + void apply(LookDirection& lookDirection) override; + void apply(Perspective& perspective) override; + void apply(Camera& camera) override; + }; + VSG_type_name(vsg::CameraSampler); + +} // namespace vsg diff --git a/include/vsg/core/ConstVisitor.h b/include/vsg/core/ConstVisitor.h index 0de8d4b0a..517c96efc 100644 --- a/include/vsg/core/ConstVisitor.h +++ b/include/vsg/core/ConstVisitor.h @@ -65,6 +65,7 @@ namespace vsg class JointSampler; class MorphSampler; class TransformSampler; + class CameraSampler; class Joint; // forward declare vulkan classes @@ -157,6 +158,7 @@ namespace vsg class Viewer; class ViewMatrix; class LookAt; + class LookDirection; class RelativeViewMatrix; class TrackingViewMatrix; class ProjectionMatrix; @@ -355,6 +357,7 @@ namespace vsg virtual void apply(const JointSampler&); virtual void apply(const MorphSampler&); virtual void apply(const TransformSampler&); + virtual void apply(const CameraSampler&); virtual void apply(const Joint&); // Vulkan nodes @@ -446,6 +449,7 @@ namespace vsg virtual void apply(const Viewer&); virtual void apply(const ViewMatrix&); virtual void apply(const LookAt&); + virtual void apply(const LookDirection&); virtual void apply(const RelativeViewMatrix&); virtual void apply(const TrackingViewMatrix&); virtual void apply(const ProjectionMatrix&); diff --git a/include/vsg/core/Visitor.h b/include/vsg/core/Visitor.h index 98977bbd6..60ad7b531 100644 --- a/include/vsg/core/Visitor.h +++ b/include/vsg/core/Visitor.h @@ -63,6 +63,7 @@ namespace vsg class AnimationGroup; class AnimationSampler; class TransformSampler; + class CameraSampler; class MorphSampler; class JointSampler; class Joint; @@ -157,6 +158,7 @@ namespace vsg class Viewer; class ViewMatrix; class LookAt; + class LookDirection; class RelativeViewMatrix; class TrackingViewMatrix; class ProjectionMatrix; @@ -355,6 +357,7 @@ namespace vsg virtual void apply(JointSampler&); virtual void apply(MorphSampler&); virtual void apply(TransformSampler&); + virtual void apply(CameraSampler&); virtual void apply(Joint&); // Vulkan nodes @@ -446,6 +449,7 @@ namespace vsg virtual void apply(Viewer&); virtual void apply(ViewMatrix&); virtual void apply(LookAt&); + virtual void apply(LookDirection&); virtual void apply(RelativeViewMatrix&); virtual void apply(TrackingViewMatrix&); virtual void apply(ProjectionMatrix&); diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index dffbe08be..d31cf533d 100644 --- a/src/vsg/CMakeLists.txt +++ b/src/vsg/CMakeLists.txt @@ -204,6 +204,7 @@ set(SOURCES animation/Joint.cpp animation/JointSampler.cpp animation/MorphSampler.cpp + animation/CameraSampler.cpp animation/TransformSampler.cpp ui/UIEvent.cpp diff --git a/src/vsg/animation/CameraSampler.cpp b/src/vsg/animation/CameraSampler.cpp new file mode 100644 index 000000000..fa450be19 --- /dev/null +++ b/src/vsg/animation/CameraSampler.cpp @@ -0,0 +1,255 @@ +/* + +Copyright(c) 2024 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace vsg; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// CameraKeyframes +// +CameraKeyframes::CameraKeyframes() +{ +} + +void CameraKeyframes::read(Input& input) +{ + Object::read(input); + + input.read("name", name); + + // read position key frames + uint32_t num_positions = input.readValue("positions"); + positions.resize(num_positions); + for (auto& position : positions) + { + input.matchPropertyName("position"); + input.read(1, &position.time); + input.read(1, &position.value); + } + + // read rotation key frames + uint32_t num_rotations = input.readValue("rotations"); + rotations.resize(num_rotations); + for (auto& rotation : rotations) + { + input.matchPropertyName("rotation"); + input.read(1, &rotation.time); + input.read(1, &rotation.value); + } + + // read scale key frames + uint32_t num_projections = input.readValue("projections"); + projections.resize(num_projections); + for (auto& scale : projections) + { + input.matchPropertyName("scale"); + input.read(1, &scale.time); + input.read(1, &scale.value); + } +} + +void CameraKeyframes::write(Output& output) const +{ + Object::write(output); + + output.write("name", name); + + // write position key frames + output.writeValue("positions", positions.size()); + for (const auto& position : positions) + { + output.writePropertyName("position"); + output.write(1, &position.time); + output.write(1, &position.value); + output.writeEndOfLine(); + } + + // write rotation key frames + output.writeValue("rotations", rotations.size()); + for (const auto& rotation : rotations) + { + output.writePropertyName("rotation"); + output.write(1, &rotation.time); + output.write(1, &rotation.value); + output.writeEndOfLine(); + } + + // write scale key frames + output.writeValue("projections", projections.size()); + for (const auto& scale : projections) + { + output.writePropertyName("scale"); + output.write(1, &scale.time); + output.write(1, &scale.value); + output.writeEndOfLine(); + } +} + +template +bool sample(double time, const T& values, V& value) +{ + if (values.size() == 0) return false; + + if (values.size() == 1) + { + value = values.front().value; + return true; + } + + auto pos_itr = values.begin(); + if (time <= pos_itr->time) + { + value = pos_itr->value; + return true; + } + else + { + using value_type = typename T::value_type; + pos_itr = std::lower_bound(values.begin(), values.end(), time, [](const value_type& elem, double t) -> bool { return elem.time < t; }); + + if (pos_itr == values.begin()) + { + value = values.front().value; + return true; + } + + if (pos_itr == values.end()) + { + value = values.back().value; + return true; + } + + auto before_pos_itr = pos_itr - 1; + double delta_time = (pos_itr->time - before_pos_itr->time); + double r = delta_time != 0.0 ? (time - before_pos_itr->time) / delta_time : 0.5; + + value = mix(before_pos_itr->value, pos_itr->value, r); + + return true; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// CameraSampler +// +CameraSampler::CameraSampler() : + origin(0.0, 0.0, 0.0), + position(0.0, 0.0, 0.0), + rotation(), + projection(60.0, 0.1, 1000.0) +{ +} + +CameraSampler::CameraSampler(const CameraSampler& rhs, const CopyOp& copyop) : + Inherit(rhs, copyop), + keyframes(copyop(rhs.keyframes)), + object(copyop(rhs.object)), + position(rhs.position), + rotation(rhs.rotation), + projection(rhs.projection) +{ +} + +int CameraSampler::compare(const Object& rhs_object) const +{ + int result = AnimationSampler::compare(rhs_object); + if (result != 0) return result; + + const auto& rhs = static_cast(rhs_object); + if ((result = compare_pointer(keyframes, rhs.keyframes)) != 0) return result; + return compare_pointer(object, rhs.object); +} + +void CameraSampler::update(double time) +{ + if (keyframes) + { + sample(time, keyframes->origins, origin); + sample(time, keyframes->positions, position); + sample(time, keyframes->rotations, rotation); + sample(time, keyframes->projections, projection); + } + + if (object) object->accept(*this); +} + +double CameraSampler::maxTime() const +{ + double maxTime = 0.0; + if (keyframes) + { + if (!keyframes->origins.empty()) maxTime = std::max(maxTime, keyframes->origins.back().time); + if (!keyframes->positions.empty()) maxTime = std::max(maxTime, keyframes->positions.back().time); + if (!keyframes->rotations.empty()) maxTime = std::max(maxTime, keyframes->rotations.back().time); + if (!keyframes->projections.empty()) maxTime = std::max(maxTime, keyframes->projections.back().time); + } + + return maxTime; +} + +void CameraSampler::apply(mat4Value& matrix) +{ + matrix.set(mat4(transform())); +} + +void CameraSampler::apply(dmat4Value& matrix) +{ + matrix.set(transform()); +} + +void CameraSampler::apply(LookAt& lookAt) +{ + lookAt.set(transform()); +} + +void CameraSampler::apply(LookDirection& lookDirection) +{ + lookDirection.set(transform()); +} + +void CameraSampler::apply(Perspective& perspective) +{ + perspective.fieldOfViewY = projection.x; + perspective.nearDistance = projection.y; + perspective.farDistance = projection.z; +} + +void CameraSampler::apply(Camera& camera) +{ + if (camera.projectionMatrix) camera.projectionMatrix->accept(*this); + if (camera.viewMatrix) camera.viewMatrix->accept(*this); +} + +void CameraSampler::read(Input& input) +{ + AnimationSampler::read(input); + input.read("keyframes", keyframes); + input.read("object", object); +} + +void CameraSampler::write(Output& output) const +{ + AnimationSampler::write(output); + output.write("keyframes", keyframes); + output.write("object", object); +} diff --git a/src/vsg/animation/TransformSampler.cpp b/src/vsg/animation/TransformSampler.cpp index 5c4b7cc02..12da7d8b8 100644 --- a/src/vsg/animation/TransformSampler.cpp +++ b/src/vsg/animation/TransformSampler.cpp @@ -176,10 +176,7 @@ int TransformSampler::compare(const Object& rhs_object) const const auto& rhs = static_cast(rhs_object); if ((result = compare_pointer(keyframes, rhs.keyframes)) != 0) return result; - if ((result = compare_pointer(object, rhs.object)) != 0) return result; - if ((result = compare_value(position, rhs.position)) != 0) return result; - if ((result = compare_value(rotation, rhs.rotation)) != 0) return result; - return compare_value(scale, rhs.scale); + return compare_pointer(object, rhs.object); } void TransformSampler::update(double time) diff --git a/src/vsg/core/ConstVisitor.cpp b/src/vsg/core/ConstVisitor.cpp index 3c85f747c..dcbc6dc5d 100644 --- a/src/vsg/core/ConstVisitor.cpp +++ b/src/vsg/core/ConstVisitor.cpp @@ -683,6 +683,10 @@ void ConstVisitor::apply(const TransformSampler& sampler) { apply(static_cast(sampler)); } +void ConstVisitor::apply(const CameraSampler& sampler) +{ + apply(static_cast(sampler)); +} void ConstVisitor::apply(const Joint& value) { apply(static_cast(value)); @@ -1032,6 +1036,10 @@ void ConstVisitor::apply(const LookAt& value) { apply(static_cast(value)); } +void ConstVisitor::apply(const LookDirection& value) +{ + apply(static_cast(value)); +} void ConstVisitor::apply(const RelativeViewMatrix& value) { apply(static_cast(value)); diff --git a/src/vsg/core/Visitor.cpp b/src/vsg/core/Visitor.cpp index a2482e5f4..146f2dace 100644 --- a/src/vsg/core/Visitor.cpp +++ b/src/vsg/core/Visitor.cpp @@ -683,6 +683,10 @@ void Visitor::apply(TransformSampler& sampler) { apply(static_cast(sampler)); } +void Visitor::apply(CameraSampler& sampler) +{ + apply(static_cast(sampler)); +} void Visitor::apply(Joint& value) { apply(static_cast(value)); @@ -1032,6 +1036,10 @@ void Visitor::apply(LookAt& value) { apply(static_cast(value)); } +void Visitor::apply(LookDirection& value) +{ + apply(static_cast(value)); +} void Visitor::apply(RelativeViewMatrix& value) { apply(static_cast(value)); From 3e0135ba6bfa3cdaedfd579d0b826c7a4290a7b7 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 11 Dec 2024 18:39:11 +0000 Subject: [PATCH 02/14] Added direct setting of LookDirection. --- src/vsg/animation/CameraSampler.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vsg/animation/CameraSampler.cpp b/src/vsg/animation/CameraSampler.cpp index fa450be19..0fb0c7270 100644 --- a/src/vsg/animation/CameraSampler.cpp +++ b/src/vsg/animation/CameraSampler.cpp @@ -219,12 +219,15 @@ void CameraSampler::apply(dmat4Value& matrix) void CameraSampler::apply(LookAt& lookAt) { + lookAt.origin = origin; lookAt.set(transform()); } void CameraSampler::apply(LookDirection& lookDirection) { - lookDirection.set(transform()); + lookDirection.origin = origin; + lookDirection.position = origin; + lookDirection.rotation = rotation; } void CameraSampler::apply(Perspective& perspective) From 12f8c15986320b22ec48ea4147b0c34fdaa79164 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 12 Dec 2024 14:50:38 +0000 Subject: [PATCH 03/14] Added use of CameraSampler to CameraAnimation. --- include/vsg/animation/CameraAnimation.h | 6 +-- src/vsg/animation/CameraAnimation.cpp | 71 ++++++++++++++++--------- src/vsg/animation/CameraSampler.cpp | 35 ++++++++---- src/vsg/io/ObjectFactory.cpp | 2 + 4 files changed, 75 insertions(+), 39 deletions(-) diff --git a/include/vsg/animation/CameraAnimation.h b/include/vsg/animation/CameraAnimation.h index 52f45e722..6139f8797 100644 --- a/include/vsg/animation/CameraAnimation.h +++ b/include/vsg/animation/CameraAnimation.h @@ -12,7 +12,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -#include +#include #include #include #include @@ -37,8 +37,8 @@ namespace vsg // animation to play/record to ref_ptr animation; - // transformSampler to play/record to - ref_ptr transformSampler; + // CameraSampler to play/record to + ref_ptr cameraSampler; KeySymbol toggleRecordingKey = KEY_r; KeySymbol togglePlaybackKey = KEY_p; diff --git a/src/vsg/animation/CameraAnimation.cpp b/src/vsg/animation/CameraAnimation.cpp index 8e54c68fd..3f7443725 100644 --- a/src/vsg/animation/CameraAnimation.cpp +++ b/src/vsg/animation/CameraAnimation.cpp @@ -11,6 +11,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ #include +#include #include #include #include @@ -35,28 +36,46 @@ CameraAnimation::CameraAnimation(ref_ptr in_object, const Path& in_filen { for (auto sampler : animation->samplers) { - if (auto ts = sampler.cast()) + if (auto cs = sampler.cast()) { - transformSampler = ts; + cameraSampler = cs; break; } } } - else if ((transformSampler = read_object.cast())) + else if ((cameraSampler = read_object.cast())) { animation = Animation::create(); - animation->samplers.push_back(transformSampler); + animation->samplers.push_back(cameraSampler); + } + else if (auto ts = read_object.cast()) + { + auto tkf = ts->keyframes; + + // convert TransformSampler to CameraSampler + cameraSampler = CameraSampler::create(); + cameraSampler->name = ts->name; + auto& ckf = cameraSampler->keyframes = CameraKeyframes::create(); + + ckf->positions = tkf->positions; + ckf->rotations = tkf->rotations; + + animation = Animation::create(); + animation->samplers.push_back(cameraSampler); } else if (auto keyframes = read_object.cast()) { - transformSampler = TransformSampler::create(); - transformSampler->keyframes = keyframes; + cameraSampler = CameraSampler::create(); + auto& ckf = cameraSampler->keyframes = CameraKeyframes::create(); + + ckf->positions = keyframes->positions; + ckf->rotations = keyframes->rotations; animation = Animation::create(); - animation->samplers.push_back(transformSampler); + animation->samplers.push_back(cameraSampler); } } - if (object && transformSampler) transformSampler->object = object; + if (object && cameraSampler) cameraSampler->object = object; } else { @@ -74,10 +93,10 @@ CameraAnimation::CameraAnimation(ref_ptr in_object, ref_ptr i { for (auto& sampler : animation->samplers) { - if (auto ts = sampler.cast()) + if (auto ts = sampler.cast()) { - transformSampler = ts; - transformSampler->object = object; + cameraSampler = ts; + cameraSampler->object = object; break; } } @@ -86,33 +105,33 @@ CameraAnimation::CameraAnimation(ref_ptr in_object, ref_ptr i void CameraAnimation::apply(Camera& camera) { - if (transformSampler) + if (cameraSampler) { - auto& keyframes = transformSampler->keyframes; - if (!keyframes) keyframes = TransformKeyframes::create(); + auto& keyframes = cameraSampler->keyframes; + if (!keyframes) keyframes = CameraKeyframes::create(); dvec3 position, scale; dquat orientation; auto matrix = camera.viewMatrix->inverse(); if (decompose(matrix, position, orientation, scale)) { - keyframes->add(simulationTime - startTime, position, orientation, scale); + keyframes->add(simulationTime - startTime, position, orientation); } } } void CameraAnimation::apply(MatrixTransform& transform) { - if (transformSampler) + if (cameraSampler) { - auto& keyframes = transformSampler->keyframes; - if (!keyframes) keyframes = TransformKeyframes::create(); + auto& keyframes = cameraSampler->keyframes; + if (!keyframes) keyframes = CameraKeyframes::create(); dvec3 position, scale; dquat orientation; if (decompose(transform.matrix, position, orientation, scale)) { - keyframes->add(simulationTime - startTime, position, orientation, scale); + keyframes->add(simulationTime - startTime, position, orientation); } } } @@ -137,21 +156,21 @@ void CameraAnimation::record() { animation = Animation::create(); } - if (!transformSampler) + if (!cameraSampler) { - transformSampler = TransformSampler::create(); - transformSampler->object = object; + cameraSampler = CameraSampler::create(); + cameraSampler->object = object; - animation->samplers.push_back(transformSampler); + animation->samplers.push_back(cameraSampler); } - if (transformSampler->keyframes) + if (cameraSampler->keyframes) { - transformSampler->keyframes->clear(); + cameraSampler->keyframes->clear(); } else { - transformSampler->keyframes = TransformKeyframes::create(); + cameraSampler->keyframes = CameraKeyframes::create(); } } diff --git a/src/vsg/animation/CameraSampler.cpp b/src/vsg/animation/CameraSampler.cpp index 0fb0c7270..afbd563c7 100644 --- a/src/vsg/animation/CameraSampler.cpp +++ b/src/vsg/animation/CameraSampler.cpp @@ -61,7 +61,7 @@ void CameraKeyframes::read(Input& input) projections.resize(num_projections); for (auto& scale : projections) { - input.matchPropertyName("scale"); + input.matchPropertyName("projection"); input.read(1, &scale.time); input.read(1, &scale.value); } @@ -97,7 +97,7 @@ void CameraKeyframes::write(Output& output) const output.writeValue("projections", projections.size()); for (const auto& scale : projections) { - output.writePropertyName("scale"); + output.writePropertyName("projection"); output.write(1, &scale.time); output.write(1, &scale.value); output.writeEndOfLine(); @@ -219,22 +219,37 @@ void CameraSampler::apply(dmat4Value& matrix) void CameraSampler::apply(LookAt& lookAt) { - lookAt.origin = origin; - lookAt.set(transform()); + if (keyframes) + { + vsg::info("CameraSampler::apply(LookAt&)"); + if (!keyframes->origins.empty()) lookAt.origin = origin; + if (!keyframes->positions.empty() || !keyframes->rotations.empty()) + { + lookAt.set(transform()); + } + } } void CameraSampler::apply(LookDirection& lookDirection) { - lookDirection.origin = origin; - lookDirection.position = origin; - lookDirection.rotation = rotation; + if (keyframes) + { + vsg::info("CameraSampler::apply(LookDirection&)"); + if (!keyframes->origins.empty()) lookDirection.origin = origin; + if (!keyframes->positions.empty()) lookDirection.position = position; + if (!keyframes->rotations.empty()) lookDirection.rotation = rotation; + } } void CameraSampler::apply(Perspective& perspective) { - perspective.fieldOfViewY = projection.x; - perspective.nearDistance = projection.y; - perspective.farDistance = projection.z; + if (keyframes && !keyframes->projections.empty()) + { + vsg::info("CameraSampler::apply(Perspective&)"); + perspective.fieldOfViewY = projection.x; + perspective.nearDistance = projection.y; + perspective.farDistance = projection.z; + } } void CameraSampler::apply(Camera& camera) diff --git a/src/vsg/io/ObjectFactory.cpp b/src/vsg/io/ObjectFactory.cpp index ad490db6a..1fe3644bb 100644 --- a/src/vsg/io/ObjectFactory.cpp +++ b/src/vsg/io/ObjectFactory.cpp @@ -300,6 +300,8 @@ ObjectFactory::ObjectFactory() // animation add(); add(); + add(); + add(); add(); add(); add(); From beb377f5192137b19e4ac4d4b8734f729ab3cdf3 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 12 Dec 2024 18:12:45 +0000 Subject: [PATCH 04/14] Created a template class for time key values. --- include/vsg/animation/TransformSampler.h | 18 ++--------- include/vsg/animation/time_value.h | 38 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 include/vsg/animation/time_value.h diff --git a/include/vsg/animation/TransformSampler.h b/include/vsg/animation/TransformSampler.h index ca4b2c4ff..b8dc420af 100644 --- a/include/vsg/animation/TransformSampler.h +++ b/include/vsg/animation/TransformSampler.h @@ -13,27 +13,15 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ #include +#include #include #include namespace vsg { - struct VectorKey - { - double time; - dvec3 value; - - bool operator<(const VectorKey& rhs) const { return time < rhs.time; } - }; - - struct QuatKey - { - double time; - dquat value; - - bool operator<(const QuatKey& rhs) const { return time < rhs.time; } - }; + using VectorKey = time_dvec3; + using QuatKey = time_dquat; class VSG_DECLSPEC TransformKeyframes : public Inherit { diff --git a/include/vsg/animation/time_value.h b/include/vsg/animation/time_value.h new file mode 100644 index 000000000..7aba32c39 --- /dev/null +++ b/include/vsg/animation/time_value.h @@ -0,0 +1,38 @@ +#pragma once + +/* + +Copyright(c) 2024 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include +#include + +namespace vsg +{ + + template + struct time_value + { + using value_type = T; + double time; + value_type value; + + bool operator<(const time_value& rhs) const { return time < rhs.time; } + }; + + using time_double = time_value; + using time_dvec2 = time_value; + using time_dvec3 = time_value; + using time_dvec4 = time_value; + using time_dquat = time_value; + +} // namespace vsg From afb1a0a585e62cb40c56438150f0a1cdd02f92b5 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 12 Dec 2024 18:56:34 +0000 Subject: [PATCH 05/14] Added time_value and sample templates and fieldOfview/nearFar support to CameraSampler. --- include/vsg/animation/CameraSampler.h | 42 ++++++++++---- include/vsg/animation/time_value.h | 45 +++++++++++++++ src/vsg/animation/CameraSampler.cpp | 80 +++++++------------------- src/vsg/animation/TransformSampler.cpp | 44 -------------- 4 files changed, 97 insertions(+), 114 deletions(-) diff --git a/include/vsg/animation/CameraSampler.h b/include/vsg/animation/CameraSampler.h index 7e84db849..a6b269fb1 100644 --- a/include/vsg/animation/CameraSampler.h +++ b/include/vsg/animation/CameraSampler.h @@ -28,38 +28,59 @@ namespace vsg std::string name; /// position key frames - std::vector origins; + std::vector origins; /// position key frames - std::vector positions; + std::vector positions; /// rotation key frames - std::vector rotations; + std::vector rotations; /// field of view key frames - std::vector projections; + std::vector fieldOfViews; + + /// near/far key frames + std::vector nearFars; void clear() { origins.clear(); positions.clear(); rotations.clear(); - projections.clear(); + fieldOfViews.clear(); + nearFars.clear(); + } + + void add(double time, const dvec3& origin, const dvec3& position, const dquat& rotation, double fov, const dvec2& nearFar) + { + origins.push_back(VectorKey{time, origin}); + positions.push_back(VectorKey{time, position}); + rotations.push_back(QuatKey{time, rotation}); + fieldOfViews.push_back(time_double{time, fov}); + nearFars.push_back(time_dvec2{time, nearFar}); } - void add(double time, const dvec3& origin, const dvec3& position, const dquat& rotation, const dvec3& projection) + void add(double time, const dvec3& origin, const dvec3& position, const dquat& rotation, double fov) { origins.push_back(VectorKey{time, origin}); positions.push_back(VectorKey{time, position}); rotations.push_back(QuatKey{time, rotation}); - projections.push_back(VectorKey{time, projection}); + fieldOfViews.push_back(time_double{time, fov}); + } + + void add(double time, const dvec3& position, const dquat& rotation, double fov, const dvec2& nearFar) + { + positions.push_back(VectorKey{time, position}); + rotations.push_back(QuatKey{time, rotation}); + fieldOfViews.push_back(time_double{time, fov}); + nearFars.push_back(time_dvec2{time, nearFar}); } - void add(double time, const dvec3& position, const dquat& rotation, const dvec3& projection) + void add(double time, const dvec3& position, const dquat& rotation, double fov) { positions.push_back(VectorKey{time, position}); rotations.push_back(QuatKey{time, rotation}); - projections.push_back(VectorKey{time, projection}); + fieldOfViews.push_back(time_double{time, fov}); } void add(double time, const dvec3& origin, const dvec3& position, const dquat& rotation) @@ -94,7 +115,8 @@ namespace vsg dvec3 origin; dvec3 position; dquat rotation; - dvec3 projection; + double fieldOfView; + dvec2 nearFar; void update(double time) override; double maxTime() const override; diff --git a/include/vsg/animation/time_value.h b/include/vsg/animation/time_value.h index 7aba32c39..8b60180b6 100644 --- a/include/vsg/animation/time_value.h +++ b/include/vsg/animation/time_value.h @@ -35,4 +35,49 @@ namespace vsg using time_dvec4 = time_value; using time_dquat = time_value; + template + bool sample(double time, const T& values, V& value) + { + if (values.size() == 0) return false; + + if (values.size() == 1) + { + value = values.front().value; + return true; + } + + auto pos_itr = values.begin(); + if (time <= pos_itr->time) + { + value = pos_itr->value; + return true; + } + else + { + using value_type = typename T::value_type; + pos_itr = std::lower_bound(values.begin(), values.end(), time, [](const value_type& elem, double t) -> bool { return elem.time < t; }); + + if (pos_itr == values.begin()) + { + value = values.front().value; + return true; + } + + if (pos_itr == values.end()) + { + value = values.back().value; + return true; + } + + auto before_pos_itr = pos_itr - 1; + double delta_time = (pos_itr->time - before_pos_itr->time); + double r = delta_time != 0.0 ? (time - before_pos_itr->time) / delta_time : 0.5; + + value = mix(before_pos_itr->value, pos_itr->value, r); + + return true; + } + } + + } // namespace vsg diff --git a/src/vsg/animation/CameraSampler.cpp b/src/vsg/animation/CameraSampler.cpp index afbd563c7..79fb98ab0 100644 --- a/src/vsg/animation/CameraSampler.cpp +++ b/src/vsg/animation/CameraSampler.cpp @@ -57,9 +57,9 @@ void CameraKeyframes::read(Input& input) } // read scale key frames - uint32_t num_projections = input.readValue("projections"); - projections.resize(num_projections); - for (auto& scale : projections) + uint32_t num_fieldOfViews = input.readValue("fieldOfViews"); + fieldOfViews.resize(num_fieldOfViews); + for (auto& scale : fieldOfViews) { input.matchPropertyName("projection"); input.read(1, &scale.time); @@ -94,8 +94,8 @@ void CameraKeyframes::write(Output& output) const } // write scale key frames - output.writeValue("projections", projections.size()); - for (const auto& scale : projections) + output.writeValue("fieldOfViews", fieldOfViews.size()); + for (const auto& scale : fieldOfViews) { output.writePropertyName("projection"); output.write(1, &scale.time); @@ -104,50 +104,6 @@ void CameraKeyframes::write(Output& output) const } } -template -bool sample(double time, const T& values, V& value) -{ - if (values.size() == 0) return false; - - if (values.size() == 1) - { - value = values.front().value; - return true; - } - - auto pos_itr = values.begin(); - if (time <= pos_itr->time) - { - value = pos_itr->value; - return true; - } - else - { - using value_type = typename T::value_type; - pos_itr = std::lower_bound(values.begin(), values.end(), time, [](const value_type& elem, double t) -> bool { return elem.time < t; }); - - if (pos_itr == values.begin()) - { - value = values.front().value; - return true; - } - - if (pos_itr == values.end()) - { - value = values.back().value; - return true; - } - - auto before_pos_itr = pos_itr - 1; - double delta_time = (pos_itr->time - before_pos_itr->time); - double r = delta_time != 0.0 ? (time - before_pos_itr->time) / delta_time : 0.5; - - value = mix(before_pos_itr->value, pos_itr->value, r); - - return true; - } -} - //////////////////////////////////////////////////////////////////////////////////////////////////// // // CameraSampler @@ -156,7 +112,8 @@ CameraSampler::CameraSampler() : origin(0.0, 0.0, 0.0), position(0.0, 0.0, 0.0), rotation(), - projection(60.0, 0.1, 1000.0) + fieldOfView(60.0), + nearFar(1.0, 1e10) { } @@ -166,7 +123,8 @@ CameraSampler::CameraSampler(const CameraSampler& rhs, const CopyOp& copyop) : object(copyop(rhs.object)), position(rhs.position), rotation(rhs.rotation), - projection(rhs.projection) + fieldOfView(rhs.fieldOfView), + nearFar(rhs.nearFar) { } @@ -187,7 +145,8 @@ void CameraSampler::update(double time) sample(time, keyframes->origins, origin); sample(time, keyframes->positions, position); sample(time, keyframes->rotations, rotation); - sample(time, keyframes->projections, projection); + sample(time, keyframes->fieldOfViews, fieldOfView); + sample(time, keyframes->nearFars, nearFar); } if (object) object->accept(*this); @@ -201,7 +160,8 @@ double CameraSampler::maxTime() const if (!keyframes->origins.empty()) maxTime = std::max(maxTime, keyframes->origins.back().time); if (!keyframes->positions.empty()) maxTime = std::max(maxTime, keyframes->positions.back().time); if (!keyframes->rotations.empty()) maxTime = std::max(maxTime, keyframes->rotations.back().time); - if (!keyframes->projections.empty()) maxTime = std::max(maxTime, keyframes->projections.back().time); + if (!keyframes->fieldOfViews.empty()) maxTime = std::max(maxTime, keyframes->fieldOfViews.back().time); + if (!keyframes->nearFars.empty()) maxTime = std::max(maxTime, keyframes->nearFars.back().time); } return maxTime; @@ -221,7 +181,6 @@ void CameraSampler::apply(LookAt& lookAt) { if (keyframes) { - vsg::info("CameraSampler::apply(LookAt&)"); if (!keyframes->origins.empty()) lookAt.origin = origin; if (!keyframes->positions.empty() || !keyframes->rotations.empty()) { @@ -234,7 +193,6 @@ void CameraSampler::apply(LookDirection& lookDirection) { if (keyframes) { - vsg::info("CameraSampler::apply(LookDirection&)"); if (!keyframes->origins.empty()) lookDirection.origin = origin; if (!keyframes->positions.empty()) lookDirection.position = position; if (!keyframes->rotations.empty()) lookDirection.rotation = rotation; @@ -243,12 +201,14 @@ void CameraSampler::apply(LookDirection& lookDirection) void CameraSampler::apply(Perspective& perspective) { - if (keyframes && !keyframes->projections.empty()) + if (keyframes && !keyframes->fieldOfViews.empty()) + { + perspective.fieldOfViewY = fieldOfView; + } + if (keyframes && !keyframes->nearFars.empty()) { - vsg::info("CameraSampler::apply(Perspective&)"); - perspective.fieldOfViewY = projection.x; - perspective.nearDistance = projection.y; - perspective.farDistance = projection.z; + perspective.nearDistance = nearFar[0]; + perspective.farDistance = nearFar[1]; } } diff --git a/src/vsg/animation/TransformSampler.cpp b/src/vsg/animation/TransformSampler.cpp index 12da7d8b8..b81ce3629 100644 --- a/src/vsg/animation/TransformSampler.cpp +++ b/src/vsg/animation/TransformSampler.cpp @@ -104,50 +104,6 @@ void TransformKeyframes::write(Output& output) const } } -template -bool sample(double time, const T& values, V& value) -{ - if (values.size() == 0) return false; - - if (values.size() == 1) - { - value = values.front().value; - return true; - } - - auto pos_itr = values.begin(); - if (time <= pos_itr->time) - { - value = pos_itr->value; - return true; - } - else - { - using value_type = typename T::value_type; - pos_itr = std::lower_bound(values.begin(), values.end(), time, [](const value_type& elem, double t) -> bool { return elem.time < t; }); - - if (pos_itr == values.begin()) - { - value = values.front().value; - return true; - } - - if (pos_itr == values.end()) - { - value = values.back().value; - return true; - } - - auto before_pos_itr = pos_itr - 1; - double delta_time = (pos_itr->time - before_pos_itr->time); - double r = delta_time != 0.0 ? (time - before_pos_itr->time) / delta_time : 0.5; - - value = mix(before_pos_itr->value, pos_itr->value, r); - - return true; - } -} - //////////////////////////////////////////////////////////////////////////////////////////////////// // // TransformSampler From 0678e6cdf447440562a2876e2d555f6fb8fcc870 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 13 Dec 2024 09:13:24 +0000 Subject: [PATCH 06/14] Fixed io support for new member variables --- src/vsg/animation/CameraSampler.cpp | 43 ++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/vsg/animation/CameraSampler.cpp b/src/vsg/animation/CameraSampler.cpp index 79fb98ab0..4dadabca4 100644 --- a/src/vsg/animation/CameraSampler.cpp +++ b/src/vsg/animation/CameraSampler.cpp @@ -56,14 +56,24 @@ void CameraKeyframes::read(Input& input) input.read(1, &rotation.value); } - // read scale key frames + // read field of view key frames uint32_t num_fieldOfViews = input.readValue("fieldOfViews"); fieldOfViews.resize(num_fieldOfViews); - for (auto& scale : fieldOfViews) + for (auto& fov : fieldOfViews) { - input.matchPropertyName("projection"); - input.read(1, &scale.time); - input.read(1, &scale.value); + input.matchPropertyName("fov"); + input.read(1, &fov.time); + input.read(1, &fov.value); + } + + // read near/far key frames + uint32_t num_nearFars = input.readValue("nearFars"); + nearFars.resize(num_nearFars); + for (auto& nf : nearFars) + { + input.matchPropertyName("nearfar"); + input.read(1, &nf.time); + input.read(1, &nf.value); } } @@ -94,14 +104,33 @@ void CameraKeyframes::write(Output& output) const } // write scale key frames - output.writeValue("fieldOfViews", fieldOfViews.size()); for (const auto& scale : fieldOfViews) { - output.writePropertyName("projection"); + output.writePropertyName("fov"); output.write(1, &scale.time); output.write(1, &scale.value); output.writeEndOfLine(); } + + // write field of view key frames + output.writeValue("fieldOfViews", fieldOfViews.size()); + for (const auto& fov : fieldOfViews) + { + output.writePropertyName("fov"); + output.write(1, &fov.time); + output.write(1, &fov.value); + output.writeEndOfLine(); + } + + // read near/far key frames + output.writeValue("nearFars", nearFars.size()); + for (const auto& nf : nearFars) + { + output.writePropertyName("nearfar"); + output.write(1, &nf.time); + output.write(1, &nf.value); + output.writeEndOfLine(); + } } //////////////////////////////////////////////////////////////////////////////////////////////////// From 966e57501b9f7dece689be5461f24c29c68672a3 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 13 Dec 2024 09:13:46 +0000 Subject: [PATCH 07/14] Ran clang-format --- include/vsg/animation/time_value.h | 1 - src/vsg/animation/CameraSampler.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/vsg/animation/time_value.h b/include/vsg/animation/time_value.h index 8b60180b6..303f36b96 100644 --- a/include/vsg/animation/time_value.h +++ b/include/vsg/animation/time_value.h @@ -79,5 +79,4 @@ namespace vsg } } - } // namespace vsg diff --git a/src/vsg/animation/CameraSampler.cpp b/src/vsg/animation/CameraSampler.cpp index 4dadabca4..608a29b90 100644 --- a/src/vsg/animation/CameraSampler.cpp +++ b/src/vsg/animation/CameraSampler.cpp @@ -11,8 +11,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ #include -#include #include +#include #include #include #include From 63146678d0b7c65ebb334c068be0553f35c18fbe Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 13 Dec 2024 12:28:22 +0000 Subject: [PATCH 08/14] fixed cppcheck reported suggestion. --- src/vsg/animation/CameraAnimation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vsg/animation/CameraAnimation.cpp b/src/vsg/animation/CameraAnimation.cpp index 3f7443725..cab01b975 100644 --- a/src/vsg/animation/CameraAnimation.cpp +++ b/src/vsg/animation/CameraAnimation.cpp @@ -55,7 +55,7 @@ CameraAnimation::CameraAnimation(ref_ptr in_object, const Path& in_filen // convert TransformSampler to CameraSampler cameraSampler = CameraSampler::create(); cameraSampler->name = ts->name; - auto& ckf = cameraSampler->keyframes = CameraKeyframes::create(); + const auto& ckf = cameraSampler->keyframes = CameraKeyframes::create(); ckf->positions = tkf->positions; ckf->rotations = tkf->rotations; @@ -66,7 +66,7 @@ CameraAnimation::CameraAnimation(ref_ptr in_object, const Path& in_filen else if (auto keyframes = read_object.cast()) { cameraSampler = CameraSampler::create(); - auto& ckf = cameraSampler->keyframes = CameraKeyframes::create(); + const auto& ckf = cameraSampler->keyframes = CameraKeyframes::create(); ckf->positions = keyframes->positions; ckf->rotations = keyframes->rotations; From 130761eaeed53b491e2b7d9f566bddeb98205138 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 13 Dec 2024 12:31:13 +0000 Subject: [PATCH 09/14] Added support for CoordinateFrame to ComputeTransform visitor. --- include/vsg/maths/transform.h | 2 ++ src/vsg/maths/maths_transform.cpp | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/include/vsg/maths/transform.h b/include/vsg/maths/transform.h index bd979e79b..a07b1a131 100644 --- a/include/vsg/maths/transform.h +++ b/include/vsg/maths/transform.h @@ -263,10 +263,12 @@ namespace vsg /// usage: auto matrix = vsg::visit(nodePath).matrix; struct VSG_DECLSPEC ComputeTransform : public ConstVisitor { + dvec3 origin; dmat4 matrix; void apply(const Transform& transform) override; void apply(const MatrixTransform& mt) override; + void apply(const CoordinateFrame& cf) override; void apply(const Camera& camera) override; }; diff --git a/src/vsg/maths/maths_transform.cpp b/src/vsg/maths/maths_transform.cpp index f7b8074a0..24a8e17ea 100644 --- a/src/vsg/maths/maths_transform.cpp +++ b/src/vsg/maths/maths_transform.cpp @@ -14,6 +14,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include using namespace vsg; @@ -441,6 +442,12 @@ void ComputeTransform::apply(const MatrixTransform& mt) matrix = matrix * mt.matrix; } +void ComputeTransform::apply(const CoordinateFrame& cf) +{ + origin = cf.origin; + matrix = vsg::rotate(cf.rotation); +} + void ComputeTransform::apply(const Camera& camera) { if (camera.viewMatrix) From cd7b7c86c7da40d1f1b5b504180f4eb841bf6809 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 16 Dec 2024 13:22:18 +0000 Subject: [PATCH 10/14] Implemented support for camera animation with tracking. --- cmake/cppcheck-suppression-list.txt | 3 +- include/vsg/animation/CameraAnimation.h | 3 +- include/vsg/animation/CameraSampler.h | 5 ++ src/vsg/animation/CameraAnimation.cpp | 7 +++ src/vsg/animation/CameraSampler.cpp | 83 +++++++++++++++++++++++-- 5 files changed, 94 insertions(+), 7 deletions(-) diff --git a/cmake/cppcheck-suppression-list.txt b/cmake/cppcheck-suppression-list.txt index 4a7735e9e..ce6ba1e79 100644 --- a/cmake/cppcheck-suppression-list.txt +++ b/cmake/cppcheck-suppression-list.txt @@ -1,4 +1,4 @@ -// suppress Key related errors +s// suppress Key related errors noExplicitConstructor:*/include/vsg/core/ref_ptr.h noExplicitConstructor:*/include/vsg/core/Inherit.h:31 noExplicitConstructor:*/include/vsg/core/Allocator.h:138 @@ -192,6 +192,7 @@ duplInheritedMember:*/src/vsg/nodes/Node.cpp shadowFunction:*/include/vsg/maths/transform.h shadowFunction:*/src/io/Path.cpp shadowFunction:*/src/vsg/animation/CameraAnimation.cpp +shadowFunction:*/src/vsg/animation/CameraSampler.cpp shadowFunction:*/src/vsg/animation/TransformSampler.cpp shadowFunction:*/src/vsg/io/tile.cpp shadowFunction:*/src/vsg/io/FileSystem.cpp diff --git a/include/vsg/animation/CameraAnimation.h b/include/vsg/animation/CameraAnimation.h index 6139f8797..75ab61e6e 100644 --- a/include/vsg/animation/CameraAnimation.h +++ b/include/vsg/animation/CameraAnimation.h @@ -24,8 +24,9 @@ namespace vsg class VSG_DECLSPEC CameraAnimation : public Inherit { public: - explicit CameraAnimation(ref_ptr in_object, const Path& in_filename = "saved_animation.vsgt", ref_ptr in_options = {}); + CameraAnimation(); CameraAnimation(ref_ptr in_object, ref_ptr in_animation, const Path& in_filename = "saved_animation.vsgt", ref_ptr in_options = {}); + explicit CameraAnimation(ref_ptr in_object, const Path& in_filename = "saved_animation.vsgt", ref_ptr in_options = {}); /// object to track/modify ref_ptr object; diff --git a/include/vsg/animation/CameraSampler.h b/include/vsg/animation/CameraSampler.h index a6b269fb1..7cc43d70a 100644 --- a/include/vsg/animation/CameraSampler.h +++ b/include/vsg/animation/CameraSampler.h @@ -19,6 +19,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI namespace vsg { + using time_path = time_value; + class VSG_DECLSPEC CameraKeyframes : public Inherit { public: @@ -27,6 +29,9 @@ namespace vsg /// name of node std::string name; + // object tracking key frames + std::vector tracking; + /// position key frames std::vector origins; diff --git a/src/vsg/animation/CameraAnimation.cpp b/src/vsg/animation/CameraAnimation.cpp index cab01b975..65cdb0201 100644 --- a/src/vsg/animation/CameraAnimation.cpp +++ b/src/vsg/animation/CameraAnimation.cpp @@ -23,6 +23,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI using namespace vsg; +CameraAnimation::CameraAnimation() +{ +} + CameraAnimation::CameraAnimation(ref_ptr in_object, const Path& in_filename, ref_ptr in_options) : object(in_object), filename(in_filename), @@ -105,8 +109,11 @@ CameraAnimation::CameraAnimation(ref_ptr in_object, ref_ptr i void CameraAnimation::apply(Camera& camera) { + info("CameraAnimation::apply(Camera& camera) ", cameraSampler); + if (cameraSampler) { + auto& keyframes = cameraSampler->keyframes; if (!keyframes) keyframes = CameraKeyframes::create(); diff --git a/src/vsg/animation/CameraSampler.cpp b/src/vsg/animation/CameraSampler.cpp index 608a29b90..687092014 100644 --- a/src/vsg/animation/CameraSampler.cpp +++ b/src/vsg/animation/CameraSampler.cpp @@ -36,6 +36,16 @@ void CameraKeyframes::read(Input& input) input.read("name", name); + // read tracking key frames + uint32_t num_tracking = input.readValue("tracking"); + tracking.resize(num_tracking); + for (auto& track : tracking) + { + input.matchPropertyName("track"); + input.read(1, &track.time); + input.readObjects("path", track.value); + } + // read position key frames uint32_t num_positions = input.readValue("positions"); positions.resize(num_positions); @@ -83,6 +93,17 @@ void CameraKeyframes::write(Output& output) const output.write("name", name); + // write position key frames + output.writeValue("tracking", tracking.size()); + for (const auto& track : tracking) + { + output.writePropertyName("track"); + output.write(1, &track.time); + output.writeEndOfLine(); + + output.writeObjects("path", track.value); + } + // write position key frames output.writeValue("positions", positions.size()); for (const auto& position : positions) @@ -176,6 +197,55 @@ void CameraSampler::update(double time) sample(time, keyframes->rotations, rotation); sample(time, keyframes->fieldOfViews, fieldOfView); sample(time, keyframes->nearFars, nearFar); + + auto find_values = [](const RefObjectPath& path, dvec3& in_origin, dvec3& in_position, dquat& in_rotation) -> void + { + ComputeTransform ct; + for(auto& obj : path) obj->accept(ct); + + in_origin = ct.origin; + + dvec3 scale; + vsg::decompose(ct.matrix, in_position, in_rotation, scale); + }; + + auto& tracking = keyframes->tracking; + if (tracking.size() == 1) + { + find_values(tracking.front().value, origin, position, rotation); + } + else if (!tracking.empty()) + { + auto pos_itr = std::lower_bound(tracking.begin(), tracking.end(), time, [](const time_path& elem, double t) -> bool { return elem.time < t; }); + if (pos_itr == tracking.begin()) + { + find_values(tracking.front().value, origin, position, rotation); + } + else if (pos_itr == tracking.end()) + { + find_values(tracking.back().value, origin, position, rotation); + } + else + { + auto before_pos_itr = pos_itr - 1; + double delta_time = (pos_itr->time - before_pos_itr->time); + double r = delta_time != 0.0 ? (time - before_pos_itr->time) / delta_time : 0.5; + + dvec3 origin_before, position_before; + dquat rotation_before; + find_values(before_pos_itr->value, origin_before, position_before, rotation_before); + + dvec3 origin_after, position_after; + dquat rotation_after; + find_values(pos_itr->value, origin_after, position_after, rotation_after); + + // convert origin input values and ratio to long double to minimize the intermediate rounding errors. + origin = mix(ldvec3(origin_before), ldvec3(origin_after), static_cast(r)); + + position = mix(position_before, position_after, r); + rotation = mix(rotation_before, rotation_after, r); + } + } } if (object) object->accept(*this); @@ -186,6 +256,7 @@ double CameraSampler::maxTime() const double maxTime = 0.0; if (keyframes) { + if (!keyframes->tracking.empty()) maxTime = std::max(maxTime, keyframes->tracking.back().time); if (!keyframes->origins.empty()) maxTime = std::max(maxTime, keyframes->origins.back().time); if (!keyframes->positions.empty()) maxTime = std::max(maxTime, keyframes->positions.back().time); if (!keyframes->rotations.empty()) maxTime = std::max(maxTime, keyframes->rotations.back().time); @@ -210,8 +281,9 @@ void CameraSampler::apply(LookAt& lookAt) { if (keyframes) { - if (!keyframes->origins.empty()) lookAt.origin = origin; - if (!keyframes->positions.empty() || !keyframes->rotations.empty()) + bool has_tracking = !keyframes->tracking.empty(); + if (!keyframes->origins.empty() || has_tracking) lookAt.origin = origin; + if (!keyframes->positions.empty() || !keyframes->rotations.empty() || has_tracking) { lookAt.set(transform()); } @@ -222,9 +294,10 @@ void CameraSampler::apply(LookDirection& lookDirection) { if (keyframes) { - if (!keyframes->origins.empty()) lookDirection.origin = origin; - if (!keyframes->positions.empty()) lookDirection.position = position; - if (!keyframes->rotations.empty()) lookDirection.rotation = rotation; + bool has_tracking = !keyframes->tracking.empty(); + if (!keyframes->origins.empty() || has_tracking) lookDirection.origin = origin; + if (!keyframes->positions.empty() || has_tracking) lookDirection.position = position; + if (!keyframes->rotations.empty() || has_tracking) lookDirection.rotation = rotation; } } From 7a3ac31c5135a06417a9825e563a3e6ec74a6613 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 16 Dec 2024 18:34:11 +0000 Subject: [PATCH 11/14] Renamed vsg::CameraAnimation to vsg::CameraAnimationHandler --- include/vsg/all.h | 3 ++- ...raAnimation.h => CameraAnimationHandler.h} | 13 ++++++---- src/vsg/CMakeLists.txt | 2 +- ...imation.cpp => CameraAnimationHandler.cpp} | 24 +++++++++---------- 4 files changed, 23 insertions(+), 19 deletions(-) rename include/vsg/animation/{CameraAnimation.h => CameraAnimationHandler.h} (78%) rename src/vsg/animation/{CameraAnimation.cpp => CameraAnimationHandler.cpp} (88%) diff --git a/include/vsg/all.h b/include/vsg/all.h index c6a7a32fb..4d514ae65 100644 --- a/include/vsg/all.h +++ b/include/vsg/all.h @@ -85,13 +85,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include -#include +#include #include #include #include #include #include #include +#include // Lighting header files #include diff --git a/include/vsg/animation/CameraAnimation.h b/include/vsg/animation/CameraAnimationHandler.h similarity index 78% rename from include/vsg/animation/CameraAnimation.h rename to include/vsg/animation/CameraAnimationHandler.h index 75ab61e6e..09116b6f5 100644 --- a/include/vsg/animation/CameraAnimation.h +++ b/include/vsg/animation/CameraAnimationHandler.h @@ -21,12 +21,12 @@ namespace vsg { /// event handler for controlling the playing and recording of camera animation paths - class VSG_DECLSPEC CameraAnimation : public Inherit + class VSG_DECLSPEC CameraAnimationHandler : public Inherit { public: - CameraAnimation(); - CameraAnimation(ref_ptr in_object, ref_ptr in_animation, const Path& in_filename = "saved_animation.vsgt", ref_ptr in_options = {}); - explicit CameraAnimation(ref_ptr in_object, const Path& in_filename = "saved_animation.vsgt", ref_ptr in_options = {}); + CameraAnimationHandler(); + CameraAnimationHandler(ref_ptr in_object, ref_ptr in_animation, const Path& in_filename = "saved_animation.vsgt", ref_ptr in_options = {}); + explicit CameraAnimationHandler(ref_ptr in_object, const Path& in_filename = "saved_animation.vsgt", ref_ptr in_options = {}); /// object to track/modify ref_ptr object; @@ -62,6 +62,9 @@ namespace vsg protected: }; - VSG_type_name(vsg::CameraAnimation); + VSG_type_name(vsg::CameraAnimationHandler); + + // fallback for naming prior to VulkanSceneGraph-1.1.9. + using CameraAnimation = vsg::CameraAnimationHandler; } // namespace vsg diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index d31cf533d..263122d5a 100644 --- a/src/vsg/CMakeLists.txt +++ b/src/vsg/CMakeLists.txt @@ -199,7 +199,7 @@ set(SOURCES animation/Animation.cpp animation/AnimationGroup.cpp animation/AnimationManager.cpp - animation/CameraAnimation.cpp + animation/CameraAnimationHandler.cpp animation/FindAnimations.cpp animation/Joint.cpp animation/JointSampler.cpp diff --git a/src/vsg/animation/CameraAnimation.cpp b/src/vsg/animation/CameraAnimationHandler.cpp similarity index 88% rename from src/vsg/animation/CameraAnimation.cpp rename to src/vsg/animation/CameraAnimationHandler.cpp index 65cdb0201..de809cfb4 100644 --- a/src/vsg/animation/CameraAnimation.cpp +++ b/src/vsg/animation/CameraAnimationHandler.cpp @@ -10,7 +10,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -#include +#include #include #include #include @@ -23,11 +23,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI using namespace vsg; -CameraAnimation::CameraAnimation() +CameraAnimationHandler::CameraAnimationHandler() { } -CameraAnimation::CameraAnimation(ref_ptr in_object, const Path& in_filename, ref_ptr in_options) : +CameraAnimationHandler::CameraAnimationHandler(ref_ptr in_object, const Path& in_filename, ref_ptr in_options) : object(in_object), filename(in_filename), options(in_options) @@ -87,7 +87,7 @@ CameraAnimation::CameraAnimation(ref_ptr in_object, const Path& in_filen } } -CameraAnimation::CameraAnimation(ref_ptr in_object, ref_ptr in_animation, const Path& in_filename, ref_ptr in_options) : +CameraAnimationHandler::CameraAnimationHandler(ref_ptr in_object, ref_ptr in_animation, const Path& in_filename, ref_ptr in_options) : object(in_object), filename(in_filename), options(in_options), @@ -107,9 +107,9 @@ CameraAnimation::CameraAnimation(ref_ptr in_object, ref_ptr i } } -void CameraAnimation::apply(Camera& camera) +void CameraAnimationHandler::apply(Camera& camera) { - info("CameraAnimation::apply(Camera& camera) ", cameraSampler); + info("CameraAnimationHandler::apply(Camera& camera) ", cameraSampler); if (cameraSampler) { @@ -127,7 +127,7 @@ void CameraAnimation::apply(Camera& camera) } } -void CameraAnimation::apply(MatrixTransform& transform) +void CameraAnimationHandler::apply(MatrixTransform& transform) { if (cameraSampler) { @@ -143,7 +143,7 @@ void CameraAnimation::apply(MatrixTransform& transform) } } -void CameraAnimation::play() +void CameraAnimationHandler::play() { if (playing) return; @@ -151,7 +151,7 @@ void CameraAnimation::play() if (playing) info("Starting playback."); } -void CameraAnimation::record() +void CameraAnimationHandler::record() { if (recording) return; @@ -181,7 +181,7 @@ void CameraAnimation::record() } } -void CameraAnimation::stop() +void CameraAnimationHandler::stop() { if (playing) { @@ -205,7 +205,7 @@ void CameraAnimation::stop() } } -void CameraAnimation::apply(KeyPressEvent& keyPress) +void CameraAnimationHandler::apply(KeyPressEvent& keyPress) { if (keyPress.keyModified == togglePlaybackKey) { @@ -235,7 +235,7 @@ void CameraAnimation::apply(KeyPressEvent& keyPress) } } -void CameraAnimation::apply(FrameEvent& frame) +void CameraAnimationHandler::apply(FrameEvent& frame) { simulationTime = frame.frameStamp->simulationTime; From e951e227489104421f88b8c2c54d17f3afcb128f Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 16 Dec 2024 18:34:49 +0000 Subject: [PATCH 12/14] Ran clang-format --- src/vsg/animation/CameraSampler.cpp | 7 +++---- src/vsg/maths/maths_transform.cpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vsg/animation/CameraSampler.cpp b/src/vsg/animation/CameraSampler.cpp index 687092014..647d0fb0d 100644 --- a/src/vsg/animation/CameraSampler.cpp +++ b/src/vsg/animation/CameraSampler.cpp @@ -198,10 +198,9 @@ void CameraSampler::update(double time) sample(time, keyframes->fieldOfViews, fieldOfView); sample(time, keyframes->nearFars, nearFar); - auto find_values = [](const RefObjectPath& path, dvec3& in_origin, dvec3& in_position, dquat& in_rotation) -> void - { + auto find_values = [](const RefObjectPath& path, dvec3& in_origin, dvec3& in_position, dquat& in_rotation) -> void { ComputeTransform ct; - for(auto& obj : path) obj->accept(ct); + for (auto& obj : path) obj->accept(ct); in_origin = ct.origin; @@ -283,7 +282,7 @@ void CameraSampler::apply(LookAt& lookAt) { bool has_tracking = !keyframes->tracking.empty(); if (!keyframes->origins.empty() || has_tracking) lookAt.origin = origin; - if (!keyframes->positions.empty() || !keyframes->rotations.empty() || has_tracking) + if (!keyframes->positions.empty() || !keyframes->rotations.empty() || has_tracking) { lookAt.set(transform()); } diff --git a/src/vsg/maths/maths_transform.cpp b/src/vsg/maths/maths_transform.cpp index 24a8e17ea..b36d532f2 100644 --- a/src/vsg/maths/maths_transform.cpp +++ b/src/vsg/maths/maths_transform.cpp @@ -13,8 +13,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include -#include #include +#include using namespace vsg; From 26cc6ef7573f8a9744f51530207354d592d037d1 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 16 Dec 2024 19:28:42 +0000 Subject: [PATCH 13/14] Removed typo --- cmake/cppcheck-suppression-list.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/cppcheck-suppression-list.txt b/cmake/cppcheck-suppression-list.txt index ce6ba1e79..b6601161c 100644 --- a/cmake/cppcheck-suppression-list.txt +++ b/cmake/cppcheck-suppression-list.txt @@ -1,4 +1,4 @@ -s// suppress Key related errors +// suppress Key related errors noExplicitConstructor:*/include/vsg/core/ref_ptr.h noExplicitConstructor:*/include/vsg/core/Inherit.h:31 noExplicitConstructor:*/include/vsg/core/Allocator.h:138 From a12c1a972373b67e55931802b87cfa8a18cc3579 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 16 Dec 2024 19:29:26 +0000 Subject: [PATCH 14/14] Updated filename --- cmake/cppcheck-suppression-list.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/cppcheck-suppression-list.txt b/cmake/cppcheck-suppression-list.txt index b6601161c..0c8b0c7a7 100644 --- a/cmake/cppcheck-suppression-list.txt +++ b/cmake/cppcheck-suppression-list.txt @@ -191,7 +191,7 @@ duplInheritedMember:*/src/vsg/nodes/Node.cpp // suppress unhelpful warning of shadowFunction shadowFunction:*/include/vsg/maths/transform.h shadowFunction:*/src/io/Path.cpp -shadowFunction:*/src/vsg/animation/CameraAnimation.cpp +shadowFunction:*/src/vsg/animation/CameraAnimationHandler.cpp shadowFunction:*/src/vsg/animation/CameraSampler.cpp shadowFunction:*/src/vsg/animation/TransformSampler.cpp shadowFunction:*/src/vsg/io/tile.cpp