From beed54fd18f99b726c6b2e280b2fb4492a09569b Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Thu, 12 Mar 2026 10:02:40 +0700 Subject: [PATCH] Extract scene hiearchy and matrices, render recursively --- src/nol/core.clj | 109 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 32 deletions(-) diff --git a/src/nol/core.clj b/src/nol/core.clj index e58cf35..e1fc93b 100644 --- a/src/nol/core.clj +++ b/src/nol/core.clj @@ -3,7 +3,7 @@ [clojure.math]) (:import [java.nio FloatBuffer IntBuffer] - [org.lwjgl.assimp AIColor4D AIMaterial AIMesh AIScene AIString AITexture Assimp] + [org.lwjgl.assimp AIColor4D AIMaterial AIMatrix4x4 AIMesh AINode AIScene AIString AITexture Assimp] [org.lwjgl.glfw GLFW GLFWKeyCallbackI] [org.lwjgl.opengl GL GL11 GL20 GL30 GL45] [org.lwjgl.stb STBImage] @@ -44,10 +44,55 @@ (throw (RuntimeException. (str "Program link error: " (GL20/glGetProgramInfoLog program))))) program)) -(def loaded-scenes (atom [])) -(def uploaded-scenes (atom [])) +(defn ai-matrix->matrix4f [^AIMatrix4x4 m] + (Matrix4f. (.a1 m) (.a2 m) (.a3 m) (.a4 m) + (.b1 m) (.b2 m) (.b3 m) (.b4 m) + (.c1 m) (.c2 m) (.c3 m) (.c4 m) + (.d1 m) (.d2 m) (.d3 m) (.d4 m))) + +(defn matrix4f->vectors [^Matrix4f m] + [(vector (.m00 m) (.m01 m) (.m02 m) (.m03 m)) + (vector (.m10 m) (.m11 m) (.m12 m) (.m13 m)) + (vector (.m20 m) (.m21 m) (.m22 m) (.m23 m)) + (vector (.m30 m) (.m31 m) (.m32 m) (.m33 m))]) + +(defn node-matrix4f [^AINode c] + (-> c + (.mTransformation) + (ai-matrix->matrix4f))) + +(defn node-matrix [^AINode c] + (-> c + (.mTransformation) + (ai-matrix->matrix4f) + (matrix4f->vectors))) + +(def loaded-scene (atom nil)) +(def uploaded-scene (atom nil)) (def shaders (atom nil)) +(defn render-scene [scene node mtx] + (when-let [mesh-indices (seq (:meshes node))] + (let [{:keys [gl-meshes gl-textures]} scene + {:keys [program uniforms]} @shaders] + (doseq [idx mesh-indices + :let [gl-mesh (nth gl-meshes idx) + mesh (:mesh gl-mesh) + [r g b a] (:color mesh) + tex-idx (:texture-idx mesh)]] + (GL20/glUniform4f (:color uniforms) r g b a) + (GL20/glUniformMatrix4fv (:mm uniforms) false mtx #_(:transform node)) + (GL30/glBindVertexArray (:vao gl-mesh)) + (when tex-idx + (let [tex-id (:gl-id (nth gl-textures tex-idx))] + (GL45/glActiveTexture GL45/GL_TEXTURE0) + (GL11/glBindTexture GL11/GL_TEXTURE_2D tex-id) + (GL20/glUniform1i (:tex uniforms) 0))) + (GL11/glDrawElements GL11/GL_TRIANGLES (:indices-count gl-mesh) GL11/GL_UNSIGNED_INT 0)))) + (when-let [children (seq (:children node))] + (doseq [child children] + (render-scene scene child mtx)))) + (defn- update-loop [window stack data] (let [w-buf (.mallocInt stack 1) h-buf (.mallocInt stack 1) @@ -57,31 +102,20 @@ t (GLFW/glfwGetTime)] (GL11/glViewport 0 0 w h) (GL11/glClear GL11/GL_COLOR_BUFFER_BIT) + (GL11/glClear (bit-or GL11/GL_COLOR_BUFFER_BIT GL11/GL_DEPTH_BUFFER_BIT)) ;; (swap! state assoc :last-time t) (try - (when (and (seq @uploaded-scenes) @shaders) - (doseq [scene @uploaded-scenes - :let [{:keys [meshes gl-meshes gl-textures]} scene - {:keys [program uniforms]} @shaders]] + (when (and @uploaded-scene @shaders) + (let [scene @uploaded-scene + {:keys [program uniforms]} @shaders] (GL20/glUseProgram program) - (doseq [m gl-meshes - :let [[r g b a] (:color (:mesh m)) - tex-idx (:texture-idx (:mesh m))]] - (GL20/glUniform4f (:color uniforms) r g b a) - (let [buf (.mallocFloat stack 16) - m (Matrix4f.)] - (.get m buf) - (GL20/glUniformMatrix4fv (:mm uniforms) false buf) - (GL20/glUniformMatrix4fv (:mv uniforms) false buf) - (GL20/glUniformMatrix4fv (:mp uniforms) false buf)) - (GL30/glBindVertexArray (:vao m)) - (when tex-idx - (let [tex-id (:gl-id (nth gl-textures tex-idx))] - (GL45/glActiveTexture GL45/GL_TEXTURE0) - (GL11/glBindTexture GL11/GL_TEXTURE_2D tex-id) - (GL20/glUniform1i (:tex uniforms) 0))) - (GL11/glDrawElements GL11/GL_TRIANGLES (:indices-count m) GL11/GL_UNSIGNED_INT 0)))) + (let [buf (.mallocFloat stack 16) + m (Matrix4f.)] + (.get m buf) + (GL20/glUniformMatrix4fv (:mv uniforms) false buf) + (GL20/glUniformMatrix4fv (:mp uniforms) false buf) + (render-scene scene (:hiearchy scene) buf)))) (catch Exception e (println "Update Loop GL thread error:" e))) @@ -91,7 +125,7 @@ (GLFW/glfwSwapBuffers window))) (defn stop! [] - (reset! uploaded-scenes []) + (reset! uploaded-scene nil) (reset! shaders nil) (with-gl (GLFW/glfwSetWindowShouldClose @@ -105,7 +139,7 @@ (GLFW/glfwWindowHint GLFW/GLFW_CONTEXT_VERSION_MINOR 5) (GLFW/glfwWindowHint GLFW/GLFW_OPENGL_PROFILE GLFW/GLFW_OPENGL_CORE_PROFILE) - (let [window (GLFW/glfwCreateWindow 960 #_1900 300 #_1100 "NOL" MemoryUtil/NULL MemoryUtil/NULL)] + (let [window (GLFW/glfwCreateWindow 960 300 #_#_1900 1100 "NOL" MemoryUtil/NULL MemoryUtil/NULL)] (when (= window MemoryUtil/NULL) (GLFW/glfwTerminate) (throw (RuntimeException. "Failed to create window"))) @@ -199,6 +233,14 @@ Assimp/aiProcess_FlipUVs)] (Assimp/aiImportFile path flags))) +(defn traverse [^AINode node] + {:node node + :meshes (let [buf (.mMeshes node)] + (mapv #(.get buf %) (range (.mNumMeshes node)))) + :transform (node-matrix4f node) + :children (mapv #(traverse (AINode/create ^long (.get (.mChildren node) %))) + (range (.mNumChildren node)))}) + (defn load-scene [path] (let [scene (load-model path) meshes (doall @@ -213,8 +255,10 @@ h (int-array 1) channels (int-array 1)] {:data (STBImage/stbi_load_from_memory buf w h channels 4) - :w (aget w 0) :h (aget h 0)}))))] - {:scene scene :meshes meshes :textures textures})) + :w (aget w 0) :h (aget h 0)})))) + hiearchy (traverse (.mRootNode scene))] + (Assimp/aiReleaseImport scene) + {:meshes meshes :textures textures :hiearchy hiearchy})) (defn upload-scene! [scene] (let [gl-meshes @@ -264,16 +308,17 @@ :mv (GL20/glGetUniformLocation program "uView") :mp (GL20/glGetUniformLocation program "uProjection")}})) +(reset! loaded-scene (load-scene "assets/model.glb")) + (comment (start!) (stop!) - (@loaded-scenes) - - (swap! loaded-scenes conj (load-scene "assets/model.glb")) - (swap! uploaded-scenes conj (with-gl (upload-scene! (first @loaded-scenes)))) + (reset! uploaded-scene (with-gl (upload-scene! @loaded-scene))) (reset! shaders (with-gl (load-shaders! "shaders/base.vert" "shaders/base.frag"))) + (with-gl + (GL11/glClear (bit-or GL11/GL_COLOR_BUFFER_BIT GL11/GL_DEPTH_BUFFER_BIT))) (with-gl (GL11/glClearColor 0.392 0.584 0.929 1.0)) (with-gl