MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SpatialExport.hpp
Go to the documentation of this file.
1#pragma once
2
4
5namespace MayaFlux::Buffers {
6class RelaxationGridBuffer;
7class NetworkGeometryBuffer;
8}
9
11class GraphicsOperator;
12}
13
14namespace MayaFlux::IO {
15
16/**
17 * @brief Generate the fixed grid positions and cell ids a RelaxationGridBuffer's
18 * cells occupy, for feeding SpatialCache::write() with
19 * PrimitiveTopology::POINT_LIST.
20 *
21 * Matches exactly the row-major, cell-center-sampled layout its own emit
22 * shaders use (data/shaders/relax_vertex_emit.comp,
23 * relax_scalar_emit.comp): cell (col, row) at linear index row*width+col
24 * samples at ((col+0.5)/width, (row+0.5)/height), remapped to
25 * [-extent, extent] on both axes, z always 0.
26 *
27 * Positions and ids are fixed for a given width/height/extent: a
28 * RelaxationGridBuffer's topology never changes generation to generation,
29 * only its cell state does (obtained separately via
30 * RelaxationGridBuffer::request_snapshot()/snapshot_source(), whose raw
31 * bytes only the caller can correctly reinterpret, since state format
32 * varies by rule: a single float, a uint32 automaton state, a vec2
33 * reaction-diffusion pair, or anything else a rule shader defines). Call
34 * once and reuse the result across every sample of a capture rather than
35 * regenerating it per frame.
36 *
37 * ids are the cell's own linear index, so a consumer can track one cell's
38 * identity across samples even though every other field about it changes
39 * generation to generation.
40 *
41 * @param grid Source buffer, for width/height.
42 * @param extent NDC half-span. Match whatever was set via
43 * RelaxationEmitProcessor::set_extent(); default 1.0
44 * matches RelaxationEmitProcessor::EmitParams's own default.
45 * @param positions Output, resized to grid->get_cell_count().
46 * @param ids Output, resized to grid->get_cell_count().
47 * @return False if grid is null; positions/ids are left untouched in that case.
48 */
50 const std::shared_ptr<Buffers::RelaxationGridBuffer>& grid,
51 float extent,
52 std::vector<glm::vec3>& positions,
53 std::vector<uint64_t>& ids);
54
55/**
56 * @brief Pack one GraphicsOperator's current vertex state into a
57 * SpatialCache stream, as a Points or Curves sample depending on
58 * what the operator declares.
59 *
60 * Reads op->get_vertex_data() as Kakshya::Vertex records: PointVertex,
61 * LineVertex, and MeshVertex all share its exact 60-byte layout, so this
62 * works unchanged for any GraphicsOperator, not only PhysicsOperator. Every
63 * field comes along, not only position: color, scalar (size/thickness/
64 * weight depending on the concrete type), uv, normal, and tangent each
65 * become their own SpatialAttribute, so a vertex reaches the archive whole
66 * rather than reduced to a coordinate. Always attaches a "cluster" attribute
67 * from op->build_cluster_ids() (0 for every vertex on an operator that never
68 * overrides it), plus one SpatialAttribute per op->extract_vertex_attributes()
69 * entry (extra state beyond the vertex record itself, e.g. PhysicsOperator's
70 * mass).
71 *
72 * op->declared_topology() decides the sample's shape:
73 * - nullopt or POINT_LIST: the point path. ids are the vertex's own index
74 * within this operator, for cross-sample identity tracking, and native
75 * velocities come from op->extract_vertex_velocities() when non-empty.
76 * - LINE_STRIP (PathOperator): one curve per contiguous build_cluster_ids()
77 * run, matching one path per continuous interpolated strip.
78 * - LINE_LIST (TopologyOperator): fixed 2-vertex curves, one per expanded
79 * edge, since a graph's edges are independent segments, not one
80 * connected strip through the whole graph.
81 * Curve samples carry no ids/velocities (Alembic's Curves schema has
82 * neither) and fail outright if declared_topology() reports LINE_LIST for
83 * an odd vertex count, which no known producer of that topology should do.
84 *
85 * @param cache Target cache, already open().
86 * @param stream_name Stream to write.
87 * @param op Source operator. Must be non-null, report at least one
88 * vertex, and use the Kakshya::Vertex record layout
89 * (every GraphicsOperator does today).
90 * @return False if op is null, reports zero vertices, its vertex layout is
91 * not a Kakshya::Vertex record, its vertex buffer is smaller than
92 * layout.stride_bytes * get_vertex_count(), any
93 * extract_vertex_attributes()/extract_vertex_velocities() entry
94 * disagrees with get_vertex_count() in size, or a LINE_LIST
95 * topology's vertex count is odd.
96 */
98 SpatialCache& cache,
99 const std::string& stream_name,
100 const Nodes::Network::GraphicsOperator* op);
101
102/**
103 * @brief Pack a NetworkGeometryBuffer's driving network into one or more
104 * SpatialCache streams, choosing CPU or GPU readback depending on
105 * whether the network's CPU-side vertex state is still authoritative.
106 *
107 * A GpuFieldOperator anywhere in the network's operator chain (detected via
108 * OperatorChain::find<GpuFieldOperator>()) means vertex positions are
109 * mutated directly on the GPU: the CPU-side GraphicsOperator buffer
110 * write_operator_sample() would otherwise read is stale. In that case this
111 * downloads the live vertex bytes straight from the buffer itself (it is a
112 * VKBuffer, so the same download_from_gpu_async() pattern
113 * download_compute_mesh() uses for ComputeMeshBuffer applies directly),
114 * using the still-CPU-tracked get_vertex_count()/get_vertex_layout()/
115 * declared_topology() for population size, record schema, and sample shape
116 * (these describe the buffer's contract, not its live GPU bytes, so they
117 * stay valid regardless of which side owns the vertex data), then reads the
118 * downloaded bytes as Kakshya::Vertex records exactly as
119 * write_operator_sample() reads them from CPU memory: color, scalar, uv,
120 * normal, and tangent all come along with position, since the record
121 * schema is unchanged by which side owns the bytes; only the transfer
122 * differs. A curve topology chunks on build_cluster_ids() the same way
123 * write_operator_sample() does, since graph/path membership is structural
124 * and unaffected by what a GpuFieldOperator does to positions. Also
125 * attaches the declared hash_cluster_id state field as a "cluster"
126 * attribute when present. Written as a single stream named @p stream_name:
127 * once GPU-driven, the buffer is one flat array and no longer separable by
128 * originating operator. Velocities and any per-rule state beyond
129 * hash_cluster_id are left out deliberately, the same way
130 * relaxation_grid_positions() leaves per-cell state to the caller: a
131 * GpuFieldOperator's own bespoke state fields have no shape this function
132 * can decode generically.
133 *
134 * Without a GpuFieldOperator, every GraphicsOperator on the network (its
135 * primary operator plus any in get_operator_chain()) is CPU-readable and
136 * each is written through write_operator_sample() as its own set: a
137 * network with exactly one GraphicsOperator keeps the plain @p stream_name
138 * unchanged, while a network chaining several writes one child stream per
139 * operator, named "<stream_name>_<get_type_name()>" (a trailing index
140 * appended for a repeated type), the same role multiple named aiMesh
141 * entries play for a multi-submesh ModelWriter export. A per-operator
142 * "cluster" attribute (from that operator's own build_cluster_ids())
143 * continues to mark distinct populations within one operator, e.g.
144 * PhysicsOperator's collections.
145 *
146 * @param cache Target cache, already open().
147 * @param stream_name Stream (or stream-name prefix, if the network chains
148 * several GraphicsOperators) to write.
149 * @param buffer Source buffer. Must be non-null, with a non-null
150 * network exposing at least one GraphicsOperator.
151 * @return False if buffer/network is missing, no GraphicsOperator is found,
152 * or any underlying write_operator_sample()/cache.write() call
153 * fails.
154 */
156 SpatialCache& cache,
157 const std::string& stream_name,
158 const std::shared_ptr<Buffers::NetworkGeometryBuffer>& buffer);
159
160} // namespace MayaFlux::IO
std::shared_ptr< NetworkGeometryBuffer > buffer
bool relaxation_grid_positions(const std::shared_ptr< Buffers::RelaxationGridBuffer > &grid, float extent, std::vector< glm::vec3 > &positions, std::vector< uint64_t > &ids)
Generate the fixed grid positions and cell ids a RelaxationGridBuffer's cells occupy,...
bool write_operator_sample(SpatialCache &cache, const std::string &stream_name, const Nodes::Network::GraphicsOperator *op)
Pack one GraphicsOperator's current vertex state into a SpatialCache stream, as a Points or Curves sa...
bool write_network_geometry_buffer_sample(SpatialCache &cache, const std::string &stream_name, const std::shared_ptr< Buffers::NetworkGeometryBuffer > &buffer)
Pack a NetworkGeometryBuffer's driving network into one or more SpatialCache streams,...