Skip to content
Draft
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions library/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,9 @@
"invert_zoom": {
"type": "bool",
"default_value": "false"
},
"axis_lock": {
"type": "direction"
}
}
}
28 changes: 28 additions & 0 deletions library/src/interactor_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,22 @@ interactor& interactor_impl::initCommands()
std::bind(complNames, std::placeholders::_1,
std::vector<std::string>{ "field", "array", "component" }));

this->addCommand("toggle_axis_lock",
[&](const std::vector<std::string>& args)
{
check_args(args, 1, "toggle_axis_lock");
if (this->Internals->Options.interactor.axis_lock &&
args[0] == this->Internals->Options.getAsString("interactor.axis_lock"))
{
this->Internals->Options.interactor.axis_lock = std::nullopt;
}
else
{
this->Internals->Options.interactor.axis_lock = options::parse<f3d::direction_t>(args[0]);
}
},
command_documentation_t{ "toggle_axis_lock direction", "lock rotation to one direction" });

this->addCommand(
"roll_camera",
[&](const std::vector<std::string>& args)
Expand Down Expand Up @@ -1363,6 +1379,15 @@ interactor& interactor_impl::initBindings()
"Verbose level", this->Internals->VerboseLevelToString(log::getVerboseLevel()));
};

auto docAxisTgl = [&](const std::string& doc, const std::string& val)
{
return std::make_pair(doc,
(opts.interactor.axis_lock &&
val == this->Internals->Options.getAsString("interactor.axis_lock"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be cleaner to not use string here I think, can you use direction_t directly to compare against ?

? "ON"
: "OFF");
};

// clang-format off
this->addBinding({mod_t::NONE, "W"}, "cycle_animation", "Scene", docAnim, f3d::interactor::BindingType::CYCLIC);
this->addBinding({mod_t::NONE, "C"}, "cycle_coloring field", "Scene", docField, f3d::interactor::BindingType::CYCLIC);
Expand Down Expand Up @@ -1391,6 +1416,9 @@ interactor& interactor_impl::initBindings()
this->addBinding({mod_t::NONE, "O"}, "toggle model.point_sprites.enable","Scene", std::bind(docTgl, "Point sprites rendering", std::cref(opts.model.point_sprites.enable)), f3d::interactor::BindingType::TOGGLE);
this->addBinding({mod_t::NONE, "U"}, "toggle render.background.blur.enable","Scene", std::bind(docTgl, "Blur background", std::cref(opts.render.background.blur.enable)), f3d::interactor::BindingType::TOGGLE);
this->addBinding({mod_t::NONE, "K"}, "toggle interactor.trackball","Scene", std::bind(docTgl, "Trackball interaction", std::cref(opts.interactor.trackball)), f3d::interactor::BindingType::TOGGLE);
this->addBinding({mod_t::CTRL, "X"}, "toggle_axis_lock +X", "Scene", [=]() { return docAxisTgl("Toggle x axis lock", "+X"); });
this->addBinding({mod_t::CTRL, "Y"}, "toggle_axis_lock +Y", "Scene", [=]() { return docAxisTgl("Toggle y axis lock", "+Y"); });
this->addBinding({mod_t::CTRL, "Z"}, "toggle_axis_lock +Z", "Scene", [=]() { return docAxisTgl("Toggle z axis lock", "+Z"); });
this->addBinding({mod_t::NONE, "F"}, "toggle render.hdri.ambient","Scene", std::bind(docTgl, "HDRI ambient lighting", std::cref(opts.render.hdri.ambient)), f3d::interactor::BindingType::TOGGLE);
this->addBinding({mod_t::NONE, "J"}, "toggle render.background.skybox","Scene", std::bind(docTgl, "HDRI skybox", std::cref(opts.render.background.skybox)), f3d::interactor::BindingType::TOGGLE);
this->addBinding({mod_t::NONE, "L"}, "increase_light_intensity", "Scene", std::bind(docDbl, "Increase lights intensity", std::cref(opts.render.light.intensity)), f3d::interactor::BindingType::NUMERICAL);
Expand Down
1 change: 1 addition & 0 deletions library/src/window_impl.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ void window_impl::UpdateDynamicOptions()
renderer->ShowAxis(opt.ui.axis);
renderer->SetUseTrackball(opt.interactor.trackball);
renderer->SetInvertZoom(opt.interactor.invert_zoom);
renderer->SetRotationAxis(opt.interactor.axis_lock);

std::string bindsStr = opt.ui.drop_zone.custom_binds;
std::vector<std::pair<std::string, std::string>> dropZoneBinds;
Expand Down
86 changes: 55 additions & 31 deletions vtkext/private/module/vtkF3DInteractorStyle.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -153,49 +153,73 @@ void vtkF3DInteractorStyle::Rotate()

vtkCamera* camera = ren->GetActiveCamera();

if (!ren->GetUseTrackball())
{
double up[3];
this->InterpolateTemporaryUp(0.1, ren->GetUpVector(), up);
vtkNew<vtkTransform> Transform;
const double* fp = camera->GetFocalPoint();
double newPos[3];

double envUpCamDirCross[3];
vtkMath::Cross(up, camera->GetDirectionOfProjection(), envUpCamDirCross);
constexpr double EPSILON = 128 * std::numeric_limits<double>::epsilon();
if (vtkMath::Norm(envUpCamDirCross) < EPSILON)
{
// Keep setting the temporary up to the camera's up vector until the interpolated up vector
// and the camera direction vector are not collinear
this->SetTemporaryUp(camera->GetViewUp());
this->InterpolateTemporaryUp(0.1, ren->GetUpVector(), up);
}
if (ren->GetUseRotationAxis())
{
// pick whichever mouse component is larger
double delta = (std::abs(rxf) > std::abs(ryf)) ? rxf : ryf;

// Rotate camera around the focal point about the environment's up vector
vtkNew<vtkTransform> Transform;
Transform->Identity();
const double* fp = camera->GetFocalPoint();
Transform->Translate(+fp[0], +fp[1], +fp[2]);
Transform->RotateWXYZ(rxf, ren->GetUpVector());
Transform->RotateWXYZ(delta, ren->GetRotationAxis());
Transform->Translate(-fp[0], -fp[1], -fp[2]);
Transform->TransformPoint(camera->GetPosition(), camera->GetPosition());

camera->SetViewUp(up);

// Clamp parameter to `camera->Elevation()` to maintain -90 < elevation < +90
constexpr double maxAbsElevation = 90 - 1e-10;
const double elevation = vtkMath::DegreesFromRadians(
vtkMath::AngleBetweenVectors(ren->GetUpVector(), camera->GetDirectionOfProjection()) -
vtkMath::Pi() / 2);
camera->Elevation(std::clamp(ryf, -maxAbsElevation - elevation, +maxAbsElevation - elevation));
Transform->TransformPoint(camera->GetPosition(), newPos);
camera->SetPosition(newPos);

camera->OrthogonalizeViewUp();
double newViewUp[3];
Transform->TransformVector(camera->GetViewUp(), newViewUp);
camera->SetViewUp(newViewUp);
}
else
{
camera->Azimuth(rxf);
camera->Elevation(ryf);
camera->OrthogonalizeViewUp();
if (!ren->GetUseTrackball())
{
double up[3];
this->InterpolateTemporaryUp(0.1, ren->GetUpVector(), up);

double envUpCamDirCross[3];
vtkMath::Cross(up, camera->GetDirectionOfProjection(), envUpCamDirCross);
constexpr double EPSILON = 128 * std::numeric_limits<double>::epsilon();
if (vtkMath::Norm(envUpCamDirCross) < EPSILON)
{
// Keep setting the temporary up to the camera's up vector until the interpolated up vector
// and the camera direction vector are not collinear
this->SetTemporaryUp(camera->GetViewUp());
this->InterpolateTemporaryUp(0.1, ren->GetUpVector(), up);
}

// Rotate camera around the focal point about the environment's up vector
Transform->Identity();
Transform->Translate(+fp[0], +fp[1], +fp[2]);
Transform->RotateWXYZ(rxf, ren->GetUpVector());
Transform->Translate(-fp[0], -fp[1], -fp[2]);

Transform->TransformPoint(camera->GetPosition(), newPos);
camera->SetPosition(newPos);

// Clamp parameter to `camera->Elevation()` to maintain -90 < elevation < +90
constexpr double maxAbsElevation = 90 - 1e-10;
const double elevation = vtkMath::DegreesFromRadians(
vtkMath::AngleBetweenVectors(ren->GetUpVector(), camera->GetDirectionOfProjection()) -
vtkMath::Pi() / 2);
camera->Elevation(
std::clamp(ryf, -maxAbsElevation - elevation, +maxAbsElevation - elevation));

camera->SetViewUp(up);
}
else
{
camera->Azimuth(rxf);
camera->Elevation(ryf);
}
}

camera->OrthogonalizeViewUp();

this->UpdateRendererAfterInteraction();

rwi->Render();
Expand Down
21 changes: 21 additions & 0 deletions vtkext/private/module/vtkF3DRenderer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,27 @@ void vtkF3DRenderer::SetUseTrackball(bool use)
}
}

//----------------------------------------------------------------------------
void vtkF3DRenderer::SetRotationAxis(const std::optional<std::array<double, 3>>& axis)
{
if (!axis)
{
this->UseRotationAxis = false;
this->CheatSheetConfigured = false;
return;
}

if (!UseRotationAxis || RotationAxis[0] != (*axis)[0] || RotationAxis[1] != (*axis)[1] || RotationAxis[2] != (*axis)[2])
{
this->RotationAxis[0] = (*axis)[0];
this->RotationAxis[1] = (*axis)[1];
this->RotationAxis[2] = (*axis)[2];

this->UseRotationAxis = true;
this->CheatSheetConfigured = false;
}
}

//----------------------------------------------------------------------------
void vtkF3DRenderer::UpdateActors()
{
Expand Down
9 changes: 9 additions & 0 deletions vtkext/private/module/vtkF3DRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ class vtkF3DRenderer : public vtkOpenGLRenderer
///@}

/**
* Set/Get RotationAxis
*/
void SetRotationAxis(const std::optional<std::array<double, 3>>& axis);
vtkGetMacro(UseRotationAxis, bool);
vtkGetVector3Macro(RotationAxis, double);

/**
* Reimplemented to configure:
* - ActorsProperties
* - Timer
Expand Down Expand Up @@ -581,6 +588,8 @@ class vtkF3DRenderer : public vtkOpenGLRenderer
std::optional<bool> UseOrthographicProjection = false;
bool UseTrackball = false;
bool InvertZoom = false;
bool UseRotationAxis = false;
double RotationAxis[3] = { 0.0, 0.0, 0.0 };
Comment on lines +605 to +606
Copy link
Member

@mwestphal mwestphal Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can just store this as an std::optional<std::array<double, 3>>


int RaytracingSamples = 0;
double UpVector[3] = { 0.0, 1.0, 0.0 };
Expand Down