From 0358ae789a6aa5c161c3b9017651b7d2c2f28fd8 Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Sat, 17 Mar 2018 12:10:16 +0300 Subject: [PATCH] Fix node-nodebox lighting difference in direct sunlight (#7061) --- src/content_mapblock.cpp | 50 +++++++++++++++++++++++++++------------- src/content_mapblock.h | 37 ++++++++++++++++++++--------- src/mapblock_mesh.cpp | 13 +++++++++-- 3 files changed, 71 insertions(+), 29 deletions(-) diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 69982c335..348748c91 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -151,7 +151,7 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal, // the faces in the list is up-down-right-left-back-front // (compatible with ContentFeatures). void MapblockMeshGenerator::drawCuboid(const aabb3f &box, - TileSpec *tiles, int tilecount, const LightPair *lights, const f32 *txc) + TileSpec *tiles, int tilecount, const LightInfo *lights, const f32 *txc) { assert(tilecount >= 1 && tilecount <= 6); // pre-condition @@ -263,10 +263,12 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box, if (data->m_smooth_lighting) { for (int j = 0; j < 24; ++j) { - vertices[j].Color = encode_light(lights[light_indices[j]], + video::S3DVertex &vertex = vertices[j]; + vertex.Color = encode_light( + lights[light_indices[j]].getPair(MYMAX(0.0f, vertex.Normal.Y)), f->light_source); if (!f->light_source) - applyFacesShading(vertices[j].Color, vertices[j].Normal); + applyFacesShading(vertex.Color, vertex.Normal); } } @@ -280,30 +282,45 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box, // Gets the base lighting values for a node void MapblockMeshGenerator::getSmoothLightFrame() { + for (int k = 0; k < 8; ++k) + frame.sunlight[k] = false; for (int k = 0; k < 8; ++k) { LightPair light(getSmoothLightTransparent(blockpos_nodes + p, light_dirs[k], data)); - frame.lightsA[k] = light.lightA; - frame.lightsB[k] = light.lightB; + frame.lightsDay[k] = light.lightDay; + frame.lightsNight[k] = light.lightNight; + // If there is direct sunlight and no ambient occlusion at some corner, + // mark the vertical edge (top and bottom corners) containing it. + if (light.lightDay == 255) { + frame.sunlight[k] = true; + frame.sunlight[k ^ 2] = true; + } } } // Calculates vertex light level // vertex_pos - vertex position in the node (coordinates are clamped to [0.0, 1.0] or so) -LightPair MapblockMeshGenerator::blendLight(const v3f &vertex_pos) +LightInfo MapblockMeshGenerator::blendLight(const v3f &vertex_pos) { + // Light levels at (logical) node corners are known. Here, + // trilinear interpolation is used to calculate light level + // at a given point in the node. f32 x = core::clamp(vertex_pos.X / BS + 0.5, 0.0 - SMOOTH_LIGHTING_OVERSIZE, 1.0 + SMOOTH_LIGHTING_OVERSIZE); f32 y = core::clamp(vertex_pos.Y / BS + 0.5, 0.0 - SMOOTH_LIGHTING_OVERSIZE, 1.0 + SMOOTH_LIGHTING_OVERSIZE); f32 z = core::clamp(vertex_pos.Z / BS + 0.5, 0.0 - SMOOTH_LIGHTING_OVERSIZE, 1.0 + SMOOTH_LIGHTING_OVERSIZE); - f32 lightA = 0.0; - f32 lightB = 0.0; + f32 lightDay = 0.0; // daylight + f32 lightNight = 0.0; + f32 lightBoosted = 0.0; // daylight + direct sunlight, if any for (int k = 0; k < 8; ++k) { f32 dx = (k & 4) ? x : 1 - x; f32 dy = (k & 2) ? y : 1 - y; f32 dz = (k & 1) ? z : 1 - z; - lightA += dx * dy * dz * frame.lightsA[k]; - lightB += dx * dy * dz * frame.lightsB[k]; + // Use direct sunlight (255), if any; use daylight otherwise. + f32 light_boosted = frame.sunlight[k] ? 255 : frame.lightsDay[k]; + lightDay += dx * dy * dz * frame.lightsDay[k]; + lightNight += dx * dy * dz * frame.lightsNight[k]; + lightBoosted += dx * dy * dz * light_boosted; } - return LightPair(lightA, lightB); + return LightInfo{lightDay, lightNight, lightBoosted}; } // Calculates vertex color to be used in mapblock mesh @@ -311,14 +328,15 @@ LightPair MapblockMeshGenerator::blendLight(const v3f &vertex_pos) // tile_color - node's tile color video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos) { - LightPair light = blendLight(vertex_pos); - return encode_light(light, f->light_source); + LightInfo light = blendLight(vertex_pos); + return encode_light(light.getPair(), f->light_source); } video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal) { - video::SColor color = blendLightColor(vertex_pos); + LightInfo light = blendLight(vertex_pos); + video::SColor color = encode_light(light.getPair(MYMAX(0.0f, vertex_normal.Y)), f->light_source); if (!f->light_source) applyFacesShading(color, vertex_normal); return color; @@ -365,7 +383,7 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc, tile_count = 1; } if (data->m_smooth_lighting) { - LightPair lights[8]; + LightInfo lights[8]; for (int j = 0; j < 8; ++j) { v3f d; d.X = (j & 4) ? dx2 : dx1; @@ -403,7 +421,7 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing() // If this liquid emits light and doesn't contain light, draw // it at what it emits, for an increased effect u8 e = decode_light(f->light_source); - light = LightPair(std::max(e, light.lightA), std::max(e, light.lightB)); + light = LightPair(std::max(e, light.lightDay), std::max(e, light.lightNight)); } else if (nodedef->get(ntop).param_type == CPT_LIGHT) { // Otherwise, use the light of the node on top if possible light = LightPair(getInteriorLight(ntop, 0, nodedef)); diff --git a/src/content_mapblock.h b/src/content_mapblock.h index 7b90ce4b9..97947cdbe 100644 --- a/src/content_mapblock.h +++ b/src/content_mapblock.h @@ -26,21 +26,36 @@ struct MeshMakeData; struct MeshCollector; struct LightPair { - u8 lightA; - u8 lightB; + u8 lightDay; + u8 lightNight; LightPair() = default; - explicit LightPair(u16 value) : lightA(value & 0xff), lightB(value >> 8) {} - LightPair(u8 valueA, u8 valueB) : lightA(valueA), lightB(valueB) {} + explicit LightPair(u16 value) : lightDay(value & 0xff), lightNight(value >> 8) {} + LightPair(u8 valueA, u8 valueB) : lightDay(valueA), lightNight(valueB) {} LightPair(float valueA, float valueB) : - lightA(core::clamp(core::round32(valueA), 0, 255)), - lightB(core::clamp(core::round32(valueB), 0, 255)) {} - operator u16() const { return lightA | lightB << 8; } + lightDay(core::clamp(core::round32(valueA), 0, 255)), + lightNight(core::clamp(core::round32(valueB), 0, 255)) {} + operator u16() const { return lightDay | lightNight << 8; } +}; + +struct LightInfo { + float light_day; + float light_night; + float light_boosted; + + LightPair getPair(float sunlight_boost = 0.0) const + { + return LightPair( + (1 - sunlight_boost) * light_day + + sunlight_boost * light_boosted, + light_night); + } }; struct LightFrame { - f32 lightsA[8]; - f32 lightsB[8]; + f32 lightsDay[8]; + f32 lightsNight[8]; + bool sunlight[8]; }; class MapblockMeshGenerator @@ -69,7 +84,7 @@ public: // lighting void getSmoothLightFrame(); - LightPair blendLight(const v3f &vertex_pos); + LightInfo blendLight(const v3f &vertex_pos); video::SColor blendLightColor(const v3f &vertex_pos); video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal); @@ -85,7 +100,7 @@ public: // cuboid drawing! void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount, - const LightPair *lights , const f32 *txc); + const LightInfo *lights , const f32 *txc); void generateCuboidTextureCoords(aabb3f const &box, f32 *coords); void drawAutoLightedCuboid(aabb3f box, const f32 *txc = NULL, TileSpec *tiles = NULL, int tile_count = 0); diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index bdf791c0b..6a94e78df 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -196,6 +196,7 @@ static u16 getSmoothLightCombined(const v3s16 &p, u8 light_source_max = 0; u16 light_day = 0; u16 light_night = 0; + bool direct_sunlight = false; auto add_node = [&] (u8 i, bool obstructed = false) -> bool { if (obstructed) { @@ -210,8 +211,12 @@ static u16 getSmoothLightCombined(const v3s16 &p, light_source_max = f.light_source; // Check f.solidness because fast-style leaves look better this way if (f.param_type == CPT_LIGHT && f.solidness != 2) { - light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f)); - light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f)); + u8 light_level_day = n.getLightNoChecks(LIGHTBANK_DAY, &f); + u8 light_level_night = n.getLightNoChecks(LIGHTBANK_NIGHT, &f); + if (light_level_day == LIGHT_SUN) + direct_sunlight = true; + light_day += decode_light(light_level_day); + light_night += decode_light(light_level_night); light_count++; } else { ambient_occlusion++; @@ -243,6 +248,10 @@ static u16 getSmoothLightCombined(const v3s16 &p, light_night /= light_count; } + // boost direct sunlight, if any + if (direct_sunlight) + light_day = 0xFF; + // Boost brightness around light sources bool skip_ambient_occlusion_day = false; if (decode_light(light_source_max) >= light_day) { -- 2.25.1