From 6ff37ff5a4df554869801efbb860fbd4501fe93d Mon Sep 17 00:00:00 2001 From: Yukari Hafner Date: Tue, 21 Jan 2025 15:50:42 +0100 Subject: [PATCH] Fix reloading of optimized meshes --- formats/gltf/mesh.lisp | 7 ++-- formats/gltf/optimize.lisp | 73 ++++++++++++++++++-------------------- formats/gltf/physics.lisp | 30 ++++++++-------- formats/gltf/scene.lisp | 2 +- 4 files changed, 54 insertions(+), 58 deletions(-) diff --git a/formats/gltf/mesh.lisp b/formats/gltf/mesh.lisp index 8e7f352e..3bc765ad 100644 --- a/formats/gltf/mesh.lisp +++ b/formats/gltf/mesh.lisp @@ -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) @@ -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))) @@ -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) diff --git a/formats/gltf/optimize.lisp b/formats/gltf/optimize.lisp index 79728830..08e97b11 100644 --- a/formats/gltf/optimize.lisp +++ b/formats/gltf/optimize.lisp @@ -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) @@ -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) @@ -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)) diff --git a/formats/gltf/physics.lisp b/formats/gltf/physics.lisp index 111435e0..cb162f3f 100644 --- a/formats/gltf/physics.lisp +++ b/formats/gltf/physics.lisp @@ -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) diff --git a/formats/gltf/scene.lisp b/formats/gltf/scene.lisp index b82083f9..98f8a6bb 100644 --- a/formats/gltf/scene.lisp +++ b/formats/gltf/scene.lisp @@ -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