Architectural Differences Between renderpathforward.c, renderpathbase.c, renderpathsphere.c, and renderenvsphere.c for PBR Texture Painting
ArmorPaint’s four render path modules implement distinct lighting strategies—from lightweight forward rendering to dynamic HDRI environments—while sharing a common base in renderpathbase.c that centralizes GPU resource management for real-time PBR texture painting.
The armory3d/armorpaint repository organizes its real-time rendering pipeline into specialized C modules that determine how physically-based materials appear during texture painting. Each render path file optimizes for specific performance and visual fidelity requirements, allowing artists to balance brush responsiveness against accurate lighting previews. Understanding these architectural distinctions enables developers to extend the pipeline or troubleshoot rendering artifacts during PBR workflow.
renderpathbase.c: The Shared Foundation for All Render Paths
renderpathbase.c provides the common substrate that unifies every rendering mode in ArmorPaint. It initializes shared GPU resources including uniform buffers, texture samplers, and vertex formats, ensuring that PBR material data remains consistent regardless of the active lighting strategy. The file exposes a generic drawObjects() routine that concrete render paths invoke after configuring their specific pipeline states, along with utility functions for camera control, viewport sizing, and default clear states. By centralizing texture upload logic—such as the uploadTexture() function used by the brush system—this module guarantees that painted layers reach the GPU efficiently without duplicating code across renderer variants.
renderpathforward.c: Forward Rendering for Immediate Brush Feedback
renderpathforward.c implements a classic forward rendering path optimized for rapid iteration during PBR texture painting. The architecture sets up a single render pass that draws geometry directly to the back buffer, binding vertex and fragment shaders specific to the PBR material. Per-pixel lighting calculations—including directional, point, and spot lights—execute inside the fragment shader with minimal post-processing limited to optional tone-mapping and gamma correction. Because this path avoids multi-pass deferred techniques or complex environment sampling, it delivers the lowest latency for brush feedback, making it ideal for painting albedo, metallic, and roughness channels where instant visual response is critical.
renderpathsphere.c: Static Environment Sphere Lighting
renderpathsphere.c introduces global illumination preview capabilities through a static environment sphere architecture. The module renders the scene onto a sphere that samples a pre-computed HDR irradiance map, using a single baked sky-sphere as the dominant light source rather than multiple dynamic lights. It implements a lightweight ambient occlusion approximation based on sphere curvature to ground the model in the environment. This design provides artists with a fast preview of how diffuse lighting interacts with painted textures, offering a middle-ground between the minimal forward path and full dynamic lighting without the runtime cost of HDR environment probes.
renderenvsphere.c: Dynamic HDRI Environment Rendering
renderenvsphere.c extends the sphere concept into a fully dynamic PBR preview system. The file loads high-dynamic-range environment textures at runtime and projects them onto a surrounding sphere, generating pre-filtered mip-mapped cubemaps that drive accurate specular reflections based on material roughness. It exposes UI hooks—invoked through the render path interface—that allow users to rotate or recolor the environment sphere in real time, triggering immediate updates to reflections. This architecture delivers the highest fidelity preview for metallic and specular channel validation, ensuring that PBR textures react realistically to varying lighting conditions.
Render Path Integration Example
The following C snippet demonstrates how ArmorPaint switches between these architectures at runtime and maintains brush functionality across all modes:
// Selection logic based on user preference
if (uiDropdownSelection == "Forward") {
setRenderPath(&renderPathForward);
}
else if (uiDropdownSelection == "Sphere") {
setRenderPath(&renderPathSphere);
}
else if (uiDropdownSelection == "Env Sphere") {
setRenderPath(&renderPathEnvSphere);
}
// Brush update routine independent of active path
void brushStrokeUpdate(PaintLayer *layer, Brush *brush) {
uploadTexture(layer->texture);
currentRenderPath->reloadMaterials();
}
The setRenderPath() dispatcher activates the appropriate vtable of functions defined in each file, while uploadTexture() and reloadMaterials() remain consistent due to their reliance on the shared base implementation.
Summary
- renderpathbase.c provides the foundational GPU utilities and
drawObjects()routine shared across all paths, ensuring consistent resource management for PBR materials. - renderpathforward.c implements a single-pass forward renderer with per-pixel lighting, optimized for immediate brush feedback during texture painting.
- renderpathsphere.c offers a performance-balanced global illumination preview using a static environment sphere with baked irradiance maps.
- renderenvsphere.c delivers the highest fidelity PBR preview through dynamic HDRI environments with pre-filtered specular reflections and real-time rotation controls.
Frequently Asked Questions
Which render path provides the fastest brush response during PBR texture painting?
renderpathforward.c delivers the fastest feedback by executing a single render pass with minimal overhead. Because it computes lighting directly in the fragment shader without environment sampling or multi-pass deferred techniques, material updates appear instantly as you paint.
How does renderenvsphere.c improve PBR preview accuracy compared to renderpathsphere.c?
While renderpathsphere.c relies on static baked irradiance, renderenvsphere.c loads full HDR environment textures at runtime and generates pre-filtered mip-mapped cubemaps. This allows accurate roughness-based specular reflections and dynamic environment rotation, providing the realistic lighting response needed for metallic and glossy material validation.
Can artists switch between render paths without restarting ArmorPaint?
Yes. The architecture decouples the brush system from the active renderer through renderpathbase.c's common interface. Functions like uploadTexture() and reloadMaterials() operate identically across all paths, allowing seamless switching via setRenderPath() during active PBR texture painting sessions.
Why does renderpathbase.c not handle lighting calculations?
renderpathbase.c intentionally omits lighting logic to serve as a renderer-agnostic foundation. By restricting itself to GPU resource initialization, viewport management, and the generic drawObjects() dispatch, it allows specialized paths like renderpathforward.c and renderenvsphere.c to implement divergent lighting strategies while sharing the same material data structures.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →