mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 07:40:14 +00:00
Fix lamp posts as glass and hide distance-only LOD groups when close
Two WMO rendering fixes: 1. Glass batch merging: BatchKey didn't include isWindow, so window and non-window batches sharing the same texture got merged together. If the window batch was processed first, the entire merged batch (lamp base, iron frame, etc.) rendered as transparent glass. Add isWindow to the batch key so glass/non-glass batches stay separate. 2. LOD group culling: WMO groups named with "LOD" are distance-only impostor geometry (e.g. cathedral tower extension, hill tower). They should only render beyond 200 units. Store raw MOGN chunk for offset-based name lookup, detect "lod" in group names during load, and skip LOD groups in both main and shadow passes when camera is within range.
This commit is contained in:
parent
4acba4110f
commit
3ffb7ccc50
4 changed files with 49 additions and 5 deletions
|
|
@ -483,9 +483,23 @@ bool WMORenderer::loadModel(const pipeline::WMOModel& model, uint32_t id) {
|
|||
modelData.materialFlags.push_back(mat.flags);
|
||||
}
|
||||
|
||||
// Helper: look up group name from MOGN raw data via MOGI nameOffset
|
||||
auto getGroupName = [&](uint32_t groupIdx) -> std::string {
|
||||
if (groupIdx < model.groupInfo.size()) {
|
||||
int32_t nameOff = model.groupInfo[groupIdx].nameOffset;
|
||||
if (nameOff >= 0 && static_cast<size_t>(nameOff) < model.groupNameRaw.size()) {
|
||||
const char* str = reinterpret_cast<const char*>(model.groupNameRaw.data() + nameOff);
|
||||
size_t maxLen = model.groupNameRaw.size() - nameOff;
|
||||
return std::string(str, strnlen(str, maxLen));
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
// Create GPU resources for each group
|
||||
uint32_t loadedGroups = 0;
|
||||
for (const auto& wmoGroup : model.groups) {
|
||||
for (size_t gi = 0; gi < model.groups.size(); gi++) {
|
||||
const auto& wmoGroup = model.groups[gi];
|
||||
// Skip empty groups
|
||||
if (wmoGroup.vertices.empty() || wmoGroup.indices.empty()) {
|
||||
continue;
|
||||
|
|
@ -493,6 +507,17 @@ bool WMORenderer::loadModel(const pipeline::WMOModel& model, uint32_t id) {
|
|||
|
||||
GroupResources resources;
|
||||
if (createGroupResources(wmoGroup, resources, wmoGroup.flags)) {
|
||||
// Detect distance-only LOD groups by name pattern
|
||||
std::string gname = getGroupName(static_cast<uint32_t>(gi));
|
||||
if (!gname.empty()) {
|
||||
std::string lower = gname;
|
||||
std::transform(lower.begin(), lower.end(), lower.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
if (lower.find("lod") != std::string::npos) {
|
||||
resources.isLOD = true;
|
||||
LOG_INFO("WMO group ", gi, " '", gname, "' marked as LOD (distance-only)");
|
||||
}
|
||||
}
|
||||
modelData.groups.push_back(resources);
|
||||
loadedGroups++;
|
||||
}
|
||||
|
|
@ -510,11 +535,12 @@ bool WMORenderer::loadModel(const pipeline::WMOModel& model, uint32_t id) {
|
|||
uintptr_t texPtr;
|
||||
bool alphaTest;
|
||||
bool unlit;
|
||||
bool operator==(const BatchKey& o) const { return texPtr == o.texPtr && alphaTest == o.alphaTest && unlit == o.unlit; }
|
||||
bool isWindow;
|
||||
bool operator==(const BatchKey& o) const { return texPtr == o.texPtr && alphaTest == o.alphaTest && unlit == o.unlit && isWindow == o.isWindow; }
|
||||
};
|
||||
struct BatchKeyHash {
|
||||
size_t operator()(const BatchKey& k) const {
|
||||
return std::hash<uintptr_t>()(k.texPtr) ^ (std::hash<bool>()(k.alphaTest) << 1) ^ (std::hash<bool>()(k.unlit) << 2);
|
||||
return std::hash<uintptr_t>()(k.texPtr) ^ (std::hash<bool>()(k.alphaTest) << 1) ^ (std::hash<bool>()(k.unlit) << 2) ^ (std::hash<bool>()(k.isWindow) << 3);
|
||||
}
|
||||
};
|
||||
std::unordered_map<BatchKey, GroupResources::MergedBatch, BatchKeyHash> batchMap;
|
||||
|
|
@ -551,7 +577,7 @@ bool WMORenderer::loadModel(const pipeline::WMOModel& model, uint32_t id) {
|
|||
// lamp posts, lanterns, etc. — those should NOT be glass.
|
||||
bool isWindow = (matFlags & 0x40) != 0;
|
||||
|
||||
BatchKey key{ reinterpret_cast<uintptr_t>(tex), alphaTest, unlit };
|
||||
BatchKey key{ reinterpret_cast<uintptr_t>(tex), alphaTest, unlit, isWindow };
|
||||
auto& mb = batchMap[key];
|
||||
if (mb.draws.empty()) {
|
||||
mb.texture = tex;
|
||||
|
|
@ -1385,6 +1411,13 @@ void WMORenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const
|
|||
vkCmdPushConstants(cmd, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT,
|
||||
0, sizeof(GPUPushConstants), &push);
|
||||
|
||||
// Compute camera distance to WMO bounding box center for LOD decisions
|
||||
glm::vec3 wmoCenter = instance.modelMatrix * glm::vec4(
|
||||
(model.boundingBoxMin + model.boundingBoxMax) * 0.5f, 1.0f);
|
||||
float camDistSq = glm::dot(camPos - wmoCenter, camPos - wmoCenter);
|
||||
// LOD groups render only beyond this distance squared (200 units)
|
||||
static constexpr float LOD_SHOW_DIST_SQ = 200.0f * 200.0f;
|
||||
|
||||
// Render visible groups
|
||||
for (uint32_t gi : dl.visibleGroups) {
|
||||
const auto& group = model.groups[gi];
|
||||
|
|
@ -1392,6 +1425,9 @@ void WMORenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const
|
|||
// Only skip antiportal geometry
|
||||
if (group.groupFlags & 0x4000000) continue;
|
||||
|
||||
// Skip distance-only LOD groups when camera is close
|
||||
if (group.isLOD && camDistSq < LOD_SHOW_DIST_SQ) continue;
|
||||
|
||||
// Bind vertex + index buffers
|
||||
VkDeviceSize offset = 0;
|
||||
vkCmdBindVertexBuffers(cmd, 0, 1, &group.vertexBuffer, &offset);
|
||||
|
|
@ -1630,6 +1666,9 @@ void WMORenderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceM
|
|||
// Skip antiportal geometry
|
||||
if (group.groupFlags & 0x4000000) continue;
|
||||
|
||||
// Skip LOD groups in shadow pass (they overlap real geometry)
|
||||
if (group.isLOD) continue;
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
vkCmdBindVertexBuffers(cmd, 0, 1, &group.vertexBuffer, &offset);
|
||||
vkCmdBindIndexBuffer(cmd, group.indexBuffer, 0, VK_INDEX_TYPE_UINT16);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue