Pose de esqueleto 3D

Una cadena de seis huesos creada por código y colocada cada fotograma con set_bone_pose_rotation. Cada BoneAttachment3D lleva la malla que viaja con su hueso.

El editor de arriba está ejecutando este proyecto. Cambia una línea y se recarga.

Clases de Godot usadas

Skeleton3DBoneAttachment3DMeshInstance3D

El código

scripts/main.gd
extends Node

const BONES: int = 6
const SEGMENT: float = 0.55

var skeleton: Skeleton3D
var elapsed: float = 0.0


func _ready() -> void:
	_add_environment()
	_add_light()
	_add_ground()

	skeleton = Skeleton3D.new()
	skeleton.name = 'Skeleton'
	add_child(skeleton)

	for i in BONES:
		var bone_name: String = 'bone_%d' % i
		skeleton.add_bone(bone_name)

		var index: int = skeleton.find_bone(bone_name)
		var offset: Vector3 = Vector3(0, SEGMENT if i > 0 else 0.0, 0)

		if i > 0:
			skeleton.set_bone_parent(index, index - 1)

		skeleton.set_bone_rest(index, Transform3D(Basis(), offset))
		skeleton.set_bone_pose_position(index, offset)

		var attachment: BoneAttachment3D = BoneAttachment3D.new()
		skeleton.add_child(attachment)
		attachment.bone_name = bone_name
		attachment.add_child(_make_piece(i))

	var camera: Camera3D = Camera3D.new()
	camera.position = Vector3(0, 2.4, 6.5)
	add_child(camera)
	camera.look_at(Vector3(0, 1.7, 0), Vector3.UP)
	camera.current = true

	print('every bone gets a new pose rotation each frame')


func _process(delta: float) -> void:
	elapsed += delta

	for i in BONES:
		var angle: float = sin(elapsed * 2.4 - i * 0.7) * deg_to_rad(24)
		skeleton.set_bone_pose_rotation(i, Quaternion(Vector3.BACK, angle))


func _make_piece(index: int) -> MeshInstance3D:
	var visual: MeshInstance3D = MeshInstance3D.new()

	if index == BONES - 1:
		var head: SphereMesh = SphereMesh.new()
		head.radius = 0.32
		head.height = 0.64
		visual.mesh = head
		visual.position = Vector3(0, 0.2, 0)
	else:
		var link: BoxMesh = BoxMesh.new()
		link.size = Vector3(0.34, SEGMENT * 0.86, 0.34)
		visual.mesh = link
		visual.position = Vector3(0, SEGMENT * 0.5, 0)

	var material: StandardMaterial3D = StandardMaterial3D.new()
	material.albedo_color = Color('#8da5f3').lerp(Color('#8eef97'), float(index) / (BONES - 1))
	material.roughness = 0.45
	visual.material_override = material

	return visual


func _add_ground() -> void:
	var mesh: BoxMesh = BoxMesh.new()
	mesh.size = Vector3(10, 0.4, 10)

	var material: StandardMaterial3D = StandardMaterial3D.new()
	material.albedo_color = Color('#2a2f3d')

	var ground: MeshInstance3D = MeshInstance3D.new()
	ground.mesh = mesh
	ground.material_override = material
	ground.position = Vector3(0, -0.2, 0)
	add_child(ground)


func _add_environment() -> void:
	var sky_material: ProceduralSkyMaterial = ProceduralSkyMaterial.new()
	sky_material.sky_top_color = Color(0.05, 0.06, 0.12)
	sky_material.sky_horizon_color = Color(0.14, 0.16, 0.24)
	sky_material.ground_bottom_color = Color(0.02, 0.02, 0.04)
	sky_material.ground_horizon_color = Color(0.1, 0.11, 0.16)

	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.7

	var world: WorldEnvironment = WorldEnvironment.new()
	world.environment = env
	add_child(world)


func _add_light() -> void:
	var light: DirectionalLight3D = DirectionalLight3D.new()
	light.rotation_degrees = Vector3(-52, -38, 0)
	light.light_energy = 1.2
	light.shadow_enabled = true
	add_child(light)

Más ejemplos de Animación