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

Add Cycle through animations in glTF files #1155

Merged
merged 40 commits into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
8eecaf4
Add interaction binding - Cycle Animations
kathleenhang Jan 10, 2024
ac2cf5e
Display name of current animation
kathleenhang Jan 10, 2024
010f4c1
Add cycle animation + get current animation name
kathleenhang Jan 10, 2024
30eb870
Update animation options
kathleenhang Jan 10, 2024
da0f0ae
Move animation code from importer -> animation manager class
kathleenhang Jan 11, 2024
2228aba
Add hotkey to cheat sheet
kathleenhang Jan 23, 2024
d221c1d
Add ability to cycle animation upon "W" key press
kathleenhang Jan 23, 2024
88f170a
Add display of current animation name
kathleenhang Jan 23, 2024
2f4ed58
Refactor animation code
kathleenhang Jan 24, 2024
336e301
Add animation cycling to changelog
kathleenhang Jan 24, 2024
ef9dd17
Add current animation name to cheatsheet
kathleenhang Jan 31, 2024
be0b67a
Add index -1 to display all animations
kathleenhang Jan 31, 2024
3577b53
Recover code from incorrect merge resolution
kathleenhang Feb 15, 2024
bad20ae
Add interaction test - animation cycle
kathleenhang Feb 15, 2024
3f22935
Add log file - animation cycle interaction test
kathleenhang Feb 20, 2024
d569b62
Refactor shortname func into vtkF3DRenderer
kathleenhang Feb 20, 2024
22cf2c7
Fixing cycle animaition test
mwestphal Feb 22, 2024
23c89d4
Fix segfault without importer
mwestphal Mar 2, 2024
e4817d5
Remove option for animation name
kathleenhang Mar 20, 2024
e25718b
Refactor animation cycle
kathleenhang Mar 20, 2024
76f1bf2
Update documentation - animation cycling
mwestphal Mar 24, 2024
15b6fc9
Create private api to set animation name
kathleenhang Mar 22, 2024
57a4e4d
Fix code style
kathleenhang Mar 22, 2024
708001e
Fix code style
kathleenhang Mar 22, 2024
ddd7610
fix changelog rebase
mwestphal Mar 24, 2024
05066b4
Add enable only current animation logic
kathleenhang Mar 28, 2024
10e050a
Refactor - Disable all animation at beginning
kathleenhang Mar 28, 2024
59e5e67
Fix code style
kathleenhang Mar 28, 2024
6084538
Fix cycle through range
kathleenhang Mar 28, 2024
ae8b5a5
Refactor + Add edge cases
kathleenhang Mar 28, 2024
23e0b6d
Fix formatting
kathleenhang Mar 28, 2024
ece9d57
Fix formatting
kathleenhang Mar 28, 2024
9d322dc
Add documentation for animation methods
kathleenhang Mar 28, 2024
341d699
Fix formating
mwestphal Mar 28, 2024
842e6f0
Fix formatting - animation docs
kathleenhang Mar 28, 2024
2badda9
Minor fixes
kathleenhang Mar 29, 2024
b8d0080
Add - hide cycle animation
kathleenhang Mar 29, 2024
31e6799
Update baselines
kathleenhang Mar 29, 2024
cf4a0c6
Update baseline
kathleenhang Mar 30, 2024
e87d94c
Disable test with sanitizer
mwestphal Mar 30, 2024
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
1 change: 1 addition & 0 deletions application/testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ f3d_test(NAME TestInteractionMisc DATA cow.vtp NO_BASELINE INTERACTION) #KK
f3d_test(NAME TestInteractionCycleCell DATA waveletArrays.vti INTERACTION DEFAULT_LIGHTS) #VCCC
f3d_test(NAME TestInteractionCycleComp DATA dragon.vtu INTERACTION DEFAULT_LIGHTS) #SYYYY
f3d_test(NAME TestInteractionCycleScalars DATA dragon.vtu INTERACTION DEFAULT_LIGHTS) #BSSSS
f3d_test(NAME TestInteractionCycleAnimation DATA InterpolationTest.glb INTERACTION DEFAULT_LIGHTS) #WWWWWWWWWWW;Space;Space;
f3d_test(NAME TestInteractionVolumeInverse DATA HeadMRVolume.mhd ARGS --camera-position=127.5,-400,127.5 --camera-view-up=0,0,1 INTERACTION DEFAULT_LIGHTS) #VI
f3d_test(NAME TestInteractionPointCloud DATA pointsCloud.vtp ARGS --point-size=20 INTERACTION DEFAULT_LIGHTS) #O
f3d_test(NAME TestInteractionDirectory DATA mb INTERACTION ARGS --scalars DEFAULT_LIGHTS) #Right;Right;Right;Left;Up;
Expand Down
2 changes: 2 additions & 0 deletions doc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
For F3D users:
- Added a new option `--point-type` used to specify how to display points sprites
- Add support for 3D Gaussians Splatting in binary .splat format
- Added ability to cycle through available animations by pressing "W" hotkey
- Added display of current animation name within cheatsheet

For libf3d users:
- Added a new option `model.point-sprites.type` used to specify how to display points (only if `model.point-sprites.enable` is true)
Expand Down
1 change: 1 addition & 0 deletions doc/user/INTERACTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ See the [coloring cycle](#cycling-coloring) section for more info.

Other options can be toggled directly by pressing the following hotkeys:

* <kbd>W</kbd>: cycle animations.
* <kbd>B</kbd>: display of the scalar bar, only when coloring and not using direct scalars.
* <kbd>V</kbd>: volume rendering.
* <kbd>I</kbd>: opacity function inversion during volume rendering.
Expand Down
2 changes: 1 addition & 1 deletion doc/user/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ to modify this behavior. For file formats that do not support it, **a default sc
F3D can play animations for a number of file formats (.ex2/.e/.exo/.g, .gltf/.glb, .fbx, .dae, .x, .usd) if the file contains an animation.
It is possible to select the animation to play using `--animation-index`, or to play all animations at once using `--animation-index=-1` (.gltf/.glb only).
When F3D plays an animation, it assumes the time unit is in seconds to show accurate speed of animation. Use `--animation-speed-factor` if
an adjustment is needed. By default, F3D will try update the scene 60 times per seconds, use `--animation-frame-rate` to change that if needed.
an adjustment is needed. By default, F3D will try update the scene 60 times per seconds, use `--animation-frame-rate` to change that if needed. Press "W" hotkey to cycle through available animations.

## Plugins

Expand Down
11 changes: 11 additions & 0 deletions library/private/animationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ class animationManager
void ToggleAnimation();
void StartAnimation();
void StopAnimation();
void CycleAnimation();
void EnableOnlyCurrentAnimation();
int GetAnimationIndex();
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved

/**
* Return the current animation name if any
* Can be called before initialization safely
*/
std::string GetAnimationName();

/**
* Return true if the animation manager is playing the animation
Expand Down Expand Up @@ -85,6 +94,8 @@ class animationManager
unsigned long CallBackId = 0;
double CurrentTime = 0;
bool CurrentTimeSet = false;
int AnimationIndex = 0;
int AvailAnimations = 0;
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved
std::chrono::steady_clock::time_point PreviousTick;

vtkSmartPointer<vtkProgressBarWidget> ProgressWidget;
Expand Down
1 change: 1 addition & 0 deletions library/private/window_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class window_impl : public window
image renderToImage(bool noBackground = false) override;
int getWidth() const override;
int getHeight() const override;
window& setAnimationNameInfo(const std::string& name);
window& setSize(int width, int height) override;
window& setPosition(int x, int y) override;
window& setIcon(const unsigned char* icon, size_t iconSize) override;
Expand Down
106 changes: 89 additions & 17 deletions library/src/animationManager.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,21 @@ namespace f3d::detail
bool animationManager::Initialize(
const options* options, window* window, interactor_impl* interactor, vtkImporter* importer)
{
assert(importer);
this->HasAnimation = false;
this->Playing = false;
this->CurrentTime = 0;
this->CurrentTimeSet = false;

this->AnimationIndex = 0;
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved
this->Options = options;
this->Interactor = interactor;
this->Window = window;
this->Importer = importer;

// This can be -1 if animation support is not implemented in the importer
vtkIdType availAnimations = this->Importer->GetNumberOfAnimations();
this->AvailAnimations = this->Importer->GetNumberOfAnimations();

if (availAnimations > 0 && interactor)
if (this->AvailAnimations > 0 && interactor)
{
this->ProgressWidget = vtkSmartPointer<vtkProgressBarWidget>::New();
interactor->SetInteractorOn(this->ProgressWidget);
Expand All @@ -48,7 +49,6 @@ bool animationManager::Initialize(
progressRep->DrawBackgroundOff();
progressRep->DragableOff();
progressRep->SetShowBorderToOff();

// Complete vtkProgressBarRepresentation needs
// https://gitlab.kitware.com/vtk/vtk/-/merge_requests/7359
#if VTK_VERSION_NUMBER >= VTK_VERSION_CHECK(9, 0, 20201027)
Expand All @@ -66,7 +66,7 @@ bool animationManager::Initialize(
int animationIndex = options->getAsInt("scene.animation.index");
double animationTime = options->getAsDouble("scene.animation.time");

if (availAnimations <= 0)
if (this->AvailAnimations <= 0)
{
log::debug("No animation available in this file");
if (animationIndex > 0)
Expand All @@ -85,36 +85,35 @@ bool animationManager::Initialize(
{
log::debug("Animation(s) available in this file are:");
}
for (int i = 0; i < availAnimations; i++)
for (int i = 0; i < this->AvailAnimations; i++)
{
log::debug(i, ": ", this->Importer->GetAnimationName(i));
}
log::debug("");

if (animationIndex > 0 && animationIndex >= availAnimations)
this->AnimationIndex = options->getAsInt("scene.animation.index");

if (this->AnimationIndex != 0 && this->AvailAnimations <= 0)
{
log::warn("An animation index has been specified but there are no animation available.");
}
else if (this->AnimationIndex > 0 && this->AnimationIndex >= this->AvailAnimations)
{
log::warn(
"Specified animation index is greater than the highest possible animation index, enabling "
"the first animation.");

this->Importer->EnableAnimation(0);
}
else if (animationIndex <= -1)
{
for (int i = 0; i < availAnimations; i++)
{
this->Importer->EnableAnimation(i);
}
}
else
{
this->Importer->EnableAnimation(animationIndex);
this->EnableOnlyCurrentAnimation();
}

// Recover time ranges for all enabled animations
this->TimeRange[0] = std::numeric_limits<double>::infinity();
this->TimeRange[1] = -std::numeric_limits<double>::infinity();
for (vtkIdType animIndex = 0; animIndex < availAnimations; animIndex++)
for (vtkIdType animIndex = 0; animIndex < this->AvailAnimations; animIndex++)
{
if (this->Importer->IsAnimationEnabled(animIndex))
{
Expand Down Expand Up @@ -255,6 +254,7 @@ void animationManager::Tick()
//----------------------------------------------------------------------------
bool animationManager::LoadAtTime(double timeValue)
{
assert(this->Importer);
if (!this->HasAnimation)
{
return false;
Expand All @@ -265,7 +265,6 @@ bool animationManager::LoadAtTime(double timeValue)
this->TimeRange[0], ", ", this->TimeRange[1], "] .");
return false;
}

this->CurrentTime = timeValue;
this->CurrentTimeSet = true;
this->Importer->UpdateTimeStep(this->CurrentTime);
Expand All @@ -283,10 +282,83 @@ bool animationManager::LoadAtTime(double timeValue)
return true;
}

// ---------------------------------------------------------------------------------
void animationManager::CycleAnimation()
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved
{
assert(this->Importer);
if (this->AvailAnimations <= 0)
{
return;
}

this->AnimationIndex += 1;

if (this->AnimationIndex == this->AvailAnimations)
{
this->AnimationIndex = -1;
}

this->EnableOnlyCurrentAnimation();
this->LoadAtTime(this->TimeRange[0]);
}

// ---------------------------------------------------------------------------------
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved
int animationManager::GetAnimationIndex()
{
return this->AnimationIndex;
}

// ---------------------------------------------------------------------------------
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved
std::string animationManager::GetAnimationName()
{
if (!this->Importer)
{
return "";
}

if (this->AnimationIndex == -1)
{
return "All Animations";
}
return this->Importer->GetAnimationName(this->AnimationIndex);
}

//----------------------------------------------------------------------------
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved
void animationManager::EnableOnlyCurrentAnimation()
{
assert(this->Importer);
if (this->AnimationIndex - 1 == -1)
{
this->AnimationIndex = this->AnimationIndex - 1;
for (int i = 0; i < this->AvailAnimations; i++)
{
this->Importer->DisableAnimation(i);
}
this->AnimationIndex = this->AnimationIndex + 1;
}
else
{
this->Importer->DisableAnimation(this->AnimationIndex - 1);
}
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved

if (this->AnimationIndex == -1)
{
for (int i = 0; i < this->AvailAnimations; i++)
{
this->Importer->EnableAnimation(i);
}
}
else
{
this->Importer->EnableAnimation(this->AnimationIndex);
}
}

//----------------------------------------------------------------------------
void animationManager::GetTimeRange(double timeRange[2])
{
timeRange[0] = this->TimeRange[0];
timeRange[1] = this->TimeRange[1];
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved
}

}
9 changes: 8 additions & 1 deletion library/src/interactor_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,15 @@ class interactor_impl::internals
bool checkColoring = false;
bool render = false;

// Available keycodes: W
// Available keycodes: None
switch (keyCode)
{
case 'W':
self->AnimationManager->CycleAnimation();
self->Options.set("scene.animation.index", self->AnimationManager->GetAnimationIndex());
ren->SetAnimationnameInfo(self->AnimationManager->GetAnimationName());
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved
render = true;
kathleenhang marked this conversation as resolved.
Show resolved Hide resolved
break;
case 'C':
if (renWithColor)
{
Expand Down Expand Up @@ -356,6 +362,7 @@ class interactor_impl::internals
self->Options.set("model.scivis.array-name", renWithColor->GetColoringArrayName());
self->Options.set("model.scivis.component", renWithColor->GetColoringComponent());
}

if (render)
{
self->Window.render();
Expand Down
7 changes: 6 additions & 1 deletion library/src/loader_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ class loader_impl::internals
}
}

// Set the name for animation
this->Window.setAnimationNameInfo(this->AnimationManager.GetAnimationName());

// Display the importer description
loader_impl::internals::DisplayImporterDescription(this->GenericImporter);

Expand Down Expand Up @@ -232,7 +235,6 @@ loader& loader_impl::loadGeometry(const std::string& filePath, bool reset)
throw loader::load_failure_exception(
filePath + " is not a file of a supported 3D geometry file format for default scene");
}

// Read the file
log::debug("Loading 3D geometry: ", filePath, "\n");

Expand Down Expand Up @@ -324,6 +326,9 @@ loader& loader_impl::loadScene(const std::string& filePath)
this->Internals->AnimationManager.LoadAtTime(animationTime);
}
}

// Set the name for animation
this->Internals->Window.setAnimationNameInfo(this->Internals->AnimationManager.GetAnimationName());

// Display output description
loader_impl::internals::DisplayImporterDescription(this->Internals->CurrentFullSceneImporter);
Expand Down
7 changes: 7 additions & 0 deletions library/src/window_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,13 @@ int window_impl::getHeight() const
return this->Internals->RenWin->GetSize()[1];
}

//----------------------------------------------------------------------------
window& window_impl::setAnimationNameInfo(const std::string& name)
{
this->Internals->Renderer->SetAnimationnameInfo(name);
return *this;
}

//----------------------------------------------------------------------------
window& window_impl::setSize(int width, int height)
{
Expand Down
3 changes: 3 additions & 0 deletions testing/baselines/TestInteractionCycleAnimation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading