MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
SDFFieldProcessor.cpp
Go to the documentation of this file.
2
5
6namespace MayaFlux::Buffers {
7
8namespace {
9
10 /**
11 * @brief Build the compute shader that evaluates @p field at every grid corner.
12 *
13 * Every push constant is a 4-byte scalar, so the block has no padding and
14 * matches the host struct byte for byte.
15 */
16 [[nodiscard]] Portal::Graphics::ShaderSpec field_spec(const Kinesis::FieldSource& field)
17 {
18 if (!field.valid() || field.parameter_count() > 3) {
19 error<std::invalid_argument>(
22 std::source_location::current(),
23 "SDFFieldProcessor: the field did not parse into a function of "
24 "one to three parameters. It needs a trailing return type and a body.");
25 }
26
28
29 Portal::Graphics::ShaderSpec::Assemble assemble;
30 assemble.ssbo("sdf_grid", Portal::Graphics::BindingDirection::Output, GpuDataFormat::FLOAT32);
31
32 for (const char* name : { "bounds_min_x", "bounds_min_y", "bounds_min_z", "time", "step_x", "step_y", "step_z" }) {
33 assemble.pc(name);
34 }
35 for (const char* name : { "res_x", "res_y", "res_z" }) {
36 assemble.pc(name, GpuDataFormat::UINT32);
37 }
38 for (const char* name : { "p0", "p1", "p2", "p3" }) {
39 assemble.pc(name);
40 }
41
42 assemble.workgroup(64)
43 .function(field.return_type, field.name, field.params, field.body);
44
45 std::string body;
46 body += " uint nx = res_x + 1u;\n";
47 body += " uint ny = res_y + 1u;\n";
48 body += " if (i >= nx * ny * (res_z + 1u)) { return; }\n";
49 body += " uint ix = i % nx;\n";
50 body += " uint iy = (i / nx) % ny;\n";
51 body += " uint iz = i / (nx * ny);\n";
52 body += " vec3 p = vec3(bounds_min_x + float(ix) * step_x,"
53 " bounds_min_y + float(iy) * step_y,"
54 " bounds_min_z + float(iz) * step_z);\n";
55
56 switch (field.parameter_count()) {
57 case 1:
58 body += " sdf_grid[i] = " + field.name + "(p);\n";
59 break;
60 case 2:
61 body += " sdf_grid[i] = " + field.name + "(p, time);\n";
62 break;
63 default:
64 body += " vec4 params = vec4(p0, p1, p2, p3);\n";
65 body += " sdf_grid[i] = " + field.name + "(p, time, params);\n";
66 break;
67 }
68
69 assemble.kernel(Portal::Graphics::KernelSource { .body = std::move(body) });
70 return assemble.build();
71 }
72
73} // namespace
74
76 std::shared_ptr<VKBuffer> grid_buf,
77 const glm::vec3& bounds_min,
78 const glm::vec3& bounds_max,
79 uint32_t res_x,
80 uint32_t res_y,
81 uint32_t res_z,
82 std::string shader)
83 : ComputeProcessor(shader, 64)
84 , m_grid_buf(std::move(grid_buf))
85 , m_res_x(std::max(res_x, 1U))
86 , m_res_y(std::max(res_y, 1U))
87 , m_res_z(std::max(res_z, 1U))
88{
89 m_pc.bounds_min = bounds_min;
93
94 const glm::vec3 extent = bounds_max - bounds_min;
95 m_pc.step = {
96 extent.x / static_cast<float>(m_res_x),
97 extent.y / static_cast<float>(m_res_y),
98 extent.z / static_cast<float>(m_res_z),
99 };
100
102 m_config.bindings["sdf_grid"] = ShaderBinding(0, 0, vk::DescriptorType::eStorageBuffer);
103
105 const uint32_t corners = (m_res_x + 1) * (m_res_y + 1) * (m_res_z + 1);
106 set_manual_dispatch((corners + 63U) / 64U, 1, 1);
107}
108
110 std::shared_ptr<VKBuffer> grid_buf,
111 const Kinesis::FieldSource& field,
112 const glm::vec3& bounds_min,
113 const glm::vec3& bounds_max,
114 uint32_t res_x,
115 uint32_t res_y,
116 uint32_t res_z)
117 : ComputeProcessor(field_spec(field))
118 , m_from_field(true)
119 , m_grid_buf(std::move(grid_buf))
120 , m_res_x(std::max(res_x, 1U))
121 , m_res_y(std::max(res_y, 1U))
122 , m_res_z(std::max(res_z, 1U))
123{
127 set_bounds(bounds_min, bounds_max);
128
129 m_config.bindings["sdf_grid"] = ShaderBinding(0, 0, vk::DescriptorType::eStorageBuffer);
130
132 const uint32_t corners = (m_res_x + 1) * (m_res_y + 1) * (m_res_z + 1);
133 set_manual_dispatch((corners + 63U) / 64U, 1, 1);
134}
135
136void SDFFieldProcessor::set_bounds(const glm::vec3& bounds_min, const glm::vec3& bounds_max)
137{
138 m_pc.bounds_min = bounds_min;
139 const glm::vec3 extent = bounds_max - bounds_min;
140 m_pc.step = {
141 extent.x / static_cast<float>(m_res_x),
142 extent.y / static_cast<float>(m_res_y),
143 extent.z / static_cast<float>(m_res_z),
144 };
145
146 m_field_pc.bounds_min[0] = bounds_min.x;
147 m_field_pc.bounds_min[1] = bounds_min.y;
148 m_field_pc.bounds_min[2] = bounds_min.z;
149 m_field_pc.step[0] = m_pc.step.x;
150 m_field_pc.step[1] = m_pc.step.y;
151 m_field_pc.step[2] = m_pc.step.z;
152}
153
154void SDFFieldProcessor::on_attach(const std::shared_ptr<Buffer>& buffer)
155{
157 bind_buffer("sdf_grid", m_grid_buf);
158}
159
162 const std::shared_ptr<VKBuffer>& /*buffer*/)
163{
164 if (m_from_field) {
166 } else {
168 }
169 return true;
170}
171
172} // namespace MayaFlux::Buffers
std::shared_ptr< NetworkGeometryBuffer > buffer
glm::ivec3 max
std::string name
Definition VKDevice.cpp:123
virtual void on_attach(const std::shared_ptr< Buffer > &)
Called when this processor is attached to a buffer.
void set_dispatch_mode(ShaderDispatchConfig::DispatchMode mode)
Set dispatch mode.
void set_manual_dispatch(uint32_t x, uint32_t y=1, uint32_t z=1)
Set manual dispatch group counts.
Specialized ShaderProcessor for Compute Pipelines.
bool on_before_execute(Portal::Graphics::CommandBufferID cmd_id, const std::shared_ptr< VKBuffer > &buffer) override
Called before each process callback.
void on_attach(const std::shared_ptr< Buffer > &buffer) override
Called when this processor is attached to a buffer.
SDFFieldProcessor(std::shared_ptr< VKBuffer > grid_buf, const glm::vec3 &bounds_min, const glm::vec3 &bounds_max, uint32_t res_x, uint32_t res_y, uint32_t res_z, std::string shader="sdf_field_gyroid.comp.spv")
std::shared_ptr< VKBuffer > m_grid_buf
void set_bounds(const glm::vec3 &bounds_min, const glm::vec3 &bounds_max)
Replace the evaluation volume.
void set_push_constant_data(const T &data)
Update push constant data (type-safe)
void bind_buffer(const std::string &descriptor_name, const std::shared_ptr< VKBuffer > &buffer)
Bind a VKBuffer to a named shader descriptor.
@ BufferProcessing
Buffer processing (Buffers::BufferManager, processing chains)
@ Buffers
Buffers, Managers, processors and processing chains.
GpuDataFormat
GPU data formats with explicit precision levels.
Describes how a VKBuffer binds to a shader descriptor.
std::unordered_map< std::string, ShaderBinding > bindings
Parsed representation of a stringified field lambda.