+1 vote

Hi,

I have a 3D isometric scene where player can sometimes disappear behind a wall. I would like to dynamically make a hole in a wall that stand between player and the camera or even better - make this wall half-transparent, to have a "see through walls" effect.

Kind of like here:
See through walls

How can I do this in Godot?

in Engine by (137 points)

Don't have a definitive answer but if it was for me I would look to do this with a Shader.

1 Answer

+1 vote

OK here's one way to do this:

For a start, you need a way to recognize when your character moves behind an obstacle, or a way to figure out what lies between the camera and the character. Then, it is a matter of changing the material of the obstacle into a semi-transparent material.

One way you can acquire the obstacle is by casting a ray. I suggest you look it up by yourself, because as far as I know, there are multiple ways to work with rays in Godot. Choose the one that best fits your needs.
Take a look at the following sources:
1) https://docs.godotengine.org/en/3.1/tutorials/physics/ray-casting.html
2) https://www.youtube.com/watch?v=pIOmaSNpCmE
3) and an older one: https://www.youtube.com/watch?v=y6yyDJy0uVE

Having said that, I have tested the following minimal example and it works: I have attached a script to the Camera node. This script casts a ray from the position of the Camera to 1000 units in the z direction of the Camera (again, there are other ways of casting rays that are more efficient, check the docs). If said ray detects a collision object (such as an Area or RigidBody), then it acquires the collider's MeshInstance using the collider method. Afterwards, The script sets the collider's MeshInstance's material into another semi-transparent material using the set_surface_material(0, mat) method.

extends Camera

onready var wall = get_node("/root/Spatial/Invisible_wall/Invisible_wall_mesh") # our obstacle
onready var mat = preload("res://Materials/orange.tres")# our second, transparent material

func _ready():
    pass


func _physics_process(delta):
    var space_state = get_world().direct_space_state
    var result = space_state.intersect_ray(translation, Vector3(translation.x, translation.y, translation.z-1000)) # Cast a ray from camera
    if result: # if collision is found
        print(result.collider) 
        result.collider.get_node("Invisible_wall_mesh").set_surface_material(0, mat)
        print(mat) #get the collider's MeshInstance and change its material

A few notes:

1) Raycasting works with Area and Rigidbody nodes
2) I have hardcoded everything in the example, but you can avoid that easily
3) A more efficient way to do this might be to attach the script on the colliders instead of the Camera node. That way you can set the logic in such a way that once the ray no longer collides with your obstacles, your obstacles can have their previous material.

I hope that helps!

by (1,848 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.