forked from PabloSeguraLopez/Trabajo-VC
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathblender_animation.py
164 lines (136 loc) · 5.55 KB
/
blender_animation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import bpy
import numpy as np
import argparse
import sys
def load_npz(npz_file_path):
"""
Load the NPZ file and extract the positions.
"""
data = np.load(npz_file_path)
positions = data["reconstruction"]
return positions[0] # (n_frames, n_squares, 3)
def clear_scene():
"""
Clears all objects, lights and cameras from the scene.
"""
# Eliminar todos los objetos en la escena
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# Eliminar todas las luces
bpy.ops.object.light_add(type='POINT', location=(0, 0, 0))
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# Eliminar todas las cámaras
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
def create_objects(positions):
"""
Create objects (joints) in Blender and return them.
"""
# Crear un material negro
black_material = bpy.data.materials.new(name="Black_Material")
black_material.use_nodes = True
nodes = black_material.node_tree.nodes
principled_node = nodes.get("Principled BSDF")
if principled_node:
# Establecer el color a negro (RGBA)
principled_node.inputs["Base Color"].default_value = (0.0, 0.0, 0.0, 1.0) # Negro
principled_node.inputs["Roughness"].default_value = 1.0 # Opcional: Sin reflejos
n_frames, n_joints, _ = positions.shape
bpy.ops.object.empty_add(type='PLAIN_AXES', location=(0, 0, 0))
parent_object = bpy.context.object
parent_object.name = "Joints_Parent"
objects = []
for i in range(n_joints):
# Joints 9 and 7 are redundant, part of the column
if i == 9 or i == 7:
objects.append(None)
continue
bpy.ops.mesh.primitive_uv_sphere_add(radius=0.1, location=(0, 0, 0))
obj = bpy.context.object
obj.name = f"Joint_{i}"
obj.parent = parent_object
objects.append(obj)
if obj.data.materials:
obj.data.materials[0] = black_material
else:
obj.data.materials.append(black_material)
return objects
def animate_objects(positions, objects):
"""
Animate the objects according to the positions from the NPZ.
"""
n_frames, n_squares, _ = positions.shape
for frame_idx in range(n_frames):
for square_idx, obj in enumerate(objects):
if obj is None:
continue
x, y, z = positions[frame_idx, square_idx]
obj.location = (x, y, z)
obj.keyframe_insert(data_path="location", frame=frame_idx + 1)
def setup_camera():
bpy.ops.object.camera_add(location=(0, 5.92, 1.72))
camera = bpy.context.object
camera.name = "Camera"
camera.rotation_euler = (1.466, 0, -3.1416) # Orient it towards the origin
bpy.context.scene.camera = camera
def setup_light():
bpy.ops.object.light_add(type='SUN', location=(5, -5, 10))
sun_light = bpy.context.object
sun_light.name = "Sun_Light"
def setup_world_background(background_color):
world = bpy.context.scene.world
world.use_nodes = True
nodes = world.node_tree.nodes
links = world.node_tree.links
# Clean existing nodes
for node in nodes:
nodes.remove(node)
background_node = nodes.new(type="ShaderNodeBackground")
# Convert color string to RGB
color_dict = {
"red": (1.0, 0.0, 0.0, 1.0),
"green": (0.0, 1.0, 0.0, 1.0),
"blue": (0.0, 0.0, 1.0, 1.0),
"white": (1.0, 1.0, 1.0, 1.0),
}
background_node.inputs[0].default_value = color_dict.get(background_color, (0.5, 0.2, 0.1, 1.0)) # Default to custom color if not found
output_node = nodes.new(type="ShaderNodeOutputWorld")
links.new(background_node.outputs[0], output_node.inputs[0])
def setup_render(output_path, n_frames, quality):
bpy.context.scene.render.filepath = output_path
bpy.context.scene.render.image_settings.file_format = 'FFMPEG'
bpy.context.scene.render.ffmpeg.format = 'MPEG4'
bpy.context.scene.render.ffmpeg.codec = 'MPEG4'
if quality == "low":
bpy.context.scene.render.resolution_x = 640
bpy.context.scene.render.resolution_y = 360
else:
bpy.context.scene.render.resolution_x = 1920
bpy.context.scene.render.resolution_y = 1080
bpy.context.scene.render.fps = 30
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = n_frames
bpy.context.view_layer.update()
def render_animation():
bpy.ops.render.render(animation=True)
print("Animation successfully saved as MP4.")
def main(npz_file_path, background_color, output_path, quality):
clear_scene()
positions = load_npz(npz_file_path)
n_frames, n_squares, _ = positions.shape
objects = create_objects(positions)
animate_objects(positions, objects)
setup_camera()
setup_light()
setup_world_background(background_color)
setup_render(output_path, n_frames, quality)
render_animation()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Animate and render a 3D character based on 3D skeletons from an NPZ file.")
parser.add_argument('-f', '--file', required=True, help="Path to the NPZ file.")
parser.add_argument('-c', '--color', default="white", help="Background color (e.g., 'red', 'green', 'blue').")
parser.add_argument('-o', '--output', required=True, help="Path for the output video file.")
parser.add_argument('-q', '--quality', default="low", help="Quality for the output video.")
args,_ = parser.parse_known_args(sys.argv[sys.argv.index("--") + 1:])
main(args.file, args.color, args.output, args.quality)