Polarizer is a desktop path tracing renderer written in C++17. It combines:
- A GPU compute-shader path tracer (progressive accumulation)
- A real-time previewer for interactive scene editing/selection
- An experimental polarization pipeline (Stokes-like vector + Fresnel s/p terms)
- A custom binary scene format (
*.pls) backed by a lightweight DB module - Cross-backend GFX abstraction (Vulkan + OpenGL) and an ImGui-based GUI layer
Polarizer is a cross-platform CMake project targeting Windows and Linux.
- CMake ≥ 3.15
- A C++17 compiler
- Windows: Visual Studio (MSVC) recommended
- Linux: GCC or Clang
- Vulkan headers/libs (recommended)
- The project can use a Vulkan SDK installed system-wide, or a vendored SDK path (see below).
- GPU drivers supporting:
- Vulkan compute (recommended path; the app config defaults to Vulkan)
- and/or OpenGL (there is an OpenGL backend as well)
Most dependencies are expected under third_party/ and are wired by CMakeLists.txt, including:
- GLFW
- glad
- ImGui
- stb
- tinyfiledialogs
- nlohmann/json (header-only)
CMakeLists.txt uses VULKAN_SDK_PATH to locate Vulkan headers/libraries:
- If
VULKAN_SDK_PATHis not set, it defaults to:third_party/vulkan.
If you have an installed Vulkan SDK, point CMake at it, e.g.:
cmake -S . -B build -DVULKAN_SDK_PATH="C:/VulkanSDK/1.xx.x.x" # Windows example
# or
cmake -S . -B build -DVULKAN_SDK_PATH="$VULKAN_SDK" # Linux examplecmake -S . -B build -G "Visual Studio 17 2022" -A x64
cmake --build build --config ReleaseArtifacts are placed under:
build/bin(executables)build/lib(libraries)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j- If you see missing Vulkan headers/libs at configure time, set
VULKAN_SDK_PATH(or ensure the vendoredthird_party/vulkanis present). - If Vulkan is not available on your system, you may still be able to run with the OpenGL backend (the repo contains both backends), but Vulkan is the default in app initialization.
Polarizer accepts an optional scene file (*.pls) as the first argument:
./Polarizer path/to/scene.plsDrag & drop:
- Drop a
.plsfile to open it - Drop
.objfiles to load models into the current scene
The main application is PathTracerApp (inc/app/PathTracerApp.h, src/app/PathTracerApp.cpp). The main window is composed of:
- Menu bar (
UiMenuBar) - Tool bar (
UiToolBar) with render controls (Start/Pause/Stop/Restart) and display-mode switching - Main viewport (
UiMainViewport): shows preview output or path tracer output depending on display mode - Right panel (
UiRightPanel): scene/camera/model/mesh/material properties - Status bar (
UiStatusBar): render state, samples, timing, triangle count - Settings/About/Save prompts (
UiSettingsWindow,UiAboutWindow,UiSaveDialog)
Keyboard/mouse highlights:
- Right mouse drag (in preview mode) rotates the camera; W/A/S/D moves while in camera-control mode.
- Shift+1 / Shift+2 switches display mode (Preview / Path tracer output).
- F5/F6/F7/F8 map to render Start/Pause/Stop/Restart (see
onKeyboardAction).
Strings are localized via JSON in resources/strings/.
Polarizer’s path tracer produces a 4-channel per-pixel output (vec4 in the shader / RGBA32F images on the GPU). In polarization mode, the channels are used as:
- R = S0
- G = S1
- B = S2
- A = Scene depth (a scalar depth value written by the tracer)
In the shader, polarization is represented with a 3-component Stokes-like vector:
S = (S0, S1, S2)
This is similar in spirit to the classical Stokes vector, but reduced to 3 components (classical Stokes is 4D: S0..S3). In this implementation:
S0acts like an overall intensity-like term.S1andS2encode linear polarization components in a chosen local frame.- The vector is rotated between interaction frames using a Stokes-rotation matrix (
stokesRotation(phi)), and updated using Fresnel s/p coefficients accumulated along the path (calcPolarResult).
Practical interpretation: treat
(S0,S1,S2)as “the polarization result the shader computes” rather than assuming it matches every convention of a full 4D Stokes pipeline.
The UI includes a display channel selector for the path tracer output (see UiRightPanel::OUTPUT_DISP_CHANNEL handling). This lets you visualize individual components (e.g. S0 only) in the viewport via the post-processing step.
Polarizer supports exporting:
- Text export that writes floating point channel data to a
.txt
From the implementation, the text export writes all float channels in a structured way:
- Channels are exported as separate planes (one plane per channel).
- Each plane is written row-by-row, as space-separated float values.
In polarization output mode, that means the exported text contains four planes in this order:
S0planeS1planeS2planeSceneDepthplane
So a consumer can reconstruct:
- a
(width × height)array forS0,S1,S2, anddepth.
A *.pls file is a binary dump of the custom DB:
- Magic:
P L S - Version: derived from app version
- Root object: a
PtScene
The stored scene graph is made of typed objects:
PtScene: resolution, trace depth, camera settings, list of modelsPtModel: name, file path (OBJ), transforms, list of meshesPtMesh: name, links to model + materialPtMaterial: material model + parameters + texture references used by the renderer/UI
Opening a scene resets the DB, loads it from file, validates the root PtScene, then populates the previewer and UI.
Polarization is implemented inside the path tracing compute shader (resources/shaders/pathTracer.comp), using:
- Per-bounce stored data
PolarInfo(normal, outgoing dir, Fresnel reflection coefficientsrs/rp, and a Stokes-like vector) - Fresnel s/p reflection coefficient computation (
getRsRp) - Rotation of the Stokes-like vector between interaction frames via a 3×3 rotation matrix (
stokesRotation(phi)) - Backward accumulation across the bounce history (
calcPolarResult(rayDir, depth)), rotating into each bounce frame and applying Fresnel-derived updates
This is intended to model how polarization state changes through specular-like interactions and basis changes along a path.
This repo is organized as several mostly-independent modules. Here’s a high-level map of what each does:
- Owns the main loop, window/view composition, input routing, and orchestration of previewer/path tracer/post-process.
- Scene loading/saving, model import, image export, and user workflows live here.
- Generic typed object store (
DB) with:- type registry (
DbTypeRegistry) - binary serialization/deserialization (
DbSerializer-based) - transaction log + undo/redo support
- type registry (
- Used as the authoritative backing store for
.plsscenes and editor operations.
- App-specific DB-registered types:
PtScene,PtModel,PtMesh,PtMaterial. - These define exactly what is persisted in
.pls.
- Rendering abstraction layer with multiple backends:
- OpenGL backend
- Vulkan backend
- Provides cross-backend concepts like renderer, buffers, images, pipelines, descriptor binding, and dispatch/copy operations.
- Used by:
- the previewer (raster pipeline)
- the path tracer (compute pipeline)
- post-processing
- Windowing/input layer + view/event system on top of GLFW/ImGui-style widgets.
- UI widgets/views emit
GuiEvents whichPathTracerAppconsumes to update DB state and rendering state. - Localization uses
GuiTextwith JSON string tables.
- Shaders under
resources/shaders/* - UI language strings under
resources/strings/* - Shaders are also embedded into a generated header (
inc/res/ShaderStrings.hpp) via CMake (cmake/GenerateShaderStrings.cmake).
- Shared helpers (math types, logging, image IO via stb, OBJ parsing/mesh loading, timers, etc.)
Source files include Apache-2.0 headers. See repository contents for the full license text if provided.
- stb (image loading/writing)
- GLFW
- ImGui
- Vulkan / OpenGL ecosystem
- nlohmann/json
- tinyfiledialogs