mirror of
https://github.com/minetest/minetest.git
synced 2025-01-12 08:17:31 +01:00
Smooth lighting: Fix light leaking through edge-connected corners
For solid nodes, the lighting at a corner becomes face-dependent, which means that only the four nodes in face-direction contribute to the lighting (getSmoothLightSolid). For special nodes, which use the lighting values at the eight corners of a node, the lighting is not face-dependent, but certain nodes of the eight surrounding nodes of a corner (here indices 4, 5, 6 and 7) can be obstructed. Ambient occlusion now also occurs for solid nodes, if two, three or four of the four nodes in face-direction are solid.
This commit is contained in:
parent
1ff5c20442
commit
2cf9014160
@ -276,7 +276,7 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
|
|||||||
void MapblockMeshGenerator::getSmoothLightFrame()
|
void MapblockMeshGenerator::getSmoothLightFrame()
|
||||||
{
|
{
|
||||||
for (int k = 0; k < 8; ++k) {
|
for (int k = 0; k < 8; ++k) {
|
||||||
u16 light = getSmoothLight(blockpos_nodes + p, light_dirs[k], data);
|
u16 light = getSmoothLightTransparent(blockpos_nodes + p, light_dirs[k], data);
|
||||||
frame.lightsA[k] = light & 0xff;
|
frame.lightsA[k] = light & 0xff;
|
||||||
frame.lightsB[k] = light >> 8;
|
frame.lightsB[k] = light >> 8;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "content_mapblock.h"
|
#include "content_mapblock.h"
|
||||||
#include "util/directiontables.h"
|
#include "util/directiontables.h"
|
||||||
#include "client/renderingengine.h"
|
#include "client/renderingengine.h"
|
||||||
|
#include <array>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MeshMakeData
|
MeshMakeData
|
||||||
@ -68,7 +69,7 @@ void MeshMakeData::fill(MapBlock *block)
|
|||||||
|
|
||||||
fillBlockData(v3s16(0,0,0), block->getData());
|
fillBlockData(v3s16(0,0,0), block->getData());
|
||||||
|
|
||||||
// Get map for reading neigbhor blocks
|
// Get map for reading neighbor blocks
|
||||||
Map *map = block->getParent();
|
Map *map = block->getParent();
|
||||||
|
|
||||||
for (const v3s16 &dir : g_26dirs) {
|
for (const v3s16 &dir : g_26dirs) {
|
||||||
@ -194,19 +195,9 @@ u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
|
|||||||
Calculate smooth lighting at the XYZ- corner of p.
|
Calculate smooth lighting at the XYZ- corner of p.
|
||||||
Both light banks
|
Both light banks
|
||||||
*/
|
*/
|
||||||
static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
|
static u16 getSmoothLightCombined(const v3s16 &p,
|
||||||
|
const std::array<v3s16,8> &dirs, MeshMakeData *data, bool node_solid)
|
||||||
{
|
{
|
||||||
static const v3s16 dirs8[8] = {
|
|
||||||
v3s16(0,0,0),
|
|
||||||
v3s16(0,0,1),
|
|
||||||
v3s16(0,1,0),
|
|
||||||
v3s16(0,1,1),
|
|
||||||
v3s16(1,0,0),
|
|
||||||
v3s16(1,1,0),
|
|
||||||
v3s16(1,0,1),
|
|
||||||
v3s16(1,1,1),
|
|
||||||
};
|
|
||||||
|
|
||||||
INodeDefManager *ndef = data->m_client->ndef();
|
INodeDefManager *ndef = data->m_client->ndef();
|
||||||
|
|
||||||
u16 ambient_occlusion = 0;
|
u16 ambient_occlusion = 0;
|
||||||
@ -215,32 +206,58 @@ static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
|
|||||||
u16 light_day = 0;
|
u16 light_day = 0;
|
||||||
u16 light_night = 0;
|
u16 light_night = 0;
|
||||||
|
|
||||||
for (const v3s16 &dir : dirs8) {
|
auto add_node = [&] (int i) -> const ContentFeatures& {
|
||||||
MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dir);
|
MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
|
||||||
|
|
||||||
// if it's CONTENT_IGNORE we can't do any light calculations
|
|
||||||
if (n.getContent() == CONTENT_IGNORE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const ContentFeatures &f = ndef->get(n);
|
const ContentFeatures &f = ndef->get(n);
|
||||||
if (f.light_source > light_source_max)
|
if (f.light_source > light_source_max)
|
||||||
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));
|
light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
|
||||||
light_night += decode_light(
|
light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
|
||||||
n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
|
|
||||||
light_count++;
|
light_count++;
|
||||||
} else {
|
} else {
|
||||||
ambient_occlusion++;
|
ambient_occlusion++;
|
||||||
}
|
}
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (node_solid) {
|
||||||
|
ambient_occlusion = 3;
|
||||||
|
bool corner_obstructed = true;
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
if (add_node(i).light_propagates)
|
||||||
|
corner_obstructed = false;
|
||||||
|
}
|
||||||
|
add_node(2);
|
||||||
|
add_node(3);
|
||||||
|
if (corner_obstructed)
|
||||||
|
ambient_occlusion++;
|
||||||
|
else
|
||||||
|
add_node(4);
|
||||||
|
} else {
|
||||||
|
std::array<bool, 4> obstructed = {{ 1, 1, 1, 1 }};
|
||||||
|
add_node(0);
|
||||||
|
bool opaque1 = !add_node(1).light_propagates;
|
||||||
|
bool opaque2 = !add_node(2).light_propagates;
|
||||||
|
bool opaque3 = !add_node(3).light_propagates;
|
||||||
|
obstructed[0] = opaque1 && opaque2;
|
||||||
|
obstructed[1] = opaque1 && opaque3;
|
||||||
|
obstructed[2] = opaque2 && opaque3;
|
||||||
|
for (int k = 0; k < 4; ++k) {
|
||||||
|
if (obstructed[k])
|
||||||
|
ambient_occlusion++;
|
||||||
|
else if (add_node(k + 4).light_propagates)
|
||||||
|
obstructed[3] = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(light_count == 0)
|
if (light_count == 0) {
|
||||||
return 0xffff;
|
light_day = light_night = 0;
|
||||||
|
} else {
|
||||||
light_day /= light_count;
|
light_day /= light_count;
|
||||||
light_night /= light_count;
|
light_night /= light_count;
|
||||||
|
}
|
||||||
|
|
||||||
// Boost brightness around light sources
|
// Boost brightness around light sources
|
||||||
bool skip_ambient_occlusion_day = false;
|
bool skip_ambient_occlusion_day = false;
|
||||||
@ -283,20 +300,70 @@ static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
|
|||||||
/*
|
/*
|
||||||
Calculate smooth lighting at the given corner of p.
|
Calculate smooth lighting at the given corner of p.
|
||||||
Both light banks.
|
Both light banks.
|
||||||
|
Node at p is solid, and thus the lighting is face-dependent.
|
||||||
*/
|
*/
|
||||||
u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
|
u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
|
||||||
{
|
{
|
||||||
if (corner.X == 1)
|
v3s16 neighbor_offset1, neighbor_offset2;
|
||||||
++p.X;
|
|
||||||
// else corner.X == -1
|
|
||||||
if (corner.Y == 1)
|
|
||||||
++p.Y;
|
|
||||||
// else corner.Y == -1
|
|
||||||
if (corner.Z == 1)
|
|
||||||
++p.Z;
|
|
||||||
// else corner.Z == -1
|
|
||||||
|
|
||||||
return getSmoothLightCombined(p, data);
|
/*
|
||||||
|
* face_dir, neighbor_offset1 and neighbor_offset2 define an
|
||||||
|
* orthonormal basis which is used to define the offsets of the 8
|
||||||
|
* surrounding nodes and to differentiate the "distance" (by going only
|
||||||
|
* along directly neighboring nodes) relative to the node at p.
|
||||||
|
* Apart from the node at p, only the 4 nodes which contain face_dir
|
||||||
|
* can contribute light.
|
||||||
|
*/
|
||||||
|
if (face_dir.X != 0) {
|
||||||
|
neighbor_offset1 = v3s16(0, corner.Y, 0);
|
||||||
|
neighbor_offset2 = v3s16(0, 0, corner.Z);
|
||||||
|
} else if (face_dir.Y != 0) {
|
||||||
|
neighbor_offset1 = v3s16(0, 0, corner.Z);
|
||||||
|
neighbor_offset2 = v3s16(corner.X, 0, 0);
|
||||||
|
} else if (face_dir.Z != 0) {
|
||||||
|
neighbor_offset1 = v3s16(corner.X,0,0);
|
||||||
|
neighbor_offset2 = v3s16(0,corner.Y,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array<v3s16,8> dirs = {{
|
||||||
|
// Always shine light
|
||||||
|
neighbor_offset1 + face_dir,
|
||||||
|
neighbor_offset2 + face_dir,
|
||||||
|
v3s16(0,0,0),
|
||||||
|
face_dir,
|
||||||
|
|
||||||
|
// Can be obstructed
|
||||||
|
neighbor_offset1 + neighbor_offset2 + face_dir,
|
||||||
|
|
||||||
|
// Do not shine light, only for ambient occlusion
|
||||||
|
neighbor_offset1,
|
||||||
|
neighbor_offset2,
|
||||||
|
neighbor_offset1 + neighbor_offset2
|
||||||
|
}};
|
||||||
|
return getSmoothLightCombined(p, dirs, data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calculate smooth lighting at the given corner of p.
|
||||||
|
Both light banks.
|
||||||
|
Node at p is not solid, and the lighting is not face-dependent.
|
||||||
|
*/
|
||||||
|
u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data)
|
||||||
|
{
|
||||||
|
const std::array<v3s16,8> dirs = {{
|
||||||
|
// Always shine light
|
||||||
|
v3s16(0,0,0),
|
||||||
|
v3s16(corner.X,0,0),
|
||||||
|
v3s16(0,corner.Y,0),
|
||||||
|
v3s16(0,0,corner.Z),
|
||||||
|
|
||||||
|
// Can be obstructed
|
||||||
|
v3s16(corner.X,corner.Y,0),
|
||||||
|
v3s16(corner.X,0,corner.Z),
|
||||||
|
v3s16(0,corner.Y,corner.Z),
|
||||||
|
v3s16(corner.X,corner.Y,corner.Z)
|
||||||
|
}};
|
||||||
|
return getSmoothLightCombined(p, dirs, data, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
|
void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
|
||||||
@ -816,7 +883,7 @@ static void getTileInfo(
|
|||||||
|
|
||||||
v3s16 light_p = blockpos_nodes + p_corrected;
|
v3s16 light_p = blockpos_nodes + p_corrected;
|
||||||
for (u16 i = 0; i < 4; i++)
|
for (u16 i = 0; i < 4; i++)
|
||||||
lights[i] = getSmoothLight(light_p, vertex_dirs[i], data);
|
lights[i] = getSmoothLightSolid(light_p, face_dir_corrected, vertex_dirs[i], data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +232,8 @@ video::SColor encode_light(u16 light, u8 emissive_light);
|
|||||||
// Compute light at node
|
// Compute light at node
|
||||||
u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef);
|
u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef);
|
||||||
u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef);
|
u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef);
|
||||||
u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data);
|
u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data);
|
||||||
|
u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns the sunlight's color from the current
|
* Returns the sunlight's color from the current
|
||||||
|
Loading…
Reference in New Issue
Block a user