extends RigidBody3D @export var raycast3d: RayCast3D @export var camera3d: Camera3D @export var label3d: Label3D @export var camera_offset: Vector3 = Vector3(0, 2, 4) @export var move_speed = 100.0 var hit_face_index = -1 var hit_surface_index = -1 var hit_surface_name = " " var init_pos: Vector3 func _ready(): init_pos = global_position func _process(delta): if Input.is_action_just_pressed("ui_home"): global_position = init_pos linear_velocity *= 0 if Input.is_action_just_pressed("ui_accept"): apply_central_impulse(Vector3(0, 0.25, 0)) var d = Vector3.ZERO d.x = Input.get_axis("ui_left", "ui_right") d.z = Input.get_axis("ui_up", "ui_down") apply_central_force(d.normalized() * move_speed * delta) raycast3d.global_position = global_position camera3d.global_position = global_position + camera_offset label3d.global_position = global_position + Vector3(0, 1.2, 0) label3d.text = "Hit face[%d]\n[%d] %s" % [hit_face_index, hit_surface_index, hit_surface_name] func _on_body_entered(body): var starttime = Time.get_ticks_msec() print("call _on_body_entered()") print(body) if not is_instance_of(body, StaticBody3D): print("Not StaticBody3D") return if not body.is_in_group("ground"): print("Not ground group") return # Check collision position of the RayCast3D and StaticBody3D var col_pos = Vector3.ZERO raycast3d.global_position = global_position raycast3d.force_raycast_update() if raycast3d.is_colliding(): var c = raycast3d.get_collider() if c is StaticBody3D: col_pos = raycast3d.get_collision_point() print("RayCast3D hit StaticBody3D, Pos: ", col_pos) else: print("Not RayCast3D hit StaticBody3D") else: print("Not hit RayCast3D") if col_pos == Vector3.ZERO: return hit_face_index = -1 hit_surface_index = -1 hit_surface_name = " " var staticbody3d: StaticBody3D = body var meshinstance3d = staticbody3d.get_node("MeshInstance3D") print(meshinstance3d) var mesh: Mesh = meshinstance3d.mesh print(mesh) var mesh_face_count = len(mesh.get_faces()) print("Mesh face count : %d" % mesh_face_count) var surface_count = mesh.get_surface_count() # surface is blender material print("Surface count : %d" % surface_count) var fcnt = 0 for surface_index in range(surface_count): var mdt = MeshDataTool.new() mdt.create_from_surface(mesh, surface_index) # get materal name var material = mesh.surface_get_material(surface_index) var matname = material.resource_name var face_count = mdt.get_face_count() print("[%d %s] face count %d" % [surface_index, matname, face_count]) fcnt += face_count for face_index in range(face_count): # get vertext index var i0 = mdt.get_face_vertex(face_index, 0) var i1 = mdt.get_face_vertex(face_index, 1) var i2 = mdt.get_face_vertex(face_index, 2) # get vertex position var p0 = mdt.get_vertex(i0) var p1 = mdt.get_vertex(i1) var p2 = mdt.get_vertex(i2) var cp = Vector2(col_pos.x, col_pos.z) var a = Vector2(p0.x, p0.z) var b = Vector2(p1.x, p1.z) var c = Vector2(p2.x, p2.z) if is_point_in_triangle(cp, a, b, c): hit_face_index = face_index hit_surface_index = surface_index hit_surface_name = matname print("Hit face index : %d" % hit_face_index) if hit_face_index >= 0: print("Hit face index : %d, surface index, name : %d, %s" % [hit_face_index, hit_surface_index, hit_surface_name]) var endtime = Time.get_ticks_msec() print("%d msec, face count : %d" % [(endtime - starttime), fcnt]) func cross2d(a: Vector2, b: Vector2): return a.x * b.y - a.y * b.x func is_point_in_triangle(point: Vector2, a: Vector2, b: Vector2, c: Vector2): var an: Vector2 = a - point var bn: Vector2 = b - point var cn: Vector2 = c - point var orientation: bool = cross2d(an, bn) > 0 if ((cross2d(bn,cn) > 0) != orientation): return false return (cross2d(cn,an) > 0) == orientation