How to make .blend objects that are too close to camera partially transparent?

Godot Version

4.2.1

Question

I am new to Godot 4 and I am following many tutorials right now. I am trying to make a 3rd person game, and I already got the camera sort of ok, thanks to https://www.youtube.com/watch?v=j_rf8zc5kTE however, when the camera looks at the character from the ground (see around 3:48 in the Youtube video to see this), it just blocks the view and the player can’t see anything above at all.

So I am trying to make the character partially transparent to fix this problem. In fact, what I would like to do is to make whatever 3D models that are too close or obstruct the view of the player partially transparent.

I found Transparent objects between camera and player using RayCast and set_albedo but the thing is my 3D model is a .blend file, and when I drag and drop the resource to the scene, it became just a Node3D and from the editor, there is no “Change Type” in the right click menu of this Node3D that housed the blender file. How can I access the materials and such of my 3D model in this case?

So in this case, how to take care of this issue for .blend files here?

You’ll need to get the materials from the .blend scene and modify the Distance fade Standard Material 3D and ORM Material 3D — Godot Engine (stable) documentation in English

To get all the materials of the .blend file you’ll need to:

Example of an EditorScenePostImport script:

@tool
extends EditorScenePostImport


func _post_import(scene):
	iterate(scene)
	return scene


func iterate(node):
	if node != null:
		if node is MeshInstance3D:
			for surface in node.mesh.get_surface_count():
				var material = node.get_active_material(surface) as BaseMaterial3D
				material = material.duplicate()
				material.distance_fade_mode = BaseMaterial3D.DISTANCE_FADE_OBJECT_DITHER
				material.distance_fade_min_distance = 2.0
				material.distance_fade_max_distance = 3.0
				node.set_surface_override_material(surface, material)

		for child in node.get_children():
			iterate(child)

You could also modify the GeometryInstance3D.transparency property at runtime with the method you linked by getting all the MeshInstance3D nodes using Node.find_children() but that may introduce visual artifacts as it changes the rendering pass of the object to the transparent pass.

Example:

func change_transparency(value:float) -> void:
	var mesh_instances = find_children("*", "MeshInstance3D", true, false)
	for mesh_instance in mesh_instances:
		mesh_instance.transparency = value
1 Like

Let me try this when I can.

Also, from what you mentioned, it seems .blend files require some extra cares. Do other file extensions require something like this? To make things simpler, Is it recommended to use other file types instead then?

Right now, I see that .blend files allow you to work directly from Blender to Godot but you need some extra cares here. I also haven’t touched on animation, bone rigging, etc. but I read around that they are not directly transferrable, so will the end justify the mean here in term of workflow?

Any 3D scene format (dae, gltf, fbx,…) will need the same modifications. It’s not exclusive to blend files.

I am slowly digesting the documents, but from here:

@mrcdk I am not sure if I am missing something, but the Node3D that houses my .blend file could not be changed. The “Change Type…” option that normally is below “Rename” option in the right click menu does not exist, so I couldn’t use the transparency variable here. Or am I missing something here?

For the imported Node3D of .blend file, you can just access its children such as MeshInstance3D directly. While these are present in the Advanced Import Setting, you can also make them visible in the scene panel by right clicking on this .blend Node3D, look for the option “Editable Children” and enable it.

For a simpler game, I found one quick fix. If the camera’s angle is too low, I just make the object partially transparent like this:

	if event is InputEventMouseMotion:
		rotate_y(deg_to_rad( -event.relative.x * sens ))
		pivot.rotate_x(deg_to_rad( -event.relative.y * sens ))
		pivot.rotation.x = clamp(pivot.rotation.x, deg_to_rad(-90), deg_to_rad(45))
		var ConeMeshInstance3D : MeshInstance3D = get_node("myTank/myMesh3D")
		if pivot.rotation.x > -0.3:
			ConeMeshInstance3D.transparency = 0.66
		else:
			ConeMeshInstance3D.transparency = 0

Sure, this does not address any other cases when there are other objects obstructing the camera - that’s why I said “for a simpler game”.

For instantiating new objects and have them doing object dithering automatically if they are too close to the camera, I now have this code for them:

func _ready():
	...
	...
	var MyMeshInstance3D : MeshInstance3D = get_node("Node3DThatHousesBlendFile/ItsMeshInstance3D")
	for surface in MyMeshInstance3D.mesh.get_surface_count():
		var material = MyMeshInstance3D.get_active_material(surface) as BaseMaterial3D
		material = material.duplicate()
		material.distance_fade_mode = BaseMaterial3D.DISTANCE_FADE_OBJECT_DITHER
		material.distance_fade_min_distance = 2.5
		material.distance_fade_max_distance = 4.0
		MyMeshInstance3D.set_surface_override_material(surface, material)

This way, no need for checking via gdscript for all instances, and this object dithering method should be faster than the usual transparency as described in the document mentioned by @mrcdk