From 8bd5105c8ac5ac8771a40e3bbca52aa480a27eaa Mon Sep 17 00:00:00 2001 From: Vijay Dirisala Date: Mon, 18 May 2026 00:45:58 -0700 Subject: [PATCH] UV data can be indexed in some FBX files. This patch exposes the underlying vertex_uv.indices data via uv_indices property. --- ufbx/_ufbx.pyx | 17 +++++++++++++++++ ufbx/src/ufbx_wrapper.c | 10 ++++++++++ ufbx/src/ufbx_wrapper.h | 1 + 3 files changed, 28 insertions(+) diff --git a/ufbx/_ufbx.pyx b/ufbx/_ufbx.pyx index 58cd2bc..00cf5f5 100644 --- a/ufbx/_ufbx.pyx +++ b/ufbx/_ufbx.pyx @@ -446,6 +446,7 @@ cdef extern from "ufbx_wrapper.h": const float* ufbx_wrapper_mesh_get_vertex_bitangents(const ufbx_mesh *mesh, size_t *out_count) const float* ufbx_wrapper_mesh_get_vertex_colors(const ufbx_mesh *mesh, size_t *out_count) const uint32_t* ufbx_wrapper_mesh_get_indices(const ufbx_mesh *mesh, size_t *out_count) + const uint32_t* ufbx_wrapper_mesh_get_uv_indices(const ufbx_mesh *mesh, size_t *out_count) # Mesh face data size_t ufbx_wrapper_mesh_get_face_count(const ufbx_mesh *mesh) @@ -2482,6 +2483,22 @@ cdef class Mesh(Element): shape[0] = count return np.PyArray_SimpleNewFromData(1, shape, np.NPY_UINT32, data) + @property + def uv_indices(self): + """UV indices as numpy array (N,)""" + if self._scene._closed: + raise RuntimeError("Scene is closed") + + cdef size_t count = 0 + cdef const uint32_t* data = ufbx_wrapper_mesh_get_uv_indices(self._mesh, &count) + + if data == NULL or count == 0: + return None + + cdef np.npy_intp shape[1] + shape[0] = count + return np.PyArray_SimpleNewFromData(1, shape, np.NPY_UINT32, data) + @property def materials(self): """Materials used by this mesh""" diff --git a/ufbx/src/ufbx_wrapper.c b/ufbx/src/ufbx_wrapper.c index dba25f8..665d940 100644 --- a/ufbx/src/ufbx_wrapper.c +++ b/ufbx/src/ufbx_wrapper.c @@ -280,6 +280,16 @@ const uint32_t* ufbx_wrapper_mesh_get_indices(const ufbx_mesh *mesh, size_t *out return mesh->vertex_position.indices.data; } +const uint32_t* ufbx_wrapper_mesh_get_uv_indices(const ufbx_mesh *mesh, size_t *out_count) { + if (!mesh || !mesh->vertex_uv.exists || !out_count) { + if (out_count) *out_count = 0; + return NULL; + } + + *out_count = mesh->vertex_uv.indices.count; + return mesh->vertex_uv.indices.data; +} + // Mesh face data size_t ufbx_wrapper_mesh_get_face_count(const ufbx_mesh *mesh) { return mesh ? mesh->faces.count : 0; diff --git a/ufbx/src/ufbx_wrapper.h b/ufbx/src/ufbx_wrapper.h index 31bace3..908de30 100644 --- a/ufbx/src/ufbx_wrapper.h +++ b/ufbx/src/ufbx_wrapper.h @@ -82,6 +82,7 @@ const float* ufbx_wrapper_mesh_get_vertex_tangents(const ufbx_mesh *mesh, size_t const float* ufbx_wrapper_mesh_get_vertex_bitangents(const ufbx_mesh *mesh, size_t *out_count); const float* ufbx_wrapper_mesh_get_vertex_colors(const ufbx_mesh *mesh, size_t *out_count); const uint32_t* ufbx_wrapper_mesh_get_indices(const ufbx_mesh *mesh, size_t *out_count); +const uint32_t* ufbx_wrapper_mesh_get_uv_indices(const ufbx_mesh *mesh, size_t *out_count); // Mesh face data size_t ufbx_wrapper_mesh_get_face_count(const ufbx_mesh *mesh);