Loading...
Searching...
No Matches
Instancer.hpp
1#pragma once
2#include "TransformHelper.hpp"
3
4#include <Threedim/TinyObj.hpp>
5#include <halp/buffer.hpp>
6#include <halp/controls.hpp>
7#include <halp/geometry.hpp>
8#include <halp/meta.hpp>
9
10#include <ossia/dataflow/geometry_port.hpp>
11
12#include <Gfx/Graph/GpuResourceRegistry.hpp>
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// GPU-instancing authoring node. Takes a scene containing a mesh and a GPU buffer
29// of per-instance transforms, plus optional colors and custom data, and emits a
30// scene_spec wrapping an instance_component that ScenePreprocessor forwards
31// downstream as the standard instance_transforms / instance_colors /
32// instance_custom auxiliary buffers.
33//
34// Consumer shaders read the per-instance attributes through the VERTEX_INPUTS
35// location 3..5 convention already in GeometryToBufferStrategies.hpp:
36// 3 = translation / rotation / transform_matrix, 4 = color0, 5 = scale/custom.
37//
38// Transform formats, packed floats per instance:
39// mat4 16 floats, column-major
40// trs 10 floats: 3 translation + 4 quaternion + 3 scale
41// translation 3 floats, rotation and scale identity
43{
44public:
45 halp_meta(name, "Instancer")
46 halp_meta(category, "Visuals/3D/Scene")
47 halp_meta(c_name, "instancer")
48 halp_meta(authors, "ossia team")
49 halp_meta(
50 manual_url,
51 "https://ossia.io/score-docs/processes/instancer.html")
52 halp_meta(uuid, "5e8a2c7f-9b4d-4e3a-a1c6-2d7f0b3e8c4a")
53
54 enum TransformFormat
55 {
56 Mat4,
57 TRS,
58 Translation
59 };
60
61 struct ins
62 {
63 struct
64 {
65 halp_meta(name, "Scene In");
66 ossia::scene_spec scene;
67 uint8_t dirty{0};
68 } scene_in;
69
70 halp::gpu_buffer_input<"Transforms"> transforms;
71 halp::gpu_buffer_input<"Colors"> colors;
72 halp::gpu_buffer_input<"Custom"> custom;
73
74 // Optional point-cloud geometry input. When wired, its semantic attributes
75 // override the raw buffer inputs above: translation / position and
76 // transform_matrix feed the Transforms buffer in Translation and Mat4 mode,
77 // color0 feeds the Colors buffer. The `count` inlet is then overridden by the
78 // geometry's vertex_count, so shaderlib presets can feed Instancer directly
79 // without a glue repack.
80 struct
81 {
82 halp_meta(name, "Points");
83 halp::dynamic_gpu_geometry mesh;
84 float transform[16]{};
85 bool dirty_mesh = false;
86 bool dirty_transform = false;
87 } points;
88
89 // Port-driven rebuild: scalar controls trigger Instancer::rebuild().
90 // Upstream scene_in / buffer handles are detected in operator()()
91 // because they can change without a port-update event.
92 struct : halp::combobox_t<"Format", TransformFormat>
93 {
94 struct range
95 {
96 std::string_view values[3]{"mat4", "trs", "translation"};
97 int init{0};
98 };
99 void update(Instancer& n) { n.rebuild(); }
100 } format;
101
102 struct : halp::spinbox_i32<"Count", halp::irange{1, 1000000, 1}>
103 { void update(Instancer& n) { n.rebuild(); } } count;
104
105 // Optional TRS applied to the prototype before instancing — lets
106 // the node place the instanced cloud without a separate
107 // Transform3D upstream.
108 struct : PositionControl
109 { void update(Instancer& n) { n.rebuild(); } } position;
110 struct : RotationControl
111 { void update(Instancer& n) { n.rebuild(); } } rotation;
112 struct : ScaleControl
113 { void update(Instancer& n) { n.rebuild(); } } scale;
114 } inputs;
115
116 struct outs
117 {
118 struct
119 {
120 halp_meta(name, "Scene Out");
121 ossia::scene_spec scene;
122 uint8_t dirty{0};
123 } scene_out;
124 } outputs;
125
126 void rebuild();
127 void operator()();
128
129 void init(score::gfx::RenderList& r, QRhiResourceUpdateBatch& res);
130 void update(
131 score::gfx::RenderList& r, QRhiResourceUpdateBatch& res,
133 void release(score::gfx::RenderList& r);
134
135 // Cache so we republish a stable shared_ptr when inputs haven't
136 // changed — ScenePreprocessor's identity caches stay warm.
137 std::shared_ptr<ossia::scene_state> m_wrapped_state;
138 uint8_t m_pending_dirty{0xFF};
139 CachedTRS m_cachedTRS{};
140 // Track input identity to detect when a rebuild is needed without
141 // relying on buffer-contents equality.
142 const ossia::scene_state* m_cached_in_state{};
143 // The VIEW, not just the handle. A producer that re-points a buffer at a
144 // different offset, or shrinks it to a smaller window of the same
145 // allocation, keeps the handle -- and the instance-count capacity clamp
146 // below depends on the size. Comparing handles alone would let a shrink go
147 // unnoticed and the cloud would draw past the end of its transforms.
149 {
150 void* handle{};
151 int64_t byte_offset{};
152 int64_t byte_size{};
153 friend bool operator==(const CachedView&, const CachedView&) = default;
154 };
155 static CachedView viewOf(const halp::gpu_buffer& b) noexcept
156 {
157 return {b.handle, (int64_t)b.byte_offset, (int64_t)b.byte_size};
158 }
159 CachedView m_cached_transforms{};
160 CachedView m_cached_colors{};
161 CachedView m_cached_custom{};
162 int32_t m_cached_count{-1};
163 int m_cached_format{-1};
164 // For the point-cloud input: cache the primary-buffer identity so we
165 // detect upstream handle replacements without poking every buffer
166 // every frame.
167 void* m_cached_points_buf{};
168 int64_t m_cached_points_vertices{-1};
169 // Fingerprint of ALL Points buffer handles (not just buffers[0]), so a
170 // reallocated secondary attribute buffer (transform_matrix / color0)
171 // that leaves the primary buffer + vertex count untouched still forces a
172 // rebuild instead of republishing a dangling handle.
173 uintptr_t m_cached_points_fingerprint{};
174 int64_t m_version_counter{0};
175
176 score::gfx::GpuResourceRegistry::Slot raw_transform_slot;
177 ossia::gpu_slot_ref m_xform_ref{};
178};
179
180}
Definition Instancer.hpp:43
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 TransformHelper.hpp:26
Definition Instancer.hpp:149
Definition Instancer.hpp:62
Definition Instancer.hpp:117
Definition TinyObj.hpp:98
Definition TinyObj.hpp:103
Definition TinyObj.hpp:107
Definition TinyObj.hpp:27
Definition MIDISync.hpp:126
Connection between two score::gfx::Port.
Definition score-plugin-gfx/Gfx/Graph/Utils.hpp:103
Definition GpuResourceRegistry.hpp:84