forked from townforge/townforge
game: fix missing and spurious faces with smooth voxels
This commit is contained in:
parent
e0ad81a097
commit
719ad3f515
@ -105,6 +105,14 @@ static uint16_t get_material_for_block(const std::shared_ptr<Flag> &flag, uint8_
|
||||
return variant;
|
||||
}
|
||||
|
||||
static uint8_t get_item_for_block(const std::shared_ptr<Flag> &flag, uint8_t block)
|
||||
{
|
||||
const uint16_t variant = get_material_for_block(flag, block);
|
||||
if (variant == cc::BLOCK_VARIANT_NONE)
|
||||
return 0;
|
||||
return cc::get_block_variant(variant).item;
|
||||
}
|
||||
|
||||
CityMeshResources::CityMeshResources(ResourceCache *cache)
|
||||
{
|
||||
ownershipMaterial = cache->GetResource<Material>("Materials/Ownership.xml");
|
||||
@ -1423,7 +1431,7 @@ std::vector<::Tile> CityMeshSection::MakeFlagLOD(const std::shared_ptr<Flag> &fl
|
||||
return lod;
|
||||
}
|
||||
|
||||
static void GenerateNormals(std::vector<float> &vertex_data, const std::vector<uint32_t> &index_data, int32_t ox, int32_t oy, uint16_t base_height, float material_hscale, float material_vscale, float lod_scale)
|
||||
static void GenerateUVs(std::vector<float> &vertex_data, const std::vector<uint32_t> &index_data, int32_t ox, int32_t oy, uint16_t base_height, float material_hscale, float material_vscale, float lod_scale)
|
||||
{
|
||||
for (size_t i = 0; i < index_data.size(); i += 3)
|
||||
{
|
||||
@ -1439,10 +1447,6 @@ static void GenerateNormals(std::vector<float> &vertex_data, const std::vector<u
|
||||
Vector3& n1 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * i1 + 3]));
|
||||
Vector3& n2 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * i2 + 3]));
|
||||
|
||||
const Vector3 edge1 = v0 - v1;
|
||||
const Vector3 edge2 = v0 - v2;
|
||||
n0 = n1 = n2 = edge1.CrossProduct(edge2).Normalized();
|
||||
|
||||
Vector2& uv0 = *(reinterpret_cast<Vector2*>(&vertex_data[8 * i0 + 6]));
|
||||
Vector2& uv1 = *(reinterpret_cast<Vector2*>(&vertex_data[8 * i1 + 6]));
|
||||
Vector2& uv2 = *(reinterpret_cast<Vector2*>(&vertex_data[8 * i2 + 6]));
|
||||
@ -1632,10 +1636,6 @@ void CityMeshSection::GenerateSurfaceNets(const std::shared_ptr<Flag> &flag, Sha
|
||||
v[i] = x[i] + 0.5f + (s * v[i] - 0.5f) * smoothness;
|
||||
}
|
||||
|
||||
const uint16_t material = flat_data[block_idx] & 0xff;
|
||||
const uint16_t mv = (flat_data[block_idx] >> 8) & 3;
|
||||
std::vector<uint32_t> &idata = index_data[material][mv];
|
||||
|
||||
//Add vertex to buffer, store pointer to vertex index in buffer
|
||||
buffer[m] = vertex_data.size() / 8;
|
||||
|
||||
@ -1671,62 +1671,70 @@ void CityMeshSection::GenerateSurfaceNets(const std::shared_ptr<Flag> &flag, Sha
|
||||
//Otherwise, look up adjacent edges in buffer
|
||||
const int32_t du = R[iu] , dv = R[iv];
|
||||
|
||||
if (1)
|
||||
{
|
||||
// without interpolation, we're going to keep flat shading,
|
||||
// so we duplicate all vertices
|
||||
// also need to do this for UVs
|
||||
const uint32_t base = vertex_data.size() / 8;
|
||||
vertex_data.resize(vertex_data.size() + 8 * 4);
|
||||
memcpy(vertex_data.data() + base * 8, vertex_data.data() + buffer[m-du-dv] * 8, 8 * sizeof(float));
|
||||
memcpy(vertex_data.data() + (base + 1) * 8, vertex_data.data() + buffer[m-du] * 8, 8 * sizeof(float));
|
||||
memcpy(vertex_data.data() + (base + 2) * 8, vertex_data.data() + buffer[m-dv] * 8, 8 * sizeof(float));
|
||||
memcpy(vertex_data.data() + (base + 3) * 8, vertex_data.data() + buffer[m] * 8, 8 * sizeof(float));
|
||||
// without interpolation, we're going to keep flat shading,
|
||||
// so we duplicate all vertices
|
||||
// also need to do this for UVs
|
||||
const uint32_t base = vertex_data.size() / 8;
|
||||
vertex_data.resize(vertex_data.size() + 8 * 4);
|
||||
memcpy(vertex_data.data() + base * 8, vertex_data.data() + buffer[m-du-dv] * 8, 8 * sizeof(float));
|
||||
memcpy(vertex_data.data() + (base + 1) * 8, vertex_data.data() + buffer[m-du] * 8, 8 * sizeof(float));
|
||||
memcpy(vertex_data.data() + (base + 2) * 8, vertex_data.data() + buffer[m-dv] * 8, 8 * sizeof(float));
|
||||
memcpy(vertex_data.data() + (base + 3) * 8, vertex_data.data() + buffer[m] * 8, 8 * sizeof(float));
|
||||
|
||||
if (!(mask & 1))
|
||||
{
|
||||
idata.push_back(base);
|
||||
idata.push_back(base + 1);
|
||||
idata.push_back(base + 3);
|
||||
idata.push_back(base + 2);
|
||||
idata.push_back(base);
|
||||
idata.push_back(base + 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
idata.push_back(base);
|
||||
idata.push_back(base + 2);
|
||||
idata.push_back(base + 3);
|
||||
idata.push_back(base + 1);
|
||||
idata.push_back(base);
|
||||
idata.push_back(base + 3);
|
||||
}
|
||||
Vector3& v0 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * base]));
|
||||
Vector3& v1 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * (base+1)]));
|
||||
Vector3& v2 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * (base+2)]));
|
||||
Vector3& v3 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * (base+3)]));
|
||||
Vector3& n0 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * base + 3]));
|
||||
Vector3& n1 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * (base+1) + 3]));
|
||||
Vector3& n2 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * (base+2) + 3]));
|
||||
Vector3& n3 = *(reinterpret_cast<Vector3*>(&vertex_data[8 * (base+3) + 3]));
|
||||
|
||||
const Vector3 edge1 = v0 - v1;
|
||||
const Vector3 edge2 = v0 - v2;
|
||||
const Vector3 &normal = edge1.CrossProduct(edge2).Normalized();
|
||||
|
||||
uint32_t indices[6];
|
||||
if (!(mask & 1))
|
||||
{
|
||||
indices[0] = base;
|
||||
indices[1] = base + 1;
|
||||
indices[2] = base + 3;
|
||||
indices[3] = base + 2;
|
||||
indices[4] = base;
|
||||
indices[5] = base + 3;
|
||||
n0 = n1 = n2 = n3 = normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Remember to flip orientation depending on the sign of the corner.
|
||||
if (!(mask & 1))
|
||||
{
|
||||
idata.push_back(buffer[m-du-dv]);
|
||||
idata.push_back(buffer[m-du]);
|
||||
idata.push_back(buffer[m]);
|
||||
idata.push_back(buffer[m-dv]);
|
||||
idata.push_back(buffer[m-du-dv]);
|
||||
idata.push_back(buffer[m]);
|
||||
}
|
||||
else
|
||||
{
|
||||
idata.push_back(buffer[m-du-dv]);
|
||||
idata.push_back(buffer[m-dv]);
|
||||
idata.push_back(buffer[m]);
|
||||
idata.push_back(buffer[m-du]);
|
||||
idata.push_back(buffer[m-du-dv]);
|
||||
idata.push_back(buffer[m]);
|
||||
}
|
||||
indices[0] = base;
|
||||
indices[1] = base + 2;
|
||||
indices[2] = base + 3;
|
||||
indices[3] = base + 1;
|
||||
indices[4] = base;
|
||||
indices[5] = base + 3;
|
||||
n0 = n1 = n2 = n3 = -normal;
|
||||
}
|
||||
|
||||
const Vector3 bar = (v0 + v1 + v2 + v3) / 4.0f + Vector3(0.5f, 0.5f, 0.5f) - n0 * 0.1f - Vector3(dx, h, dy);
|
||||
|
||||
const uint32_t bar_x = (uint32_t)bar.x_;
|
||||
const uint32_t bar_y = (uint32_t)bar.z_;
|
||||
const uint32_t bar_z = (uint32_t)bar.y_;
|
||||
block_idx = bar_x + bar_y * x_len + bar_z * x_len * y_len;
|
||||
|
||||
const uint8_t type = flat_data[block_idx] & 0xff;
|
||||
const uint16_t material = get_material_for_block(flag, type);
|
||||
const uint16_t mv = (flat_data[block_idx] >> 8) & 3;
|
||||
std::vector<uint32_t> &idata = index_data[material][mv];
|
||||
|
||||
if (!(flat_data[block_idx] & 0x8000))
|
||||
printf("NOT GOOD: flag %u, pos %d %d %d\n", flag->id, x[0], x[1], x[2]);
|
||||
|
||||
const uint16_t skip = flat_data[block_idx] & 0x4000;
|
||||
if (skip)
|
||||
idata.resize(idata.size() - 6);
|
||||
if (!skip)
|
||||
for (int i = 0; i < 6; ++i)
|
||||
idata.push_back(indices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1760,7 +1768,7 @@ void CityMeshSection::GenerateSurfaceNets(const std::shared_ptr<Flag> &flag, Sha
|
||||
const uint32_t material_vscale = resources.materials[i].vscale;
|
||||
#if 1
|
||||
const uint32_t base_height = std::max<uint32_t>(flag->base_height, -lod_base_depth) + lod_base_depth;
|
||||
GenerateNormals(vertex_data, idata, (int32_t)(flag->x0 - ox), (int32_t)(flag->y0 - oy), base_height, material_hscale, material_vscale, lod_scale);
|
||||
GenerateUVs(vertex_data, idata, (int32_t)(flag->x0 - ox), (int32_t)(flag->y0 - oy), base_height, material_hscale, material_vscale, lod_scale);
|
||||
#else
|
||||
GenerateSmoothNormals(vertex_data, idata, material_hscale, material_vscale, lod_scale, dx + 0.5f, dy + 0.5f, ox, oy);
|
||||
#endif
|
||||
@ -2053,12 +2061,12 @@ void CityMeshSection::RebuildFlags(const C &flags, const Selection &selection, b
|
||||
++n_total;
|
||||
const uint8_t type = tiles[tile_idx].get_type(h);
|
||||
const uint16_t material_type = get_material_for_block(flag, type);
|
||||
bool hidden = type == 0;
|
||||
bool hidden = material_type == 0;
|
||||
bool bottom_hidden = false, top_hidden = false, left_hidden = false, right_hidden = false, front_hidden = false, back_hidden = false;
|
||||
if (!hidden)
|
||||
{
|
||||
#define OPAQUE(material) ((fully_opaque_block[material] & fully_opaque) == fully_opaque)
|
||||
const uint8_t fully_opaque = fully_opaque_block[type];
|
||||
#define OPAQUE(type) ((fully_opaque_block[get_item_for_block(flag, type)] & fully_opaque) == fully_opaque)
|
||||
const uint8_t fully_opaque = fully_opaque_block[get_item_for_block(flag, type)];
|
||||
bottom_hidden = h == 0 || OPAQUE(tiles[tile_idx].get_type(h-1));
|
||||
top_hidden = h+1 < th && OPAQUE(tiles[tile_idx].get_type(h+1));
|
||||
left_hidden = x > firstx && tiles[tile_idx-1].get_height() > h && OPAQUE(tiles[tile_idx-1].get_type(h));
|
||||
@ -2072,8 +2080,6 @@ void CityMeshSection::RebuildFlags(const C &flags, const Selection &selection, b
|
||||
if (!hidden && !(left_hidden && right_hidden && front_hidden && back_hidden) && cc::get_block_variant(material_type).item == ITEM_WATER)
|
||||
++n_flowing_water[flag->id];
|
||||
|
||||
const bool has_smoothness = check_smoothness(tiles, x, y, h, tile_idx, firstx, firsty, lastx, lasty, tile_width);
|
||||
|
||||
auto &blocks = (*node.blocks);
|
||||
|
||||
if (IS_NEW(blocks[h]))
|
||||
@ -2092,6 +2098,8 @@ void CityMeshSection::RebuildFlags(const C &flags, const Selection &selection, b
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool has_smoothness = check_smoothness(tiles, x, y, h, tile_idx, firstx, firsty, lastx, lasty, tile_width);
|
||||
|
||||
#ifdef ENABLE_RENDER_CUBE_MODELS
|
||||
if (0 && flagRenderMode == RenderCubeModels)
|
||||
{
|
||||
@ -2492,15 +2500,16 @@ void CityMeshSection::RebuildFlags(const C &flags, const Selection &selection, b
|
||||
|
||||
if (flagRenderMode == RenderSurfaceNets || flagRenderMode == RenderMixedSurfaceNets)
|
||||
{
|
||||
const uint32_t x_len = (fx1 - fx0) / (1 << shift) + 1 + 2;
|
||||
const uint32_t y_len = (fy1 - fy0) / (1 << shift) + 1 + 2;
|
||||
const uint32_t x_len = (fx1 - fx0 + 1 + (1 << shift) - 1) / (1 << shift) + 2;
|
||||
const uint32_t y_len = (fy1 - fy0 + 1 + (1 << shift) - 1) / (1 << shift) + 2;
|
||||
const uint32_t z_len = max_height + 1 + 2;
|
||||
|
||||
// data:
|
||||
// 0-7: 8 bits: material
|
||||
// 8-9: 2 bits: material version (normal/selected/new/burning)
|
||||
// 10-12: 3 bits: smoothness
|
||||
// 13-14: 2 bits: free
|
||||
// 13: 1 bit: free
|
||||
// 14: 1 bit: skip (already drawn)
|
||||
// 15: 1 bit: present
|
||||
std::vector<uint16_t> sndata;
|
||||
sndata.resize(x_len * y_len * z_len, 0);
|
||||
@ -2565,8 +2574,7 @@ void CityMeshSection::RebuildFlags(const C &flags, const Selection &selection, b
|
||||
for (uint32_t h = 0; h < th; ++h)
|
||||
{
|
||||
const uint8_t type = tiles[tile_idx].get_type(h);
|
||||
const uint16_t material_type = get_material_for_block(flag, type);
|
||||
if (material_type == 0)
|
||||
if (type == 0)
|
||||
continue;
|
||||
|
||||
const bool has_smoothness = check_smoothness(tiles, x, y, h, tile_idx, firstx, firsty, lastx, lasty, tile_width);
|
||||
@ -2581,7 +2589,7 @@ void CityMeshSection::RebuildFlags(const C &flags, const Selection &selection, b
|
||||
x, y, h, snx, sny, snz, x_len, y_len, z_len, offset, sndata.size(), fx0, fy0, fx1, fy1, shift);
|
||||
const uint16_t smoothness = tiles[tile_idx].get_smoothness(h);
|
||||
const uint16_t skip = has_smoothness ? 0 : 1;
|
||||
sndata[offset] = 0x8000 | (skip << 14) | (smoothness << 10) | (mv << 8) | material_type;
|
||||
sndata[offset] = 0x8000 | (skip << 14) | (smoothness << 10) | (mv << 8) | type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user