Architecture Overview
RayTracer Studio follows a clean separation between the rendering engine (C++) and the user interface (React).
System Architectureβ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β RayTracer Studio β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β React Application β β
β β βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββ β β
β β β Header β β Controls β β Canvas Component β β β
β β β (Stats) β β (Panels) β β (Render Target) β β β
β β βββββββββββββββ ββββββββ¬βββββββ ββββββββββββ¬βββββββββββ β β
β β β β β β
β β βΌ βΌ β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β App State (React) β β β
β β β β’ light position β’ material properties β β β
β β β β’ camera state β’ view settings β β β
β β β β’ scene preset β’ antiAliasing, shadowSamples β β β
β β βββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β WebAssembly Bridge β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β Emscripten Bindings (embind) β β β
β β β β’ render() β’ setAntiAliasing() β β β
β β β β’ updateLight() β’ setShadowSamples() β β β
β β β β’ updateMaterial() β’ setLightRadius() β β β
β β β β’ updateCamera() β’ orbitCamera() β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β C++ Ray Tracing Engine β β
β β βββββββββββ βββββββββββ βββββββββββ βββββββββββββββββββ β β
β β β Vec3 β β Ray β β Camera β β Renderer β β β
β β β β β β β β β (Anti-Alias) β β β
β β βββββββββββ βββββββββββ βββββββββββ βββββββββββββββββββ β β
β β βββββββββββ βββββββββββ βββββββββββ βββββββββββββββββββ β β
β β β Materialβ β Light β β Sphere β β Scene β β β
β β β β β (Area) β β β β (Soft Shadow) β β β
β β βββββββββββ βββββββββββ βββββββββββ βββββββββββββββββββ β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β Plane (Ground) β β β
β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key Featuresβ
| Feature | Location | Description |
|---|---|---|
| Anti-Aliasing | Renderer.h | Supersampling with jittered sampling (1, 4, or 16 samples/pixel) |
| Soft Shadows | Scene.h, Light.h | Area lights with stratified shadow ray sampling |
| Reflections | Scene.h | Recursive ray tracing with Fresnel effect |
| Blinn-Phong | Scene.h | Local illumination with diffuse + specular |
Data Flowβ
Render Loopβ
- User Interaction β React state updates
- State Change β Triggers
useEffectin Canvas component - WASM Calls β Update C++ engine state via bindings
- Render β C++ engine traces rays and produces pixel buffer
- Display β Pixel buffer copied to Canvas via
ImageData
// Simplified render flow
const renderFrame = () => {
// 1. Update C++ state
wasmModule.updateLight(light.x, light.y, light.z);
wasmModule.updateMaterial(specular, shininess, reflectivity);
wasmModule.updateCamera(camera.x, camera.y, camera.z);
// 2. Set rendering options
wasmModule.setAntiAliasing(view.antiAliasing);
wasmModule.setShadowSamples(view.shadowSamples);
// 3. Render and get pixel buffer
const pixelVector = wasmModule.render(width, height);
// 4. Copy to JavaScript array
const pixelData = new Uint8ClampedArray(pixelVector.size());
for (let i = 0; i < pixelVector.size(); i++) {
pixelData[i] = pixelVector.get(i);
}
// 5. Clean up C++ memory
pixelVector.delete();
// 6. Draw to canvas
const imageData = new ImageData(pixelData, width, height);
ctx.putImageData(imageData, 0, 0);
};
Rendering Pipelineβ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Rendering Pipeline β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β For each pixel (x, y): β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Anti-Aliasing Loop β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β For each sample (with jitter): β β β
β β β β β β
β β β 1. Generate Camera Ray β β β
β β β βββ getRay(u + jitter, v + jitter) β β β
β β β β β β
β β β 2. Trace Ray (recursive) β β β
β β β βββ Find intersection (spheres, plane) β β β
β β β βββ If hit: β β β
β β β β βββ Calculate lighting β β β
β β β β β βββ For each light: β β β
β β β β β βββ Shadow test (soft or hard) β β β
β β β β β βββ Blinn-Phong shading β β β
β β β β βββ Trace reflection (if reflective) β β β
β β β βββ Else: return background color β β β
β β β β β β
β β β 3. Accumulate sample color β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β
β β Average accumulated samples β Final pixel color β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Module Dependenciesβ
C++ Headersβ
core.cpp
βββ Vec3.h (no dependencies)
βββ Ray.h β Vec3.h
βββ Material.h β Vec3.h
βββ Light.h β Vec3.h (includes radius for area lights)
βββ Camera.h β Vec3.h, Ray.h
βββ Sphere.h β Vec3.h, Ray.h, Material.h
βββ Plane.h β Vec3.h, Ray.h, Material.h, Sphere.h
βββ Scene.h β All above (includes soft shadow logic)
βββ Renderer.h β Scene.h (includes anti-aliasing logic)
React Componentsβ
App.jsx
βββ hooks/useWasm.js
βββ layout/Header.jsx
β βββ layout/InfoModal.jsx
βββ canvas/SceneToolbar.jsx
βββ canvas/RaytracerCanvas.jsx
βββ controls/ControlPanel.jsx
βββ controls/LightControls.jsx
βββ controls/MaterialControls.jsx
βββ controls/CameraControls.jsx
βββ controls/ViewControls.jsx (AA, soft shadows)
βββ ui/Tabs.jsx
βββ ui/Slider.jsx
βββ ui/Toggle.jsx
Memory Managementβ
C++ to JavaScript Data Transferβ
The render function returns a std::vector<uint8_t> which Emscripten wraps as a JavaScript object:
std::vector<uint8_t> render(int width, int height) {
std::vector<uint8_t> buffer(width * height * 4); // RGBA
// ... ray tracing logic with AA ...
return buffer;
}
Important
Always call .delete() on the returned vector to prevent memory leaks:
const pixelVector = wasmModule.render(512, 512);
// ... use the data ...
pixelVector.delete(); // Free C++ memory!
Performance Considerationsβ
| Factor | Impact | Optimization |
|---|---|---|
| Resolution | O(nΒ²) | Use 256-512 for interaction |
| Anti-Aliasing | Γ4 or Γ16 | Use 2Γ2 for interaction, 4Γ4 for final |
| Soft Shadows | Γsamples per light | 4-9 samples for preview, 16-25 for final |
| Reflections | O(bounces) | Limit to 3-5 bounces |
| Sphere Count | O(n) per ray | Use spatial acceleration for many objects |
Combined Render Costβ
Base cost = ResolutionΒ² Γ Reflections
With features:
Total = Base Γ AA_samples Γ Shadow_samples Γ Lights
Example (worst case):
512Β² Γ 5 bounces Γ 16 AA Γ 25 shadows Γ 2 lights
= 262,144 Γ 5 Γ 16 Γ 25 Γ 2
= ~1 billion ray operations
Recommendation: Enable features progressively. Use low settings during interaction, high settings for final render.
Responsive Designβ
The UI adapts to different screen sizes:
| Breakpoint | Layout |
|---|---|
| > 900px | Side-by-side (canvas + sidebar) |
| β€ 900px | Stacked (canvas above controls) |
| β€ 640px | Compact tabs, icons only |
| Mobile | Touch support for camera orbit |