Skip to content

ImGui GIZMO widget - 3D object manipulator / orientator

License

Notifications You must be signed in to change notification settings

toplattice/imGuIZMO.quat

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

78 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

imGuIZMO.quat  v2.01

imGuIZMO.quat is a ImGui widget: like a trackball it provides a way to rotate models, lights, or objects with mouse, and graphically visualize their position in space, also around any single axis (Shift/Ctrl/Alt/Super). It uses quaternions algebra, internally, to manage rotations, but offers the possibility also to interfacing with vec3, vec4 or mat4x4 (rotation)

With imGuIZMO.quat you can manipulate an object with only 4 code lines!     (read below)

imGuIZMO.quat is written in C++ (C++11) and consist of two files imGuIZMOquat.h and imGuIZMOuat.cpp, uses vGizmo.h virtualGizmo3D (my header only screen manipulator tool in Immediate Mode) and vGizmoMath.h a small vectors/matrices/quaternions tool/lib that makes imGuIZMO.quat standalone.

No other files or external libraries are required, except ImGui (of course).

You can use vGizmoMath also externally, for your purposes: it contains classes to manipulate vectors (with 2/3/4 components), quaternions, square matricies (3x3 and 4x4), both as simple single precision float classes (Default) or, enabling template classes (simply adding a #define), both as float and double data types (also int and uint vec*). It contains also 4 helper functions to define Model/View matrix: perspective, frustrum, lookAt, ortho

If need a larger/complete library, as alternative to vGizmoMath, is also possible to interface imGuIZMO.quat with glm mathematics library (simply adding a #define)

==>  *Please, read Configure ImGuIZMO.quad section.

Live WebGL2 demo

You can run/test WebGL 2 examples of imGuIZMO from following links:

It works only on browsers with WebGl 2 and webAssembly support (FireFox/Opera/Chrome and Chromium based). Test if your browser supports WebGL2, here: WebGL2 Report

*imGuIZMO.quat was originally developed (still used) for my glChAoS.P poroject: consult the source code for more examples.

Mouse buttons and key modifiers

These are all mouse and keyModifiers controls internally used:

  • leftButton & drag -> move control in all direction
  • rightButton & drag -> used only in Axes+Spot widget: move spot in all direction
  • Rotation around a single axis
    • leftButton+SHIFT & drag -> rotate around X
    • leftButton+CTRL & drag -> rotate around Y
    • leftButton+ALT|SUPER & drag -> rotate around Z


How to use imGuIZMO.quat to manipulate an object with 4 code lines

To use imGuIZMO.quat need to include imGuIZMOquat.h file in your code.

#include "imGuIZMOquat.h"

You can think of declaring declare an object of type quat (quaternion), global or static or as member of your class, to mantain track of rotations:

// For imGuIZMO, declare static or global variable or member class quaternion
    quat qRot = quat(1.f, 0.f, 0.f, 0.f);

In your ImGui window you call/declare a widget...

    ImGui::gizmo3D("##gizmo1", qRot /*, size,  mode */);

Finally in your render function (or where you prefer) you can get back the transformations matrix

    mat4 modelMatrix = mat4_cast(qRot);
    // now you have modelMatrix with rotation then can build MV and MVP matrix

now you have modelMatrix with rotation then can build MV and MVP matrix

alternately

Maybe can be more elegant to add two helper functions

// two helper functions, not really necessary (but comfortable)
    void setRotation(const quat &q) { qRot = q; }
    quat& getRotation() { return qRot; }

And to change the widget call

    quat qt = getRotation();
    if(ImGui::gizmo3D("##gizmo1", qt /*, size,  mode */)) {  setRotation(qt); }

but the essence of the code does not change

 
 

Widget types

Axes mode:

    quat qt = getRotation();
// get/setRotation are helper funcs that you have ideally defined to manage your global/member objs
    if(ImGui::gizmo3D("##gizmo1", qt /*, size,  mode */)) {  setRotation(qt); }
    // or explicitly
    static vec4 dir;
    ImGui::gizmo3D("##Dir1", dir, 100, imguiGizmo::mode3Axes|guiGizmo::cubeAtOrigin);

    // Default size: ImGui::GetFrameHeightWithSpacing()*4
    // Default mode: guiGizmo::mode3Axes|guiGizmo::cubeAtOrigin -> 3 Axes with cube @ origin

Directional arrow:

// I assume, for a vec3, a direction starting from origin, so if you use a vec3 to identify 
// a light spot toward origin need to change direction
    vec3 light(-getLight()));
// get/setLigth are helper funcs that you have ideally defined to manage your global/member objs
    if(ImGui::gizmo3D("##Dir1", light /*, size,  mode */)  setLight(-light);
    // or explicitly
    if(ImGui::gizmo3D("##Dir1", light, 100, imguiGizmo::modeDirection)  setLight(-light);

    // Default arrow color is YELLOW: ImVec4(1.0, 1.0, 0.0, 1.0);

Directional plane:

    static vec3 dir(1.0, 0.0, 0.0);
    if(ImGui::gizmo3D("##Dir1", dir, 100,  imguiGizmo::modeDirPlane)  { }

    // Default direction color is same of default arrow color: YELLOW -> ImVec4(1.0, 1.0, 0.0, 1.0);
    // Default plane color is: ImVec4(0.0f, 0.5f, 1.0f, STARTING_ALPHA_PLANE);

Axes + spot:

// I assume, for a vec3, a direction starting from origin, so if you use a vec3 to identify 
// a light spot toward origin need to change direction, it's maintained for uniformity even in spot
    vec3 light(-getLight()));
    quat qt = getRotation();
// get/setLigth get/setRotation are helper funcs that you have ideally defined to manage your global/member objs
    if(ImGui::gizmo3D("##gizmo1", qt, light /*, size,  mode */))  { 
        setLight(-light); 
        setRotation(qt);
    }
    // Default size: ImGui::GetFrameHeightWithSpacing()*4
    // Default mode: guiGizmo::mode3Axes|guiGizmo::cubeAtOrigin -> 3 Axes with cube @ origin
    // Default spot color is same of default arrow color: YELLOW -> ImVec4(1.0, 1.0, 0.0, 1.0);

Prototypes - all possible widget calls:

IMGUI_API bool gizmo3D(const char*, quat&, float=IMGUIZMO_DEF_SIZE, const int=imguiGizmo::mode3Axes|imguiGizmo::cubeAtOrigin);
IMGUI_API bool gizmo3D(const char*, vec4&, float=IMGUIZMO_DEF_SIZE, const int=imguiGizmo::mode3Axes|imguiGizmo::cubeAtOrigin);
IMGUI_API bool gizmo3D(const char*, vec3&, float=IMGUIZMO_DEF_SIZE, const int=imguiGizmo::modeDirection);

IMGUI_API bool gizmo3D(const char*, quat&, quat&, float=IMGUIZMO_DEF_SIZE, const int=imguiGizmo::modeDual|imguiGizmo::cubeAtOrigin);
IMGUI_API bool gizmo3D(const char*, quat&, vec4&, float=IMGUIZMO_DEF_SIZE, const int=imguiGizmo::modeDual|imguiGizmo::cubeAtOrigin);
IMGUI_API bool gizmo3D(const char*, quat&, vec3&, float=IMGUIZMO_DEF_SIZE, const int=imguiGizmo::modeDual|imguiGizmo::cubeAtOrigin);

 

For for more details, more personalizations, or how to change sizes, color, thickness, etc... examine the attached example source code (uiMainDlg.cpp file), or again imGuIZMOquat.h, imGuIZMOquat.cpp files: they are well commented. The widget are also used in glChAoS.P poroject.

*If you want use (also) full-screen manipulator, outside ImGui widget, look at virtualGizmo3D (is its feature)... also in attached example, enabling #define GLAPP_USE_VIRTUALGIZMO define in glWindow.cpp file

Sizes and colors

To change size and color of one or all widgets, imGuIZMO.quat have some helper funcs

Just an example...

To change the default color for all ARROW-Direction widgets call once (maybe in your ImGui style-settings func):

    imguiGizmo::setDirectionColor(ImVec4(0.5, 1.0, 0.3, 1.0)); // change the default ArrowDirection color

Instead to change the color of a single widget:

    imguiGizmo::setDirectionColor(ImVec4(0.5, 1.0, 0.3, 1.0)); // change ArrowDirection color
    ImGui::gizmo3D("##Dir1", dir);                             // display widget with changed color
    imguiGizmo::restoreDirectionColor();                       // restore old ArrowDirection color

It's like the push/pop mechanism used in ImGui, but only that I don't have a stak (for now I don't see the reason): just a single variable where to save the value. The other functions work in the same way.

 

All widgets visualization

FOUR widget types are prvided, (six function calls with different parameters: quaternion, vec4, vec3 for different uses) each of them personalizable with several graphics options:

Axes mode

alt text alt text alt text alt text

Directional arrow

alt text alt text alt text alt text

Plane direction

alt text alt text alt text alt text

Axes + spot

alt text alt text alt text alt text

And much more...

Full configurable: Lenght, thickness, dimensions, number of polygon slices, colors and sphere tesselation:

alt text alt text alt text alt text alt text

 
 

Configure ImGuIZMOquat

virtalGizmo3D and ImGuIZMOquat use vGizmoMath tool, it contains a group of vector/matrices/quaternion classes, operators, and principal functions. It uses the "glsl" convention for types and function names so is compatible with glm types and function calls: vGizmoMath is a subset of glm mathematics library and so you can use first or upgrade to second via a simple #define. However vGizmoMath does not want replicate glm, is only intended to make virtalGizmo3D / ImGuIZMOquat standalone, and avoid template classes use in the cases of low resources or embedded systems.

The file vGizmoConfig.h allows to configure internal math used form ImGuIZMO.quat and virtalGizmo3D. In particular is possible select between:

  • simple float classes (Default) / temlpate classes
  • internal vGizmoMath tool (Default) / glm mathematics library
  • Right (Default) / Left handed coordinate system (lookAt, perspective, ortho, frustrum - functions)

You can do this simply by commenting / uncommenting a line in vGizmoConfig.h or adding related "define" to your project, as you can see below:

// uncomment to use TEMPLATE internal vGizmoMath classes/types
//
// This is if you need to extend the use of different math types in your code
//      or for your purposes, there are predefined alias:
//          float  ==>  vec2 /  vec3 /  vec4 /  quat /  mat3|mat3x3  /  mat4|mat4x4
//      and more TEMPLATE (only!) alias:
//          double ==> dvec2 / dvec3 / dvec4 / dquat / dmat3|dmat3x3 / dmat4|dmat4x4
//          int    ==> ivec2 / ivec3 / ivec4
//          uint   ==> uvec2 / uvec3 / uvec4
// If you select TEMPLATE classes the widget too will use internally them 
//      with single precision (float)
//
// Default ==> NO template
//------------------------------------------------------------------------------
//#define VGIZMO_USES_TEMPLATE
// uncomment to use "glm" (0.9.9 or higher) library instead of vGizmoMath
//      Need to have "glm" installed and in your INCLUDE research compiler path
//
// vGizmoMath is a subset of "glm" and is compatible with glm types and calls
//      change only namespace from "vgm" to "glm". It's automatically set by
//      including vGizmo.h or vGizmoMath.h or imGuIZMOquat.h
//
// Default ==> use vGizmoMath
//      If you enable GLM use, automatically is enabled also VGIZMO_USES_TEMPLATE
//------------------------------------------------------------------------------
//#define VGIZMO_USES_GLM
// uncomment to use LeftHanded 
//
// This is used only in: lookAt / perspective / ortho / frustrum - functions
//      DX is LeftHanded, OpenGL is RightHanded
//
// Default ==> RightHanded
//------------------------------------------------------------------------------
//#define VGIZMO_USES_LEFT_HAND_AXES
  • If your project grows you can upgrade/pass to glm, in any moment
  • My glChAoS.P project can switch from internal vGizmoMath (VGIZMO_USES_TEMPLATE) to glm (VGIZMO_USES_GLM), and vice versa, only changing defines: you can examine it as example

 

Changes from v. 1.1

Users of the previous versions need:

  • change #include <imGuIZMO.h>   ==>   #include <imGuIZMOquat.h>
  • in file vGizmoConfig.h uncomment #define VGIZMO_USES_GLM to continue to use glm, or add VGIZMO_USES_GLM to compiler preprocessor defines.
  • Read virtualGizmo3D Changes if you use it outside imGuIZMO.quat widget

 

Building Example

The source code example shown in the animated gif screenshot, is provided.

In example I use GLFW or SDL2 (via #define GLAPP_USE_SDL) with OpenGL, but it is simple to change if you use Vulkan/DirectX/etc, other frameworks (like GLUT) or native OS access.

To build it you can use CMake (3.10 or higher) or the Visual Studio solution project (for VS 2017) in Windows. You need to have GLFW (or SDL) in your compiler search path (LIB/INCLUDE). Instead copy of glm and ImGui are attached and included in the example.

CMake

Use the following command-line defines to enable different options:

  • -DUSE_SDL:BOOL=TRUE to enable SDL framwork instead of GLFW
  • -DUSE_VIRTUALGIZMO:BOOL=TRUE to use also (together) virtualGizmo3D to manipulate objects

*this flags are aviables also in CMakeGUI

To build EMSCRIPTEN example, use batch/script files:

  • emsCMakeGen.cmd %EMSCRIPTEN% %BUILD_TYPE% for Windows users
  • sh emsCMakeGen.sh %EMSCRIPTEN% %BUILD_TYPE% for Linux or OS/X users

where:

  • %EMSCRIPTEN% is your emscripten installation path (e.g. C:\emsdk\emscripten\1.38.10)
  • %BUILD_TYPE% is build type: Debug | Release | RelWithDebInfo | MinSizeRel

They are located in root example directory, or examine their content to pass appropriate defines/patameters to CMake command line.

*To build with EMSCRIPTEN, obviously you need to have installed EMSCRIPTEN SDK on your computer (1.38.10 or higher)

Emscripten in Windows

To build the EMSCRIPTEN version, in Windows, with CMake, need to have mingw32-make.exe in your computer and search PATH (only the make utility is enough): it is a condition of EMSDK tool to build with CMake in Windows.

VS2017 project solution

  • To build SDL or GLFW, select appropriate build configuration
  • If you have GLFW and/or SDL headers and library directory paths added to INCLUDE and LIB environment vars, the compiler find them.
  • If you want use (also) full-screen manipulator virtualGizmo3D together with imGuIZMO.quat, enable #define GLAPP_USE_VIRTUALGIZMO define in glWindow.cpp file.
  • The current VisualStudio project solution refers to my environment variable RAMDISK (R:), and subsequent VS intrinsic variables to generate binary output: $(RAMDISK)\$(MSBuildProjectDirectoryNoRoot)\$(DefaultPlatformToolset)\$(Platform)\$(Configuration)\, so without a RAMDISK variable, executable and binary files are outputted in base to the values of these VS variables, starting from root of current drive.    (you will find built binary here... or change it)

About

ImGui GIZMO widget - 3D object manipulator / orientator

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C++ 71.1%
  • HTML 28.7%
  • Other 0.2%