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])
(: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))))
(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