Куб, нарисованный сплошными многоугольниками на Godot Engine 4
Для отрисовки куба использовал встроенную функцию _draw()
Код:
extends Node2D
var fov: float = 450.0
var camera_z: float = 3.0
var angle_x: float = 0.5
var angle_y: float = 0.5
var mouse_sensitivity: float = 0.005
var vertices: Array[Vector3] = [
Vector3(-1, -1, -1), Vector3(1, -1, -1), Vector3(1, 1, -1), Vector3(-1, 1, -1),
Vector3(-1, -1, 1), Vector3(1, -1, 1), Vector3(1, 1, 1), Vector3(-1, 1, 1)
]
var faces: Array = [
{"indices": [0, 1, 2, 3], "color": Color.RED},
{"indices": [4, 5, 6, 7], "color": Color.GREEN},
{"indices": [0, 1, 5, 4], "color": Color.BLUE},
{"indices": [2, 3, 7, 6], "color": Color.YELLOW},
{"indices": [0, 3, 7, 4], "color": Color.CYAN},
{"indices": [1, 2, 6, 5], "color": Color.MAGENTA}
]
func _input(event: InputEvent) -> void:
if event is InputEventMouseMotion and Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
angle_y -= event.relative.x * mouse_sensitivity
angle_x += event.relative.y * mouse_sensitivity
if event is InputEventMouseButton:
if Input.is_mouse_button_pressed(MOUSE_BUTTON_WHEEL_UP):
camera_z += 0.25
if Input.is_mouse_button_pressed(MOUSE_BUTTON_WHEEL_DOWN):
camera_z -= 0.25
func _process(delta: float) -> void:
if not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
angle_x -= 0.1 * delta
angle_y -= 0.2 * delta
queue_redraw()
func _draw() -> void:
var screen_center = get_viewport_rect().size / 2
var transformed_vertices: Array[Vector3] = []
var projected_points: Array[Vector2] = []
for vertex in vertices:
var y1 = vertex.y * cos(angle_x) - vertex.z * sin(angle_x)
var z1 = vertex.y * sin(angle_x) + vertex.z * cos(angle_x)
var x2 = vertex.x * cos(angle_y) + z1 * sin(angle_y)
var z2 = -vertex.x * sin(angle_y) + z1 * cos(angle_y)
var final_z = z2 + camera_z
if final_z <= 0.1: final_z = 0.1
transformed_vertices.append(Vector3(x2, y1, final_z))
var screen_x = (x2 * fov) / final_z + screen_center.x
var screen_y = (y1 * fov) / final_z + screen_center.y
projected_points.append(Vector2(screen_x, screen_y))
var render_queue: Array = []
for face in faces:
var avg_z: float = 0.0
var face_points: PackedVector2Array = PackedVector2Array()
for index in face["indices"]:
avg_z += transformed_vertices[index].z
face_points.append(projected_points[index])
avg_z /= 4.0
render_queue.append({"points": face_points, "color": face["color"], "z": avg_z})
render_queue.sort_custom(func(a, b): return a["z"] > b["z"])
for face in render_queue:
draw_polygon(face["points"], [face["color"]])
for i in range(face["points"].size()):
var p1 = face["points"][i]
var p2 = face["points"][(i + 1) % face["points"].size()]
draw_line(p1, p2, Color.BLACK, 1.5, true)