chore: auto-commit (43 archivos)
- .mcp.json - bash/functions/infra/write_mcp_jupyter_config.md - bash/functions/infra/write_mcp_jupyter_config.sh - cpp/CMakeLists.txt - cpp/apps/chart_demo - cpp/apps/shaders_lab - cpp/functions/gfx/gl_framebuffer.cpp - cpp/functions/gfx/gl_framebuffer.h - cpp/functions/gfx/gl_framebuffer.md - cpp/functions/gfx/mesh_gpu.md - ... Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
---
|
||||
name: gltf_load_mesh
|
||||
kind: function
|
||||
lang: cpp
|
||||
domain: gfx
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "Mesh gltf_load_mesh_from_file(const char* path); Mesh gltf_load_mesh_from_memory(const unsigned char* data, size_t size); const char* gltf_load_last_error()"
|
||||
description: "Parser GLB 2.0 (glTF binario): carga el primer mesh/primitive a CPU como fn::gfx::Mesh. Soporta POSITION+NORMAL (vec3 float), indices ubyte/ushort/uint, node transform TRS/matrix. Genera normales smooth area-weighted si faltan. Sin dependencias externas — BIN chunk + nlohmann JSON vendored."
|
||||
tags: [mesh, gltf, glb, 3d, loader, geometry, gfx, mesh-3d]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [gfx/mesh_obj_load.h, nlohmann/json.hpp, fstream, cstring, cmath]
|
||||
tested: true
|
||||
tests:
|
||||
- "invalid magic -> empty Mesh + last_error set"
|
||||
- "too-small buffer -> empty Mesh + last_error set"
|
||||
- "triangle without NORMAL -> normals generated, correct count"
|
||||
- "quad (2 triangles) -> positions.size()==12, indices.size()==6"
|
||||
- "explicit normals -> passed through unchanged"
|
||||
- "nonexistent file -> empty Mesh + last_error set"
|
||||
test_file_path: "cpp/tests/test_gltf_load_mesh.cpp"
|
||||
file_path: "cpp/functions/gfx/gltf_load_mesh.cpp"
|
||||
framework: opengl
|
||||
params:
|
||||
- name: path
|
||||
desc: "Ruta al archivo .glb. Solo GLB binario — .gltf+.bin separado y data-URI base64 no soportados."
|
||||
- name: data
|
||||
desc: "Puntero al buffer GLB en memoria. Debe vivir mientras dure la llamada."
|
||||
- name: size
|
||||
desc: "Longitud del buffer en bytes."
|
||||
output: "fn::gfx::Mesh con positions/normals (stride 3, mismo length) y indices uint32 (tri-list). Mesh vacio (positions.empty()==true) si parse falla. gltf_load_last_error() devuelve descripcion del error."
|
||||
notes: |
|
||||
Usa fn::gfx::Mesh de mesh_obj_load.h — mismo struct que consume mesh_gpu_upload().
|
||||
nlohmann vendored en cpp/vendor/nlohmann/json.hpp.
|
||||
El parser no aloca heap mas alla del Mesh de salida + JSON temporal.
|
||||
gltf_load_last_error() usa thread_local — seguro en multihilo siempre que
|
||||
cada hilo llame sus propias funciones.
|
||||
---
|
||||
|
||||
# gltf_load_mesh
|
||||
|
||||
Loader GLB 2.0 minimal para el registry. Parsea el contenedor GLB binario a mano
|
||||
(header 12 bytes + chunks JSON + BIN) usando nlohmann para el JSON. KISS: sin
|
||||
tinygltf ni dependencias extra.
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```cpp
|
||||
// Cargar .glb generado por TripoSR/trimesh y subir a GPU:
|
||||
#include "gfx/gltf_load_mesh.h"
|
||||
#include "gfx/mesh_gpu.h"
|
||||
|
||||
auto cpu = fn::gfx::gltf_load_mesh_from_file("model.glb");
|
||||
if (cpu.positions.empty()) {
|
||||
fprintf(stderr, "gltf load failed: %s\n", fn::gfx::gltf_load_last_error());
|
||||
return;
|
||||
}
|
||||
|
||||
// Subir a GPU (requiere contexto GL activo):
|
||||
auto gpu = fn::gfx::mesh_gpu_upload(cpu);
|
||||
if (!gpu.ok()) { /* fallo de upload GL */ return; }
|
||||
|
||||
glUseProgram(prog);
|
||||
glBindVertexArray(gpu.vao);
|
||||
glDrawElements(GL_TRIANGLES, gpu.index_count, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
fn::gfx::mesh_gpu_destroy(gpu);
|
||||
```
|
||||
|
||||
```cpp
|
||||
// Desde memoria (ej. respuesta HTTP o embedding):
|
||||
std::vector<unsigned char> glb_buf = download_glb(...);
|
||||
auto cpu = fn::gfx::gltf_load_mesh_from_memory(glb_buf.data(), glb_buf.size());
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando recibes un `.glb` (binario glTF 2.0) de un backend Python (TripoSR,
|
||||
trimesh, open3d) y necesitas renderizarlo en una app ImGui via `mesh_gpu_upload`.
|
||||
Tambien util para inspeccionar geometria en CPU sin subir a GPU.
|
||||
|
||||
## Limitaciones
|
||||
|
||||
- **Solo GLB binario**. `.gltf + .bin` separado: no soportado. Data URIs base64: no soportados.
|
||||
- **Primer mesh, primera primitive**. Archivos con multiples meshes o materiales: solo se carga el primero.
|
||||
- **Sin texturas ni materiales**. El Mesh solo contiene geometria (posicion + normal). El shader del viewer usa color uniforme.
|
||||
- **Buffer unico embebido** (chunk BIN). Referencias a buffers externos: no soportadas.
|
||||
- **Modo solo triangulos** (`"mode": 4`, default). Puntos, lineas, triangle-strip: no soportados.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `gltf_load_last_error()` es `thread_local`. Si usas multihilo, cada hilo tiene su propio error buffer — no compartas el puntero entre hilos.
|
||||
- El puntero que devuelve `gltf_load_last_error()` se sobreescribe en la siguiente llamada a `gltf_load_mesh_from_*`. Copia el string si lo necesitas despues.
|
||||
- Un `Mesh` retornado con `positions.empty() == true` es la senal de fallo — **no** lanzamos excepciones.
|
||||
- Para archivos grandes (>50 MB) la lectura es un `std::vector<uint8_t>` completo en memoria. Para streaming, usa `gltf_load_mesh_from_memory` con tu propio buffer.
|
||||
- El parser no valida que `indices` sean menores que `nv` en cada vertice — indices fuera de rango se saltan silenciosamente durante la generacion de normales pero pueden producir geometria incorrecta.
|
||||
Reference in New Issue
Block a user