Skip to content
Single file header 3D object manipulator/orienteering
C++ HTML Other
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
oglGizmo.example
screenshots
src
.gitattributes
license.txt
readme.md

readme.md

virtualGizmo3D

virtualGizmo3D is an 3D GIZMO manipulator: like a trackball it provides a way to rotate, move and scale a model, with mouse, also with dolly and pan features You can also define a way to rotate the model around any single axis. It use mouse movement on screen, mouse buttons and (eventually) key modifiers, like Shift/Ctrl/Alt/Super, that you define

It uses quaternions algebra, internally, to manage rotations, but you can also only pass your model matrix and gat back a transormation matrix with rotation, translazion and scale, inside.

alt text

virtualGizmo3D is an header only tool and is not bound to frameworks or render engines: it uses simply glm mathematics library (0.9.9 or higher), also it an header only tool. In this way you can use it with any engine, like: OpenGL, DirectX, Vulkan, Metal, etc. and/or with any framework, like: GLFW, SDL, GLUT, Native O.S. calls, etc.

Live WebGL2 example

You can run/test an emscripten WebGL 2 example of virtualGismo3D from following link:

It works only on browsers with WebGl 2 and webassembly support (FireFox/Opera/Chrome and Chromium based).

Test if your browser supports WebGL 2, here: WebGL2 Report

How to use virtualGizmo3D in your code

To use virtualGizmo3D need to include virtualGizmo.h file in your code and declare an object of type vfGizmo3DClass, global or as member of your class

#include "virtualGizmo.h"

// Global or member class declaration
vfGizmo3DClass gizmo; 
vfGizmo3DClass &getGizmo() { return gizmo; }  //optional helper

In your 3D engine initalization declare (overriding default ones) your preferred controls:

GLFW buttons/keys initialization

void onInit()
{

    //If do not using GLFW, simply use your ID defines 
    //You can freely define any button or key modifier you prefer

    //For main manipulator/rotation
    getGizmo().setGizmoRotControl( (vgButtons) GLFW_MOUSE_BUTTON_LEFT, (vgModifiers) 0 /* evNoModifier */ );

    //for pan and zoom/dolly... you can use also wheel to zoom
    getGizmo().setDollyControl((vgButtons) GLFW_MOUSE_BUTTON_RIGHT, (vgModifiers) GLFW_MOD_CONTROL|GLFW_MOD_SHIFT);
    getGizmo().setPanControl(  (vgButtons) GLFW_MOUSE_BUTTON_RIGHT, (vgModifiers) 0);
    
    //If you need, for rotations around a single axis with key modifiers
    getGizmo().setGizmoRotXControl((vgButtons) GLFW_MOUSE_BUTTON_LEFT, (vgModifiers) GLFW_MOD_SHIFT);
    getGizmo().setGizmoRotYControl((vgButtons) GLFW_MOUSE_BUTTON_LEFT, (vgModifiers) GLFW_MOD_CONTROL);
    getGizmo().setGizmoRotZControl((vgButtons) GLFW_MOUSE_BUTTON_LEFT, (vgModifiers) GLFW_MOD_ALT | GLFW_MOD_SUPER);

    // Now call viewportSize with the dimension of window/screen
    // It is need to set mouse sensitivity for rotation
    // You need to call it also in your "reshape" function: when resize the window (look below)
    getGizmo().viewportSize(GetWidth(), GetHeight());

}    

SDL buttons/keys Initialization

void onInit()
{
    //You can freely define any button or key modifier you prefer

    //For main manipulator/rotation
    getGizmo().setGizmoRotControl( (vgButtons) SDL_BUTTON_LEFT, (vgModifiers) 0 /* evNoModifier */ );

    //for pan and zoom/dolly... you can use also wheel to zoom
    getGizmo().setDollyControl((vgButtons) SDL_BUTTON_RIGHT, (vgModifiers) 0);
    getGizmo().setPanControl(  (vgButtons) SDL_BUTTON_RIGHT, (vgModifiers) KMOD_CTRL|KMOD_SHIFT);

    //If you need, for rotations around a single axis with key modifiers
    getGizmo().setGizmoRotXControl((vgButtons) SDL_BUTTON_LEFT, (vgModifiers) KMOD_SHIFT);
    getGizmo().setGizmoRotYControl((vgButtons) SDL_BUTTON_LEFT, (vgModifiers) KMOD_CTRL);
    getGizmo().setGizmoRotZControl((vgButtons) SDL_BUTTON_LEFT, (vgModifiers) KMOD_ALT);

    // Now call viewportSize with the dimension of window/screen
    // It is need to set mouse sensitivity for rotation
    // You need to call it also in your "reshape" function: when resize the window (look below)
    getGizmo().viewportSize(GetWidth(), GetHeight());
}    

Now you need to add some event funtions:

In your Mouse-Button Event function need to call:

void onMouseButton(int button, int upOrDown, int x, int y)
{
    //  Call in 'mouse button event' the gizmo.mouse() func with:
    //      button:  your mouse button
    //      mod:     your modifier key -> CTRL, SHIFT, ALT, SUPER
    //      pressed: if button is pressed (TRUE) or released (FALSE)
    //      x, y:    mouse coordinates
    bool isPressed = upOrDown==GLFW_PRESS; // or upOrDown==SDL_MOUSEBUTTONDOWN for SDL
    getGizmo().mouse((vgButtons) (button), (vgModifiers) theApp->getModifier(), isPressed, x, y);

}

In your Mouse-Motion Event function need to call:

void onMotion(int x, int y)
{
    //  Call on motion event to communicate the position
    getGizmo().motion(x, y);
}

And in your Resize-Window Event function :

void onReshape(GLint w, GLint h)
{
    // call it on resize window to re-align mouse sensitivity
    getGizmo().viewportSize(w, h);
}

And finally, in your render function (or where you prefer) you can get the transformations

void onRender() //or when you prefer
{
    glm::mat4 model(1.0f);                          // Identity matrix

    // virtualGizmo transformations
    getGizmo().applyTransform(model);           // apply transform to matrix model

    // Now the matrix 'model' has inside all the transformations:
    // rotation, pan and dolly translations, 
    // and you can build MV and MVP matrix
}

 

Other useful stuff

If you need to more feeling with the mouse use: getGizmo().setGizmoFeeling(1.0); // 1.0 default, > 1.0 more sensible, < 1.0 less

Same thing for Dolly and Pan:

 getGizmo().setDollyScale(1.0f);
 getGizmo().setPanScale(1.0f);

You probably will need to set center of rotation (default: origin), Dolly position (default: 1.0), and Pan position (default: vec2(0.0, 0.0)

 getGizmo().setDollyPosition(1.0f); 
 getGizmo().setPanPosition(vec3(0.0f);
 getGizmo().setRotationCenter(vec3(0.0));

If you want a continuous rotation, that you can stop with a click, like in example, need to add the below call in your Idle function, or inside of the main render loop

void onIdle()
{
    // call it every rendering if want an continue rotation until you do not click on screen
    // look at glApp.cpp : "mainLoop" ("newFrame") functions

    getGizmo().idle();
}

The include file virtualGizmo.h contains two classes:

  • virtualGizmoClass<T> simple rotation manipulator, used mainly for imGuIZMO (a GIZMO widget developed for ImGui user intefrace)
  • virtualGizmo3DClass<T> manipulator with dolly/zoom and pan/translatior

Helper typedef are also defined:

typedef virtualGizmoClass<float>   vfGizmoClass;
typedef virtualGizmo3DClass<float> vfGizmo3DClass;

typedef virtualGizmoClass<double>   vdGizmoClass;
typedef virtualGizmo3DClass<double> vdGizmo3DClass;

 

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 use SDL framework instead of GLFW, uncomment #define GLAPP_USE_SDL in glApp.h file, or pass -DGLAPP_USE_SDL directly to compiler.

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 is attached and included in the example.

The CMake file is able to build also an EMSCRIPTEN version, obviously you need to have installed EMSCRIPTEN SDK on your computer (1.38.10 or higher): look at or use the helper batch/script files, in main example folder, to pass appropriate defines/patameters to CMake command line.

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.

For windows users that use vs2017 project solution:

  • If you have GLFW and/or SDL headers/library directory paths added to INCLUDE and LIB environment vars, the compiler find them.
  • 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 find built binary here... or change it)
You can’t perform that action at this time.