161 lines
8.1 KiB
C++
161 lines
8.1 KiB
C++
#include "bella_engine_sdk/src/bella_sdk/bella_engine.h" // Core rendering engine
|
|
#include "bella_engine_sdk/src/bella_sdk/bella_scene.h" // Scene management
|
|
#include "bella_engine_sdk/src/dl_core/dl_logging.h" // Logging utilities
|
|
#include <thread> // For std::this_thread (C++ standard library)
|
|
#include <chrono> // For timing operations (C++ standard library)
|
|
|
|
// ============================================================================
|
|
// 🔍 C++ Concept: Observer Pattern
|
|
// This lets us "listen" for events from the rendering engine.
|
|
// When something happens (rendering starts, progress updates, etc.),
|
|
// our functions get called automatically.
|
|
// ============================================================================
|
|
|
|
struct MyEngineObserver : public dl::bella_sdk::EngineObserver {
|
|
// 🔔 Called when rendering begins
|
|
void onStarted(dl::String pass) override {
|
|
dl::logInfo("🚀 Rendering started: %s", pass.buf());
|
|
}
|
|
|
|
// 🔔 Called repeatedly as rendering progresses (0.0 to 1.0)
|
|
void onProgress(dl::String pass, dl::bella_sdk::Progress progress) override {
|
|
dl::logInfo("⏳ Progress: %.1f%% - %s",
|
|
progress.progress() * 100.0, progress.toString().buf());
|
|
}
|
|
|
|
// 🔔 Called when we get the final rendered image
|
|
void onImage(dl::String pass, dl::bella_sdk::Image image) override {
|
|
dl::logInfo("🖼️ Got image: %dx%d pixels", image.width(), image.height());
|
|
}
|
|
|
|
// 🔔 Called when rendering finishes
|
|
void onStopped(dl::String pass) override {
|
|
dl::logInfo("✅ Rendering complete: %s", pass.buf());
|
|
}
|
|
};
|
|
|
|
// ============================================================================
|
|
// 🎬 Main Function: Building Our 3D Scene
|
|
// ============================================================================
|
|
int main() {
|
|
// Step 1: Create the rendering engine and scene
|
|
dl::bella_sdk::Engine engine; // The renderer itself
|
|
dl::bella_sdk::Scene scene = engine.scene(); // Container for all our objects
|
|
scene.loadDefs(); // Load built-in object types
|
|
|
|
// Get the "world" - this is the root of our scene tree
|
|
dl::bella_sdk::Node world = scene.world();
|
|
|
|
// ========================================================================
|
|
// 📷 Step 2: Create the Camera System
|
|
// Every camera needs: sensor (film) + lens + positioning
|
|
// ========================================================================
|
|
|
|
// Create a digital "film" sensor (30mm x 30mm)
|
|
dl::bella_sdk::Node sensor = scene.createNode("sensor");
|
|
sensor["size"] = dl::Vec2::make(30.0, 30.0);
|
|
|
|
// Create a simple lens (like a magnifying glass)
|
|
auto lens = scene.createNode("thinLens"); // 'auto' = let C++ figure out the type
|
|
|
|
// Create camera positioning system + the camera itself
|
|
auto cameraXform = scene.createNode("xform"); // Transform = position/rotation
|
|
cameraXform.parentTo(world); // Attach to our world
|
|
|
|
auto camera = scene.createNode("camera"); // The actual camera
|
|
camera["resolution"] = dl::Vec2::make(320, 320); // 320x320 pixel image
|
|
camera["lens"] = lens; // Connect our lens
|
|
camera["sensor"] = sensor; // Connect our sensor
|
|
camera.parentTo(cameraXform); // Put camera in the positioning system
|
|
|
|
// Tell the scene to use this camera for rendering
|
|
auto settings = scene.settings();
|
|
settings["camera"] = camera;
|
|
|
|
// ========================================================================
|
|
// ☀️ Step 3: Add Lighting
|
|
// ========================================================================
|
|
auto skyDome = scene.createNode("skyDome"); // Simulates sky lighting
|
|
skyDome.parentTo(world);
|
|
settings["environment"] = skyDome; // Use this for scene lighting
|
|
|
|
// ========================================================================
|
|
// 🎨 Step 4: Create Materials (like paint or metal finishes)
|
|
// ========================================================================
|
|
|
|
// Golden metal material for our sphere
|
|
auto sphereMaterial = scene.createNode("conductor"); // Metal material
|
|
sphereMaterial["reflectance"] = dl::Rgba::make(0.8, 0.6, 0.2, 1.0); // Golden color (R,G,B,Alpha)
|
|
sphereMaterial["roughness"] = 26.1; // Slightly rough surface
|
|
|
|
// Glass-like material for the ground
|
|
auto groundMaterial = scene.createNode("dielectric"); // Glass/plastic material
|
|
groundMaterial["roughness"] = dl::Real(41.0); // Rough surface
|
|
|
|
// ========================================================================
|
|
// 🏀 Step 5: Create Objects (Sphere + Ground)
|
|
// ========================================================================
|
|
|
|
// Golden sphere in the center
|
|
auto sphereXform = scene.createNode("xform"); // Position controller for sphere
|
|
sphereXform["material"] = sphereMaterial; // Apply golden material
|
|
sphereXform.parentTo(world); // Add to scene
|
|
|
|
auto sphere = scene.createNode("sphere"); // The actual sphere shape
|
|
sphere["radius"] = dl::Real(1.0); // 1 unit radius
|
|
sphere.parentTo(sphereXform); // Put sphere in its position controller
|
|
|
|
// Large disk as ground plane
|
|
auto groundXform = scene.createNode("xform"); // Position controller for ground
|
|
groundXform["name"] = dl::String("groundXform"); // Give it a name (optional)
|
|
groundXform["material"] = groundMaterial; // Apply glass material
|
|
groundXform.parentTo(world); // Add to scene
|
|
|
|
auto ground = scene.createNode("disk"); // Flat circular disk
|
|
ground["radius"] = 10.0; // Large radius (10 units)
|
|
ground.parentTo(groundXform); // Put ground in its position controller
|
|
|
|
// ========================================================================
|
|
// 🎥 Step 6: Setup Rendering (what/where to save)
|
|
// ========================================================================
|
|
auto beautyPass = scene.createNode("beautyPass"); // Defines what to render
|
|
beautyPass["saveImage"] = true; // Save the image to disk
|
|
beautyPass["outputName"] = "poomer-bella-basic-renderer"; // Filename (will be my_render.png)
|
|
|
|
auto outputImagePath = scene.createNode("outputImagePath"); // Where to save
|
|
outputImagePath["dir"] = "."; // Current directory
|
|
beautyPass["overridePath"] = outputImagePath; // Connect save location
|
|
|
|
settings["beautyPass"] = beautyPass; // Tell scene to use this render setup
|
|
|
|
// ========================================================================
|
|
// 📱 Step 7: Connect Our Observer + Position Camera
|
|
// ========================================================================
|
|
MyEngineObserver observer; // Create our notification listener
|
|
engine.subscribe(&observer); // Connect it to the engine
|
|
|
|
// Position camera to look at the scene (like framing a photo)
|
|
dl::bella_sdk::zoomExtents(
|
|
scene.cameraPath(), // Camera's position controller (not camera itself!)
|
|
dl::Vec3{ 0,0,0 }, // Look at the origin (center of sphere)
|
|
3.0 // Distance from center
|
|
);
|
|
|
|
// Tilt camera down 75 degrees (like looking down from above)
|
|
dl::bella_sdk::orbitCamera(scene.cameraPath(), dl::Vec2{ 0.0, -75.0 });
|
|
|
|
// ========================================================================
|
|
// 🚀 Step 8: Render!
|
|
// ========================================================================
|
|
engine.start(); // Begin rendering
|
|
|
|
// Wait for rendering to complete (check every 100ms)
|
|
while (engine.rendering()) {
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
}
|
|
|
|
engine.stop(); // Clean shutdown
|
|
engine.unsubscribe(&observer); // Disconnect our listener
|
|
|
|
return 0; // Tell operating system: "Success!"
|
|
} |