Fix node-nodebox lighting difference in direct sunlight (#7061)

This commit is contained in:
Vitaliy 2018-03-17 12:10:16 +03:00 committed by Loïc Blot
parent b1c0e9953f
commit 0358ae789a
3 changed files with 71 additions and 29 deletions

@ -151,7 +151,7 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
// the faces in the list is up-down-right-left-back-front // the faces in the list is up-down-right-left-back-front
// (compatible with ContentFeatures). // (compatible with ContentFeatures).
void MapblockMeshGenerator::drawCuboid(const aabb3f &box, 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 assert(tilecount >= 1 && tilecount <= 6); // pre-condition
@ -263,10 +263,12 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
if (data->m_smooth_lighting) { if (data->m_smooth_lighting) {
for (int j = 0; j < 24; ++j) { 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); f->light_source);
if (!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 // Gets the base lighting values for a node
void MapblockMeshGenerator::getSmoothLightFrame() void MapblockMeshGenerator::getSmoothLightFrame()
{ {
for (int k = 0; k < 8; ++k)
frame.sunlight[k] = false;
for (int k = 0; k < 8; ++k) { for (int k = 0; k < 8; ++k) {
LightPair light(getSmoothLightTransparent(blockpos_nodes + p, light_dirs[k], data)); LightPair light(getSmoothLightTransparent(blockpos_nodes + p, light_dirs[k], data));
frame.lightsA[k] = light.lightA; frame.lightsDay[k] = light.lightDay;
frame.lightsB[k] = light.lightB; 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 // Calculates vertex light level
// vertex_pos - vertex position in the node (coordinates are clamped to [0.0, 1.0] or so) // 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 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 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 z = core::clamp(vertex_pos.Z / BS + 0.5, 0.0 - SMOOTH_LIGHTING_OVERSIZE, 1.0 + SMOOTH_LIGHTING_OVERSIZE);
f32 lightA = 0.0; f32 lightDay = 0.0; // daylight
f32 lightB = 0.0; f32 lightNight = 0.0;
f32 lightBoosted = 0.0; // daylight + direct sunlight, if any
for (int k = 0; k < 8; ++k) { for (int k = 0; k < 8; ++k) {
f32 dx = (k & 4) ? x : 1 - x; f32 dx = (k & 4) ? x : 1 - x;
f32 dy = (k & 2) ? y : 1 - y; f32 dy = (k & 2) ? y : 1 - y;
f32 dz = (k & 1) ? z : 1 - z; f32 dz = (k & 1) ? z : 1 - z;
lightA += dx * dy * dz * frame.lightsA[k]; // Use direct sunlight (255), if any; use daylight otherwise.
lightB += dx * dy * dz * frame.lightsB[k]; 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 // 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 // tile_color - node's tile color
video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos) video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos)
{ {
LightPair light = blendLight(vertex_pos); LightInfo light = blendLight(vertex_pos);
return encode_light(light, f->light_source); return encode_light(light.getPair(), f->light_source);
} }
video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos, video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos,
const v3f &vertex_normal) 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) if (!f->light_source)
applyFacesShading(color, vertex_normal); applyFacesShading(color, vertex_normal);
return color; return color;
@ -365,7 +383,7 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
tile_count = 1; tile_count = 1;
} }
if (data->m_smooth_lighting) { if (data->m_smooth_lighting) {
LightPair lights[8]; LightInfo lights[8];
for (int j = 0; j < 8; ++j) { for (int j = 0; j < 8; ++j) {
v3f d; v3f d;
d.X = (j & 4) ? dx2 : dx1; d.X = (j & 4) ? dx2 : dx1;
@ -403,7 +421,7 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing()
// If this liquid emits light and doesn't contain light, draw // If this liquid emits light and doesn't contain light, draw
// it at what it emits, for an increased effect // it at what it emits, for an increased effect
u8 e = decode_light(f->light_source); 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) { } else if (nodedef->get(ntop).param_type == CPT_LIGHT) {
// Otherwise, use the light of the node on top if possible // Otherwise, use the light of the node on top if possible
light = LightPair(getInteriorLight(ntop, 0, nodedef)); light = LightPair(getInteriorLight(ntop, 0, nodedef));

@ -26,21 +26,36 @@ struct MeshMakeData;
struct MeshCollector; struct MeshCollector;
struct LightPair { struct LightPair {
u8 lightA; u8 lightDay;
u8 lightB; u8 lightNight;
LightPair() = default; LightPair() = default;
explicit LightPair(u16 value) : lightA(value & 0xff), lightB(value >> 8) {} explicit LightPair(u16 value) : lightDay(value & 0xff), lightNight(value >> 8) {}
LightPair(u8 valueA, u8 valueB) : lightA(valueA), lightB(valueB) {} LightPair(u8 valueA, u8 valueB) : lightDay(valueA), lightNight(valueB) {}
LightPair(float valueA, float valueB) : LightPair(float valueA, float valueB) :
lightA(core::clamp(core::round32(valueA), 0, 255)), lightDay(core::clamp(core::round32(valueA), 0, 255)),
lightB(core::clamp(core::round32(valueB), 0, 255)) {} lightNight(core::clamp(core::round32(valueB), 0, 255)) {}
operator u16() const { return lightA | lightB << 8; } 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 { struct LightFrame {
f32 lightsA[8]; f32 lightsDay[8];
f32 lightsB[8]; f32 lightsNight[8];
bool sunlight[8];
}; };
class MapblockMeshGenerator class MapblockMeshGenerator
@ -69,7 +84,7 @@ public:
// lighting // lighting
void getSmoothLightFrame(); 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);
video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal); video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal);
@ -85,7 +100,7 @@ public:
// cuboid drawing! // cuboid drawing!
void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount, 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 generateCuboidTextureCoords(aabb3f const &box, f32 *coords);
void drawAutoLightedCuboid(aabb3f box, const f32 *txc = NULL, void drawAutoLightedCuboid(aabb3f box, const f32 *txc = NULL,
TileSpec *tiles = NULL, int tile_count = 0); TileSpec *tiles = NULL, int tile_count = 0);

@ -196,6 +196,7 @@ static u16 getSmoothLightCombined(const v3s16 &p,
u8 light_source_max = 0; u8 light_source_max = 0;
u16 light_day = 0; u16 light_day = 0;
u16 light_night = 0; u16 light_night = 0;
bool direct_sunlight = false;
auto add_node = [&] (u8 i, bool obstructed = false) -> bool { auto add_node = [&] (u8 i, bool obstructed = false) -> bool {
if (obstructed) { if (obstructed) {
@ -210,8 +211,12 @@ static u16 getSmoothLightCombined(const v3s16 &p,
light_source_max = f.light_source; light_source_max = f.light_source;
// Check f.solidness because fast-style leaves look better this way // Check f.solidness because fast-style leaves look better this way
if (f.param_type == CPT_LIGHT && f.solidness != 2) { if (f.param_type == CPT_LIGHT && f.solidness != 2) {
light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f)); u8 light_level_day = n.getLightNoChecks(LIGHTBANK_DAY, &f);
light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &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++; light_count++;
} else { } else {
ambient_occlusion++; ambient_occlusion++;
@ -243,6 +248,10 @@ static u16 getSmoothLightCombined(const v3s16 &p,
light_night /= light_count; light_night /= light_count;
} }
// boost direct sunlight, if any
if (direct_sunlight)
light_day = 0xFF;
// Boost brightness around light sources // Boost brightness around light sources
bool skip_ambient_occlusion_day = false; bool skip_ambient_occlusion_day = false;
if (decode_light(light_source_max) >= light_day) { if (decode_light(light_source_max) >= light_day) {