mirror of
https://github.com/minetest/minetest.git
synced 2024-12-24 15:12:23 +01:00
Avoid rendering invisible faces of simple nodeboxes (#12262)
* Skip rendering faces adjacent to opaque nodes * Cancel out opposite faces of adjacent nodebox nodes of the same type Fixes #6409
This commit is contained in:
parent
89c82035d8
commit
cc56ebd90d
@ -150,8 +150,10 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
|
||||
// should be (2+2)*6=24 values in the list. The order of
|
||||
// the faces in the list is up-down-right-left-back-front
|
||||
// (compatible with ContentFeatures).
|
||||
// mask - a bit mask that suppresses drawing of tiles.
|
||||
// tile i will not be drawn if mask & (1 << i) is 1
|
||||
void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
|
||||
TileSpec *tiles, int tilecount, const LightInfo *lights, const f32 *txc)
|
||||
TileSpec *tiles, int tilecount, const LightInfo *lights, const f32 *txc, u8 mask)
|
||||
{
|
||||
assert(tilecount >= 1 && tilecount <= 6); // pre-condition
|
||||
|
||||
@ -274,6 +276,8 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
|
||||
|
||||
// Add to mesh collector
|
||||
for (int k = 0; k < 6; ++k) {
|
||||
if (mask & (1 << k))
|
||||
continue;
|
||||
int tileindex = MYMIN(k, tilecount - 1);
|
||||
collector->append(tiles[tileindex], vertices + 4 * k, 4, quad_indices, 6);
|
||||
}
|
||||
@ -363,7 +367,7 @@ void MapblockMeshGenerator::generateCuboidTextureCoords(const aabb3f &box, f32 *
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
|
||||
TileSpec *tiles, int tile_count)
|
||||
TileSpec *tiles, int tile_count, u8 mask)
|
||||
{
|
||||
bool scale = std::fabs(f->visual_scale - 1.0f) > 1e-3f;
|
||||
f32 texture_coord_buf[24];
|
||||
@ -403,12 +407,49 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
|
||||
d.Z = (j & 1) ? dz2 : dz1;
|
||||
lights[j] = blendLight(d);
|
||||
}
|
||||
drawCuboid(box, tiles, tile_count, lights, txc);
|
||||
drawCuboid(box, tiles, tile_count, lights, txc, mask);
|
||||
} else {
|
||||
drawCuboid(box, tiles, tile_count, nullptr, txc);
|
||||
drawCuboid(box, tiles, tile_count, nullptr, txc, mask);
|
||||
}
|
||||
}
|
||||
|
||||
u8 MapblockMeshGenerator::getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const
|
||||
{
|
||||
const f32 NODE_BOUNDARY = 0.5 * BS;
|
||||
|
||||
// For an oversized nodebox, return immediately
|
||||
if (box.MaxEdge.X > NODE_BOUNDARY ||
|
||||
box.MinEdge.X < -NODE_BOUNDARY ||
|
||||
box.MaxEdge.Y > NODE_BOUNDARY ||
|
||||
box.MinEdge.Y < -NODE_BOUNDARY ||
|
||||
box.MaxEdge.Z > NODE_BOUNDARY ||
|
||||
box.MinEdge.Z < -NODE_BOUNDARY)
|
||||
return 0;
|
||||
|
||||
// We can skip faces at node boundary if the matching neighbor is solid
|
||||
u8 solid_mask =
|
||||
(box.MaxEdge.Y == NODE_BOUNDARY ? 1 : 0) |
|
||||
(box.MinEdge.Y == -NODE_BOUNDARY ? 2 : 0) |
|
||||
(box.MaxEdge.X == NODE_BOUNDARY ? 4 : 0) |
|
||||
(box.MinEdge.X == -NODE_BOUNDARY ? 8 : 0) |
|
||||
(box.MaxEdge.Z == NODE_BOUNDARY ? 16 : 0) |
|
||||
(box.MinEdge.Z == -NODE_BOUNDARY ? 32 : 0);
|
||||
|
||||
u8 sametype_mask = 0;
|
||||
if (f->alpha == AlphaMode::ALPHAMODE_OPAQUE) {
|
||||
// In opaque nodeboxes, faces on opposite sides can cancel
|
||||
// each other out if there is a matching neighbor of the same type
|
||||
sametype_mask =
|
||||
((solid_mask & 3) == 3 ? 3 : 0) |
|
||||
((solid_mask & 12) == 12 ? 12 : 0) |
|
||||
((solid_mask & 48) == 48 ? 48 : 0);
|
||||
}
|
||||
|
||||
// Combine masks with actual neighbors to get the faces to be skipped
|
||||
return (solid_mask & solid_neighbors) | (sametype_mask & sametype_neighbors);
|
||||
}
|
||||
|
||||
|
||||
void MapblockMeshGenerator::prepareLiquidNodeDrawing()
|
||||
{
|
||||
getSpecialTile(0, &tile_liquid_top);
|
||||
@ -1366,13 +1407,38 @@ void MapblockMeshGenerator::drawNodeboxNode()
|
||||
getTile(nodebox_tile_dirs[face], &tiles[face]);
|
||||
}
|
||||
|
||||
bool param2_is_rotation =
|
||||
f->param_type_2 == CPT2_COLORED_FACEDIR ||
|
||||
f->param_type_2 == CPT2_COLORED_WALLMOUNTED ||
|
||||
f->param_type_2 == CPT2_FACEDIR ||
|
||||
f->param_type_2 == CPT2_WALLMOUNTED;
|
||||
|
||||
bool param2_is_level =
|
||||
f->param_type_2 == CPT2_LEVELED;
|
||||
|
||||
// locate possible neighboring nodes to connect to
|
||||
u8 neighbors_set = 0;
|
||||
if (f->node_box.type == NODEBOX_CONNECTED) {
|
||||
for (int dir = 0; dir != 6; dir++) {
|
||||
u8 flag = 1 << dir;
|
||||
v3s16 p2 = blockpos_nodes + p + nodebox_connection_dirs[dir];
|
||||
MapNode n2 = data->m_vmanip.getNodeNoEx(p2);
|
||||
u8 solid_neighbors = 0;
|
||||
u8 sametype_neighbors = 0;
|
||||
for (int dir = 0; dir != 6; dir++) {
|
||||
u8 flag = 1 << dir;
|
||||
v3s16 p2 = blockpos_nodes + p + nodebox_tile_dirs[dir];
|
||||
MapNode n2 = data->m_vmanip.getNodeNoEx(p2);
|
||||
|
||||
// mark neighbors that are the same node type
|
||||
// and have the same rotation or higher level stored as param2
|
||||
if (n2.param0 == n.param0 &&
|
||||
(!param2_is_rotation || n.param2 == n2.param2) &&
|
||||
(!param2_is_level || n.param2 <= n2.param2))
|
||||
sametype_neighbors |= flag;
|
||||
|
||||
// mark neighbors that are simple solid blocks
|
||||
if (nodedef->get(n2).drawtype == NDT_NORMAL)
|
||||
solid_neighbors |= flag;
|
||||
|
||||
if (f->node_box.type == NODEBOX_CONNECTED) {
|
||||
p2 = blockpos_nodes + p + nodebox_connection_dirs[dir];
|
||||
n2 = data->m_vmanip.getNodeNoEx(p2);
|
||||
if (nodedef->nodeboxConnects(n, n2, flag))
|
||||
neighbors_set |= flag;
|
||||
}
|
||||
@ -1433,8 +1499,10 @@ void MapblockMeshGenerator::drawNodeboxNode()
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &box : boxes)
|
||||
drawAutoLightedCuboid(box, nullptr, tiles, 6);
|
||||
for (auto &box : boxes) {
|
||||
u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors);
|
||||
drawAutoLightedCuboid(box, nullptr, tiles, 6, mask);
|
||||
}
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawMeshNode()
|
||||
|
@ -100,10 +100,11 @@ public:
|
||||
|
||||
// cuboid drawing!
|
||||
void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount,
|
||||
const LightInfo *lights , const f32 *txc);
|
||||
const LightInfo *lights , const f32 *txc, u8 mask = 0);
|
||||
void generateCuboidTextureCoords(aabb3f const &box, f32 *coords);
|
||||
void drawAutoLightedCuboid(aabb3f box, const f32 *txc = NULL,
|
||||
TileSpec *tiles = NULL, int tile_count = 0);
|
||||
TileSpec *tiles = NULL, int tile_count = 0, u8 mask = 0);
|
||||
u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const;
|
||||
|
||||
// liquid-specific
|
||||
bool top_is_same_liquid;
|
||||
|
Loading…
Reference in New Issue
Block a user