Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return the surface material that was hit by a RayCast #3909

Open
elvisish opened this issue Feb 2, 2022 · 9 comments
Open

Return the surface material that was hit by a RayCast #3909

elvisish opened this issue Feb 2, 2022 · 9 comments

Comments

@elvisish
Copy link

elvisish commented Feb 2, 2022

Describe the project you are working on

A first person game using Trenchbroom maps/Qodot as level editor.

Describe the problem or limitation you are having in your project

Qodot imports levels as one big MeshInstance with hundreds of colliders, as such each material is a surface material of the MeshInstance. I need a way of being able to detect a specific surface material at a particular point (such as under the player).

Describe the feature / enhancement and how it helps to overcome the problem or limitation

For different footstep sounds, it would be easiest if I could compare the surface material and play the appropriate sound effect (grass, rock, sand, etc). I can't just cast a ray down and check as there's only one mesh for the level, but many surface materials assigned to this MeshInstance.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Integrated into Raycast that can access the surface material at the point the ray hits.

If this enhancement will not be used often, can it be worked around with a few lines of script?

Not that I know of, I'd be interested to know if possible.

Is there a reason why this should be core and not an add-on in the asset library?

I think it requires deeper integration, but I could be wrong.

@Calinou
Copy link
Member

Calinou commented Feb 2, 2022

Related to #2198.

I don't think it's possible to get the actual mesh material from a RayCast, as colliders will not always match the mesh geometry (they often need to be simplified for gameplay or performance reasons). You could however get the PhysicsMaterial associated to a PhysicsBody.

Since each PhysicsBody can only have one PhysicsMaterial assigned to it, I'd recommend creating several PhysicsBodies, one per surface type. This could be done by splitting surface types into different PhysicsBodies on import.

@Calinou Calinou changed the title Get surface material with raycast Return the surface material that was hit by a RayCast Feb 2, 2022
@elvisish
Copy link
Author

elvisish commented Feb 2, 2022

You could however get the PhysicsMaterial associated to a PhysicsBody.

Since each PhysicsBody can only have one PhysicsMaterial assigned to it, I'd recommend creating several PhysicsBodies, one per surface type. This could be done by splitting surface types into different PhysicsBodies on import.

A little difficult I think currently as Qodot handles all of the conversion from.map into nodes, unless I'm mistaken and it's a relatively trivial job to automate at runtime? I'm not even sure how surface types would factor in here as they're just materials as set in Trenchbroom that are automatically applied to whichever part of the mesh they need to be.

@Calinou
Copy link
Member

Calinou commented Feb 2, 2022

If you just want to get something working quickly, you could also add Area nodes that "tag" specific surfaces contained within the Area. When the footstep event occurs within the Area node, use a different footstep sound/effect. This could also be extended to gameplay events (such as specific surfaces negating fall damage).

@elvisish
Copy link
Author

elvisish commented Feb 2, 2022

If you just want to get something working quickly, you could also add Area nodes that "tag" specific surfaces contained within the Area. When the footstep event occurs within the Area node, use a different footstep sound/effect. This could also be extended to gameplay events (such as specific surfaces negating fall damage).

Thanks, I think that's the approach I'll have to take for now. It would be immensely useful to be able to grab a surface material with a ray though, to avoid having to manually define areas (with Trenchbroom, layers can also be used to separate sections up with might be useful in the meantime until surface materials at point can be grabbed).

@Zireael07
Copy link

Related: #2863

@Gamepro5
Copy link

Gamepro5 commented Jun 10, 2023

Here's an example of a 2004 game doing something similar in order to fetch the data needed to know what decal to spawn. I would also love something like this to be implemented.

application_example.mp4

@Okxa
Copy link

Okxa commented Aug 18, 2023

Seems like current workarounds involve iterating on the mesh vertex data and then using Geometry.ray_intersects_triangle to check if this face is the current one.

There seems to be a couple of ways to iterate upon mesh vertices, I have not tested their performance relative to each other:

In both cases you end up iterating on mesh data, which can be expensive when the mesh is complex, as seen in the video.

Therefore native implementation could be preferred. (Though I cannot say how performant that would be anyways, I am not familiar with how raycasts work at low level.)

EDIT: More thougths:

As for aforementioned source engine, it only checks for material surface properties on world geometry (== brushes). Models have a single physical property defined at model compile time, even if they have multiple materials. Not sure, but it might be a conscious decision to implement the surface properties that way to avoid checking surfaces on complex models to save on performance.

So if this (raycasting for material) would possibly be performance intensive operation (depending on how detailed the mesh is) when implemented in godot engine, then of course proper warnings should be documented.

@alexjhetherington
Copy link

I support this proposal! In addition to iterating on the mesh data, as above, there are some other solutions:

  • Pre-process the mesh at edit time to split it into a mesh + collider for each material. When you hit the collider at run time, you can traverse the tree to find the mesh, and the material is self-evident. This is easy to incorporate into the normal import model workflow, but if you're using a tool like Qodot it might be a bit difficult to get a smooth workflow.
  • Do some fancy stuff with shaders / materials / cameras to render the world as flat block colours, read the colour from a viewport texture, and map the colour (rather than material) to a sound. This works really nicely for footstep sounds, but wouldn't work for bullets or something like that where you'd need multiple cameras flying around.

You can see examples of both here: https://github.com/alexjhetherington/godot-identifying-materials-examples?tab=readme-ov-file

@solitaryurt
Copy link

This would be useful for footsteps and bullet impact effects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants