Skip to content

Commit

Permalink
Fix reloading of optimized meshes
Browse files Browse the repository at this point in the history
  • Loading branch information
Shinmera committed Jan 21, 2025
1 parent d281084 commit 6ff37ff
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 58 deletions.
7 changes: 4 additions & 3 deletions formats/gltf/mesh.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
(setf (trial::initial-weights mesh) (or weights #())))
mesh))

(defun load-mesh (mesh model &key skeleton model-name)
(defun load-mesh (mesh &key model skeleton model-name)
(let ((base-name (gltf-name mesh))
(primitives (gltf:primitives mesh)))
(flet ((load-primitive (primitive name)
Expand All @@ -157,7 +157,7 @@
for primitive = (aref primitives i)
collect (load-primitive primitive (cons base-name i))))))))

(defun load-meshes (gltf model)
(defun load-meshes (gltf &key model)
(let* ((meshes (make-array 0 :adjustable T :fill-pointer T))
(skeletons (map 'vector (lambda (skin) (load-skeleton gltf skin)) (gltf:skins gltf)))
(reorderings (map-into (make-array (length skeletons)) #'make-hash-table)))
Expand All @@ -172,7 +172,8 @@
for map = (when (gltf:skin node)
(aref reorderings (gltf:idx (gltf:skin node))))
do (when (gltf:mesh node)
(loop for mesh in (load-mesh (gltf:mesh node) model
(loop for mesh in (load-mesh (gltf:mesh node)
:model model
:model-name (gltf-name node)
:skeleton skeleton)
do (when (skinned-p mesh)
Expand Down
73 changes: 35 additions & 38 deletions formats/gltf/optimize.lisp
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
(in-package #:org.shirakumo.fraf.trial.gltf)

(defun add-convex-mesh (gltf primitives &optional name)
(flet ((make-primitive (geometry)
(gltf:make-mesh-primitive gltf (car geometry) (cdr geometry) '(:position))))
(defun add-shapes-mesh (gltf shapes &optional name)
(flet ((make-primitive (shape)
(gltf:make-mesh-primitive
gltf
(convex-mesh-vertices shape)
(convex-mesh-faces shape)
'(:position)
:matrix (marr4 (primitive-local-transform shape)))))
(gltf:make-indexed 'gltf:mesh gltf
:name name
:primitives (map 'vector #'make-primitive primitives))))

(defmethod optimize-model (file (type (eql :glb)) &rest args)
(apply #'optimize-model file :gltf args))
:primitives (map 'vector #'make-primitive shapes))))

(defun optimized-p (mesh)
(and (gltf:name mesh)
(cl-ppcre:scan "/(decomposed|rehulled)$" (gltf:name mesh))))

(defmethod optimize-model (file (type (eql :gltf)) &rest args &key (output file) &allow-other-keys)
(let ((decomposition-args (remf* args :output))
(mesh-table (make-hash-table :test 'eql))
(defun optimize-geometry (gltf geometry)
(let* ((node (gltf:node geometry))
(shapes (load-physics-geometry geometry NIL))
(shapes (trial::convexify shapes :rehull T))
(mesh (add-shapes-mesh gltf shapes (format NIL "~a/~:[decomposed~;rehulled~]"
(gltf:name (gltf:mesh node))
(gltf:convex-p geometry)))))
(v:info :trial.gltf "Creating new mesh ~a" mesh)
(gltf:make-indexed 'gltf:node node
:mesh mesh
:name (gltf:name mesh)
:virtual-p T
:matrix (gltf:matrix node)
:rotation (gltf:rotation node)
:scale (gltf:scale node)
:translation (gltf:translation node))))

(defmethod optimize-model (file (type (eql :gltf)) &key (output #p""))
(let ((mesh-table (make-hash-table :test 'eql))
(work-done-p NIL))
(trial:with-tempfile (tmp :type (pathname-type file))
(gltf:with-gltf (gltf file)
Expand All @@ -29,33 +47,9 @@
(geometry (gltf:geometry collider)))
(when (and (gltf:node geometry)
(not (optimized-p (gltf:mesh (gltf:node geometry)))))
(let ((new (gethash (gltf:mesh (gltf:node geometry)) mesh-table)))
(unless new
(let* ((node (gltf:node geometry))
(mesh (gltf:mesh node))
(meshes (loop for primitive across (gltf:primitives mesh)
for mesh = (load-primitive primitive)
collect (cons (reordered-vertex-data mesh '(location)) (faces mesh))))
(meshes (cond ((gltf:convex-p geometry)
(v:info :trial.gltf "Re-hulling ~a" mesh)
(loop for (vertices) in meshes
collect (multiple-value-bind (vertices faces) (org.shirakumo.fraf.quickhull:convex-hull vertices)
(cons vertices faces))))
(T
(v:info :trial.gltf "Decomposing ~a" mesh)
(loop for (vertices . faces) in meshes
nconc (coerce (apply #'trial::decompose-to-convex vertices faces decomposition-args) 'list)))))
(new-mesh (add-convex-mesh gltf meshes (format NIL "~a/~:[decomposed~;rehulled~]"
(gltf:name mesh) (gltf:convex-p geometry)))))
(v:info :trial.gltf "Creating new mesh ~a" new-mesh)
(setf new (gltf:make-indexed 'gltf:node node :mesh new-mesh
:name (gltf:name new-mesh)
:virtual-p T
:matrix (gltf:matrix node)
:rotation (gltf:rotation node)
:scale (gltf:scale node)
:translation (gltf:translation node)))
(setf (gethash mesh mesh-table) new)))
(let ((new (or (gethash (gltf:mesh (gltf:node geometry)) mesh-table)
(setf (gethash (gltf:mesh (gltf:node geometry)) mesh-table)
(optimize-geometry gltf geometry)))))
(v:info :trial.gltf "Updating ~a to point to ~a" node new)
(setf (gltf:node geometry) new)
(setf (gltf:convex-p geometry) T)
Expand All @@ -66,4 +60,7 @@
(gltf:serialize gltf tmp)))
(when (and work-done-p output)
;; FIXME: this does not work correctly if gltf serialises to multiple files.
(org.shirakumo.filesystem-utils:rename-file* tmp output)))))
(org.shirakumo.filesystem-utils:rename-file* tmp (merge-pathnames output file))))))

(defmethod optimize-model (file (type (eql :glb)) &rest args &key &allow-other-keys)
(apply #'optimize-model file :gltf args))
30 changes: 14 additions & 16 deletions formats/gltf/physics.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,20 @@
(float (gltf:radius-bottom shape) 0f0))
args)))
(null
(let ((mesh (gltf:mesh (gltf:node geometry))))
(map 'vector (lambda (mesh)
(apply (if (gltf:convex-p geometry)
#'trial::make-maybe-optimized-convex-mesh
#'trial:make-general-mesh)
:vertices (trial:reordered-vertex-data mesh '(trial:location))
:faces (trial::simplify (trial:faces mesh) '(unsigned-byte 16))
args))
(or (if (= 1 (length (gltf:primitives mesh)))
(find-mesh (gltf:name mesh) model NIL)
(loop for i from 0
for primitive across (gltf:primitives mesh)
for found = (find-mesh (cons (gltf:name mesh) i) model NIL)
unless found do (return NIL)
collect found))
(load-mesh mesh model))))))))
(let ((mesh (gltf:mesh (gltf:node geometry)))
(tf (getf args :local-transform #.(meye 4))))
(map 'vector (lambda (primitive)
(let ((mesh (load-primitive primitive)))
(apply (if (gltf:convex-p geometry)
#'trial::make-maybe-optimized-convex-mesh
#'trial:make-general-mesh)
:vertices (trial:reordered-vertex-data mesh '(trial:location))
:faces (trial::simplify (trial:faces mesh) '(unsigned-byte 16))
:local-transform (if (gltf:matrix primitive)
(m* tf (mat4 (gltf:matrix primitive)))
tf)
args)))
(gltf:primitives mesh)))))))

(defvar *physics-material-cache* (make-hash-table :test 'equal))
(defun physics-material-instance (material)
Expand Down
2 changes: 1 addition & 1 deletion formats/gltf/scene.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
(setf (name model) (pathname-name input)))
(load-materials gltf model generator)
(load-clips gltf NIL (clips model))
(loop for mesh across (load-meshes gltf model)
(loop for mesh across (load-meshes gltf :model model)
do (setf (gethash (name mesh) meshes) mesh)
(trial::make-vertex-array mesh (resource generator (name mesh))))
;; Construct scene graphs
Expand Down

0 comments on commit 6ff37ff

Please # to comment.