Câmera em órbita
Arraste com o botão esquerdo para girar a câmera em volta da peça central, e use a roda para dar zoom. Yaw, pitch e distância são todo o estado.
O editor acima está rodando este projeto. Mude uma linha e ele recarrega.
Classes do Godot usadas
Camera3DInputEventMouseMotionInputEventMouseButton
O código
scripts/main.gd
extends Node
const TARGET: Vector3 = Vector3(0, 1.4, 0)
const SENSITIVITY: float = 0.007
const PITCH_LIMIT: float = 1.35
const ZOOM_STEP: float = 0.7
var camera: Camera3D
var yaw: float = 0.7
var pitch: float = 0.4
var distance: float = 9.8
func _ready() -> void:
_add_environment()
_add_light()
_add_ground()
_add_centerpiece()
_add_pillars()
camera = Camera3D.new()
add_child(camera)
camera.current = true
_place_camera()
print('drag with the left button to orbit the torus, and the wheel zooms in and out')
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
var motion: InputEventMouseMotion = event
if motion.button_mask & MOUSE_BUTTON_MASK_LEFT:
yaw -= motion.relative.x * SENSITIVITY
# beyond 90 degrees the orbit direction flips and look_at goes singular against Vector3.UP
pitch = clamp(pitch - motion.relative.y * SENSITIVITY, -PITCH_LIMIT, PITCH_LIMIT)
_place_camera()
if event is InputEventMouseButton:
var click: InputEventMouseButton = event
if not click.pressed:
return
if click.button_index == MOUSE_BUTTON_WHEEL_UP:
distance = clamp(distance - ZOOM_STEP, 4.0, 24.0)
_place_camera()
elif click.button_index == MOUSE_BUTTON_WHEEL_DOWN:
distance = clamp(distance + ZOOM_STEP, 4.0, 24.0)
_place_camera()
func _place_camera() -> void:
var offset: Vector3 = Vector3(cos(pitch) * sin(yaw), sin(pitch), cos(pitch) * cos(yaw))
camera.position = TARGET + offset * distance
camera.look_at(TARGET, Vector3.UP)
func _add_centerpiece() -> void:
var base: CylinderMesh = CylinderMesh.new()
base.top_radius = 1.1
base.bottom_radius = 1.5
base.height = 1.0
var pedestal: MeshInstance3D = MeshInstance3D.new()
pedestal.mesh = base
pedestal.material_override = _make_material('#3a4152', 0.6)
pedestal.position = Vector3(0, 0.5, 0)
add_child(pedestal)
var ring: TorusMesh = TorusMesh.new()
ring.inner_radius = 0.7
ring.outer_radius = 1.25
var material: StandardMaterial3D = _make_material('#f3d48d', 0.25)
material.metallic = 0.7
material.emission_enabled = true
material.emission = Color('#f3d48d')
material.emission_energy_multiplier = 0.5
var torus: MeshInstance3D = MeshInstance3D.new()
torus.mesh = ring
torus.material_override = material
torus.position = Vector3(0, 2.0, 0)
torus.rotation_degrees = Vector3(-25, 0, 0)
add_child(torus)
func _add_pillars() -> void:
var colors: Array[String] = ['#8da5f3', '#8eef97', '#fc7f7f', '#8da5f3', '#8eef97', '#fc7f7f']
for i in colors.size():
var turn: float = TAU * i / colors.size()
var height: float = 1.4 + float(i % 3) * 0.8
var mesh: BoxMesh = BoxMesh.new()
mesh.size = Vector3(0.9, height, 0.9)
var pillar: MeshInstance3D = MeshInstance3D.new()
pillar.mesh = mesh
pillar.material_override = _make_material(colors[i], 0.5)
pillar.position = Vector3(cos(turn), 0, sin(turn)) * 5.2 + Vector3(0, height * 0.5, 0)
add_child(pillar)
func _add_ground() -> void:
var mesh: PlaneMesh = PlaneMesh.new()
mesh.size = Vector2(120, 120)
var ground: MeshInstance3D = MeshInstance3D.new()
ground.mesh = mesh
ground.material_override = _make_material('#242938', 0.95)
add_child(ground)
func _make_material(hex: String, roughness: float) -> StandardMaterial3D:
var material: StandardMaterial3D = StandardMaterial3D.new()
material.albedo_color = Color(hex)
material.roughness = roughness
return material
func _add_environment() -> void:
var sky_material: ProceduralSkyMaterial = ProceduralSkyMaterial.new()
sky_material.sky_top_color = Color(0.07, 0.09, 0.18)
sky_material.sky_horizon_color = Color(0.26, 0.29, 0.4)
sky_material.ground_bottom_color = Color(0.15, 0.17, 0.23)
sky_material.ground_horizon_color = Color(0.18, 0.2, 0.28)
var sky: Sky = Sky.new()
sky.sky_material = sky_material
var env: Environment = Environment.new()
env.background_mode = Environment.BG_SKY
env.sky = sky
env.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
env.ambient_light_energy = 0.8
var world: WorldEnvironment = WorldEnvironment.new()
world.environment = env
add_child(world)
func _add_light() -> void:
var light: DirectionalLight3D = DirectionalLight3D.new()
light.rotation_degrees = Vector3(-55, -40, 0)
light.light_energy = 1.3
light.shadow_enabled = true
add_child(light)