-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathRobotScene.h
More file actions
259 lines (215 loc) · 8.76 KB
/
RobotScene.h
File metadata and controls
259 lines (215 loc) · 8.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/// \file Visualizer.h
/// \author ManifoldFR
/// \copyright 2025 INRIA
#pragma once
#include "Multibody.h"
#include "../core/Device.h"
#include "../core/Scene.h"
#include "../core/Renderer.h"
#include "../core/LightUniforms.h"
#include "../core/Collision.h"
#include "../core/DepthAndShadowPass.h"
#include "../core/Texture.h"
#include "../posteffects/SSAO.h"
#include "../utils/MeshData.h"
#include <magic_enum/magic_enum.hpp>
#include <entt/entity/fwd.hpp>
#include <coal/fwd.hh>
#include <pinocchio/multibody/fwd.hpp>
namespace candlewick {
/// \brief Terminate the application after encountering an invalid enum value.
template <typename T>
requires std::is_enum_v<T>
[[noreturn]] void
invalid_enum(const char *msg, T type,
std::source_location location = std::source_location::current()) {
terminate_with_message(location, "Invalid enum: %s - %s", msg,
magic_enum::enum_name(type));
}
namespace multibody {
/// \brief A system for updating the transform components for robot geometry
/// entities.
///
/// This will also update the mesh materials.
///
/// Reads PinGeomObjComponent, updates TransformComponent.
void updateRobotTransforms(entt::registry ®istry,
const pin::GeometryModel &geom_model,
const pin::GeometryData &geom_data);
/// \brief A render system for Pinocchio robot geometries using Pinocchio.
///
/// This internally stores references to pinocchio::GeometryModel and
/// pinocchio::GeometryData objects.
class RobotScene final {
[[nodiscard]] bool hasInternalPointers() const {
return m_geomModel && m_geomData;
}
void compositeTransparencyPass(CommandBuffer &command_buffer);
void renderPBRTriangleGeometry(CommandBuffer &command_buffer,
const Camera &camera, bool transparent);
void renderOtherGeometry(CommandBuffer &command_buffer,
const Camera &camera);
void initGBuffer();
void initCompositePipeline(const MeshLayout &layout);
public:
enum PipelineType {
PIPELINE_TRIANGLEMESH,
PIPELINE_HEIGHTFIELD,
PIPELINE_POINTCLOUD,
};
static constexpr size_t kNumPipelineTypes =
magic_enum::enum_count<PipelineType>();
enum VertexUniformSlots : Uint32 { TRANSFORM = 0 };
enum FragmentUniformSlots : Uint32 { MATERIAL = 0, LIGHTING = 1 };
/// Map hpp-fcl/coal collision geometry to desired pipeline type.
static PipelineType pinGeomToPipeline(const coal::CollisionGeometry &geom);
/// Map pipeline type to geometry primitive.
static constexpr SDL_GPUPrimitiveType
getPrimitiveTopologyForType(PipelineType type) {
switch (type) {
case PIPELINE_TRIANGLEMESH:
return SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
case PIPELINE_HEIGHTFIELD:
return SDL_GPU_PRIMITIVETYPE_LINELIST;
case PIPELINE_POINTCLOUD:
return SDL_GPU_PRIMITIVETYPE_POINTLIST;
}
}
template <PipelineType t> using pipeline_tag = entt::tag<t>;
struct PipelineConfig {
// shader set
const char *vertex_shader_path;
const char *fragment_shader_path;
SDL_GPUCullMode cull_mode = SDL_GPU_CULLMODE_BACK;
SDL_GPUFillMode fill_mode = SDL_GPU_FILLMODE_FILL;
};
struct Config {
struct TrianglePipelineConfig {
PipelineConfig opaque{
.vertex_shader_path = "PbrBasic.vert",
.fragment_shader_path = "PbrBasic.frag",
};
PipelineConfig transparent{
.vertex_shader_path = "PbrBasic.vert",
.fragment_shader_path = "PbrTransparent.frag",
.cull_mode = SDL_GPU_CULLMODE_NONE,
};
} triangle_config;
PipelineConfig heightfield_config{
.vertex_shader_path = "Hud3dElement.vert",
.fragment_shader_path = "Hud3dElement.frag",
};
PipelineConfig pointcloud_config;
bool enable_msaa = false;
bool enable_shadows = true;
bool enable_ssao = true;
bool triangle_has_prepass = false;
bool enable_normal_target = false;
SDL_GPUSampleCount msaa_samples = SDL_GPU_SAMPLECOUNT_1;
ShadowPassConfig shadow_config;
};
struct Pipelines {
struct {
SDL_GPUGraphicsPipeline *opaque = nullptr;
SDL_GPUGraphicsPipeline *transparent = nullptr;
} triangleMesh;
SDL_GPUGraphicsPipeline *heightfield = nullptr;
SDL_GPUGraphicsPipeline *pointcloud = nullptr;
SDL_GPUGraphicsPipeline *wboitComposite = nullptr;
} pipelines;
DirectionalLight directionalLight;
ssao::SsaoPass ssaoPass{NoInit};
struct GBuffer {
Texture normalMap{NoInit};
// WBOIT buffers
Texture accumTexture{NoInit};
Texture revealTexture{NoInit};
SDL_GPUSampler *sampler = nullptr; // composite pass
} gBuffer;
ShadowMapPass shadowPass{NoInit};
AABB worldSpaceBounds;
/// \brief Non-initializing constructor.
RobotScene(entt::registry ®istry, const Renderer &renderer);
/// \brief Constructor which initializes the system.
///
/// loadModels() will be called.
RobotScene(entt::registry ®istry, const Renderer &renderer,
const pin::GeometryModel &geom_model,
const pin::GeometryData &geom_data, Config config);
RobotScene(const RobotScene &) = delete;
void setConfig(const Config &config) {
CDW_ASSERT(
!m_initialized,
"Cannot call setConfig() after render system was initialized.");
m_config = config;
}
/// \brief Set the internal geometry model and data pointers, and load the
/// corresponding models.
void loadModels(const pin::GeometryModel &geom_model,
const pin::GeometryData &geom_data);
/// \brief Update the transform component of the GeometryObject entities.
void updateTransforms();
void collectOpaqueCastables();
const std::vector<OpaqueCastable> &castables() const { return m_castables; }
entt::entity
addEnvironmentObject(MeshData &&data, Mat4f placement,
PipelineType pipe_type = PIPELINE_TRIANGLEMESH);
entt::entity
addEnvironmentObject(MeshData &&data, const Eigen::Affine3f &T,
PipelineType pipe_type = PIPELINE_TRIANGLEMESH) {
return addEnvironmentObject(std::move(data), T.matrix(), pipe_type);
}
/// \brief Destroy all entities with the EnvironmentTag component.
void clearEnvironment();
/// \brief Destroy all entities with the PinGeomObjComponent component
/// (Pinocchio geometry objects).
void clearRobotGeometries();
void createPipeline(const MeshLayout &layout,
SDL_GPUTextureFormat render_target_format,
SDL_GPUTextureFormat depth_stencil_format,
PipelineType type, bool transparent);
/// \warning Call updateTransforms() before rendering the objects with
/// this function.
void render(CommandBuffer &command_buffer, const Camera &camera);
void renderOpaque(CommandBuffer &command_buffer, const Camera &camera);
void renderTransparent(CommandBuffer &command_buffer, const Camera &camera);
/// \brief Release all resources.
void release();
Config &config() { return m_config; }
const Config &config() const { return m_config; }
inline bool pbrHasPrepass() const { return m_config.triangle_has_prepass; }
inline bool shadowsEnabled() const { return m_config.enable_shadows; }
/// \brief Getter for the pinocchio GeometryModel object.
const pin::GeometryModel &geomModel() const { return *m_geomModel; }
/// \brief Getter for the pinocchio GeometryData object.
const pin::GeometryData &geomData() const { return *m_geomData; }
const entt::registry ®istry() const { return m_registry; }
const Device &device() { return m_renderer.device; }
SDL_GPUGraphicsPipeline *getPipeline(PipelineType type,
bool transparent = false) {
return *routePipeline(type, transparent);
}
private:
entt::registry &m_registry;
const Renderer &m_renderer;
Config m_config;
const pin::GeometryModel *m_geomModel;
const pin::GeometryData *m_geomData;
std::vector<OpaqueCastable> m_castables;
bool m_initialized;
SDL_GPUGraphicsPipeline **routePipeline(PipelineType type,
bool transparent) {
switch (type) {
case PIPELINE_TRIANGLEMESH:
return transparent ? &pipelines.triangleMesh.transparent
: &pipelines.triangleMesh.opaque;
case PIPELINE_HEIGHTFIELD:
return &pipelines.heightfield;
case PIPELINE_POINTCLOUD:
return &pipelines.pointcloud;
}
}
};
static_assert(Scene<RobotScene>);
} // namespace multibody
} // namespace candlewick