Repository navigation
Ogre Backend
The Ogre backend (vgl/ogre.hpp, CMake target vgl::ogre, sources in backends/ogre) puts the globe into a classic Ogre 14 scene as an Ogre MovableObject, vgl::ogre::globe. This page covers the supported Ogre versions and render systems, enabling it with VGL_BACKEND_OGRE, how Ogre is found or downloaded, creating the globe and attaching it to a scene, its materials and unified shaders, render queue groups, the depth conventions including reversed-Z in Ogre, the Ogre sample, and installing and consuming vgl::ogre. Like the other backends it is a consumer of the render interface, using vgl through the C API only; its own interface is C++, because Ogre's is.
- Status and supported render systems
- Enabling and building
- Installing and consuming vgl::ogre
- Quick start
- The globe object
- Settings per frame
- Camera and transforms
- Depth conventions and reversed-Z in Ogre
- Materials and unified shaders
- Render queue groups
- Device loss and shutdown
- The Ogre sample
- Troubleshooting
| Item | Status |
|---|---|
| Ogre line | Ogre 14, the classic line (not Ogre-Next). The design settled on 14.6.0; the build downloads 14.6.1 when no Ogre is installed |
| OpenGL 3+ render system | Supported on Windows and Linux, checked by the sample in CI (Mesa under Xvfb) |
| Direct3D 11 render system | Supported on Windows, checked by the sample |
| Vulkan render system | After version 1 (milestone M3b) |
| macOS (Metal) | After version 1 (milestone M3b) |
| OpenGL ES 3 and Metal, Android and iOS | After version 1 (milestone M3b) |
Version 1 supports the Ogre backend on OpenGL 3+ and Direct3D 11, on Windows and Linux only.
The shaders are written with Ogre's unified shader macros, so they are meant to compile for GLSL, GLSL ES, HLSL, Vulkan's GLSL and Metal; the remaining work for the other render systems is mostly build and CI. Like the C API, the Ogre interface stays compatible within major version 1.
The backend is off by default, because building Ogre takes a while. Turn it on when configuring:
cmake --preset linux-gcc-shared -DVGL_BACKEND_OGRE=ON
cmake --build --preset linux-gcc-shared-release --target vgl_ogre_samplecmake --preset windows-msvc-static -DVGL_BACKEND_OGRE=ON
cmake --build --preset windows-msvc-static-releaseHow Ogre is found, in backends/ogre/CMakeLists.txt:
-
An installed Ogre 14, if
find_package(OGRE 14 CONFIG)finds one: pointOGRE_DIRat its CMake directory or add its prefix toCMAKE_PREFIX_PATH. Configure printsvgl: using installed Ogre <version>. -
Otherwise, with
VGL_FETCH_DEPENDENCIES(on by default), Ogre 14.6.1 is downloaded from GitHub at a pinned SHA-256 and built statically inside vgl's build, with only what the backend and its sample need: the OpenGL 3+ render system, the Direct3D 11 render system on Windows, the RTShader system, Bites, the overlay with Dear ImGui (vgl's own pinned copy) and the stb image codec. Ogre's own dependency download is off; none of it is needed. Configure printsvgl: using downloaded Ogre 14.6.1, built statically. - Otherwise configure warns "Ogre 14 was not found and VGL_FETCH_DEPENDENCIES is off; skipping the Ogre backend".
vgl_ogre is always a static library, whatever BUILD_SHARED_LIBS says, so that it shares your Ogre instead of holding a second copy of Ogre's singletons. It links OgreMain publicly. Unlike the core and the other backends it is compiled with exceptions, because Ogre throws; it catches them at its interface, so no exception crosses into your code, and failures come back as vgl::result values with a message in the context's log.
vgl::ogre is installed (and exported in vgl's CMake package) only when the backend was built against an installed Ogre. A downloaded Ogre is part of vgl's build tree, not installed, so the package could not name it. With an installed Ogre, the package's config calls find_dependency(OGRE 14 CONFIG), so consumers find Ogre the way vgl's build did:
find_package(vgl CONFIG REQUIRED)
target_link_libraries(my_app PRIVATE vgl::vgl vgl::ogre)| Route | Ogre backend |
|---|---|
| Source build, installed Ogre | Built and installed as vgl::ogre
|
| Source build, downloaded Ogre | Built and usable inside the same build (add_subdirectory), not installed |
vcpkg port (packaging/vcpkg/ports/vgl) |
Feature ogre, which depends on vcpkg's ogre port: vcpkg install vgl[ogre] --overlay-ports=<vgl>/packaging/vcpkg/ports
|
Conan recipe (packaging/conan) |
Not available: ConanCenter has no Ogre 14, so the recipe leaves the backend out |
The release archives leave the Ogre backend out; until the port and recipe are in the vcpkg registry and ConanCenter, use them from the repository as above. See Installing vgl and packaging/README.md.
When embedding vgl with add_subdirectory, set VGL_BACKEND_OGRE before adding it; vgl then looks for Ogre with find_package(OGRE 14 CONFIG) itself.
#include <vgl/ogre.hpp>
#include <vgl/vgl.hpp>
// After Ogre::Root::initialise (the globe needs a render system), with Ogre's Media/Main in
// the resource group the globe uses:
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
ogre_media_dir + "/Main", "FileSystem", Ogre::RGN_INTERNAL);
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
vgl::ogre::globe_create_info info;
info.depth_convention = VGL_DEPTH_CONVENTION_LOGARITHMIC;
info.resource_group = Ogre::RGN_INTERNAL;
vgl::expected<vgl::ogre::globe*> globe = vgl::ogre::globe::create(context, info);
if (!globe)
{
std::fprintf(stderr, "globe: %s\n", vgl::result_name_get(globe.error()));
}
// At the origin, which is ECEF's, unrotated and unscaled.
scene_manager->getRootSceneNode()->attachObject(*globe);
// Each frame:
static_cast<void>(context.view_set(&view)); // view.view_matrix: ECEF to camera, in double
static_cast<void>(context.update());
camera->setAspectRatio(static_cast<Ogre::Real>(aspect)); // match the projection in `view`
vgl::ogre::globe_settings settings;
settings.has_view_matrix = true;
settings.view_matrix = view.view_matrix;
settings.sun_direction = sun; // ECEF, optional
settings.features = VGL_DRAW_FEATURE_ATMOSPHERE;
if ((*globe)->settings_set(settings) != vgl::result::success)
{
// invalid settings; the previous ones stay
}
root->renderOneFrame();
// At the end, before the vgl context and before Ogre's render system goes:
scene_manager->getRootSceneNode()->detachObject(*globe);
vgl::ogre::globe::destroy(*globe);vgl::ogre::globe derives from Ogre::MovableObject (movable type "vgl_globe"). Create it with one of:
static vgl::expected<globe*> globe::create(vgl::context& context, const globe_create_info& info) noexcept;
static vgl::expected<globe*> globe::create(vgl_context* context, const globe_create_info& info) noexcept;globe_create_info:
| Field | Meaning | Default |
|---|---|---|
depth_convention |
How depth is written and compared | VGL_DEPTH_CONVENTION_LOGARITHMIC |
resource_group |
The resource group of the globe's programs, materials, buffers and textures. It must see Ogre's Media/Main
|
Ogre::RGN_DEFAULT |
name |
Ogre's name for the globe, unique among movable objects; also the prefix of its resources' names | "vgl/globe" |
Creation must come after Ogre::Root::initialise, since it builds programs on the current render system. It picks the first shading language the render system supports among hlsl, glsl, glsles, glslang and metal, compiles the terrain, sky and stars programs, creates the materials, and tells the context it samples RGBA8. It fails with:
| Result | Cause |
|---|---|
invalid_argument |
Null context, or an unknown depth convention |
not_supported |
Reversed-Z without the render system's "Reversed Z-Buffer" option, or a render system that compiles none of the shading languages |
backend_error |
Ogre failed: no render system yet, or a program failed to compile (Ogre's log has the error) |
out_of_memory |
Allocation failed |
The context's log says which. The context must outlive the globe, and the globe uses the context's allocator for its own records (Ogre's objects go through Ogre).
Other members:
| Member | Purpose |
|---|---|
static void destroy(globe* g) noexcept |
Destroys it; detach it from its scene node first. Null does nothing. Resets the context's render resources, so a later consumer gets them all again |
vgl::result settings_set(const globe_settings&) noexcept |
How it draws from the next frame on |
vgl::result stars_set(std::span<const vgl_star>) noexcept |
The stars for VGL_DRAW_FEATURE_STARS (Atmosphere, Stars and Clouds) |
vgl::result clouds_set(const std::uint8_t* coverage, std::uint32_t width, std::uint32_t height) noexcept |
The cloud coverage for VGL_DRAW_FEATURE_CLOUDS; null with 0 x 0 removes it |
void device_reset() noexcept |
Forgets its Ogre objects and the context's render resources after Ogre lost its device |
Its bounds are infinite (getBoundingBox returns BOX_INFINITE), so Ogre never culls it; the core culls the tiles. It casts no shadows. Call its functions on Ogre's render thread, one at a time with the calls on its context: in particular, vgl_context_update must not run while Ogre renders.
The globe runs one frame of the render interface in _updateRenderQueue, once per Ogre frame (keyed on Ogre::Root::getNextFrameNumber): it applies the resource lists (index lists become HardwareIndexBuffers, meshes HardwareVertexBuffers with the vertex layout of the render interface plus a samples texture, imagery textures with their mip chains, all through Ogre's managers), fills a pool of renderables from the draw list, and ends the frame before Ogre draws. Further viewports in the same Ogre frame reuse the renderables, all drawn from the same view. Each mesh has its own material, cloned from the globe's, whose texture units hold its samples, its draw item's layers and the clouds: Ogre binds textures by material, not by renderable.
globe_settings takes effect from the next frame on. settings_set checks it and keeps the previous settings on invalid_argument (a non-finite matrix or direction, unknown feature or debug bits, or a negative or non-finite distance, interval or height).
| Field | Meaning | Default |
|---|---|---|
has_view_matrix, view_matrix
|
The camera to draw from, in double precision, when it differs from the context's view |
false: the context's view |
sun_direction |
Towards the sun along the ECEF axes | Zero: light from the camera (with the atmosphere, a sun above the camera) |
logarithmic_far |
Far distance of the logarithmic convention, metres | 0: VGL_LOGARITHMIC_DEPTH_FAR_DEFAULT
|
upload_budget |
Bytes of resources to upload per frame | 0: VGL_UPLOAD_BUDGET_DEFAULT
|
features |
vgl_draw_feature bits |
0 |
debug_views |
vgl_debug_view bits |
0 |
earth_rotation_angle |
Radians, for the stars | 0 |
contour_interval |
Metres | 0: 500 |
cloud_height |
Metres above the ellipsoid | 0: 6000 |
The shading, features and debug views are the OpenGL backend's (OpenGL Backend).
Ogre holds its camera's view in single precision, which is too coarse at the Earth's radius. The globe therefore does not use it:
- Each tile renderable reports the draw item's
model_view(composed by the core in double precision, from the context's view orglobe_settings::view_matrix) as its world transform, withsetUseIdentityView(true), so Ogre multiplies only its camera's projection. NoOGRE_DOUBLE_PRECISIONbuild is needed. - The renderables' transforms replace the scene node's, so the node's transform has no effect; keep the globe on a node at the origin, unrotated and unscaled, as the header asks.
-
Keep Ogre's camera's projection matching the one you give the context: the same vertical field of view (
setFOVy), aspect ratio (setAspectRatio) and suitable clip distances for the convention. Tile selection uses the context's view; drawing uses Ogre's projection. - Your own scene objects are still drawn with Ogre's camera view. If you place them in ECEF near the globe, mind Ogre's single precision there too (for example, keep them relative to a local origin near the camera).
The sample sets the camera like this:
void camera_set(Ogre::Camera* camera, vgl_depth_convention depth, double altitude, double aspect)
{
camera->setAspectRatio(static_cast<Ogre::Real>(aspect));
switch (depth)
{
case VGL_DEPTH_CONVENTION_REVERSED_Z:
camera->setNearClipDistance(1.0f);
camera->setFarClipDistance(0.0f); // infinite
break;
case VGL_DEPTH_CONVENTION_CONVENTIONAL:
camera->setNearClipDistance(static_cast<Ogre::Real>(std::max(1.0, altitude * 0.05)));
camera->setFarClipDistance(static_cast<Ogre::Real>(altitude + 2.0e7));
break;
default: // logarithmic: the planes do not matter
camera->setNearClipDistance(1.0f);
camera->setFarClipDistance(1.0e9f);
break;
}
}| Convention | Ogre setup |
|---|---|
| Logarithmic (default) | Nothing special: the shaders write depth from the camera distance and move the clip-space depth onto the same curve, for OpenGL (-w to w) and Direct3D (0 to w) alike |
| Reversed-Z | Set the render system's "Reversed Z-Buffer" option to "Yes" before Root::initialise; Ogre then applies it to its projections and depth tests itself. Use a far clip distance of 0 (infinite). globe::create fails with not_supported without the option |
| Conventional | Ogre's default; small scenes only |
Ogre::RenderSystem* rs = root->getRenderSystemByName("OpenGL 3+ Rendering Subsystem");
// or "Direct3D11 Rendering Subsystem"
root->setRenderSystem(rs);
rs->setConfigOption("Reversed Z-Buffer", "Yes");
root->initialise(false);Render windows keep a 24-bit integer depth buffer even with reversed-Z, which is too coarse at planetary scale; Ogre gives render textures a 32-bit floating-point depth buffer instead. So for reversed-Z, draw the scene into a render texture the size of the window and show it, as the sample does, or use the logarithmic convention:
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(
"vgl/scene", Ogre::RGN_INTERNAL, Ogre::TEX_TYPE_2D, width, height, 0,
Ogre::PF_BYTE_RGBA, Ogre::TU_RENDERTARGET);
Ogre::Viewport* viewport = texture->getBuffer()->getRenderTarget()->addViewport(camera);
// Show `texture` in the window with a screen-space rectangle in a second scene manager.Because reversed-Z is a render-system option, switching conventions means a new Ogre root, which is what the sample's check does for each convention.
The globe creates its programs and materials in code, so you ship no vgl resource files. The shaders (backends/ogre/shaders.hpp) are one source per stage, written with Ogre's unified shader macros (#include <OgreUnifiedShader.h>), with a branch per language only where the macros do not reach (reading the samples texel by texel, and the depth output). The atmosphere code (backends/common/atmosphere.glsl) is inserted with Ogre's definitions. GLSL programs get Ogre's native version directive; HLSL programs compile for vs_4_0 and ps_4_0.
What this means for your setup:
-
Ogre's
Media/Mainmust be a resource location of the globe's resource group, forOgreUnifiedShader.h, as in any Ogre application with the shader system. With a downloaded Ogre, it is in the source tree (<build>/_deps/vgl_ogre_source-src/Media; the CMake cache variableVGL_OGRE_MEDIA_DIRnames it); with an installed Ogre, the media directory of the installation (OGRE_MEDIA_DIRfrom its CMake package). - The globe does not need the RTShader system. The sample initializes it anyway, for Ogre's own materials such as the overlay's.
- Materials are named after
globe_create_info::name("vgl/globe/terrain","vgl/globe/sky","vgl/globe/stars", and per-mesh clones); keep the name unique if you create several globes. - Mesh samples are stored as a two-channel 32-bit float texture, the normal packed into a float, because Ogre's Direct3D 11 render system has no integer textures.
- Culling is
CULL_CLOCKWISE(counter-clockwise front faces, as the data has them); Ogre turns it over for mirrored and flipped targets itself, so there is nomirroredsetting.
| What | Group |
|---|---|
| Terrain tiles | The globe's own render queue group: RENDER_QUEUE_MAIN unless you call setRenderQueueGroup on it |
| Stars | RENDER_QUEUE_SKIES_LATE - 1 |
| Sky (the atmosphere) | RENDER_QUEUE_SKIES_LATE |
The sky and stars draw at the far depth where nothing was drawn before them, so your opaque objects in earlier groups keep them out. Objects that write no depth and should appear in front of the sky (transparent effects, for example) belong in a group after RENDER_QUEUE_SKIES_LATE; the overlay's group comes after it anyway.
- After Ogre's render system lost its device and recreated its resources, call
globe->device_reset(): the globe forgets its Ogre objects and the context's render resources, which upload again over the next frames. Stars and clouds are kept on the CPU. - Shut down in this order: detach the globe,
vgl::ogre::globe::destroy, then the packs and the vgl context, then Ogre (Root). The globe removes its materials, programs and textures from Ogre's managers when destroyed.
samples/ogre/main.cpp, executable vgl-ogre, built when VGL_BACKEND_OGRE is on and GLFW and Ogre's overlay and Bites are available. GLFW owns the window (created with GLFW_NO_API) and the input; Ogre renders into it through externalWindowHandle on Windows, or a child window under parentWindowHandle on X11. The panel is the samples' shared Dear ImGui overlay, drawn by Ogre's ImGui overlay. It has the same navigation and keys as the OpenGL sample.
vgl-ogre [--data <directory> | --pack <uri>...] [--cache <directory> [--cache-budget <MiB>]]
[--rs gl|d3d11] [--depth logarithmic|reversed|conventional] [--check]
[--save <directory>] [--stars <catalog>]-
--rspicks the render system:gl("OpenGL 3+ Rendering Subsystem", the default) ord3d11("Direct3D11 Rendering Subsystem", Windows). -
--depthdefaults to reversed-Z; the globe is drawn into a render texture and shown in the window, for the 32-bit depth buffer. -
--checkruns hidden: it draws a few views offscreen with each convention, with a new Ogre root for each, checks the images and that the conventions agree, and exits with 1 on failure.--savewrites the images as PPM files. - Ogre's log goes to
vgl-ogre.login the working directory.
The checks are the CTest tests ogre_gl and, on Windows, ogre_d3d11, added with -DVGL_TEST_GL=ON since they need a display. CI runs ogre_gl on Linux with Mesa under Xvfb, outside pushes, as building Ogre takes a while.
| Symptom | Likely cause |
|---|---|
| Configure skips the backend | No Ogre 14 found and VGL_FETCH_DEPENDENCIES off; set OGRE_DIR or turn fetching on |
vgl::ogre missing from an installed vgl |
vgl was built with a downloaded Ogre; build it against an installed Ogre 14 |
create fails with backend_error, "Ogre has no render system yet" |
Create the globe after Root::initialise
|
A program fails to compile, OgreUnifiedShader.h not found |
Media/Main is not in the globe's resource group |
create fails with not_supported
|
Reversed-Z without "Reversed Z-Buffer" set to "Yes"
|
| Distant terrain z-fights with reversed-Z | Drawing into a render window's 24-bit depth buffer; use a render texture |
| The globe is offset or stretched | Ogre's camera's field of view or aspect does not match the context's projection |
Render Interface, OpenGL Backend, Direct3D 11 Backend, Atmosphere, Stars and Clouds, Building vgl, Installing vgl, Samples, and the header backends/ogre/include/vgl/ogre.hpp.
Getting vgl
Using the library
Rendering
Data
Reference
Specifications