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:
parent
2f1171e2a7
commit
d17f22f536
4 changed files with 80 additions and 47 deletions
|
@ -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)
|
);
|
||||||
),
|
f32 txc[24];
|
||||||
tile);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue