From 8249a8a6d72ff1797ef864d50da40d58df4fd077 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 17 Aug 2018 17:55:31 -0700 Subject: [PATCH] Always sort lights by distance to the camera-plane This will be useful later. --- filament/src/Scene.cpp | 55 +++++++++++++++--------------------- filament/src/View.cpp | 6 ++-- filament/src/details/Scene.h | 2 +- 3 files changed, 26 insertions(+), 37 deletions(-) diff --git a/filament/src/Scene.cpp b/filament/src/Scene.cpp index d82969da46..0c49cd1d24 100644 --- a/filament/src/Scene.cpp +++ b/filament/src/Scene.cpp @@ -168,58 +168,47 @@ void FScene::terminate(FEngine& engine) { mGpuLightData.terminate(engine); } -void FScene::prepareLights(const CameraInfo& camera, ArenaScope& rootArena) noexcept { +void FScene::prepareDynamicLights(const CameraInfo& camera, ArenaScope& rootArena) noexcept { FLightManager& lcm = mEngine.getLightManager(); GpuLightBuffer& gpuLightData = mGpuLightData; FScene::LightSoa& lightData = getLightData(); /* * Here we copy our lights data into the GPU buffer, some lights might be left out if there - * are more than the GPU buffer allows (i.e. 255). + * are more than the GPU buffer allows (i.e. 256). * - * Sorting light by distance to the camera for dropping the ones in excess doesn't - * work well because a light far from the camera could light an object close to it - * (e.g. a search light). - * - * When we have too many lights, there is nothing better we can do though. - * However, when the froxelization "record buffer" runs out of space, it's better to drop - * froxels far from the camera instead. This would happen during froxelization. + * We always sort lights by distance to the camera plane so that: + * - we can build light trees + * - lights farther from the camera are dropped when in excess + * (note this doesn't work well, e.g. for search-lights) */ - // don't count the directional light - if (UTILS_UNLIKELY(lightData.size() > CONFIG_MAX_LIGHT_COUNT + DIRECTIONAL_LIGHTS_COUNT)) { - ArenaScope arena(rootArena.getAllocator()); - float* const UTILS_RESTRICT distances = arena.allocate(lightData.size(), CACHELINE_SIZE); + ArenaScope arena(rootArena.getAllocator()); + float* const UTILS_RESTRICT distances = arena.allocate(lightData.size(), CACHELINE_SIZE); - // pre-compute the lights' distance to the camera, for sorting below. - float3 const position = camera.getPosition(); - - // skip directional light - for (size_t i = DIRECTIONAL_LIGHTS_COUNT, c = lightData.size(); i < c; ++i) { - // TODO: this should take spot-light direction into account - // TODO: maybe we could also take the intensity into account - float4 s = lightData.elementAt(i); - distances[i] = std::max(0.0f, length(position - s.xyz) - s.w); - } - - // skip directional light - Zip2Iterator b = { lightData.begin(), distances }; - std::sort(b + DIRECTIONAL_LIGHTS_COUNT, b + lightData.size(), - [](auto const& lhs, auto const& rhs) { return lhs.second < rhs.second; }); - - lightData.resize(std::min(lightData.size(), CONFIG_MAX_LIGHT_COUNT + DIRECTIONAL_LIGHTS_COUNT)); + // pre-compute the lights' distance to the camera plane, for sorting below, + // skipping the directional light. + float4 const* const UTILS_RESTRICT spheres = lightData.data(); + for (size_t i = DIRECTIONAL_LIGHTS_COUNT, c = lightData.size(); i < c; ++i) { + float4 p = camera.view * spheres[i].xyz; + distances[i] = std::max(0.0f, -p.z); } - assert(lightData.size() <= CONFIG_MAX_LIGHT_COUNT + DIRECTIONAL_LIGHTS_COUNT); + // skip directional light + Zip2Iterator b = { lightData.begin(), distances }; + std::sort(b + DIRECTIONAL_LIGHTS_COUNT, b + lightData.size(), + [](auto const& lhs, auto const& rhs) { return lhs.second < rhs.second; }); + + // drop excess lights + lightData.resize(std::min(lightData.size(), CONFIG_MAX_LIGHT_COUNT + DIRECTIONAL_LIGHTS_COUNT)); - auto const* UTILS_RESTRICT positions = lightData.data(); auto const* UTILS_RESTRICT directions = lightData.data(); auto const* UTILS_RESTRICT instances = lightData.data(); for (size_t i = DIRECTIONAL_LIGHTS_COUNT, c = lightData.size(); i < c; ++i) { GpuLightBuffer::LightIndex gpuIndex = GpuLightBuffer::LightIndex(i - DIRECTIONAL_LIGHTS_COUNT); GpuLightBuffer::LightParameters& lp = gpuLightData.getLightParameters(gpuIndex); auto li = instances[i]; - lp.positionFalloff = { positions[i].xyz, lcm.getSquaredFalloffInv(li) }; + lp.positionFalloff = { spheres[i].xyz, lcm.getSquaredFalloffInv(li) }; lp.colorIntensity = { lcm.getColor(li), lcm.getIntensity(li) }; lp.directionIES = { directions[i], 0 }; lp.spotScaleOffset.xy = { lcm.getSpotParams(li).scaleOffset }; diff --git a/filament/src/View.cpp b/filament/src/View.cpp index 20b453eeca..5026bfc921 100644 --- a/filament/src/View.cpp +++ b/filament/src/View.cpp @@ -163,9 +163,9 @@ math::float2 FView::updateScale(duration frameTime) noexcept { // apply a median filter to get a good representation of the frame time of the last // N frames. - std::array median; + std::array median; // NOLINT -- it's initialized below size_t size = std::min(history.size(), median.size()); - std::copy_n(history.begin(), size, median.begin()); + std::uninitialized_copy_n(history.begin(), size, median.begin()); std::sort(median.begin(), median.begin() + size); duration filteredFrameTime = median[size / 2]; @@ -305,7 +305,7 @@ void FView::prepareLighting(FEngine& engine, FEngine::DriverApi& driver, ArenaSc const CameraInfo& camera = mViewingCameraInfo; FScene* const scene = mScene; - scene->prepareLights(camera, arena); + scene->prepareDynamicLights(camera, arena); // here the array of visible lights has been shrunk to CONFIG_MAX_LIGHT_COUNT auto const& lightData = scene->getLightData(); diff --git a/filament/src/details/Scene.h b/filament/src/details/Scene.h index 6cbe0187dc..59a5fa1175 100644 --- a/filament/src/details/Scene.h +++ b/filament/src/details/Scene.h @@ -83,7 +83,7 @@ public: void terminate(FEngine& engine); void prepare(const math::mat4f& worldOriginTansform); - void prepareLights(const CameraInfo& camera, ArenaScope& arena) noexcept; + void prepareDynamicLights(const CameraInfo& camera, ArenaScope& arena) noexcept; void computeBounds(Aabb& castersBox, Aabb& receiversBox, uint32_t visibleLayers) const noexcept; /*