Fix node-nodebox lighting difference in direct sunlight (#7061)
authorVitaliy <silverunicorn2011@yandex.ru>
Sat, 17 Mar 2018 09:10:16 +0000 (12:10 +0300)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Sat, 17 Mar 2018 09:10:16 +0000 (10:10 +0100)
src/content_mapblock.cpp
src/content_mapblock.h
src/mapblock_mesh.cpp

index 69982c335234f8b55823b7ccc5d8e5c7d0d94d2f..348748c911882d4690e42cbe04bfc0cc6b16b788 100644 (file)
@@ -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));
index 7b90ce4b9081cb4c28502058e8444b5863ce6763..97947cdbe093bea1b9d1ea739fee0943719aaf8b 100644 (file)
@@ -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);
index bdf791c0bf1aae335cff5406c264cda47964ad1f..6a94e78df1cb1f37f61b263ad71d2812bd17924a 100644 (file)
@@ -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) {