Visual Computing Library  devel
Loading...
Searching...
No Matches
mesh_render_buffers.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_BGFX_DRAWABLE_MESH_MESH_RENDER_BUFFERS_H
24#define VCL_BGFX_DRAWABLE_MESH_MESH_RENDER_BUFFERS_H
25
26#include "mesh_render_buffers_macros.h"
27
28#include <vclib/algorithms/core/create.h>
29#include <vclib/bgfx/buffers.h>
30#include <vclib/bgfx/context.h>
31#include <vclib/bgfx/drawable/uniforms/drawable_mesh_uniforms.h>
32#include <vclib/bgfx/texture_unit.h>
33#include <vclib/io/image/load.h>
34#include <vclib/render/drawable/mesh/mesh_render_data.h>
35#include <vclib/render/drawable/mesh/mesh_render_settings.h>
36#include <vclib/space/core/image.h>
37
38#include <bgfx/bgfx.h>
39
40namespace vcl {
41
42template<MeshConcept Mesh>
43class MeshRenderBuffers : public MeshRenderData<MeshRenderBuffers<Mesh>>
44{
45 using MeshType = Mesh;
47 using MRI = MeshRenderInfo;
48
49 friend Base;
50
51 VertexBuffer mVertexPositionsBuffer;
52 VertexBuffer mVertexNormalsBuffer;
53 VertexBuffer mVertexColorsBuffer;
54 VertexBuffer mVertexUVBuffer;
55 VertexBuffer mVertexWedgeUVBuffer;
56
57 // point splatting
58 IndexBuffer mVertexQuadIndexBuffer;
59 DynamicVertexBuffer mVertexQuadBuffer;
60 mutable bool mVertexQuadBufferGenerated = false;
61
62 IndexBuffer mTriangleIndexBuffer;
63 IndexBuffer mTriangleNormalBuffer;
64 IndexBuffer mTriangleColorBuffer;
65
66 IndexBuffer mVertexTextureIndexBuffer;
67 IndexBuffer mWedgeTextureIndexBuffer;
68
69 // TODO: manage wireframe with proper lines
70 IndexBuffer mEdgeIndexBuffer;
71 IndexBuffer mEdgeNormalBuffer;
72 IndexBuffer mEdgeColorBuffer;
73
74 // TODO: manage wireframe with proper lines
75 IndexBuffer mWireframeIndexBuffer;
76
77 std::vector<std::unique_ptr<TextureUnit>> mTextureUnits;
78
79 DrawableMeshUniforms mMeshUniforms;
80
81public:
82 MeshRenderBuffers() = default;
83
85 const MeshType& mesh,
86 MRI::BuffersBitSet buffersToFill = MRI::BUFFERS_ALL) :
88 {
89 Base::update(mesh, buffersToFill);
90 }
91
93
95
96 MeshRenderBuffers& operator=(const MeshRenderBuffers& other) = delete;
97
99 {
100 swap(other);
101 return *this;
102 }
103
104 void swap(MeshRenderBuffers& other)
105 {
106 using std::swap;
107 Base::swap(other);
108 swap(mVertexPositionsBuffer, other.mVertexPositionsBuffer);
109 swap(mVertexNormalsBuffer, other.mVertexNormalsBuffer);
110 swap(mVertexColorsBuffer, other.mVertexColorsBuffer);
111 swap(mVertexUVBuffer, other.mVertexUVBuffer);
112 swap(mVertexWedgeUVBuffer, other.mVertexWedgeUVBuffer);
113 swap(mVertexQuadIndexBuffer, other.mVertexQuadIndexBuffer);
114 swap(mVertexQuadBuffer, other.mVertexQuadBuffer);
115 swap(mVertexQuadBufferGenerated, other.mVertexQuadBufferGenerated);
116 swap(mTriangleIndexBuffer, other.mTriangleIndexBuffer);
117 swap(mTriangleNormalBuffer, other.mTriangleNormalBuffer);
118 swap(mTriangleColorBuffer, other.mTriangleColorBuffer);
119 swap(mVertexTextureIndexBuffer, other.mVertexTextureIndexBuffer);
120 swap(mWedgeTextureIndexBuffer, other.mWedgeTextureIndexBuffer);
121 swap(mEdgeIndexBuffer, other.mEdgeIndexBuffer);
122 swap(mEdgeNormalBuffer, other.mEdgeNormalBuffer);
123 swap(mEdgeColorBuffer, other.mEdgeColorBuffer);
124 swap(mWireframeIndexBuffer, other.mWireframeIndexBuffer);
125 swap(mTextureUnits, other.mTextureUnits);
126 swap(mMeshUniforms, other.mMeshUniforms);
127 }
128
129 friend void swap(MeshRenderBuffers& a, MeshRenderBuffers& b) { a.swap(b); }
130
131 void bindVertexBuffers(const MeshRenderSettings& mrs) const
132 {
133 // bgfx allows a maximum number of 4 vertex streams...
134 mVertexPositionsBuffer.bindVertex(VCL_MRB_VERTEX_POSITION_STREAM);
135 mVertexNormalsBuffer.bindVertex(VCL_MRB_VERTEX_NORMAL_STREAM);
136 mVertexColorsBuffer.bindVertex(VCL_MRB_VERTEX_COLOR_STREAM);
137
138 if (mrs.isSurface(MeshRenderInfo::Surface::COLOR_VERTEX_TEX)) {
139 mVertexUVBuffer.bind(VCL_MRB_VERTEX_TEXCOORD_STREAM);
140 }
141 else if (mrs.isSurface(MeshRenderInfo::Surface::COLOR_WEDGE_TEX)) {
142 mVertexWedgeUVBuffer.bind(VCL_MRB_VERTEX_TEXCOORD_STREAM);
143 }
144 }
145
146 // to generate splats
147 void computeQuadVertexBuffers(
148 const MeshType& mesh,
149 const bgfx::ViewId viewId) const
150 {
151 if (!mVertexQuadBuffer.isValid() || mVertexQuadBufferGenerated) {
152 return;
153 }
154
155 // fill the buffer using compute shader
156 mVertexPositionsBuffer.bindCompute(
157 VCL_MRB_VERTEX_POSITION_STREAM, bgfx::Access::Read);
158 mVertexNormalsBuffer.bindCompute(
159 VCL_MRB_VERTEX_NORMAL_STREAM, bgfx::Access::Read);
160 mVertexColorsBuffer.bindCompute(
161 VCL_MRB_VERTEX_COLOR_STREAM, bgfx::Access::Read);
162
163 mVertexQuadBuffer.bindCompute(4, bgfx::Access::Write);
164
165 auto& pm = Context::instance().programManager();
166 bgfx::dispatch(
167 viewId,
168 pm.getComputeProgram<ComputeProgram::DRAWABLE_MESH_POINTS>(),
169 mesh.vertexNumber(),
170 1,
171 1);
172
173 mVertexQuadBufferGenerated = true;
174 }
175
176 // to draw splats
177 void bindVertexQuadBuffer() const
178 {
179 mVertexQuadBuffer.bind(VCL_MRB_VERTEX_POSITION_STREAM);
180 mVertexQuadIndexBuffer.bind();
181 }
182
183 void bindIndexBuffers(
184 const MeshRenderSettings& mrs,
185 MRI::Buffers indexBufferToBind = MRI::Buffers::TRIANGLES) const
186 {
187 using enum MRI::Buffers;
188
189 if (indexBufferToBind == TRIANGLES) {
190 mTriangleIndexBuffer.bind();
191
192 mTriangleNormalBuffer.bind(VCL_MRB_PRIMITIVE_NORMAL_BUFFER);
193
194 mTriangleColorBuffer.bind(VCL_MRB_PRIMITIVE_COLOR_BUFFER);
195
196 if (mrs.isSurface(MeshRenderInfo::Surface::COLOR_VERTEX_TEX)) {
197 mVertexTextureIndexBuffer.bind(
198 VCL_MRB_TRIANGLE_TEXTURE_ID_BUFFER);
199 }
200 else if (mrs.isSurface(MeshRenderInfo::Surface::COLOR_WEDGE_TEX)) {
201 mWedgeTextureIndexBuffer.bind(
202 VCL_MRB_TRIANGLE_TEXTURE_ID_BUFFER);
203 }
204 }
205 else if (indexBufferToBind == EDGES) {
206 mEdgeIndexBuffer.bind();
207
208 mEdgeNormalBuffer.bind(VCL_MRB_PRIMITIVE_NORMAL_BUFFER);
209
210 mEdgeColorBuffer.bind(VCL_MRB_PRIMITIVE_COLOR_BUFFER);
211 }
212 else if (indexBufferToBind == WIREFRAME) {
213 mWireframeIndexBuffer.bind();
214 }
215 }
216
217 void bindTextures() const
218 {
219 uint i = VCL_MRB_TEXTURE0; // first slot available is VCL_MRB_TEXTURE0
220 for (const auto& ptr : mTextureUnits) {
221 ptr->bind(i);
222 i++;
223 }
224 }
225
226 void bindUniforms() const { mMeshUniforms.bind(); }
227
228private:
229 void setVertexPositionsBuffer(const MeshType& mesh) // override
230 {
231 uint nv = Base::numVerts();
232
233 auto [buffer, releaseFn] =
235
236 Base::fillVertexPositions(mesh, buffer);
237
238 mVertexPositionsBuffer.createForCompute(
239 buffer,
240 nv,
241 bgfx::Attrib::Position,
242 3,
243 PrimitiveType::FLOAT,
244 false,
245 bgfx::Access::Read,
246 releaseFn);
247
248 // Creates the buffers to be used with compute for splatting
249 if (Context::instance().supportsCompute()) {
250 // create a layout <coordinates, colors, normals, float>
251 // 2 X vec4
252 bgfx::VertexLayout layout;
253 layout.begin()
254 .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
255 .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
256 .add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float)
257 .add(bgfx::Attrib::TexCoord0, 1, bgfx::AttribType::Float)
258 .end();
259
260 // create the dynamic vertex buffer for splatting
261 mVertexQuadBuffer.create(
262 mesh.vertexNumber() * 4, layout, BGFX_BUFFER_COMPUTE_WRITE);
263
264 // create the index buffer for splatting
266
267 // record that the vertex quad buffer must be generated
268 mVertexQuadBufferGenerated = false;
269 }
270 }
271
279 {
280 const uint totalIndices = mesh.vertexNumber() * 6;
281
282 auto [buffer, releaseFn] =
284
285 Base::fillVertexQuadIndices(mesh, buffer);
286
287 mVertexQuadIndexBuffer.create(buffer, totalIndices, true, releaseFn);
288
289 // if number of vertices is not zero, the index buffer must be valid
290 assert(mVertexQuadIndexBuffer.isValid() || totalIndices == 0);
291 }
292
293 void setVertexNormalsBuffer(const MeshType& mesh) // override
294 {
295 uint nv = Base::numVerts();
296
297 auto [buffer, releaseFn] =
299
300 Base::fillVertexNormals(mesh, buffer);
301
302 mVertexNormalsBuffer.createForCompute(
303 buffer,
304 nv,
305 bgfx::Attrib::Normal,
306 3,
307 PrimitiveType::FLOAT,
308 false,
309 bgfx::Access::Read,
310 releaseFn);
311 }
312
313 void setVertexColorsBuffer(const MeshType& mesh) // override
314 {
315 uint nv = Base::numVerts();
316
317 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(nv);
318
319 Base::fillVertexColors(mesh, buffer, Color::Format::ABGR);
320
321 mVertexColorsBuffer.createForCompute(
322 buffer,
323 nv,
324 bgfx::Attrib::Color0,
325 4,
326 PrimitiveType::UCHAR,
327 true,
328 bgfx::Access::Read,
329 releaseFn);
330 }
331
332 void setVertexTexCoordsBuffer(const MeshType& mesh) // override
333 {
334 uint nv = Base::numVerts();
335
336 auto [buffer, releaseFn] =
337 getAllocatedBufferAndReleaseFn<float>(nv * 2);
338
339 Base::fillVertexTexCoords(mesh, buffer);
340
341 mVertexUVBuffer.create(
342 buffer,
343 nv,
344 bgfx::Attrib::TexCoord0,
345 2,
346 PrimitiveType::FLOAT,
347 false,
348 releaseFn);
349 }
350
351 void setWedgeTexCoordsBuffer(const MeshType& mesh) // override
352 {
353 uint nv = Base::numVerts();
354
355 auto [buffer, releaseFn] =
356 getAllocatedBufferAndReleaseFn<float>(nv * 2);
357
358 Base::fillWedgeTexCoords(mesh, buffer);
359
360 mVertexWedgeUVBuffer.create(
361 buffer,
362 nv,
363 bgfx::Attrib::TexCoord1,
364 2,
365 PrimitiveType::FLOAT,
366 false,
367 releaseFn);
368 }
369
370 void setTriangleIndicesBuffer(const MeshType& mesh) // override
371 {
372 uint nt = Base::numTris();
373
374 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(nt * 3);
375
376 Base::fillTriangleIndices(mesh, buffer);
377
378 mTriangleIndexBuffer.create(buffer, nt * 3, true, releaseFn);
379 }
380
381 void setTriangleNormalsBuffer(const MeshType& mesh) // override
382 {
383 uint nt = Base::numTris();
384
385 auto [buffer, releaseFn] =
386 getAllocatedBufferAndReleaseFn<float>(nt * 3);
387
388 Base::fillTriangleNormals(mesh, buffer);
389
390 mTriangleNormalBuffer.createForCompute(
391 buffer,
392 nt * 3,
393 PrimitiveType::FLOAT,
394 bgfx::Access::Read,
395 releaseFn);
396 }
397
398 void setTriangleColorsBuffer(const MeshType& mesh) // override
399 {
400 uint nt = Base::numTris();
401
402 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(nt);
403
404 Base::fillTriangleColors(mesh, buffer, Color::Format::ABGR);
405
406 mTriangleColorBuffer.createForCompute(
407 buffer, nt, PrimitiveType::UINT, bgfx::Access::Read, releaseFn);
408 }
409
410 void setVertexTextureIndicesBuffer(const MeshType& mesh) // override
411 {
412 uint nt = Base::numTris();
413
414 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(nt);
415
416 Base::fillVertexTextureIndices(mesh, buffer);
417
418 mVertexTextureIndexBuffer.createForCompute(
419 buffer, nt, PrimitiveType::UINT, bgfx::Access::Read, releaseFn);
420 }
421
422 void setWedgeTextureIndicesBuffer(const MeshType& mesh) // override
423 {
424 uint nt = Base::numTris();
425
426 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(nt);
427
428 Base::fillWedgeTextureIndices(mesh, buffer);
429
430 mWedgeTextureIndexBuffer.createForCompute(
431 buffer, nt, PrimitiveType::UINT, bgfx::Access::Read, releaseFn);
432 }
433
434 void setEdgeIndicesBuffer(const MeshType& mesh) // override
435 {
436 uint ne = Base::numEdges();
437
438 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(ne * 2);
439
440 Base::fillEdgeIndices(mesh, buffer);
441
442 mEdgeIndexBuffer.create(buffer, ne * 2);
443 }
444
445 void setEdgeNormalsBuffer(const MeshType& mesh) // override
446 {
447 uint ne = Base::numEdges();
448
449 auto [buffer, releaseFn] =
450 getAllocatedBufferAndReleaseFn<float>(ne * 3);
451
452 Base::fillEdgeNormals(mesh, buffer);
453
454 mEdgeNormalBuffer.createForCompute(
455 buffer,
456 ne * 3,
457 PrimitiveType::FLOAT,
458 bgfx::Access::Read,
459 releaseFn);
460 }
461
462 void setEdgeColorsBuffer(const MeshType& mesh) // override
463 {
464 uint ne = Base::numEdges();
465
466 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(ne);
467
468 Base::fillEdgeColors(mesh, buffer, Color::Format::ABGR);
469
470 mEdgeColorBuffer.createForCompute(
471 buffer, ne, PrimitiveType::UINT, bgfx::Access::Read, releaseFn);
472 }
473
474 void setWireframeIndicesBuffer(const MeshType& mesh) // override
475 {
476 const uint nw = Base::numWireframeLines();
477
478 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(nw * 2);
479
480 Base::fillWireframeIndices(mesh, buffer);
481
482 mWireframeIndexBuffer.create(buffer, nw * 2, true, releaseFn);
483 }
484
485 void setTextureUnits(const MeshType& mesh) // override
486 {
487 mTextureUnits.clear();
488 mTextureUnits.reserve(mesh.textureNumber());
489 for (uint i = 0; i < mesh.textureNumber(); ++i) {
490 vcl::Image txt;
491 if constexpr (vcl::HasTextureImages<MeshType>) {
492 if (mesh.texture(i).image().isNull()) {
493 txt = vcl::loadImage(
494 mesh.meshBasePath() + mesh.texturePath(i));
495 }
496 else {
497 txt = mesh.texture(i).image();
498 }
499 }
500 else {
501 txt = vcl::loadImage(mesh.meshBasePath() + mesh.texturePath(i));
502 }
503 if (txt.isNull()) {
505 }
506
507 txt.mirror();
508
509 const uint size = txt.width() * txt.height();
510 assert(size > 0);
511
512 auto [buffer, releaseFn] =
513 getAllocatedBufferAndReleaseFn<uint>(size);
514
515 const uint* tdata = reinterpret_cast<const uint*>(txt.data());
516
517 std::copy(tdata, tdata + size, buffer);
518
519 auto tu = std::make_unique<TextureUnit>();
520 tu->set(
521 buffer,
522 vcl::Point2i(txt.width(), txt.height()),
523 "s_tex" + std::to_string(i),
524 false,
525 releaseFn);
526
527 mTextureUnits.push_back(std::move(tu));
528 }
529 }
530
531 void setMeshUniforms(const MeshType& mesh) // override
532 {
533 mMeshUniforms.update(mesh);
534 }
535
536 template<typename T>
537 std::pair<T*, bgfx::ReleaseFn> getAllocatedBufferAndReleaseFn(uint size)
538 {
539 T* buffer = new T[size];
540
541 return std::make_pair(buffer, [](void* ptr, void*) {
542 delete[] static_cast<T*>(ptr);
543 });
544 }
545};
546
547} // namespace vcl
548
549#endif // VCL_BGFX_DRAWABLE_MESH_MESH_RENDER_BUFFERS_H
The BitSet class allows to treat an integral type as an array of booleans of a guaranteed size.
Definition bit_set.h:52
A class representing a box in N-dimensional space.
Definition box.h:46
void add(const PointT &p)
Adds the given point to the current box, expanding this box in order to contain also the values of th...
Definition box.h:385
static Context & instance(void *windowHandle=nullptr, void *displayHandle=nullptr)
Return the context instance.
Definition context.cpp:371
Definition drawable_mesh_uniforms.h:32
The DynamicVertexBuffer manages the lifetime of a bgfx::DynamicVertexBufferHandle.
Definition dynamic_vertex_buffer.h:48
void bindCompute(uint stage, bgfx::Access::Enum access=bgfx::Access::Read) const
Bind the vertex buffer to the compute shader.
Definition dynamic_vertex_buffer.h:264
void create(uint vertNum, bgfx::Attrib::Enum attrib, uint attribNumPerVertex, PrimitiveType attribType, bool normalize=false, bool allowResize=true)
Creates the dynamic vertex buffer data for rendering, with the layout given by the vertex attributes ...
Definition dynamic_vertex_buffer.h:101
void bind(uint stream, bgfx::Access::Enum access=bgfx::Access::Read) const
Bind the dynamic vertex buffer to the rendering pipeline.
Definition dynamic_vertex_buffer.h:242
The Image class stores an Image in 4 bytes RGBA format.
Definition image.h:44
The IndexBuffer manages the lifetime of a bgfx::IndexBufferHandle.
Definition index_buffer.h:43
void create(const void *bufferIndices, const uint bufferSize, bool is32Bit=true, bgfx::ReleaseFn releaseFn=nullptr)
Creates the index buffer and sets the data for rendering.
Definition index_buffer.h:103
void bind(uint stage=UINT_NULL, bgfx::Access::Enum access=bgfx::Access::Read) const
Bind the index buffer to the rendering pipeline.
Definition index_buffer.h:193
void createForCompute(const void *bufferIndices, const uint bufferSize, PrimitiveType type, bgfx::Access::Enum access=bgfx::Access::Read, bgfx::ReleaseFn releaseFn=nullptr)
Creates the index buffer and sets the data for compute shaders.
Definition index_buffer.h:141
Definition mesh_render_buffers.h:44
void setVertexQuadIndexBuffer(const MeshType &mesh)
The function allocates and fills a GPU index buffer to render a quad for each vertex of the mesh.
Definition mesh_render_buffers.h:278
The MeshRenderData class provides a common interface to automatically update the buffers used to rend...
Definition mesh_render_data.h:81
The MeshRenderInfo class is a collection of rendering settings for a Mesh.
Definition mesh_render_info.h:61
The MeshRenderSettings class allows an easy management of render settings of a Mesh....
Definition mesh_render_settings.h:70
The Mesh class represents a generic 3D mesh. A mesh is composed of a generic number of containers of ...
Definition mesh.h:68
The Point class represents an N-dimensional point containing N scalar values.
Definition point.h:55
The VertexBuffer manages the lifetime of a bgfx::VertexBufferHandle.
Definition vertex_buffer.h:43
void bindCompute(uint stage, bgfx::Access::Enum access=bgfx::Access::Read) const
Bind the vertex buffer to the compute shader.
Definition vertex_buffer.h:253
void create(const void *bufferData, uint vertNum, bgfx::Attrib::Enum attrib, uint attribNumPerVertex, PrimitiveType attribType, bool normalize=false, bgfx::ReleaseFn releaseFn=nullptr)
Creates the vertex buffer and sets the data for rendering.
Definition vertex_buffer.h:106
void createForCompute(const void *bufferData, const uint vertNum, bgfx::Attrib::Enum attrib, uint attribNumPerVertex, PrimitiveType attribType, bool normalize=false, bgfx::Access::Enum access=bgfx::Access::Read, bgfx::ReleaseFn releaseFn=nullptr)
Creates the vertex buffer and sets the data for compute shaders.
Definition vertex_buffer.h:160
void bind(uint stream, bgfx::Access::Enum access=bgfx::Access::Read) const
Bind the vertex buffer to the rendering pipeline.
Definition vertex_buffer.h:231
Concept that checks if a Mesh has the TextureImages component.
Definition mesh_requirements.h:96
Image createCheckBoardImage(uint imageSize, uint checkNum=8)
Create a checkboard image.
Definition create.h:109