I know its retarded but am i?

So far i have created a Decal, with a texture.
The Decal supposed to do this:
Expand the size of it based on character movement. Cast a ray, get ray length to ground, then set the size of the decal, then offset the decal position = size.y / 2 and it should be visible. on the ground.

What i dont understand is that why its not visible...

I tried many things.. but so fat with no luck.

It is visible once i jump high enough ( further than my raycast) then it gets projected at the end of the green mesh.

extends Node3D

@export_category("Player node")
@export var player_node: CharacterBody3D
@export_category("Shadow distance")
@export var shadow_distance = 10.0

@onready var ray_cast_3d: RayCast3D = $RayCast3D
@onready var shadow: Decal = $Shadow
@onready var mesh_instance_3d: MeshInstance3D = $MeshInstance3D

const BIAS = 0.01

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	ray_cast_3d.target_position = Vector3.DOWN * shadow_distance
	
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:

	if ray_cast_3d.is_colliding():
		var collision_point_global = ray_cast_3d.get_collision_point()
		var collision_point_local = self.to_local(collision_point_global)
		

		var ray_len = (player_node.global_position - collision_point_global) * Vector3.UP
		shadow.size.y = ray_len.y
		
		if shadow.size.y < 0.1:
			shadow.size.y = 0.3
			shadow.position = Vector3(0,0,0)
		else:
			
			var haf_size = (shadow.size.y/2)
			shadow.position = collision_point_local + (Vector3.UP * haf_size ) + (Vector3.UP * BIAS)# Vector3(0,BIAS,0)
		
		mesh_instance_3d.mesh.size = shadow.size
		mesh_instance_3d.position = shadow.position
		
		print("Result: ",ray_len)
	else:
		shadow.position = Vector3.DOWN * shadow_distance + Vector3(0,BIAS,0)
		print("Not")
	pass


The goal is to have the blob shadow show underneath the player so that you can see where you are landing. but if the height is higher than the predefined then dont show the shadow..

  • kuligs2 4 corner rays would suffice. Or just set the decal height so it covers the maximal possible slope but doesn't go deeper than that. Might be sufficient in practice. You also may deduce the decal height from the collider normal using only a single raycast and a bit of math.

Well.. as per usual, once you ask for help, you figure it out on your own..

All i did is set the constant size of the shadow and just position it at the raycast collision point.

func _process(_delta: float) -> void:
	shadow.size.y = 0.3
	if ray_cast_3d.is_colliding():
		var collision_point_global = ray_cast_3d.get_collision_point()
		var collision_point_local = self.to_local(collision_point_global)
		shadow.position = collision_point_local + (Vector3.UP * BIAS)# Vector3(0,BIAS,0)
	else:
		shadow.position = Vector3.DOWN * shadow_distance + Vector3(0,BIAS,0)
		print("Not")

But as you can see, on the slopes its not conforming, also you can see that its showing on the character model botom...

Not sure what is the best way to have the blob shadow..?

    kuligs2 All i did is set the constant size of the shadow and just position it at the raycast collision point.

    That obviously won't work as the rayhit point on slopes will be above the character's lowest butt point.

    Just exclude the character mesh from decal projection via VisualInstance layers, i.e. set visual instance layer mask of the player to not overlap decal's cull_mask. And move the decal high enough to fully project onto maximal slopes.

      xyz A roblem with this approach:

      I have tried to extend the decal cube to cut through the slopes, but if there is a pathway underneath the decal will be projected on the ground under the ledge.

      A way to mitigate would be to shoot bunch of rays around your char in maybe 2 or 3 rings, and get the highest and lowest points, and then stretch the Decal so that it includes the slope? But idk how expensive this is.

      Seems like simple things in games are actually very complicated 😃

      • xyz replied to this.

        kuligs2 4 corner rays would suffice. Or just set the decal height so it covers the maximal possible slope but doesn't go deeper than that. Might be sufficient in practice. You also may deduce the decal height from the collider normal using only a single raycast and a bit of math.

          xyz As i lack the magical powers to use maths, so i just did this thing.

          For the decal i made it 0.5 high so that i could cover the slopes. This is up for debate, as i seen some situation where it has to be higher.. anyways..

          Get the raycast collision normal and rotate the decal along the normal.

          func _process(deltoid):
          	if ray_cast_3d.is_colliding():
          		var collision_point_global = ray_cast_3d.get_collision_point()
          		var collision_point_local = self.to_local(collision_point_global)
          		var collision_normal = ray_cast_3d.get_collision_normal()
          	
          		shadow.position = collision_point_local
          		shadow.global_transform = look_at_with_y(shadow.global_transform,collision_normal)
          		mesh_instance_3d.mesh.size = shadow.size
          		mesh_instance_3d.position = shadow.position
          		mesh_instance_3d.global_transform = look_at_with_y(mesh_instance_3d.global_transform,collision_normal)
          	else:
          		shadow.global_transform = look_at_with_y(shadow.global_transform,Vector3.UP)
          		mesh_instance_3d.global_transform = look_at_with_y(mesh_instance_3d.global_transform,Vector3.UP)
          		
          	pass
          func look_at_with_y(trans,new_y):
          	trans.basis.y=new_y
          	trans.basis.x = -trans.basis.z.cross(new_y)
          	trans.basis = trans.basis.orthonormalized() 
          	return trans

          But there are problems, sometimes when you go from slope to flat, the ray will shoot though the mesh and will project under the mesh.. this is not desirable.. Not sure how to mitigate and limit the ray not to shoot over.. (too deep)

          The Meshinstance3D is that green transparent mesh to see if it rotates corectly

          • xyz replied to this.