Vephor allows for interactive visualizations in situations where visualizations are infeasible, such as on headless systems, or where it is inconvenient to include graphics libraries.
Vephor creates graphics library agnostic visualization definitions before either saving them to disk for later viewing or sending them to a visualizer elsewhere for immediate viewing.
When running in server mode, Vephor visualization code is meant to be as dormant as possible, only using resources when a client connects and requests the visualization.
Vephor supports both C++ and Python.
Vephor requires the following dependencies
| Dependency [version] | Core | OpenGL |
|---|---|---|
| Eigen [≥ 3.3.0] | ✔️ | ✔️ |
| manif | ✔️ | ✔️ |
| GLEW | ❌ | ✔️ |
| GLFW | ❌ | ✔️ |
See core/README.md and opengl/README.md for more details on separated dependencies.
All required dependencies can be installed via vcpkg if you opt to build the software with their toolchain.
This requires that you have vcpkg installed on your system. If not yet installed, you may install as follows. See the official documentation for additional details and instructions for Windows systems. Install vcpkg in a persistent directory on your system.
cd <persistent-directory>
# Download and bootstrap vcpkg
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
# Set VCPKG_ROOT and prepend it to your path
vcpkg_root=$(pwd)
echo "export VCPKG_ROOT=$vcpkg_root" >> ~/.bashrc
echo "export PATH=\${VCPKG_ROOT}\${PATH:+:\${PATH}}" >> ~/.bashrcRefer to the following instructions to manually install dependencies on an Ubuntu system. Feel free to adapt to your distro and package manager of choice.
sudo apt install libeigen3-devNote that manif depends on Eigen. If Eigen is installed in a non-standard location, be sure to provide a
CMAKE_PREFIX_PATH when configuring.
git clone https://github.com/artivis/manif.git
cd manif
cmake -S . -B build
cmake --build build
sudo cmake --install buildsudo apt install libglew-devsudo apt install libglfw3-devBelow are supported methods for building and installing the Vephor C++ library.
Build and install as described in the following sections but with the additional CMake configuration flag
-DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake. Alternately, for Linux systems, build with the
--preset=vcpkg flag. See the following example configure steps.
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake ...
cmake -S . -B build --preset=vcpkg ... # Linux onlycd <vephor-root>
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
sudo cmake --install buildcd <vephor-root>
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=c:/msys64/mingw64
cd build
mingw32-make
sudo mingw32-make installInstall the Vephor library Python bindings in the active Python environment as follows.
pip install --upgrade pip
pip install .pip install . --config-settings=cmake.generator="MinGW Makefiles"pip install . --config-settings=cmake.define.VEPHOR_BUILD_OPENGL=OFFor
pip install python/no-openglRefer to the contained sections for common Python installation issues.
Conda employs their own set of compiler tools over those installed on the system. There is a known compatability bug between these tools and modern versions of the GCC compiler (see ContinuumIO/anaconda-issues#11152). If you encounter linker errors when installing (e.g. those shown below), then attempt one of the solutions described here.
In particular, this solution is recommended:
conda install -c conda-forge ld_impl_linux-64 # Modify the suffix to correspond with your platformIf, on importing vephor, you have an error complaining about a missing GLIBCXX version, try this:
conda install -c conda-forge libstdcxx-ngExample linker error
/home/username/conda/envs/my_env/compiler_compat/ld: warning: libGLdispatch.so.0, needed by /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libGL.so, not found (try using -rpath or -rpath-link)
/home/username/conda/envs/my_env/compiler_compat/ld: warning: libGLX.so.0, needed by /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libGL.so, not found (try using -rpath or -rpath-link)
/home/username/conda/envs/my_env/compiler_compat/ld: warning: libxcb.so.1, needed by /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so, not found (try using -rpath or -rpath-link)
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_get_maximum_request_length'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libGL.so: undefined reference to `__glDispatchRegisterStubCallbacks'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libGL.so: undefined reference to `__glXGLLoadGLXFunction'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_poll_for_queued_event'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_wait_for_event'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_get_setup'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_poll_for_event'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_connection_has_error'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libGL.so: undefined reference to `__glDispatchFini'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_take_socket'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_disconnect'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_generate_id'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libGL.so: undefined reference to `__glDispatchUnregisterStubCallbacks'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libGL.so: undefined reference to `__GLXGL_CORE_FUNCTIONS'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libGL.so: undefined reference to `_glapi_tls_Current'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_parse_display'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libGL.so: undefined reference to `__glDispatchInit'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_wait_for_reply64'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_poll_for_reply64'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_connect'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_writev'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_connect_to_display_with_auth_info'
/home/username/conda/envs/my_env/compiler_compat/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libX11.so: undefined reference to `xcb_get_file_descriptor'
collect2: error: ld returned 1 exit status
The Window class is the primary way to interact with the library. Objects that implement certain render functions can be added to the Window, yielding a RenderNode that can be used to control the object's pose, scale, visibility, and which allows object destruction.
w = Window()
s = Sphere()
node = w.add(s)
node.setScale(2.0)
w.render()
For 2d plotting, the Plot class is the recommended way to interact with the library. This presents an interface similar to matplotlib, though the underlying Window can also be accessed.
p = Plot()
p.plot([0,10],[0,10])
p.scatter([0,10],[10,0])
p.show()
The list of supported objects and function calls can be found farther down.
Note that the following examples alternate between C++ and Python, but all features are available in both.
This is the default mode for viewing Vephor visualizations - your visualization will be written to a temporary location on disk, and a vephor_show process will be created and pointed to that location. Note that these visualizations are not interactive apart from allowing camera movement - only network based visualizations allow the creator to respond to callbacks.
#include "vephor_ext.h"
using namespace vephor;
int main()
{
Window window;
window.add(make_shared<Axes>(), Vec3(500,-1000,2000));
window.add(make_shared<Sphere>(), Vec3(495,-1000,2000));
window.add(make_shared<Cone>(), Vec3(505,-1000,2000));
window.add(make_shared<Cylinder>(), Vec3(500,-995,2000));
window.add(make_shared<Cube>(), Vec3(500,-1005,2000));
window.render();
return 0;
}
#! /usr/bin/env python3
import vephor as v4
import numpy as np
w = v4.Window()
points = []
for i in range(0,100):
for j in range(0,100):
points.append((i,j,0))
points = np.array(points)
p = v4.Particle(points)
p.setScreenSpaceMode()
p.setSize(0.001)
w.add(p)
w.save("test_scene")
This will create a folder called test_scene. The visualization can then be viewed by calling:
vephor_show test_scene
The following code will open a server on the default Vephor port, 5533. The port can be set when enabling server mode.
In addition to server use, this example also shows how to allow the client to continue updating the visualization. The visualization will run separately from any client being connected, and a new client will begin visualizing at the current state of the client.
Note that multiple clients can connect to one server.
#include "vephor_ext.h"
using namespace vephor;
int main()
{
Window window;
window.setServerMode();
double obj_mesh_dist = 5.0f;
// Make a "clock"
for (int i = 1; i <= 12; i++)
{
float angle = i / 12.0 * 2 * M_PI;
Vec3 dir = Vec3(cos(angle), sin(angle), 0);
auto text = make_shared<Text>(std::to_string(i));
text->setAnchorCentered();
window.add(text, dir * obj_mesh_dist * 1.5);
vector<Vec3> verts = {
Vec3(0,0,0),
dir * obj_mesh_dist * 1.5
};
window.add(make_shared<Lines>(verts), Vec3::Zero());
}
// Use a mesh for the clock hand
string base_asset_dir = getBaseAssetDir();
auto obj_mesh = make_shared<ObjMesh>(base_asset_dir+"/assets/pyramid.obj");
auto obj_mesh_node = window.add(obj_mesh, Transform3(Vec3(obj_mesh_dist,0,0)));
float angle = 0;
while (true)
{
angle += 0.01;
obj_mesh_node->setPos(Vec3(cos(angle), sin(angle), 0) * obj_mesh_dist);
obj_mesh_node->setOrient(Vec3(0,0,angle+M_PI));
window.render(false /*wait*/);
std::this_thread::sleep_for(std::chrono::milliseconds((int)(33)));
}
return 0;
}
Once this server is running, connect to it using:
vephor_show -m client
"Bring your own client" mode allows you to create interactive visualizations without needing to separately call vephor_show. It will create a server and also create a client process to talk to that server.
TODO
TODO
TODO
#! /usr/bin/env python3
import os
import vephor as v4
import numpy as np
image = np.zeros((16,16,3))
image[:8,8:] = np.array((0.5,0.5,0.5))
image[8:,:8] = np.array((0.75,0.75,0.75))
image[8:,8:] = np.array((1,1,1))
plt = v4.Plot()
plt.imshow(image)
plt.show()
TODO
Here are, as compactly as possible, all the relevant functions this library provides. This is meant to give an overview - see source for explicit data types.
| Window | Window | Create a window. Width/height of (-1,-1) means the window should fill the screen. | (width=-1, height=-1, title="show") |
|---|---|---|---|
| add | Add an object to the window for rendering. | (obj, transform=identity, overlay=false, layer=0) | |
| canRender | Check if rendering is possible, for example when a client is connected in server mode. | ||
| render | Render current window contents. | (wait_close=true, wait_key=false) | |
| save | Save current window contents to a file. | (path) | |
| clear | Remove all current window contents. | ||
| setTitle | Set window title. | (title) | |
| setTrackballMode | Set up the standard 3d camera mode. | (to=(0,0,0), from=(-1,0,-1), up=(0,0,-1), use_3d=false) | |
| setPlotMode | Set up the 2d plotting camera mode. | equal=false | |
| setServerMode | Put the window in server mode. | (wait=false, port=5533, record_also=false, record_path="", metadata=default) | |
| setServerModeBYOC | Put the window in server mode, and spawns a client to connect. | (record_also=false,record_path="") | |
| setRecordMode | Put the window in record mode. | (path="") | |
| checkAndConsumeFlag | Check a server metadata flag, and consume it if it is a one-shot flag. | (flag) | |
| setKeyPressCallback | Set key press callback function. | (callback) | |
| RenderNode | |||
| getPos | Get position of node in parent frame. | ||
| setPos | Set position of node in parent frame. | (pos_in_world) | |
| getOrient | Get rotation that rotates node frame to parent frame. | ||
| setOrient | Set rotation that rotates node frame to parent frame. | (parent_from_node_rotation) | |
| getTransform | Get transform that transforms node frame to parent frame. | ||
| setTransform | Set transform that transforms node frame to parent frame. | (parent_from_node) | |
| getScale | Get scale of the node. | ||
| setScale | Set scale of the node. | (scale) | |
| setParent | Set the transform parent of this node. Replaces world frame as parent. | (parent) | |
| getShow | Get whether node should be shown. | ||
| setShow | Set whether node should be shown. | (show) | |
| getDestroy | Get whether node has been destroyed. | ||
| setDestroy | Set node to be destroyed. | ||
| Plot | Plot | Create a plot. | (title) |
| plot | Plot a continuous line. | (x_list, y_list, options) | |
| scatter | Plot a set of points. | (x_list, y_list, options) | |
| show | Render current plot contents. | (wait_close=true, wait_key=false) | |
| save | Save current window contents to a file. | (path) | |
| clear | Remove all current plot contents. | ||
| title | Set plot title. | (title) | |
| xlabel | Set x axis label. | (label) | |
| ylabel | Set y axis label. | (label) | |
| equal | Set plot axes to have equal scales. | (is_equal) | |
| limits | Set plot limits. | (min_x, max_x, min_y, max_y) | |
| text | Add text to the plot. | (text, height, pos, color) | |
| polygon | Add a polygon to the plot. 0 thickness for a thin line border, -1 for filled. | (verts, color, thickness=0) | |
| circle | Add a circle to the plot. 0 thickness for a thin line border, -1 for filled. | (center, rad, color, thickness=0, slices=16) | |
| rect | Add a rectangle to the plot. 0 thickness for a thin line border, -1 for filled. | (center, width, height, color, thickness=0 | |
| line | Add a line to the plot. | (vert_list, color, thickness) | |
| imshow | Add an image to the plot. | (image, nearest_filtering=false, pos=(0,0)) | |
| Arrow | Arrow | Create an arrow. | (start, end, rad=1.0, slices=16) |
| setColor | Set color. | (color) | |
| Axes | Axes | Create a set of axes. | (size=1.0) |
| Circle | Circle | Create a circular disc with a z axis normal. Outer rim of the disc is set by rad, inner rim is thickness units inwards. | (rad=1.0, thickness=1.0, slices=16) |
| setColor | Set color. | (color) | |
| Cone | Cone | Create a cone with the flat surface in the z=0 plane, with the top height units along the z axis. | (rad=1.0, height=1.0, slices=16) |
| setColor | Set color. | (color) | |
| Cube | Cube | Create a cube. | (rad) |
| setColor | Set color. | (color) | |
| Cylinder | Cylinder | Create a cylinder along the z axis, with half of height on either side. | (rad=1.0, height=1.0, slices=16) |
| setColor | Set color. | (color) | |
| Grid | Grid | Create a grid. | (rad, normal=(0,0,1), right=(1,0,0), cell_size=1.0) |
| setColor | Set color. | (color) | |
| Lines | Lines | Create a line. | (vert_list, color_list) |
| setColor | Set color. | (color) | |
| setLineStrip | Set if verts form a continuous line - if false, each pair is a separate line. Initial state is a continuous line. | (is_strip) | |
| Mesh | Mesh | Create a mesh. | (mesh_data) |
| setTexture | Set texture for this mesh. | (image, nearest_filtering=false) | |
| setColor | Set color. | (color) | |
| setSpecular | Set whether specular highlights should be used. | (specular) | |
| setCull | Set whether faces should be culled if facing away from the camera. | (cull) | |
| ObjMesh | ObjMesh | Create geometry using a .obj mesh file. | (path) |
| setColor | Set color. | (color) | |
| Particle | Particle | Create a point cloud. | (vert_list, color_list) |
| setSize | Set size of each particle. | (size) | |
| setColor | Set color. | (color) | |
| setTexture | Set texture for each particle. | (image, nearest_filtering=false) | |
| setScreenSpaceMode | Set whether particle size is in metric space or screen space. If in screen space, size is taken as a screen space portion from 0 to 1. | (is_screen_space) | |
| Plane | Plane | Create a rectangular plane segment. | (rads) |
| setColor | Set color. | (color) | |
| setTexture | Set texture for each particle. | (image, nearest_filtering=false) | |
| Sphere | Sphere | Create a sphere. | (rad=1.0, slices=16, stacks=16) |
| setColor | Set color. | (color) | |
| Sprite | Sprite | Create a screen-facing rectangle bearing an image. | (image, nearest_filtering=false) |
| setColor | Set color. | (color) | |
| setFlip | Set whether image should be flipped vertically. | (flip) | |
| setNormalSpriteSheet | Set normal texture for the sprite. | (image, nearest_filtering=false) | |
| Text | Text | Create text. Initial zero point is at the bottom left. | (text) |
| setColor | Set color. | (color) | |
| setAnchorBottomLeft | Set zero point of text to the bottom left. | ||
| setAnchorLeft | Set zero point of text to the left. | ||
| setAnchorTopLeft | Set zero point of text to the top left. | ||
| setAnchorBottom | Set zero point of text to the bottom middle. | ||
| setAnchorCentered | Set zero point of text to the middle. | ||
| setAnchorTop | Set zero point of text to the top middle. | ||
| setAnchorBottomRight | Set zero point of text to the bottom right. | ||
| setAnchorRight | Set zero point of text to the right. | ||
| setAnchorTopRight | Set zero point of text to the top right. | ||
| ThickLines | ThickLines | Create a set of lines with consistent screen space thickness. | (vert_list, color_list) |
| setColor | Set color. | (color) | |
| setLineWidth | Set line width in screen space portion. | (line_width) | |
| Loose functions | TODO | ||
| MeshData | TODO | ||
| formLine | Make mesh data for a 3d line with some thickness. | (vert_list, rad) | |
| formLineLoop | Make mesh data for a 3d line with some thickness. Same as formLine, but makes the line into a loop by repeating the first vertex. | (vert_list, rad) | |
| formPolygon | Make mesh data for an XY plane polygon. | (vert_list) | |
| formCube | Make mesh data for a cube. | ||
| formSphere | Make mesh data for a sphere. | (slices, stacks) | |
| formCone | Make mesh data for a cone. | (rad, height, slices, smooth=true) | |
| formCylinder | Make mesh data for a cylinder. | (rad, height, slices, smooth=true) | |
| formPlane | Make mesh data for an XY plane segment. | (rads) | |
| formCircle | Make mesh data for an XY plane circle. | (rad, thickness, slices) | |
| formHeightMap | Make mesh data for a height map. | (height, res, uv_callback=none) | |
| Image | TODO | ||
| generateSimpleImage | |||
| generateGradientImage | |||
| generateCheckerboardImage | |||
| loadImage | |||
| saveImage |
