Skip to content

Commit 2cf9014

Browse files
DTA7paramat
authored andcommittedOct 10, 2017
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.
1 parent 1ff5c20 commit 2cf9014

File tree

3 files changed

+110
-42
lines changed

3 files changed

+110
-42
lines changed
 

Diff for: ‎src/content_mapblock.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
276276
void MapblockMeshGenerator::getSmoothLightFrame()
277277
{
278278
for (int k = 0; k < 8; ++k) {
279-
u16 light = getSmoothLight(blockpos_nodes + p, light_dirs[k], data);
279+
u16 light = getSmoothLightTransparent(blockpos_nodes + p, light_dirs[k], data);
280280
frame.lightsA[k] = light & 0xff;
281281
frame.lightsB[k] = light >> 8;
282282
}

Diff for: ‎src/mapblock_mesh.cpp

+107-40
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2828
#include "content_mapblock.h"
2929
#include "util/directiontables.h"
3030
#include "client/renderingengine.h"
31+
#include <array>
3132

3233
/*
3334
MeshMakeData
@@ -68,7 +69,7 @@ void MeshMakeData::fill(MapBlock *block)
6869

6970
fillBlockData(v3s16(0,0,0), block->getData());
7071

71-
// Get map for reading neigbhor blocks
72+
// Get map for reading neighbor blocks
7273
Map *map = block->getParent();
7374

7475
for (const v3s16 &dir : g_26dirs) {
@@ -194,19 +195,9 @@ u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
194195
Calculate smooth lighting at the XYZ- corner of p.
195196
Both light banks
196197
*/
197-
static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
198+
static u16 getSmoothLightCombined(const v3s16 &p,
199+
const std::array<v3s16,8> &dirs, MeshMakeData *data, bool node_solid)
198200
{
199-
static const v3s16 dirs8[8] = {
200-
v3s16(0,0,0),
201-
v3s16(0,0,1),
202-
v3s16(0,1,0),
203-
v3s16(0,1,1),
204-
v3s16(1,0,0),
205-
v3s16(1,1,0),
206-
v3s16(1,0,1),
207-
v3s16(1,1,1),
208-
};
209-
210201
INodeDefManager *ndef = data->m_client->ndef();
211202

212203
u16 ambient_occlusion = 0;
@@ -215,32 +206,58 @@ static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
215206
u16 light_day = 0;
216207
u16 light_night = 0;
217208

218-
for (const v3s16 &dir : dirs8) {
219-
MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dir);
220-
221-
// if it's CONTENT_IGNORE we can't do any light calculations
222-
if (n.getContent() == CONTENT_IGNORE)
223-
continue;
224-
209+
auto add_node = [&] (int i) -> const ContentFeatures& {
210+
MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
225211
const ContentFeatures &f = ndef->get(n);
226212
if (f.light_source > light_source_max)
227213
light_source_max = f.light_source;
228214
// Check f.solidness because fast-style leaves look better this way
229215
if (f.param_type == CPT_LIGHT && f.solidness != 2) {
230216
light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
231-
light_night += decode_light(
232-
n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
217+
light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
233218
light_count++;
234219
} else {
235220
ambient_occlusion++;
236221
}
237-
}
222+
return f;
223+
};
238224

239-
if(light_count == 0)
240-
return 0xffff;
225+
if (node_solid) {
226+
ambient_occlusion = 3;
227+
bool corner_obstructed = true;
228+
for (int i = 0; i < 2; ++i) {
229+
if (add_node(i).light_propagates)
230+
corner_obstructed = false;
231+
}
232+
add_node(2);
233+
add_node(3);
234+
if (corner_obstructed)
235+
ambient_occlusion++;
236+
else
237+
add_node(4);
238+
} else {
239+
std::array<bool, 4> obstructed = {{ 1, 1, 1, 1 }};
240+
add_node(0);
241+
bool opaque1 = !add_node(1).light_propagates;
242+
bool opaque2 = !add_node(2).light_propagates;
243+
bool opaque3 = !add_node(3).light_propagates;
244+
obstructed[0] = opaque1 && opaque2;
245+
obstructed[1] = opaque1 && opaque3;
246+
obstructed[2] = opaque2 && opaque3;
247+
for (int k = 0; k < 4; ++k) {
248+
if (obstructed[k])
249+
ambient_occlusion++;
250+
else if (add_node(k + 4).light_propagates)
251+
obstructed[3] = false;
252+
}
253+
}
241254

242-
light_day /= light_count;
243-
light_night /= light_count;
255+
if (light_count == 0) {
256+
light_day = light_night = 0;
257+
} else {
258+
light_day /= light_count;
259+
light_night /= light_count;
260+
}
244261

245262
// Boost brightness around light sources
246263
bool skip_ambient_occlusion_day = false;
@@ -283,20 +300,70 @@ static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
283300
/*
284301
Calculate smooth lighting at the given corner of p.
285302
Both light banks.
303+
Node at p is solid, and thus the lighting is face-dependent.
286304
*/
287-
u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
305+
u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
288306
{
289-
if (corner.X == 1)
290-
++p.X;
291-
// else corner.X == -1
292-
if (corner.Y == 1)
293-
++p.Y;
294-
// else corner.Y == -1
295-
if (corner.Z == 1)
296-
++p.Z;
297-
// else corner.Z == -1
298-
299-
return getSmoothLightCombined(p, data);
307+
v3s16 neighbor_offset1, neighbor_offset2;
308+
309+
/*
310+
* face_dir, neighbor_offset1 and neighbor_offset2 define an
311+
* orthonormal basis which is used to define the offsets of the 8
312+
* surrounding nodes and to differentiate the "distance" (by going only
313+
* along directly neighboring nodes) relative to the node at p.
314+
* Apart from the node at p, only the 4 nodes which contain face_dir
315+
* can contribute light.
316+
*/
317+
if (face_dir.X != 0) {
318+
neighbor_offset1 = v3s16(0, corner.Y, 0);
319+
neighbor_offset2 = v3s16(0, 0, corner.Z);
320+
} else if (face_dir.Y != 0) {
321+
neighbor_offset1 = v3s16(0, 0, corner.Z);
322+
neighbor_offset2 = v3s16(corner.X, 0, 0);
323+
} else if (face_dir.Z != 0) {
324+
neighbor_offset1 = v3s16(corner.X,0,0);
325+
neighbor_offset2 = v3s16(0,corner.Y,0);
326+
}
327+
328+
const std::array<v3s16,8> dirs = {{
329+
// Always shine light
330+
neighbor_offset1 + face_dir,
331+
neighbor_offset2 + face_dir,
332+
v3s16(0,0,0),
333+
face_dir,
334+
335+
// Can be obstructed
336+
neighbor_offset1 + neighbor_offset2 + face_dir,
337+
338+
// Do not shine light, only for ambient occlusion
339+
neighbor_offset1,
340+
neighbor_offset2,
341+
neighbor_offset1 + neighbor_offset2
342+
}};
343+
return getSmoothLightCombined(p, dirs, data, true);
344+
}
345+
346+
/*
347+
Calculate smooth lighting at the given corner of p.
348+
Both light banks.
349+
Node at p is not solid, and the lighting is not face-dependent.
350+
*/
351+
u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data)
352+
{
353+
const std::array<v3s16,8> dirs = {{
354+
// Always shine light
355+
v3s16(0,0,0),
356+
v3s16(corner.X,0,0),
357+
v3s16(0,corner.Y,0),
358+
v3s16(0,0,corner.Z),
359+
360+
// Can be obstructed
361+
v3s16(corner.X,corner.Y,0),
362+
v3s16(corner.X,0,corner.Z),
363+
v3s16(0,corner.Y,corner.Z),
364+
v3s16(corner.X,corner.Y,corner.Z)
365+
}};
366+
return getSmoothLightCombined(p, dirs, data, false);
300367
}
301368

302369
void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
@@ -816,7 +883,7 @@ static void getTileInfo(
816883

817884
v3s16 light_p = blockpos_nodes + p_corrected;
818885
for (u16 i = 0; i < 4; i++)
819-
lights[i] = getSmoothLight(light_p, vertex_dirs[i], data);
886+
lights[i] = getSmoothLightSolid(light_p, face_dir_corrected, vertex_dirs[i], data);
820887
}
821888
}
822889

Diff for: ‎src/mapblock_mesh.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ video::SColor encode_light(u16 light, u8 emissive_light);
232232
// Compute light at node
233233
u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef);
234234
u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef);
235-
u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data);
235+
u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data);
236+
u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data);
236237

237238
/*!
238239
* Returns the sunlight's color from the current

0 commit comments

Comments
 (0)
Please sign in to comment.