Always sort lights by distance to the camera-plane
This will be useful later.
This commit is contained in:
committed by
Mathias Agopian
parent
d9c07220c8
commit
8249a8a6d7
@@ -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<float>(lightData.size(), CACHELINE_SIZE);
|
||||
ArenaScope arena(rootArena.getAllocator());
|
||||
float* const UTILS_RESTRICT distances = arena.allocate<float>(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<FScene::POSITION_RADIUS>(i);
|
||||
distances[i] = std::max(0.0f, length(position - s.xyz) - s.w);
|
||||
}
|
||||
|
||||
// skip directional light
|
||||
Zip2Iterator<FScene::LightSoa::iterator, float*> 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<FScene::POSITION_RADIUS>();
|
||||
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<FScene::LightSoa::iterator, float*> 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<FScene::POSITION_RADIUS>();
|
||||
auto const* UTILS_RESTRICT directions = lightData.data<FScene::DIRECTION>();
|
||||
auto const* UTILS_RESTRICT instances = lightData.data<FScene::LIGHT_INSTANCE>();
|
||||
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 };
|
||||
|
||||
@@ -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<duration, 30> median;
|
||||
std::array<duration, 30> 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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user