mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
Make InvisibleTrap objects invisible and non-collidable
Event objects like Fire Festival Fury Trap and Mercutio Post use SpellObject_InvisibleTrap.m2 models which were rendering as white tiles using WHITE1.BLP texture. These are meant to be invisible spell trigger objects that should not obstruct player movement. Changes: - Added isInvisibleTrap flag to M2ModelGPU struct - Detect models with "invisibletrap" in name during loading - Skip rendering invisible trap instances in render loop - Disable all collision checks (floor/wall/occlusion) for invisible traps - Objects remain functional for spell casting but are now invisible
This commit is contained in:
parent
0f38268c24
commit
540b3cde45
3 changed files with 65 additions and 6 deletions
|
|
@ -60,6 +60,7 @@ struct M2ModelGPU {
|
||||||
bool collisionNoBlock = false;
|
bool collisionNoBlock = false;
|
||||||
bool collisionStatue = false;
|
bool collisionStatue = false;
|
||||||
bool isSmallFoliage = false; // Small foliage (bushes, grass, plants) - skip during taxi
|
bool isSmallFoliage = false; // Small foliage (bushes, grass, plants) - skip during taxi
|
||||||
|
bool isInvisibleTrap = false; // Invisible trap objects (don't render, no collision)
|
||||||
|
|
||||||
// Collision mesh with spatial grid (from M2 bounding geometry)
|
// Collision mesh with spatial grid (from M2 bounding geometry)
|
||||||
struct CollisionMesh {
|
struct CollisionMesh {
|
||||||
|
|
|
||||||
|
|
@ -792,6 +792,16 @@ bool M2Renderer::loadModel(const pipeline::M2Model& model, uint32_t modelId) {
|
||||||
|
|
||||||
M2ModelGPU gpuModel;
|
M2ModelGPU gpuModel;
|
||||||
gpuModel.name = model.name;
|
gpuModel.name = model.name;
|
||||||
|
|
||||||
|
// Detect invisible trap models (event objects that should not render or collide)
|
||||||
|
std::string lowerName = model.name;
|
||||||
|
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(),
|
||||||
|
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||||
|
bool isInvisibleTrap = (lowerName.find("invisibletrap") != std::string::npos);
|
||||||
|
gpuModel.isInvisibleTrap = isInvisibleTrap;
|
||||||
|
if (isInvisibleTrap) {
|
||||||
|
LOG_INFO("Loading InvisibleTrap model: ", model.name, " (will be invisible, no collision)");
|
||||||
|
}
|
||||||
// Use tight bounds from actual vertices for collision/camera occlusion.
|
// Use tight bounds from actual vertices for collision/camera occlusion.
|
||||||
// Header bounds in some M2s are overly conservative.
|
// Header bounds in some M2s are overly conservative.
|
||||||
glm::vec3 tightMin( std::numeric_limits<float>::max());
|
glm::vec3 tightMin( std::numeric_limits<float>::max());
|
||||||
|
|
@ -1045,10 +1055,22 @@ bool M2Renderer::loadModel(const pipeline::M2Model& model, uint32_t modelId) {
|
||||||
// Load ALL textures from the model into a local vector
|
// Load ALL textures from the model into a local vector
|
||||||
std::vector<GLuint> allTextures;
|
std::vector<GLuint> allTextures;
|
||||||
if (assetManager) {
|
if (assetManager) {
|
||||||
for (const auto& tex : model.textures) {
|
for (size_t ti = 0; ti < model.textures.size(); ti++) {
|
||||||
|
const auto& tex = model.textures[ti];
|
||||||
if (!tex.filename.empty()) {
|
if (!tex.filename.empty()) {
|
||||||
allTextures.push_back(loadTexture(tex.filename));
|
GLuint texId = loadTexture(tex.filename);
|
||||||
|
if (texId == whiteTexture) {
|
||||||
|
LOG_WARNING("M2 model ", model.name, " texture[", ti, "] failed to load: ", tex.filename);
|
||||||
|
}
|
||||||
|
if (isInvisibleTrap) {
|
||||||
|
LOG_INFO(" InvisibleTrap texture[", ti, "]: ", tex.filename, " -> ", (texId == whiteTexture ? "WHITE" : "OK"));
|
||||||
|
}
|
||||||
|
allTextures.push_back(texId);
|
||||||
} else {
|
} else {
|
||||||
|
LOG_WARNING("M2 model ", model.name, " texture[", ti, "] has empty filename (using white fallback)");
|
||||||
|
if (isInvisibleTrap) {
|
||||||
|
LOG_INFO(" InvisibleTrap texture[", ti, "]: EMPTY (using white fallback)");
|
||||||
|
}
|
||||||
allTextures.push_back(whiteTexture);
|
allTextures.push_back(whiteTexture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1669,7 +1691,7 @@ void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm::
|
||||||
auto it = models.find(instance.modelId);
|
auto it = models.find(instance.modelId);
|
||||||
if (it == models.end()) continue;
|
if (it == models.end()) continue;
|
||||||
const M2ModelGPU& model = it->second;
|
const M2ModelGPU& model = it->second;
|
||||||
if (!model.isValid() || model.isSmoke) continue;
|
if (!model.isValid() || model.isSmoke || model.isInvisibleTrap) continue;
|
||||||
|
|
||||||
glm::vec3 toCam = instance.position - camPos;
|
glm::vec3 toCam = instance.position - camPos;
|
||||||
float distSq = glm::dot(toCam, toCam);
|
float distSq = glm::dot(toCam, toCam);
|
||||||
|
|
@ -2671,7 +2693,7 @@ std::optional<float> M2Renderer::getFloorHeight(float glX, float glY, float glZ)
|
||||||
if (instance.scale <= 0.001f) continue;
|
if (instance.scale <= 0.001f) continue;
|
||||||
|
|
||||||
const M2ModelGPU& model = it->second;
|
const M2ModelGPU& model = it->second;
|
||||||
if (model.collisionNoBlock) continue;
|
if (model.collisionNoBlock || model.isInvisibleTrap) continue;
|
||||||
|
|
||||||
// --- Mesh-based floor: vertical ray vs collision triangles ---
|
// --- Mesh-based floor: vertical ray vs collision triangles ---
|
||||||
// Does NOT skip the AABB path — both contribute and highest wins.
|
// Does NOT skip the AABB path — both contribute and highest wins.
|
||||||
|
|
@ -2818,7 +2840,7 @@ bool M2Renderer::checkCollision(const glm::vec3& from, const glm::vec3& to,
|
||||||
if (it == models.end()) continue;
|
if (it == models.end()) continue;
|
||||||
|
|
||||||
const M2ModelGPU& model = it->second;
|
const M2ModelGPU& model = it->second;
|
||||||
if (model.collisionNoBlock) continue;
|
if (model.collisionNoBlock || model.isInvisibleTrap) continue;
|
||||||
if (instance.scale <= 0.001f) continue;
|
if (instance.scale <= 0.001f) continue;
|
||||||
|
|
||||||
// --- Mesh-based wall collision: closest-point push ---
|
// --- Mesh-based wall collision: closest-point push ---
|
||||||
|
|
@ -3058,7 +3080,7 @@ float M2Renderer::raycastBoundingBoxes(const glm::vec3& origin, const glm::vec3&
|
||||||
if (it == models.end()) continue;
|
if (it == models.end()) continue;
|
||||||
|
|
||||||
const M2ModelGPU& model = it->second;
|
const M2ModelGPU& model = it->second;
|
||||||
if (model.collisionNoBlock) continue;
|
if (model.collisionNoBlock || model.isInvisibleTrap) continue;
|
||||||
glm::vec3 localMin, localMax;
|
glm::vec3 localMin, localMax;
|
||||||
getTightCollisionBounds(model, localMin, localMax);
|
getTightCollisionBounds(model, localMin, localMax);
|
||||||
// Skip tiny doodads for camera occlusion; they cause jitter and false hits.
|
// Skip tiny doodads for camera occlusion; they cause jitter and false hits.
|
||||||
|
|
|
||||||
36
test_gameobject_display.cpp
Normal file
36
test_gameobject_display.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include "pipeline/dbc.hpp"
|
||||||
|
#include "pipeline/asset_manager.hpp"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
wowee::pipeline::AssetManager assetManager;
|
||||||
|
assetManager.initialize("Data");
|
||||||
|
|
||||||
|
auto godi = assetManager.loadDBC("GameObjectDisplayInfo.dbc");
|
||||||
|
if (!godi || !godi->isLoaded()) {
|
||||||
|
std::cerr << "Failed to load GameObjectDisplayInfo.dbc\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "GameObjectDisplayInfo.dbc loaded with " << godi->getRecordCount() << " records\n\n";
|
||||||
|
|
||||||
|
// Check displayIds 35 and 1287
|
||||||
|
uint32_t targetIds[] = {35, 1287};
|
||||||
|
for (uint32_t targetId : targetIds) {
|
||||||
|
bool found = false;
|
||||||
|
for (uint32_t i = 0; i < godi->getRecordCount(); i++) {
|
||||||
|
uint32_t displayId = godi->getUInt32(i, 0);
|
||||||
|
if (displayId == targetId) {
|
||||||
|
std::string modelName = godi->getString(i, 1);
|
||||||
|
std::cout << "DisplayId " << displayId << ": " << modelName << "\n";
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
std::cout << "DisplayId " << targetId << ": NOT FOUND\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue