1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Fix texture coordinates of cuboid drawtypes (#16091)

Fixes issues related to combining animated and world-aligned textures.
Changes texture coordinates of cuboid drawtypes to stay in the [0,1] range, instead of carrying the mapblock alignment and becoming negative after transformations.
This commit is contained in:
cx384 2025-05-24 15:59:32 +02:00 committed by GitHub
parent 2f1171e2a7
commit d17f22f536
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 80 additions and 47 deletions

View file

@ -137,11 +137,20 @@ void MapblockMeshGenerator::drawQuad(const TileSpec &tile, v3f *coords, const v3
} }
static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box, static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box,
const f32 *txc, const TileSpec *tiles, int tilecount) const f32 *txc, const TileSpec *tiles, int tilecount, v3s16 alignment)
{ {
v3f min = box.MinEdge; v3f min = box.MinEdge;
v3f max = box.MaxEdge; v3f max = box.MaxEdge;
// Texture coords are [0,1] if not specified otherwise
f32 uniform_txc[24];
if (!txc) {
for (int i = 0; i != 24; ++i) {
uniform_txc[i] = (i % 4 < 2) ? 0.0f : 1.0f;
}
txc = uniform_txc;
}
std::array<video::S3DVertex, 24> vertices = {{ std::array<video::S3DVertex, 24> vertices = {{
// top // top
video::S3DVertex(min.X, max.Y, max.Z, 0, 1, 0, {}, txc[0], txc[1]), video::S3DVertex(min.X, max.Y, max.Z, 0, 1, 0, {}, txc[0], txc[1]),
@ -185,15 +194,47 @@ static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box,
case TileRotation::None: case TileRotation::None:
break; break;
case TileRotation::R90: case TileRotation::R90:
tcoords.set(-tcoords.Y, tcoords.X); tcoords.set(1 - tcoords.Y, tcoords.X);
break; break;
case TileRotation::R180: case TileRotation::R180:
tcoords.set(-tcoords.X, -tcoords.Y); tcoords.set(1 - tcoords.X, 1 - tcoords.Y);
break; break;
case TileRotation::R270: case TileRotation::R270:
tcoords.set(tcoords.Y, -tcoords.X); tcoords.set(tcoords.Y, 1 - tcoords.X);
break; break;
} }
if (tile.world_aligned) {
// Maps uv dimension of every face to world dimension xyz
constexpr int coord_dim[12] = {
0, 2, // up
0, 2, // down
2, 1, // right
2, 1, // left
0, 1, // back
0, 1, // front
};
auto scale = tile.layers[0].scale;
f32 scale_factor = 1.0f / scale;
float x = alignment[coord_dim[face*2]] % scale;
float y = alignment[coord_dim[face*2 + 1]] % scale;
// Faces grow in different directions
if (face != 1) {
y = tcoords.Y + ((scale-1)-y);
} else {
y = tcoords.Y + y;
}
if (face == 3 || face == 4) {
x = tcoords.X + ((scale-1)-x);
} else {
x = tcoords.X + x;
}
tcoords.set(x * scale_factor, y * scale_factor);
}
} }
} }
@ -212,6 +253,7 @@ enum class QuadDiagonal {
// for the opposite corners of each face - therefore, there // for the opposite corners of each face - therefore, there
// should be (2+2)*6=24 values in the list. The order of // 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 // the faces in the list is up-down-right-left-back-front
// if nullptr use standard [0,1] coords
// (compatible with ContentFeatures). // (compatible with ContentFeatures).
// mask - a bit mask that suppresses drawing of tiles. // mask - a bit mask that suppresses drawing of tiles.
// tile i will not be drawn if mask & (1 << i) is 1 // tile i will not be drawn if mask & (1 << i) is 1
@ -224,7 +266,7 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
{ {
assert(tilecount >= 1 && tilecount <= 6); // pre-condition assert(tilecount >= 1 && tilecount <= 6); // pre-condition
auto vertices = setupCuboidVertices(box, txc, tiles, tilecount); auto vertices = setupCuboidVertices(box, txc, tiles, tilecount, cur_node.p);
for (int k = 0; k < 6; ++k) { for (int k = 0; k < 6; ++k) {
if (mask & (1 << k)) if (mask & (1 << k))
@ -301,12 +343,13 @@ video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos,
void MapblockMeshGenerator::generateCuboidTextureCoords(const aabb3f &box, f32 *coords) void MapblockMeshGenerator::generateCuboidTextureCoords(const aabb3f &box, f32 *coords)
{ {
f32 tx1 = (box.MinEdge.X / BS) + 0.5; // Generate texture coords which are aligned to coords of a solid nodes
f32 ty1 = (box.MinEdge.Y / BS) + 0.5; f32 tx1 = (box.MinEdge.X / BS) + 0.5f;
f32 tz1 = (box.MinEdge.Z / BS) + 0.5; f32 ty1 = (box.MinEdge.Y / BS) + 0.5f;
f32 tx2 = (box.MaxEdge.X / BS) + 0.5; f32 tz1 = (box.MinEdge.Z / BS) + 0.5f;
f32 ty2 = (box.MaxEdge.Y / BS) + 0.5; f32 tx2 = (box.MaxEdge.X / BS) + 0.5f;
f32 tz2 = (box.MaxEdge.Z / BS) + 0.5; f32 ty2 = (box.MaxEdge.Y / BS) + 0.5f;
f32 tz2 = (box.MaxEdge.Z / BS) + 0.5f;
f32 txc[24] = { f32 txc[24] = {
tx1, 1 - tz2, tx2, 1 - tz1, // up tx1, 1 - tz2, tx2, 1 - tz1, // up
tx1, tz1, tx2, tz2, // down tx1, tz1, tx2, tz2, // down
@ -334,7 +377,6 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box,
const TileSpec *tiles, int tile_count, const f32 *txc, u8 mask) const TileSpec *tiles, int tile_count, const f32 *txc, u8 mask)
{ {
bool scale = std::fabs(cur_node.f->visual_scale - 1.0f) > 1e-3f; bool scale = std::fabs(cur_node.f->visual_scale - 1.0f) > 1e-3f;
f32 texture_coord_buf[24];
f32 dx1 = box.MinEdge.X; f32 dx1 = box.MinEdge.X;
f32 dy1 = box.MinEdge.Y; f32 dy1 = box.MinEdge.Y;
f32 dz1 = box.MinEdge.Z; f32 dz1 = box.MinEdge.Z;
@ -342,19 +384,11 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box,
f32 dy2 = box.MaxEdge.Y; f32 dy2 = box.MaxEdge.Y;
f32 dz2 = box.MaxEdge.Z; f32 dz2 = box.MaxEdge.Z;
if (scale) { if (scale) {
if (!txc) { // generate texture coords before scaling
generateCuboidTextureCoords(box, texture_coord_buf);
txc = texture_coord_buf;
}
box.MinEdge *= cur_node.f->visual_scale; box.MinEdge *= cur_node.f->visual_scale;
box.MaxEdge *= cur_node.f->visual_scale; box.MaxEdge *= cur_node.f->visual_scale;
} }
box.MinEdge += cur_node.origin; box.MinEdge += cur_node.origin;
box.MaxEdge += cur_node.origin; box.MaxEdge += cur_node.origin;
if (!txc) {
generateCuboidTextureCoords(box, texture_coord_buf);
txc = texture_coord_buf;
}
if (data->m_smooth_lighting) { if (data->m_smooth_lighting) {
LightInfo lights[8]; LightInfo lights[8];
for (int j = 0; j < 8; ++j) { for (int j = 0; j < 8; ++j) {
@ -442,10 +476,8 @@ void MapblockMeshGenerator::drawSolidNode()
u8 mask = faces ^ 0b0011'1111; // k-th bit is set if k-th face is to be *omitted*, as expected by cuboid drawing functions. u8 mask = faces ^ 0b0011'1111; // k-th bit is set if k-th face is to be *omitted*, as expected by cuboid drawing functions.
cur_node.origin = intToFloat(cur_node.p, BS); cur_node.origin = intToFloat(cur_node.p, BS);
auto box = aabb3f(v3f(-0.5 * BS), v3f(0.5 * BS)); auto box = aabb3f(v3f(-0.5 * BS), v3f(0.5 * BS));
f32 texture_coord_buf[24];
box.MinEdge += cur_node.origin; box.MinEdge += cur_node.origin;
box.MaxEdge += cur_node.origin; box.MaxEdge += cur_node.origin;
generateCuboidTextureCoords(box, texture_coord_buf);
if (data->m_smooth_lighting) { if (data->m_smooth_lighting) {
LightPair lights[6][4]; LightPair lights[6][4];
for (int face = 0; face < 6; ++face) { for (int face = 0; face < 6; ++face) {
@ -458,7 +490,7 @@ void MapblockMeshGenerator::drawSolidNode()
} }
} }
drawCuboid(box, tiles, 6, texture_coord_buf, mask, [&] (int face, video::S3DVertex vertices[4]) { drawCuboid(box, tiles, 6, nullptr, mask, [&] (int face, video::S3DVertex vertices[4]) {
auto final_lights = lights[face]; auto final_lights = lights[face];
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
video::S3DVertex &vertex = vertices[j]; video::S3DVertex &vertex = vertices[j];
@ -471,7 +503,7 @@ void MapblockMeshGenerator::drawSolidNode()
return QuadDiagonal::Diag02; return QuadDiagonal::Diag02;
}); });
} else { } else {
drawCuboid(box, tiles, 6, texture_coord_buf, mask, [&] (int face, video::S3DVertex vertices[4]) { drawCuboid(box, tiles, 6, nullptr, mask, [&] (int face, video::S3DVertex vertices[4]) {
video::SColor color = encode_light(lights[face], cur_node.f->light_source); video::SColor color = encode_light(lights[face], cur_node.f->light_source);
if (!cur_node.f->light_source) if (!cur_node.f->light_source)
applyFacesShading(color, vertices[0].Normal); applyFacesShading(color, vertices[0].Normal);
@ -952,7 +984,10 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
edge_invisible = nb[nb_triplet[edge][0]] ^ nb[nb_triplet[edge][1]]; edge_invisible = nb[nb_triplet[edge][0]] ^ nb[nb_triplet[edge][1]];
if (edge_invisible) if (edge_invisible)
continue; continue;
drawAutoLightedCuboid(frame_edges[edge], tiles[1]);
f32 txc[24];
generateCuboidTextureCoords(frame_edges[edge], txc);
drawAutoLightedCuboid(frame_edges[edge], tiles[1], txc);
} }
for (int face = 0; face < 6; face++) { for (int face = 0; face < 6; face++) {
@ -996,16 +1031,17 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
float vlev = (param2 / 63.0f) * 2.0f - 1.0f; float vlev = (param2 / 63.0f) * 2.0f - 1.0f;
TileSpec tile; TileSpec tile;
getSpecialTile(0, &tile); getSpecialTile(0, &tile);
drawAutoLightedCuboid( aabb3f box(
aabb3f(
-(nb[5] ? g : b), -(nb[5] ? g : b),
-(nb[4] ? g : b), -(nb[4] ? g : b),
-(nb[3] ? g : b), -(nb[3] ? g : b),
(nb[2] ? g : b), (nb[2] ? g : b),
(nb[1] ? g : b) * vlev, (nb[1] ? g : b) * vlev,
(nb[0] ? g : b) (nb[0] ? g : b)
), );
tile); f32 txc[24];
generateCuboidTextureCoords(box, txc);
drawAutoLightedCuboid(box, tile, txc);
} }
} }
@ -1649,7 +1685,10 @@ void MapblockMeshGenerator::drawNodeboxNode()
for (auto &box : boxes) { for (auto &box : boxes) {
u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors); u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors);
drawAutoLightedCuboid(box, tiles, 6, nullptr, mask);
f32 txc[24];
generateCuboidTextureCoords(box, txc);
drawAutoLightedCuboid(box, tiles, 6, txc, mask);
} }
} }

View file

@ -86,7 +86,7 @@ private:
template <typename Fn> template <typename Fn>
void drawCuboid(const aabb3f &box, const TileSpec *tiles, int tilecount, void drawCuboid(const aabb3f &box, const TileSpec *tiles, int tilecount,
const f32 *txc, u8 mask, Fn &&face_lighter); const f32 *txc, u8 mask, Fn &&face_lighter);
void generateCuboidTextureCoords(aabb3f const &box, f32 *coords); static void generateCuboidTextureCoords(aabb3f const &box, f32 *coords);
void drawAutoLightedCuboid(aabb3f box, const TileSpec &tile, f32 const *txc = nullptr, u8 mask = 0); void drawAutoLightedCuboid(aabb3f box, const TileSpec &tile, f32 const *txc = nullptr, u8 mask = 0);
void drawAutoLightedCuboid(aabb3f box, const TileSpec *tiles, int tile_count, f32 const *txc = nullptr, u8 mask = 0); void drawAutoLightedCuboid(aabb3f box, const TileSpec *tiles, int tile_count, f32 const *txc = nullptr, u8 mask = 0);
u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const; u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const;

View file

@ -14,25 +14,19 @@ void MeshCollector::append(const TileSpec &tile, const video::S3DVertex *vertice
const TileLayer *layer = &tile.layers[layernum]; const TileLayer *layer = &tile.layers[layernum];
if (layer->empty()) if (layer->empty())
continue; continue;
append(*layer, vertices, numVertices, indices, numIndices, layernum, append(*layer, vertices, numVertices, indices, numIndices, layernum);
tile.world_aligned);
} }
} }
void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *vertices, void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *vertices,
u32 numVertices, const u16 *indices, u32 numIndices, u8 layernum, u32 numVertices, const u16 *indices, u32 numIndices, u8 layernum)
bool use_scale)
{ {
PreMeshBuffer &p = findBuffer(layer, layernum, numVertices); PreMeshBuffer &p = findBuffer(layer, layernum, numVertices);
f32 scale = 1.0f;
if (use_scale)
scale = 1.0f / layer.scale;
u32 vertex_count = p.vertices.size(); u32 vertex_count = p.vertices.size();
for (u32 i = 0; i < numVertices; i++) { for (u32 i = 0; i < numVertices; i++) {
p.vertices.emplace_back(vertices[i].Pos + offset, vertices[i].Normal, p.vertices.emplace_back(vertices[i].Pos + offset, vertices[i].Normal,
vertices[i].Color, scale * vertices[i].TCoords); vertices[i].Color, vertices[i].TCoords);
m_bounding_radius_sq = std::max(m_bounding_radius_sq, m_bounding_radius_sq = std::max(m_bounding_radius_sq,
(vertices[i].Pos - m_center_pos).getLengthSQ()); (vertices[i].Pos - m_center_pos).getLengthSQ());
} }

View file

@ -55,7 +55,7 @@ private:
void append(const TileLayer &material, void append(const TileLayer &material,
const video::S3DVertex *vertices, u32 numVertices, const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices, const u16 *indices, u32 numIndices,
u8 layernum, bool use_scale = false); u8 layernum);
PreMeshBuffer &findBuffer(const TileLayer &layer, u8 layernum, u32 numVertices); PreMeshBuffer &findBuffer(const TileLayer &layer, u8 layernum, u32 numVertices);
}; };