Repository: godotengine/godot
File: scene/3d/ray_cast_3d.cpp (C++)

Code before:
void RayCast3D::_update_debug_shape() {
	if (!enabled) {
		return;
	}

	if (!debug_shape) {
		_create_debug_shape();
	}

	MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
	Ref<ArrayMesh> mesh = mi->get_mesh();
	if (!mesh.is_valid()) {
		return;
	}

	Vector<Vector3> verts;
	verts.push_back(Vector3());
	verts.push_back(target_position);

	if (mesh->get_surface_count() == 0) {
		Array a;
		a.resize(Mesh::ARRAY_MAX);
		a[Mesh::ARRAY_VERTEX] = verts;

		uint32_t flags = Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;

		mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags);
		mesh->surface_set_material(0, debug_material);
	} else {
		Vector<uint8_t> byte_array;
		int array_size = sizeof(Vector3) * verts.size();
		byte_array.resize(array_size);
		copymem(byte_array.ptrw(), verts.ptr(), array_size);

		RS::get_singleton()->mesh_surface_update_region(mesh->get_rid(), 0, 0, byte_array);
	}
}

void RayCast3D::_clear_debug_shape() {
	if (!debug_shape) {
		return;
	}

	MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
	if (mi->is_inside_tree()) {
		mi->queue_delete();
	} else {
		memdelete(mi);
	}

	debug_shape = nullptr;

Review comment (bug):
And in order to keep things consistent, I think this method could be:
```
void RayCast3D::set_debug_shape_thickness(const float p_debug_shape_thickness) {
	debug_shape_thickness = p_debug_shape_thickness;
	update_gizmo();

	if (Engine::get_singleton()->is_editor_hint()) {
		if (is_inside_tree()) {
			_update_debug_vertices();
		}
	} else if (debug_shape) {
		_update_debug_shape();
	}
```

Code after:
	debug_shape_vertices.clear();
	debug_line_vertices.clear();

	if (target_position == Vector3()) {
		return;
	}

	debug_line_vertices.push_back(Vector3());
	debug_line_vertices.push_back(target_position);

	if (debug_shape_thickness > 1) {
		float scale_factor = 100.0;
		Vector3 dir = Vector3(target_position).normalized();
		// Draw truncated pyramid
		Vector3 normal = (fabs(dir.x) + fabs(dir.y) > CMP_EPSILON) ? Vector3(-dir.y, dir.x, 0).normalized() : Vector3(0, -dir.z, dir.y).normalized();
		normal *= debug_shape_thickness / scale_factor;
		int vertices_strip_order[14] = { 4, 5, 0, 1, 2, 5, 6, 4, 7, 0, 3, 2, 7, 6 };
		for (int v = 0; v < 14; v++) {
			Vector3 vertex = vertices_strip_order[v] < 4 ? normal : normal / 3.0 + target_position;
			debug_shape_vertices.push_back(vertex.rotated(dir, Math_PI * (0.5 * (vertices_strip_order[v] % 4) + 0.25)));
		}
	}
}

void RayCast3D::set_debug_shape_thickness(const float p_debug_shape_thickness) {
	debug_shape_thickness = p_debug_shape_thickness;
	update_gizmo();

	if (Engine::get_singleton()->is_editor_hint()) {
		if (is_inside_tree()) {
			_update_debug_shape_vertices();
		}
	} else if (debug_shape) {
		_update_debug_shape();
	}
}

const Vector<Vector3> &RayCast3D::get_debug_shape_vertices() const {
	return debug_shape_vertices;
}

const Vector<Vector3> &RayCast3D::get_debug_line_vertices() const {
	return debug_line_vertices;
}

void RayCast3D::set_debug_shape_custom_color(const Color &p_color) {
	debug_shape_custom_color = p_color;
	if (debug_material.is_valid()) {
		_update_debug_shape_material();
	}
}