Loading...
Searching...
No Matches
Light.hpp
1#pragma once
2#include <Threedim/TinyObj.hpp>
3#include <halp/controls.hpp>
4#include <halp/meta.hpp>
5
6#include <ossia/dataflow/geometry_port.hpp>
7
8#include <Gfx/Graph/GpuResourceRegistry.hpp>
9
10#include <QMatrix4x4>
11#include <QQuaternion>
12#include <QVector3D>
13
14#include <cstdint>
15#include <memory>
16
17class QRhiResourceUpdateBatch;
18
19namespace score::gfx
20{
21class RenderList;
22struct Edge;
23}
24
25namespace Threedim
26{
27
28// Unified light producer. One node with a mode combobox covers every
29// punctual / area light type ossia::light_component defines —
30// directional, point, spot, rect, disk, sphere, cylinder, dome —
31// mirroring UsdLux's RectLight/DiskLight/SphereLight and glTF
32// KHR_lights_punctual.
33//
34// Emits an ossia::scene_spec containing one scene_node with:
35// - child[0] = scene_transform (position + rotation, no scale)
36// - child[1] = light_component_ptr
37// ScenePreprocessor packs it into the scene-wide `scene_lights` SSBO via
38// packLight(). Current consumer shaders (`classic_pbr_*.frag`) only
39// sample the common fields (position/direction/color/intensity/range +
40// spot cone angles) — area-light shapes pass through correctly but
41// are rendered as point-light approximations until shaders add the
42// Rect/Disk/Sphere sampling math.
43class Light
44{
45public:
46 halp_meta(name, "Light")
47 halp_meta(category, "Visuals/3D/Scene")
48 halp_meta(c_name, "light")
49 halp_meta(authors, "ossia team")
50 halp_meta(
51 manual_url,
52 "https://ossia.io/score-docs/processes/light.html")
53 halp_meta(uuid, "9f3c1a5e-4b7d-4e2a-8c5f-1d6e0b9a3c7f")
54
55 enum Mode
56 {
57 Directional,
58 Point,
59 Spot,
60 Rect,
61 Disk,
62 Sphere,
63 Dome
64 };
65
66 enum Decay
67 {
68 DecayNone,
69 DecayLinear,
70 DecayQuadratic, // physically correct
71 DecayCubic
72 };
73
74 struct ins
75 {
76 // Port-driven rebuild: each control's update() callback triggers
77 // Light::rebuild() on user change. operator()() just republishes.
78 struct : halp::combobox_t<"Mode", Mode>
79 {
80 struct range
81 {
82 std::string_view values[7]{
83 "Directional", "Point", "Spot",
84 "Rect", "Disk", "Sphere", "Dome"};
85 int init{0};
86 };
87 void update(Light& n) { n.rebuild(); }
88 } mode;
89
90 // Common — always applies
91 struct : halp::color_chooser<"Color">
92 { void update(Light& n) { n.rebuild(); } } color;
93 struct : halp::hslider_f32<"Intensity", halp::range{0., 100., 1.}>
94 { void update(Light& n) { n.rebuild(); } } intensity;
95 // range=0 → infinite falloff (directional / dome ignore this field)
96 struct : halp::hslider_f32<"Range", halp::range{0., 1000., 0.}>
97 { void update(Light& n) { n.rebuild(); } } range;
98
99 struct : halp::combobox_t<"Falloff", Decay>
100 {
101 struct range
102 {
103 std::string_view values[4]{
104 "None", "Linear", "Quadratic (physical)", "Cubic"};
105 int init{2};
106 };
107 void update(Light& n) { n.rebuild(); }
108 } decay;
109
110 // Spot cone (radians via hsliders taking degrees; converted in cpp)
111 struct : halp::hslider_f32<"Inner cone °", halp::range{0., 90., 0.}>
112 { void update(Light& n) { n.rebuild(); } } inner_cone;
113 struct : halp::hslider_f32<"Outer cone °", halp::range{0., 90., 45.}>
114 { void update(Light& n) { n.rebuild(); } } outer_cone;
115
116 // Area shapes
117 struct : halp::hslider_f32<"Width", halp::range{0.01, 100., 1.}>
118 { void update(Light& n) { n.rebuild(); } } width;
119 struct : halp::hslider_f32<"Height", halp::range{0.01, 100., 1.}>
120 { void update(Light& n) { n.rebuild(); } } height;
121 struct : halp::hslider_f32<"Radius", halp::range{0.01, 100., 0.5}>
122 { void update(Light& n) { n.rebuild(); } } radius;
123
124 // Shadow settings
125 struct : halp::toggle<"Cast shadow">
126 { void update(Light& n) { n.rebuild(); } } cast_shadow;
127 struct : halp::hslider_f32<"Shadow bias", halp::range{0., 0.1, 0.001}>
128 { void update(Light& n) { n.rebuild(); } } shadow_bias;
129 struct : halp::hslider_f32<"Shadow normal bias", halp::range{0., 0.1, 0.01}>
130 { void update(Light& n) { n.rebuild(); } } shadow_normal_bias;
131
132 // Transform: position for positional lights, rotation encodes the
133 // direction used by Directional / Spot (local -Z mapped to the
134 // light direction, glTF / Vulkan convention).
135 struct : PositionControl
136 { void update(Light& n) { n.rebuild(); } } position;
137 struct : RotationControl
138 { void update(Light& n) { n.rebuild(); } } rotation;
139 } inputs;
140
141 struct outs
142 {
143 struct
144 {
145 halp_meta(name, "Scene");
146 ossia::scene_spec scene;
147 uint8_t dirty{0};
148 } scene_out;
149 } outputs;
150
151 // Built once from control values whenever a port's update() fires.
152 // operator()() just republishes m_state.
153 void rebuild();
154 void operator()();
155
156 // Render-thread hooks. init claims one RawLight slot; update packs
157 // color / intensity / type / local-direction / range / cone angles /
158 // decay / shadow into a RawLightData and uploads; release returns
159 // the slot. Final world-direction composition happens inside the
160 // preprocessor (parent-chain world matrix), so this slot carries
161 // only the node-local fields.
162 void init(score::gfx::RenderList& r, QRhiResourceUpdateBatch& res);
163 void update(
164 score::gfx::RenderList& r, QRhiResourceUpdateBatch& res,
166 void release(score::gfx::RenderList& r);
167
168 std::shared_ptr<ossia::scene_state> m_state;
169 int64_t m_version{0};
170 uint8_t m_pending_dirty{ossia::scene_port::dirty_lights};
171 // Stable id for the single light_component this node emits. Minted
172 // lazily on first rebuild() and reused across all subsequent rebuilds
173 // so downstream caches (preprocessor fingerprint, SER coherence key)
174 // stay keyed on identity, not pointer.
175 uint64_t m_light_stable_id{};
176 uint64_t m_xform_stable_id{};
177
179 score::gfx::GpuResourceRegistry::Slot raw_transform_slot;
180
181 // Ossia-facing snapshots. Written once in init() on the render
182 // thread; copied onto each emitted light_component / scene_transform
183 // raw_slot in operator()() on the execution thread.
184 ossia::gpu_slot_ref m_light_ref{};
185 ossia::gpu_slot_ref m_xform_ref{};
186};
187
188}
Definition Light.hpp:44
List of nodes to be rendered to an output.
Definition RenderList.hpp:30
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11
Definition Light.hpp:75
Definition Light.hpp:142
Definition TinyObj.hpp:98
Definition TinyObj.hpp:103
Definition Primitive.hpp:99
Definition MIDISync.hpp:126
Connection between two score::gfx::Port.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:103
Definition GpuResourceRegistry.hpp:84