Extract scene hiearchy and matrices, render recursively

This commit is contained in:
Joseph Ferano 2026-03-12 10:02:40 +07:00
parent fccb0ef878
commit beed54fd18

View File

@ -3,7 +3,7 @@
[clojure.math]) [clojure.math])
(:import (:import
[java.nio FloatBuffer IntBuffer] [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.glfw GLFW GLFWKeyCallbackI]
[org.lwjgl.opengl GL GL11 GL20 GL30 GL45] [org.lwjgl.opengl GL GL11 GL20 GL30 GL45]
[org.lwjgl.stb STBImage] [org.lwjgl.stb STBImage]
@ -44,10 +44,55 @@
(throw (RuntimeException. (str "Program link error: " (GL20/glGetProgramInfoLog program))))) (throw (RuntimeException. (str "Program link error: " (GL20/glGetProgramInfoLog program)))))
program)) program))
(def loaded-scenes (atom [])) (defn ai-matrix->matrix4f [^AIMatrix4x4 m]
(def uploaded-scenes (atom [])) (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)) (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] (defn- update-loop [window stack data]
(let [w-buf (.mallocInt stack 1) (let [w-buf (.mallocInt stack 1)
h-buf (.mallocInt stack 1) h-buf (.mallocInt stack 1)
@ -57,31 +102,20 @@
t (GLFW/glfwGetTime)] t (GLFW/glfwGetTime)]
(GL11/glViewport 0 0 w h) (GL11/glViewport 0 0 w h)
(GL11/glClear GL11/GL_COLOR_BUFFER_BIT) (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) ;; (swap! state assoc :last-time t)
(try (try
(when (and (seq @uploaded-scenes) @shaders) (when (and @uploaded-scene @shaders)
(doseq [scene @uploaded-scenes (let [scene @uploaded-scene
:let [{:keys [meshes gl-meshes gl-textures]} scene {:keys [program uniforms]} @shaders]
{:keys [program uniforms]} @shaders]]
(GL20/glUseProgram program) (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) (let [buf (.mallocFloat stack 16)
m (Matrix4f.)] m (Matrix4f.)]
(.get m buf) (.get m buf)
(GL20/glUniformMatrix4fv (:mm uniforms) false buf)
(GL20/glUniformMatrix4fv (:mv uniforms) false buf) (GL20/glUniformMatrix4fv (:mv uniforms) false buf)
(GL20/glUniformMatrix4fv (:mp uniforms) false buf)) (GL20/glUniformMatrix4fv (:mp uniforms) false buf)
(GL30/glBindVertexArray (:vao m)) (render-scene scene (:hiearchy scene) buf))))
(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))))
(catch Exception e (catch Exception e
(println "Update Loop GL thread error:" e))) (println "Update Loop GL thread error:" e)))
@ -91,7 +125,7 @@
(GLFW/glfwSwapBuffers window))) (GLFW/glfwSwapBuffers window)))
(defn stop! [] (defn stop! []
(reset! uploaded-scenes []) (reset! uploaded-scene nil)
(reset! shaders nil) (reset! shaders nil)
(with-gl (with-gl
(GLFW/glfwSetWindowShouldClose (GLFW/glfwSetWindowShouldClose
@ -105,7 +139,7 @@
(GLFW/glfwWindowHint GLFW/GLFW_CONTEXT_VERSION_MINOR 5) (GLFW/glfwWindowHint GLFW/GLFW_CONTEXT_VERSION_MINOR 5)
(GLFW/glfwWindowHint GLFW/GLFW_OPENGL_PROFILE GLFW/GLFW_OPENGL_CORE_PROFILE) (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) (when (= window MemoryUtil/NULL)
(GLFW/glfwTerminate) (GLFW/glfwTerminate)
(throw (RuntimeException. "Failed to create window"))) (throw (RuntimeException. "Failed to create window")))
@ -199,6 +233,14 @@
Assimp/aiProcess_FlipUVs)] Assimp/aiProcess_FlipUVs)]
(Assimp/aiImportFile path flags))) (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] (defn load-scene [path]
(let [scene (load-model path) (let [scene (load-model path)
meshes (doall meshes (doall
@ -213,8 +255,10 @@
h (int-array 1) h (int-array 1)
channels (int-array 1)] channels (int-array 1)]
{:data (STBImage/stbi_load_from_memory buf w h channels 4) {:data (STBImage/stbi_load_from_memory buf w h channels 4)
:w (aget w 0) :h (aget h 0)}))))] :w (aget w 0) :h (aget h 0)}))))
{:scene scene :meshes meshes :textures textures})) hiearchy (traverse (.mRootNode scene))]
(Assimp/aiReleaseImport scene)
{:meshes meshes :textures textures :hiearchy hiearchy}))
(defn upload-scene! [scene] (defn upload-scene! [scene]
(let [gl-meshes (let [gl-meshes
@ -264,16 +308,17 @@
:mv (GL20/glGetUniformLocation program "uView") :mv (GL20/glGetUniformLocation program "uView")
:mp (GL20/glGetUniformLocation program "uProjection")}})) :mp (GL20/glGetUniformLocation program "uProjection")}}))
(reset! loaded-scene (load-scene "assets/model.glb"))
(comment (comment
(start!) (start!)
(stop!) (stop!)
(@loaded-scenes) (reset! uploaded-scene (with-gl (upload-scene! @loaded-scene)))
(swap! loaded-scenes conj (load-scene "assets/model.glb"))
(swap! uploaded-scenes conj (with-gl (upload-scene! (first @loaded-scenes))))
(reset! shaders (with-gl (load-shaders! "shaders/base.vert" "shaders/base.frag"))) (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 (with-gl
(GL11/glClearColor 0.392 0.584 0.929 1.0)) (GL11/glClearColor 0.392 0.584 0.929 1.0))
(with-gl (with-gl