¿Qué es un Archivo OBJ?
OBJ — Wavefront Object — es uno de los formatos de archivo 3D más antiguos y universalmente compatibles. Desarrollado por Wavefront Technologies a finales de los años 80 para su software Advanced Visualizer, OBJ almacena geometría de malla 3D como texto ASCII plano. A pesar de tener más de 30 años, OBJ sigue siendo la lingua franca de los gráficos 3D: prácticamente todas las aplicaciones de modelado 3D, animación, motores de juegos y renderizado lo soportan.
A diferencia de STL (que solo almacena triángulos), OBJ soporta:
- Polígonos de cualquier número de vértices (triángulos, quads, n-gons)
- Coordenadas UV de textura para mapear imágenes 2D sobre superficies 3D
- Normales de vértices para sombreado suave
- Grupos y objetos con nombre para organizar componentes de malla
- Referencias de material mediante archivos
.mtlacompañantes
Estructura del Archivo OBJ
Un archivo OBJ es una secuencia de líneas con prefijos de palabras clave:
| Palabra clave | Datos | Ejemplo |
|---|---|---|
v |
Posición de vértice (x y z) | v 1.0 2.0 0.5 |
vt |
Coordenada de textura (u v) | vt 0.500 0.750 |
vn |
Normal de vértice (x y z) | vn 0.0 1.0 0.0 |
f |
Cara — índices de vértices (base 1) | f 1 2 3 o f 1/1/1 2/2/2 3/3/3 |
o |
Nombre del objeto | o Cuerpo |
g |
Nombre del grupo | g brazo_izquierdo |
usemtl |
Usar material del archivo .mtl | usemtl MetalAzul |
mtllib |
Referencia al archivo .mtl | mtllib escena.mtl |
OBJ Mínimo: Un Triángulo Simple
# Triángulo simple
o Triangulo
v 0.0 0.0 0.0
v 1.0 0.0 0.0
v 0.5 1.0 0.0
f 1 2 3
OBJ con Coordenadas de Textura y Normales
# Quad texturizado (dos triángulos)
mtllib cubo.mtl
o Cubo
v -1.0 -1.0 1.0
v 1.0 -1.0 1.0
v 1.0 1.0 1.0
v -1.0 1.0 1.0
vt 0.0 0.0
vt 1.0 0.0
vt 1.0 1.0
vt 0.0 1.0
vn 0.0 0.0 1.0
usemtl TexturaMadera
f 1/1/1 2/2/1 3/3/1
f 1/1/1 3/3/1 4/4/1
La Biblioteca de Materiales MTL
# Biblioteca de materiales
newmtl TexturaMadera
Ka 0.1 0.1 0.1
Kd 0.8 0.6 0.3
Ks 0.3 0.3 0.3
Ns 32.0
d 1.0
illum 2
map_Kd veta_madera.png
newmtl MetalCromo
Ka 0.25 0.25 0.25
Kd 0.4 0.4 0.4
Ks 0.9 0.9 0.9
Ns 200.0
illum 3
Trabajar con OBJ en Python
Leer Archivos OBJ con trimesh
pip install trimesh
import trimesh
def inspeccionar_obj(ruta: str) -> dict:
"""Carga y analiza un archivo OBJ."""
escena = trimesh.load(ruta)
if isinstance(escena, trimesh.Scene):
mallas = list(escena.geometry.values())
else:
mallas = [escena]
for i, malla in enumerate(mallas):
print(f"Malla {i+1}: {len(malla.vertices)} vértices, "
f"{len(malla.faces)} caras, "
f"hermética={malla.is_watertight}")
return {'mallas': len(mallas)}
inspeccionar_obj('personaje.obj')
Crear un Archivo OBJ Programáticamente
def escribir_obj(ruta: str, vertices: list, caras: list,
nombre_objeto: str = 'MiObjeto') -> None:
"""Escribe un archivo OBJ mínimo."""
with open(ruta, 'w') as f:
f.write(f"# Generado con Python\n")
f.write(f"o {nombre_objeto}\n\n")
for vx, vy, vz in vertices:
f.write(f"v {vx:.6f} {vy:.6f} {vz:.6f}\n")
f.write("\n")
for cara in caras:
indices = ' '.join(str(i) for i in cara)
f.write(f"f {indices}\n")
vertices = [
(0.0, 0.0, 0.0), (1.0, 0.0, 0.0),
(1.0, 1.0, 0.0), (0.0, 1.0, 0.0),
(0.5, 0.5, 1.0),
]
caras = [(1,2,3,4), (1,2,5), (2,3,5), (3,4,5), (4,1,5)]
escribir_obj('piramide.obj', vertices, caras, 'Piramide')
Convertir OBJ a Otros Formatos
import trimesh, os
def convertir_obj(entrada: str, salida: str) -> None:
"""Convierte OBJ a otro formato 3D."""
escena = trimesh.load(entrada)
escena.export(salida)
tam_kb = os.path.getsize(salida) / 1024
print(f"Convertido: {salida} ({tam_kb:.1f} KB)")
convertir_obj('modelo.obj', 'modelo.stl') # → STL para impresión 3D
convertir_obj('modelo.obj', 'modelo.glb') # → GLB para web/AR/VR
convertir_obj('modelo.obj', 'modelo.ply') # → PLY para nubes de puntos
Comparativa OBJ: STL, FBX, glTF
| Formato | OBJ | STL | FBX | glTF/GLB |
|---|---|---|---|---|
| Año | 1989 | 1987 | 1996 | 2015 |
| Basado en texto | Sí | Sí/No | No | JSON + binario |
| Materiales | Archivo .mtl acompañante | No | Sí (incrustado) | Sí (incrustado) |
| UV/texturas | Sí | No | Sí | Sí |
| Animaciones | No | No | Sí (esquelético) | Sí |
| Impresión 3D | Limitado | Formato principal | No | No |
| Web/AR/VR | Posible pero no ideal | No | No | Óptimo |
| Motores de juego | Universal | Limitado | Universal | Universal |
Cuándo usar OBJ: Máxima compatibilidad entre distintos programas 3D; intercambio de mallas estáticas con materiales/texturas.
Cuándo elegir otra alternativa: Juego/aplicación con animaciones → FBX o glTF; impresión 3D → STL o 3MF; web/AR/VR → glTF/GLB.
Optimización de Archivos OBJ Grandes
import trimesh
def optimizar_obj(entrada: str, salida: str) -> None:
"""Fusiona vértices duplicados y triangula una malla OBJ."""
malla = trimesh.load(entrada, force='mesh')
malla.merge_vertices()
malla.remove_degenerate_faces()
malla.remove_duplicate_faces()
print(f"Optimizado: {len(malla.vertices)} vértices, {len(malla.faces)} caras")
malla.export(salida)
optimizar_obj('escena_grande.obj', 'escena_optimizada.obj')
Conversiones relacionadas
Conversiones frecuentes del catálogo: