Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2024-03-19 18:21:54 +1100
committerKae <80987908+Novaenia@users.noreply.github.com>2024-03-19 18:21:54 +1100
commit983bb82a96707ae81be5c35e7f9af700ade7d77e (patch)
tree7594648ca829fc8b4c958d02f86b9cc22b04f5d7
parent17ea975970d8f2be994bb1c8e7646f9c8a6c4647 (diff)
Async lighting improvements
-rw-r--r--assets/opensb/rendering/effects/world.config5
-rw-r--r--assets/opensb/rendering/effects/world.frag14
-rw-r--r--source/base/StarCellularLighting.cpp13
-rw-r--r--source/client/StarClientApplication.cpp9
-rw-r--r--source/game/StarWorldClient.cpp113
-rw-r--r--source/game/StarWorldClient.hpp14
-rw-r--r--source/game/StarWorldRenderData.hpp1
-rw-r--r--source/rendering/StarWorldPainter.cpp13
-rw-r--r--source/rendering/StarWorldPainter.hpp2
9 files changed, 100 insertions, 84 deletions
diff --git a/assets/opensb/rendering/effects/world.config b/assets/opensb/rendering/effects/world.config
index 188b727..68b84fa 100644
--- a/assets/opensb/rendering/effects/world.config
+++ b/assets/opensb/rendering/effects/world.config
@@ -30,11 +30,6 @@
"textureSizeUniform" : "lightMapSize",
"textureAddressing" : "clamp",
"textureFiltering" : "linear"
- },
- "tileLightMap" : {
- "textureUniform" : "tileLightMap",
- "textureAddressing" : "clamp",
- "textureFiltering" : "linear"
}
},
diff --git a/assets/opensb/rendering/effects/world.frag b/assets/opensb/rendering/effects/world.frag
index b4450ad..10bd1ad 100644
--- a/assets/opensb/rendering/effects/world.frag
+++ b/assets/opensb/rendering/effects/world.frag
@@ -6,9 +6,7 @@ uniform sampler2D texture2;
uniform sampler2D texture3;
uniform bool lightMapEnabled;
uniform vec2 lightMapSize;
-uniform vec2 tileLightMapSize;
uniform sampler2D lightMap;
-uniform sampler2D tileLightMap;
uniform float lightMapMultiplier;
varying vec2 fragmentTextureCoordinate;
@@ -55,16 +53,6 @@ vec4 bicubicSample(sampler2D texture, vec2 texcoord, vec2 texscale) {
mix(sample1, sample0, sx), sy);
}
-vec3 sampleLightMap(vec2 texcoord, vec2 texscale) {
- vec4 b = bicubicSample(tileLightMap, texcoord, texscale);
- vec4 a = bicubicSample(lightMap, texcoord, texscale);
-
- if (b.z <= 0.0)
- return a.rgb;
-
- return mix(a.rgb, b.rgb / b.z, b.z);
-}
-
void main() {
vec4 texColor;
if (fragmentTextureIndex > 2.9) {
@@ -84,6 +72,6 @@ void main() {
if (texColor.a == 0.99607843137)
finalColor.a = fragmentColor.a;
else if (lightMapEnabled && finalLightMapMultiplier > 0.0)
- finalColor.rgb *= sampleLightMap(fragmentLightMapCoordinate, 1.0 / lightMapSize) * finalLightMapMultiplier;
+ finalColor.rgb *= bicubicSample(lightMap, fragmentLightMapCoordinate, 1.0 / lightMapSize).rgb * finalLightMapMultiplier;
gl_FragColor = finalColor;
} \ No newline at end of file
diff --git a/source/base/StarCellularLighting.cpp b/source/base/StarCellularLighting.cpp
index e4fe8dd..c0a92ea 100644
--- a/source/base/StarCellularLighting.cpp
+++ b/source/base/StarCellularLighting.cpp
@@ -89,12 +89,17 @@ void CellularLightingCalculator::calculate(Image& output) {
output.reset(arrayMax[0] - arrayMin[0], arrayMax[1] - arrayMin[1], PixelFormat::RGB24);
- for (size_t x = arrayMin[0]; x < arrayMax[0]; ++x) {
- for (size_t y = arrayMin[1]; y < arrayMax[1]; ++y) {
- if (m_monochrome)
+ if (m_monochrome) {
+ for (size_t x = arrayMin[0]; x < arrayMax[0]; ++x) {
+ for (size_t y = arrayMin[1]; y < arrayMax[1]; ++y) {
output.set24(x - arrayMin[0], y - arrayMin[1], Color::grayf(m_lightArray.right().getLight(x, y)).toRgb());
- else
+ }
+ }
+ } else {
+ for (size_t x = arrayMin[0]; x < arrayMax[0]; ++x) {
+ for (size_t y = arrayMin[1]; y < arrayMax[1]; ++y) {
output.set24(x - arrayMin[0], y - arrayMin[1], Color::v3fToByte(m_lightArray.left().getLight(x, y)));
+ }
}
}
}
diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp
index 6df7916..54c78b3 100644
--- a/source/client/StarClientApplication.cpp
+++ b/source/client/StarClientApplication.cpp
@@ -426,7 +426,14 @@ void ClientApplication::render() {
LogMap::set("client_render_world_client", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - clientStart));
auto paintStart = Time::monotonicMicroseconds();
- m_worldPainter->render(m_renderData, [&]() { worldClient->waitForLighting(&m_renderData.lightMap); });
+ m_worldPainter->render(m_renderData, [&]() -> bool {
+ if (auto newMinPosition = worldClient->waitForLighting(&m_renderData.lightMap)) {
+ m_renderData.lightMinPosition = *newMinPosition;
+ return true;
+ } else {
+ return false;
+ }
+ });
LogMap::set("client_render_world_painter", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - paintStart));
LogMap::set("client_render_world_total", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - totalStart));
}
diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp
index 489cc31..5e6dc0e 100644
--- a/source/game/StarWorldClient.cpp
+++ b/source/game/StarWorldClient.cpp
@@ -428,7 +428,7 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
}
List<LightSource> renderLightSources;
- List<PreviewTile> previewTiles;
+ m_previewTiles.clear();
renderData.geometry = m_geometry;
@@ -444,43 +444,20 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
RectI window = m_clientState.window();
RectI tileRange = window.padded(bufferTiles);
- RectI lightRange = window.padded(1);
- //Kae: Padded by one to fix light spread issues at the edges of the frame.
-
renderData.tileMinPosition = tileRange.min();
- renderData.lightMinPosition = lightRange.min();
-
- Vec2U lightSize(lightRange.size());
-
- renderData.tileLightMap.reset(lightSize, PixelFormat::RGBA32);
- renderData.tileLightMap.fill(Vec4B::filled(0));
-
- if (m_fullBright) {
- renderData.lightMap.reset(lightSize, PixelFormat::RGB24);
- renderData.lightMap.fill(Vec3B(255, 255, 255));
- } else {
- m_lightingCalculator.begin(lightRange);
-
- if (!m_asyncLighting)
- lightingTileGather();
-
- for (auto const& light : renderLightSources) {
- Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), light.position);
- if (light.pointLight)
- m_lightingCalculator.addPointLight(position, Color::v3bToFloat(light.color), light.pointBeam, light.beamAngle, light.beamAmbience);
- else
- m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(light.color));
- }
- for (auto const& lightPair : m_particles->lightSources()) {
- Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), lightPair.first);
- m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(lightPair.second));
- }
+ if (!m_fullBright) {
+ {
+ MutexLocker m_prepLocker(m_lightMapPrepMutex);
+ m_pendingLights = std::move(renderLightSources);
+ m_pendingParticleLights = std::move(m_particles->lightSources());
+ m_pendingLightRange = window.padded(1);
+ } //Kae: Padded by one to fix light spread issues at the edges of the frame.
if (m_asyncLighting)
m_lightingCond.signal();
else
- m_lightingCalculator.calculate(m_lightMap);
+ lightingCalc();
}
float pulseAmount = Root::singleton().assets()->json("/highlights.config:interactivePulseAmount").toFloat();
@@ -545,7 +522,7 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
m_particles->addParticles(std::move(renderCallback.particles));
m_samples.appendAll(std::move(renderCallback.audios));
- previewTiles.appendAll(std::move(renderCallback.previewTiles));
+ m_previewTiles.appendAll(std::move(renderCallback.previewTiles));
renderData.overheadBars.appendAll(std::move(renderCallback.overheadBars));
}, [](EntityPtr const& a, EntityPtr const& b) {
@@ -596,7 +573,7 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
}
}
- for (auto const& previewTile : previewTiles) {
+ for (auto const& previewTile : m_previewTiles) {
Vec2I tileArrayPos = m_geometry.diff(previewTile.position, renderData.tileMinPosition);
if (tileArrayPos[0] >= 0 && tileArrayPos[0] < (int)renderData.tiles.size(0) && tileArrayPos[1] >= 0 && tileArrayPos[1] < (int)renderData.tiles.size(1)) {
RenderTile& renderTile = renderData.tiles(tileArrayPos[0], tileArrayPos[1]);
@@ -621,12 +598,6 @@ void WorldClient::render(WorldRenderData& renderData, unsigned bufferTiles) {
renderTile.liquidLevel = 255;
}
}
-
- if (previewTile.updateLight) {
- Vec2I lightArrayPos = m_geometry.diff(previewTile.position, renderData.lightMinPosition);
- if (lightArrayPos[0] >= 0 && lightArrayPos[0] < (int)renderData.tileLightMap.width() && lightArrayPos[1] >= 0 && lightArrayPos[1] < (int)renderData.tileLightMap.height())
- renderData.tileLightMap.set(Vec2U(lightArrayPos), previewTile.light);
- }
}
renderData.particles = &m_particles->particles();
@@ -1090,8 +1061,6 @@ void WorldClient::update(float dt) {
auto assets = Root::singleton().assets();
- m_lightingCalculator.setMonochrome(Root::singleton().configuration()->get("monochromeLighting").toBool());
-
float expireTime = min(float(m_latency + 800), 2000.f);
auto now = Time::monotonicMilliseconds();
eraseWhere(m_predictedTiles, [&](auto& pair) {
@@ -1406,10 +1375,21 @@ void WorldClient::collectLiquid(List<Vec2I> const& tilePositions, LiquidId liqui
m_outgoingPackets.append(make_shared<CollectLiquidPacket>(tilePositions, liquidId));
}
-void WorldClient::waitForLighting(Image* out) {
- MutexLocker lock(m_lightMapMutex);
- if (out)
+Maybe<Vec2I> WorldClient::waitForLighting(Image* out) {
+ MutexLocker prepLocker(m_lightMapPrepMutex);
+ MutexLocker lightMapLocker(m_lightMapMutex);
+ if (out && !m_lightMap.empty()) {
+ for (auto& previewTile : m_previewTiles) {
+ if (previewTile.updateLight) {
+ Vec2I lightArrayPos = m_geometry.diff(previewTile.position, m_lightMinPosition);
+ if (lightArrayPos[0] >= 0 && lightArrayPos[0] < (int)m_lightMap.width() && lightArrayPos[1] >= 0 && lightArrayPos[1] < (int)m_lightMap.height())
+ m_lightMap.set(Vec2U(lightArrayPos), previewTile.light);
+ }
+ }
*out = std::move(m_lightMap);
+ return m_lightMinPosition;
+ }
+ return {};
}
WorldClient::BroadcastCallback& WorldClient::broadcastCallback() {
@@ -1629,11 +1609,11 @@ void WorldClient::lightingTileGather() {
// Each column in tileEvalColumns is guaranteed to be no larger than the sector size.
+ size_t lights = 0;
m_tileArray->tileEvalColumns(m_lightingCalculator.calculationRegion(), [&](Vec2I const& pos, ClientTile const* column, size_t ySize) {
size_t baseIndex = m_lightingCalculator.baseIndexFor(pos);
for (size_t y = 0; y < ySize; ++y) {
auto& tile = column[y];
-
Vec3F light;
if (tile.foreground != EmptyMaterialId || tile.foregroundMod != NoModId)
light += materialDatabase->radiantLight(tile.foreground, tile.foregroundMod);
@@ -1646,9 +1626,43 @@ void WorldClient::lightingTileGather() {
if (tile.backgroundLightTransparent && pos[1] + y > undergroundLevel)
light += environmentLight;
}
- m_lightingCalculator.setCellIndex(baseIndex + y, std::move(light), !tile.foregroundLightTransparent);
+ if (light.max() > 0.0f)
+ ++lights;
+ m_lightingCalculator.setCellIndex(baseIndex + y, light, !tile.foregroundLightTransparent);
}
});
+ LogMap::set("client_render_world_async_light_tiles", toString(lights));
+}
+
+void WorldClient::lightingCalc() {
+ MutexLocker prepLocker(m_lightMapPrepMutex);
+ RectI lightRange = m_pendingLightRange;
+ List<LightSource> lights = std::move(m_pendingLights);
+ List<std::pair<Vec2F, Vec3B>> particleLights = std::move(m_pendingParticleLights);
+ m_lightingCalculator.setMonochrome(Root::singleton().configuration()->get("monochromeLighting").toBool());
+ m_lightingCalculator.begin(lightRange);
+ lightingTileGather();
+ prepLocker.unlock();
+
+ for (auto const& light : lights) {
+ Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), light.position);
+ if (light.pointLight)
+ m_lightingCalculator.addPointLight(position, Color::v3bToFloat(light.color), light.pointBeam, light.beamAngle, light.beamAmbience);
+ else
+ m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(light.color));
+ }
+
+ for (auto const& lightPair : particleLights) {
+ Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), lightPair.first);
+ m_lightingCalculator.addSpreadLight(position, Color::v3bToFloat(lightPair.second));
+ }
+
+ m_lightingCalculator.calculate(m_pendingLightMap);
+ {
+ MutexLocker mapLocker(m_lightMapMutex);
+ m_lightMinPosition = lightRange.min();
+ m_lightMap = std::move(m_pendingLightMap);
+ }
}
void WorldClient::lightingMain() {
@@ -1658,11 +1672,8 @@ void WorldClient::lightingMain() {
if (m_stopLightingThread)
return;
- MutexLocker mapLocker(m_lightMapMutex);
int64_t start = Time::monotonicMicroseconds();
- lightingTileGather();
- m_lightingCalculator.calculate(m_lightMap);
- mapLocker.unlock();
+ lightingCalc();
LogMap::set("client_render_world_async_light_calc", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
}
}
diff --git a/source/game/StarWorldClient.hpp b/source/game/StarWorldClient.hpp
index 3fe66eb..6ccd52e 100644
--- a/source/game/StarWorldClient.hpp
+++ b/source/game/StarWorldClient.hpp
@@ -170,7 +170,7 @@ public:
void collectLiquid(List<Vec2I> const& tilePositions, LiquidId liquidId);
- void waitForLighting(Image* out = nullptr);
+ Maybe<Vec2I> waitForLighting(Image* out = nullptr);
typedef std::function<bool(PlayerPtr, StringView)> BroadcastCallback;
BroadcastCallback& broadcastCallback();
@@ -210,6 +210,7 @@ private:
typedef function<ClientTile const& (Vec2I)> ClientTileGetter;
void lightingTileGather();
+ void lightingCalc();
void lightingMain();
void initWorld(WorldStartPacket const& packet);
@@ -272,9 +273,18 @@ private:
Mutex m_lightingMutex;
ConditionVariable m_lightingCond;
+ atomic<bool> m_stopLightingThread;
+
+ Mutex m_lightMapPrepMutex;
Mutex m_lightMapMutex;
+
+ Image m_pendingLightMap;
Image m_lightMap;
- atomic<bool> m_stopLightingThread;
+ List<LightSource> m_pendingLights;
+ List<std::pair<Vec2F, Vec3B>> m_pendingParticleLights;
+ RectI m_pendingLightRange;
+ Vec2I m_lightMinPosition;
+ List<PreviewTile> m_previewTiles;
SkyPtr m_sky;
diff --git a/source/game/StarWorldRenderData.hpp b/source/game/StarWorldRenderData.hpp
index 96fec29..b392615 100644
--- a/source/game/StarWorldRenderData.hpp
+++ b/source/game/StarWorldRenderData.hpp
@@ -26,7 +26,6 @@ struct WorldRenderData {
RenderTileArray tiles;
Vec2I lightMinPosition;
Image lightMap;
- Image tileLightMap;
List<EntityDrawables> entityDrawables;
List<Particle> const* particles;
diff --git a/source/rendering/StarWorldPainter.cpp b/source/rendering/StarWorldPainter.cpp
index 15fb9b9..c55f372 100644
--- a/source/rendering/StarWorldPainter.cpp
+++ b/source/rendering/StarWorldPainter.cpp
@@ -49,7 +49,7 @@ void WorldPainter::update(float dt) {
m_environmentPainter->update(dt);
}
-void WorldPainter::render(WorldRenderData& renderData, function<void()> lightWaiter) {
+void WorldPainter::render(WorldRenderData& renderData, function<bool()> lightWaiter) {
m_camera.setScreenSize(m_renderer->screenSize());
m_camera.setTargetPixelRatio(Root::singleton().configuration()->get("zoomLevel").toFloat());
@@ -76,23 +76,24 @@ void WorldPainter::render(WorldRenderData& renderData, function<void()> lightWai
m_renderer->flush();
+ bool lightMapUpdated = false;
if (lightWaiter) {
auto start = Time::monotonicMicroseconds();
- lightWaiter();
+ lightMapUpdated = lightWaiter();
LogMap::set("client_render_world_async_light_wait", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
}
if (renderData.isFullbright) {
m_renderer->setEffectTexture("lightMap", Image::filled(Vec2U(1, 1), { 255, 255, 255, 255 }, PixelFormat::RGB24));
- m_renderer->setEffectTexture("tileLightMap", Image::filled(Vec2U(1, 1), { 0, 0, 0, 0 }, PixelFormat::RGBA32));
m_renderer->setEffectParameter("lightMapMultiplier", 1.0f);
} else {
- adjustLighting(renderData);
+ if (lightMapUpdated) {
+ adjustLighting(renderData);
+ m_renderer->setEffectTexture("lightMap", renderData.lightMap);
+ }
m_renderer->setEffectParameter("lightMapMultiplier", m_assets->json("/rendering.config:lightMapMultiplier").toFloat());
m_renderer->setEffectParameter("lightMapScale", Vec2F::filled(TilePixels * m_camera.pixelRatio()));
m_renderer->setEffectParameter("lightMapOffset", m_camera.worldToScreen(Vec2F(renderData.lightMinPosition)));
- m_renderer->setEffectTexture("lightMap", renderData.lightMap);
- m_renderer->setEffectTexture("tileLightMap", renderData.tileLightMap);
}
// Parallax layers
diff --git a/source/rendering/StarWorldPainter.hpp b/source/rendering/StarWorldPainter.hpp
index 43ce83c..6cf53e2 100644
--- a/source/rendering/StarWorldPainter.hpp
+++ b/source/rendering/StarWorldPainter.hpp
@@ -23,7 +23,7 @@ public:
WorldCamera& camera();
void update(float dt);
- void render(WorldRenderData& renderData, function<void()> lightWaiter);
+ void render(WorldRenderData& renderData, function<bool()> lightWaiter);
void adjustLighting(WorldRenderData& renderData);
private: