codecat / godot-tbloader

TrenchBroom Loader for Godot 4. (Alternative to Qodot)
MIT License
243 stars 32 forks source link

Optionally build worldspawn brushes as separate objects #40

Open Skaruts opened 2 years ago

Skaruts commented 2 years ago

I have a use-case that I think would require building each worldspawn brush as a separate mesh/collider.

I've been implementing a way to determine footsteps/noise level in my game, and I was testing it on a scene made with CSG objects. When I tried using it on a TB map I realized TBLoader builds the entire map as a single mesh/collider, and I'm not sure I can do it that way.

The process involves raycasting at the floor to get the material from the mesh, and then check it's metadata for the surface type. But if the map is a single mesh/collider, then it has several surfaces and materials, and I don't think I can get any information from the collision that could help me know which mesh surface is the one I'm touching.


An alternative would be to mark each floor brush in some way that makes TBLoader separate them (maybe I can even do that now, if I turn the floors into some kind of custom entity?), but I think that would be more laborious and error prone, and personally, I think it would reduce my willingness to iterate over and reshape my maps. Having worldspawn brushes separated might be just a simple checkbox, and I don't think the physics engine would care.

Skaruts commented 2 years ago

Actually, I think I was a bit off in the wrong direction. I think I'd need all brushes to be separated by material, regardless of them being worldspawn or not.

codecat commented 2 years ago

If you are using different textures for each surface, there will actually be multiple meshes generated as long as you are using "Build Meshes" and not the old CSG mesh system. Then, you can specify a custom material for each texture by having a .tscn or .material file in place where the texture would be (see the readme for more info on how this works).

Skaruts commented 2 years ago

I am using "Build Meshes", but it's still generating a single mesh, though.

2022-11-14 02_53_27-test_01 tscn - horror_fps_tutorial - Godot Engine

codecat commented 2 years ago

Oh that's right, we recently merged a PR that turned it into singular meshes. I forgot about that, my bad 😅

Regardless, each surface is a different material. If you know the specific surface that was hit, you could get the material that way. I haven't looked too much into what info you have available from a raycast though.

Skaruts commented 2 years ago

If you know the specific surface that was hit

But the problem is I don't think there's a way to know that. Or at least I don't think there's a way that isn't a whole can of worms to figure out. The collision information can give me a point in space where the collision took place, iirc, but I think that's about as useful as it can be... which doesn't seem much at all to me.

Correct me if I'm wrong.

codecat commented 2 years ago

Ah I see, you would indeed only get the collider, the actual rendered mesh is separate from that. I wonder if this is something Qodot has solved? Otherwise, we could potentially just make a setting to create multiple objects 🤔

monkey-salad commented 2 years ago

I wonder if this is something Qodot has solved?

It's not.

But they discuss it in their docs under Tips for Veterans # Footstep Sounds, maybe that's useful.

Skaruts commented 2 years ago

Qodot also creates a single mesh, but it creates a collision shape per brush. I don't think it really solves the issue, tbh. Kinda seems to me you end up in the same spot. You can get the collision point, and that's it...

Seems like their suggested solution is about the same as my alternative suggestion: create a solid class, make each floor a solid of that class. That separates the floor into entities on build, each with its own mesh and collider. It actually works perfectly, except its a bit tedious and prone to human errors. In my test map I found myself neglecting to turn some ramps and stairs into said entities. It's very easy to forget small parts as well.

Skaruts commented 2 years ago

I found a video where someone explains how to determine the mesh surface from the collision point information, but... he points out in the comments that this system ended up not being performant in practice when applied to many actors (although someone else points out some optimizations one can do to it). And also as I suspected, it's a whole can of worms to delve into (using the MeshDataTool).

https://www.youtube.com/watch?v=WhMfocT9l-o

I'm thinking of giving this a try, though.