Caméra en orbite

Glissez avec le bouton gauche pour tourner la caméra autour de la pièce centrale, et utilisez la molette pour zoomer. Lacet, tangage et distance sont tout l'état.

L'éditeur ci-dessus fait tourner ce projet. Changez une ligne et il se recharge.

Classes Godot utilisées

Camera3DInputEventMouseMotionInputEventMouseButton

Le code

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)

Plus d'exemples de Scène 3D