diff --git a/src/esp/sim/BatchReplayRenderer.cpp b/src/esp/sim/BatchReplayRenderer.cpp index e06183482e..d1ec4014b1 100644 --- a/src/esp/sim/BatchReplayRenderer.cpp +++ b/src/esp/sim/BatchReplayRenderer.cpp @@ -19,23 +19,25 @@ namespace sim { using namespace Mn::Math::Literals; // NOLINT BatchReplayRenderer::BatchReplayRenderer( - const ReplayRendererConfiguration& cfg) { + const ReplayRendererConfiguration& cfg, + gfx_batch::RendererConfiguration&& batchRendererConfiguration) { CORRADE_ASSERT(cfg.sensorSpecifications.size() == 1, "ReplayBatchRenderer: expecting exactly one sensor", ); const auto& sensor = static_cast( *cfg.sensorSpecifications.front()); - gfx_batch::RendererConfiguration configuration; - configuration.setTileSizeCount(Mn::Vector2i{sensor.resolution}.flipped(), - environmentGridSize(cfg.numEnvironments)); + batchRendererConfiguration.setTileSizeCount( + Mn::Vector2i{sensor.resolution}.flipped(), + environmentGridSize(cfg.numEnvironments)); if ((standalone_ = cfg.standalone)) renderer_.emplace( - configuration, gfx_batch::RendererStandaloneConfiguration{}); + batchRendererConfiguration, + gfx_batch::RendererStandaloneConfiguration{}); else { CORRADE_ASSERT(Mn::GL::Context::hasCurrent(), "ReplayBatchRenderer: expecting a current GL context if a " "standalone renderer is disabled", ); - renderer_.emplace(configuration); + renderer_.emplace(batchRendererConfiguration); } theOnlySensorName_ = sensor.uuid; @@ -106,6 +108,43 @@ BatchReplayRenderer::BatchReplayRenderer( Mn::Matrix4::from(rotation.toMatrix(), translation); } + void changeLightSetup(const esp::gfx::LightSetup& lights) override { + if (!renderer_.maxLightCount()) { + ESP_WARNING() << "Attempted to change" << lights.size() + << "lights for scene" << sceneId_ + << "but the renderer is configured without lights"; + return; + } + + renderer_.clearLights(sceneId_); + for (std::size_t i = 0; i != lights.size(); ++i) { + const gfx::LightInfo& light = lights[i]; + CORRADE_INTERNAL_ASSERT(light.model == gfx::LightPositionModel::Global); + + const std::size_t nodeId = renderer_.addEmptyNode(sceneId_); + + std::size_t lightId; + if (light.vector.z()) { + renderer_.transformations(sceneId_)[nodeId] = + Mn::Matrix4::translation(light.vector.xyz()); + lightId = renderer_.addLight(sceneId_, nodeId, + gfx_batch::RendererLightType::Point); + } else { + /* The matrix will be partially NaNs if the light vector is in the + direction of the Y axis, but that's fine -- we only really care + about the Z axis direction, which is always the "target" vector + normalized. */ + renderer_.transformations(sceneId_)[nodeId] = + Mn::Matrix4::lookAt({}, light.vector.xyz(), Mn::Vector3::yAxis()); + lightId = renderer_.addLight( + sceneId_, nodeId, gfx_batch::RendererLightType::Directional); + } + + renderer_.lightColors(sceneId_)[lightId] = light.color; + // TODO range, once Habitat has that + } + } + gfx_batch::Renderer& renderer_; Mn::UnsignedInt sceneId_; }; diff --git a/src/esp/sim/BatchReplayRenderer.h b/src/esp/sim/BatchReplayRenderer.h index 8f29d34c94..4d06fda61f 100644 --- a/src/esp/sim/BatchReplayRenderer.h +++ b/src/esp/sim/BatchReplayRenderer.h @@ -14,7 +14,13 @@ namespace sim { class BatchReplayRenderer : public AbstractReplayRenderer { public: - explicit BatchReplayRenderer(const ReplayRendererConfiguration& cfg); + // TODO figure out a better way how to abstract this so i don't need to + // propagate each and every batch-renderer-specific option through all these + // layers like an animal + explicit BatchReplayRenderer( + const ReplayRendererConfiguration& cfg, + gfx_batch::RendererConfiguration&& batchRendererConfiguration = + gfx_batch::RendererConfiguration{}); ~BatchReplayRenderer() override; diff --git a/src/utils/replayer/replayer.cpp b/src/utils/replayer/replayer.cpp index 1f2d8837d3..1be4370710 100644 --- a/src/utils/replayer/replayer.cpp +++ b/src/utils/replayer/replayer.cpp @@ -54,6 +54,8 @@ Replayer::Replayer(const Arguments& arguments) .setHelp("preload", "composite file(s) to preload", "file.glb") .addOption("size", "512 384") .setHelp("size", "environment size", "\"X Y\"") + .addOption("max-light-count", "0") + .setHelp("max-light-count", "max light count used per scene") .addBooleanOption("classic") .setHelp("classic", "use the classic renderer") .addBooleanOption("profile") @@ -75,11 +77,15 @@ unpauses the playback. By default the batch renderer is used, however it implicitly loads individual files from the filesystem as referenced by the gfx-replay JSON. If you pass one -or more compposite files via the -P / --preload option, it'll prefer them if +or more composite files via the -P / --preload option, it'll prefer them if they contain given referenced file, and will fall back to loading from the filesystem if not, printing a warning. The --classic option switches to the classic renderer and resource management, --preload is ignored in that case. +Default rendering is flat-shaded. Set --max-light-count to a value higher than +0 to consume also light information from the gfx-replay JSON files. Meshes with +materials marked as Flat will be rendered flat-shaded even with lights present. + For simple profiling, the --profile option will print GPU, CPU and total frame time to the console. It includes the JSON parsing overhead as well, to benchmark just the renderer itself use --once and wait until all animations @@ -161,10 +167,14 @@ settle down. rendererConfig.sensorSpecifications = std::move(sensorSpecifications); rendererConfig.numEnvironments = fileCount; rendererConfig.standalone = false; + esp::gfx_batch::RendererConfiguration batchRendererConfig; + batchRendererConfig.setMaxLightCount( + args.value("max-light-count")); if (args.isSet("classic")) replayRenderer_.emplace(rendererConfig); else - replayRenderer_.emplace(rendererConfig); + replayRenderer_.emplace( + rendererConfig, std::move(batchRendererConfig)); for (std::size_t i = 0, iMax = args.arrayValueCount("preload"); i != iMax; ++i)