Skip to content

Commit 6902cac

Browse files
committed
Render 3D noise volume
1 parent beba295 commit 6902cac

1 file changed

Lines changed: 128 additions & 37 deletions

File tree

src/volumetric_clouds/main.clj

Lines changed: 128 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
(:import [org.lwjgl.opengl GL11]
2525
[org.lwjgl BufferUtils]
2626
[org.lwjgl.glfw GLFW]
27-
[org.lwjgl.opengl GL GL11 GL12 GL15 GL20 GL30 GL32 GL42]))
27+
[org.lwjgl.opengl GL GL11 GL12 GL13 GL15 GL20 GL30 GL32 GL42]))
2828

2929

3030
;; Procedural generation of volumetric clouds
@@ -37,16 +37,18 @@
3737
;;
3838
;; References
3939
;; * https://adrianb.io/2014/08/09/perlinnoise.html
40+
;; * https://www.wedesoft.de/software/2023/05/03/volumetric-clouds/
4041

4142
;; # Worley noise
4243

44+
4345
(defn make-noise-params
4446
[size divisions dimensions]
4547
{:size size :divisions divisions :cellsize (/ size divisions) :dimensions dimensions})
4648

4749

4850
(fact "Noise parameter initialisation"
49-
(make-noise-params 512 8 2) => {:size 512 :divisions 8 :cellsize 64 :dimensions 2})
51+
(make-noise-params 256 8 2) => {:size 256 :divisions 8 :cellsize 32 :dimensions 2})
5052

5153

5254
(defn vec-n
@@ -93,7 +95,7 @@
9395
((random-points params-3d) 2 3 5) => (vec3 22.0 14.0 10.0))))
9496

9597

96-
(let [points (tensor/reshape (random-points (make-noise-params 512 8 2)) [(* 8 8)])
98+
(let [points (tensor/reshape (random-points (make-noise-params 256 8 2)) [(* 8 8)])
9799
scatter (tc/dataset {:x (map first points) :y (map second points)})]
98100
(-> scatter
99101
(plotly/base {:=title "Random points"})
@@ -194,7 +196,7 @@
194196
:double))))
195197

196198

197-
(def worley (worley-noise (make-noise-params 512 8 2)))
199+
(def worley (worley-noise (make-noise-params 256 8 2)))
198200

199201
(def worley-norm (dfn/* (/ 255 (- (dfn/reduce-max worley) (dfn/reduce-min worley))) (dfn/- (dfn/reduce-max worley) worley)))
200202

@@ -238,7 +240,7 @@
238240
((random-gradients {:divisions 8 :dimensions 3}) 0 0 0) => (roughly-vec (vec3 (sqrt (/ 1 3)) (sqrt (/ 1 3)) (sqrt (/ 1 3))) 1e-6)))
239241

240242

241-
(let [gradients (tensor/reshape (random-gradients (make-noise-params 512 8 2)) [(* 8 8)])
243+
(let [gradients (tensor/reshape (random-gradients (make-noise-params 256 8 2)) [(* 8 8)])
242244
points (tensor/reshape (tensor/compute-tensor [8 8] (fn [y x] (vec2 x y))) [(* 8 8)])
243245
scatter (tc/dataset {:x (mapcat (fn [point gradient] [(point 0) (+ (point 0) (* 0.5 (gradient 0))) nil]) points gradients)
244246
:y (mapcat (fn [point gradient] [(point 1) (+ (point 1) (* 0.5 (gradient 1))) nil]) points gradients)})]
@@ -382,7 +384,7 @@
382384
:double))))
383385

384386

385-
(def perlin (perlin-noise (make-noise-params 512 8 2)))
387+
(def perlin (perlin-noise (make-noise-params 256 8 2)))
386388

387389
(def perlin-norm (dfn/* (/ 255 (- (dfn/reduce-max perlin) (dfn/reduce-min perlin))) (dfn/- perlin (dfn/reduce-min perlin))))
388390

@@ -507,6 +509,7 @@
507509

508510
(bufimg/tensor->image (noise-octaves perlin-worley-norm (octaves 4 0.6) 120 230))
509511

512+
510513
;; # Testing shaders
511514

512515
(GLFW/glfwInit)
@@ -542,6 +545,14 @@
542545
program))
543546

544547

548+
(defn make-program-with-shaders
549+
[vertex-shader-sources fragment-shader-sources]
550+
(let [vertex-shaders (map #(make-shader % GL20/GL_VERTEX_SHADER) vertex-shader-sources)
551+
fragment-shaders (map #(make-shader % GL20/GL_FRAGMENT_SHADER) fragment-shader-sources)
552+
program (apply make-program (concat vertex-shaders fragment-shaders))]
553+
program))
554+
555+
545556
(def vertex-test "
546557
#version 130
547558
in vec3 point;
@@ -603,15 +614,19 @@ void main()
603614
result))
604615

605616

606-
(defn make-texture
617+
(defn make-texture-2d
607618
[width height]
608619
(let [texture (GL11/glGenTextures)]
609620
(GL11/glBindTexture GL11/GL_TEXTURE_2D texture)
621+
(GL11/glTexParameteri GL12/GL_TEXTURE_2D GL11/GL_TEXTURE_MIN_FILTER GL11/GL_LINEAR)
622+
(GL11/glTexParameteri GL12/GL_TEXTURE_2D GL11/GL_TEXTURE_MAG_FILTER GL11/GL_LINEAR)
623+
(GL11/glTexParameteri GL12/GL_TEXTURE_2D GL11/GL_TEXTURE_WRAP_S GL11/GL_REPEAT)
624+
(GL11/glTexParameteri GL12/GL_TEXTURE_2D GL11/GL_TEXTURE_WRAP_T GL11/GL_REPEAT)
610625
(GL42/glTexStorage2D GL11/GL_TEXTURE_2D 1 GL30/GL_RGBA32F width height)
611626
texture))
612627

613628

614-
(defn read-texture
629+
(defn read-texture-2d
615630
[texture width height]
616631
(let [buffer (BufferUtils/createFloatBuffer (* height width 4))]
617632
(GL11/glBindTexture GL11/GL_TEXTURE_2D texture)
@@ -640,20 +655,23 @@ void main()
640655
(GL20/glEnableVertexAttribArray point-attribute)))
641656

642657

658+
(defn setup-quad-vao
659+
[]
660+
(let [vertices (float-array [1.0 1.0 0.0, -1.0 1.0 0.0, -1.0 -1.0 0.0, 1.0 -1.0 0.0])
661+
indices (int-array [0 1 2 3])]
662+
(setup-vao vertices indices)))
663+
664+
643665
(defn render-pixel
644666
[vertex-sources fragment-sources]
645-
(let [vertices (float-array [1.0 1.0 0.0, -1.0 1.0 0.0, -1.0 -1.0 0.0, 1.0 -1.0 0.0])
646-
indices (int-array [0 1 2 3])
647-
vertex-shaders (map #(make-shader % GL20/GL_VERTEX_SHADER) vertex-sources)
648-
fragment-shaders (map #(make-shader % GL20/GL_FRAGMENT_SHADER) fragment-sources)
649-
program (apply make-program (concat vertex-shaders fragment-shaders))
650-
vao (setup-vao vertices indices)
651-
texture (make-texture 1 1)]
667+
(let [program (make-program-with-shaders vertex-sources fragment-sources)
668+
vao (setup-quad-vao)
669+
texture (make-texture-2d 1 1)]
652670
(setup-point-attribute program)
653671
(framebuffer-render texture 1 1
654672
(GL20/glUseProgram program)
655-
(GL11/glDrawElements GL11/GL_QUADS (count indices) GL11/GL_UNSIGNED_INT 0))
656-
(let [result (read-texture texture 1 1)]
673+
(GL11/glDrawElements GL11/GL_QUADS 4 GL11/GL_UNSIGNED_INT 0))
674+
(let [result (read-texture-2d texture 1 1)]
657675
(GL11/glDeleteTextures texture)
658676
(teardown-vao vao)
659677
(GL20/glDeleteProgram program)
@@ -663,6 +681,8 @@ void main()
663681
(render-pixel [vertex-test] [fragment-test])
664682

665683

684+
;; # Noise octaves shader
685+
666686
(def noise-mock
667687
"#version 130
668688
float noise(vec3 idx)
@@ -735,6 +755,8 @@ void main()
735755
1 0 0 [1.0 0.0] 1.0)
736756

737757

758+
;; # Shader for intersecting a ray with a box
759+
738760
(def ray-box
739761
"#version 130
740762
vec2 ray_box(vec3 box_min, vec3 box_max, vec3 origin, vec3 direction)
@@ -785,6 +807,8 @@ void main()
785807
2 0 0 1 0 0 [0.0 0.0])
786808

787809

810+
;; # Shader for light transfer through clouds
811+
788812
(def cloud-mock
789813
(template/fn [v]
790814
"#version 130
@@ -843,6 +867,8 @@ void main()
843867
0 1 0.5 0.5 [0.393 0.393 0.393 0.393])
844868

845869

870+
;; # Rendering of fog box
871+
846872
(def fragment-cloud
847873
"#version 130
848874
uniform vec2 resolution;
@@ -863,36 +889,101 @@ void main()
863889
}")
864890

865891

866-
(defn render-clouds
892+
(defn setup-fog-uniforms
893+
[program width height]
894+
(let [rotation (mulm (rotation-matrix-3d-y (to-radians 30.0)) (rotation-matrix-3d-x (to-radians -25.0)))
895+
focal-length (/ (* 0.5 width) (tan (to-radians 30.0)))]
896+
(GL20/glUseProgram program)
897+
(GL20/glUniform2f (GL20/glGetUniformLocation program "resolution") width height)
898+
(GL20/glUniformMatrix3fv (GL20/glGetUniformLocation program "rotation") true
899+
(make-float-buffer (mat->float-array rotation)))
900+
(GL20/glUniform1f (GL20/glGetUniformLocation program "focal_length") focal-length)
901+
(GL20/glUniform1f (GL20/glGetUniformLocation program "distance") 4.0)))
902+
903+
904+
(defn render-fog
867905
[width height]
868-
(let [vertices (float-array [1.0 1.0 0.0, -1.0 1.0 0.0, -1.0 -1.0 0.0, 1.0 -1.0 0.0])
869-
indices (int-array [0 1 2 3])
870-
rotation (mulm (rotation-matrix-3d-x (to-radians -25.0)) (rotation-matrix-3d-y (to-radians 30.0)))
871-
vertex-shader (make-shader vertex-test GL20/GL_VERTEX_SHADER)
872-
fragment-sources [ray-box cloud-transfer (cloud-mock 0.3) fragment-cloud]
873-
fragment-shaders (map #(make-shader % GL20/GL_FRAGMENT_SHADER) fragment-sources)
874-
program (apply make-program vertex-shader fragment-shaders)
875-
vao (setup-vao vertices indices)
876-
texture (make-texture width height)]
906+
(let [fragment-sources [ray-box cloud-transfer (cloud-mock 0.5) fragment-cloud]
907+
program (make-program-with-shaders [vertex-test] fragment-sources)
908+
vao (setup-quad-vao)
909+
texture (make-texture-2d width height)]
877910
(setup-point-attribute program)
878911
(framebuffer-render texture width height
879-
(GL20/glUseProgram program)
880-
(GL20/glUniform2f (GL20/glGetUniformLocation program "resolution") width height)
881-
(GL20/glUniformMatrix3fv (GL20/glGetUniformLocation program "rotation") true
882-
(make-float-buffer (mat->float-array rotation)))
883-
(GL20/glUniform1f (GL20/glGetUniformLocation program "focal_length") (/ (* 0.5 width) (tan (to-radians 30.0))))
884-
(GL20/glUniform1f (GL20/glGetUniformLocation program "distance") 4.0)
885-
(GL11/glDrawElements GL11/GL_QUADS (count indices) GL11/GL_UNSIGNED_INT 0))
886-
(let [result (read-texture texture width height)]
912+
(setup-fog-uniforms program width height)
913+
(GL11/glDrawElements GL11/GL_QUADS 4 GL11/GL_UNSIGNED_INT 0))
914+
(let [result (read-texture-2d texture width height)]
915+
(GL11/glDeleteTextures texture)
916+
(teardown-vao vao)
917+
(GL20/glDeleteProgram program)
918+
result)))
919+
920+
921+
(defn rgba-array->bufimg [data width height]
922+
(-> data tensor/->tensor (tensor/reshape [height width 4]) (tensor/select :all :all [2 1 0]) (dfn/* 255)))
923+
924+
925+
(bufimg/tensor->image (rgba-array->bufimg (render-fog 640 480) 640 480))
926+
927+
928+
;; # Rendering of 3D noise
929+
930+
(defn float-array->texture3d
931+
[data size]
932+
(let [buffer (make-float-buffer data)
933+
texture (GL11/glGenTextures)]
934+
(GL11/glBindTexture GL12/GL_TEXTURE_3D texture)
935+
(GL11/glTexParameteri GL12/GL_TEXTURE_3D GL11/GL_TEXTURE_MIN_FILTER GL11/GL_LINEAR)
936+
(GL11/glTexParameteri GL12/GL_TEXTURE_3D GL11/GL_TEXTURE_MAG_FILTER GL11/GL_LINEAR)
937+
(GL11/glTexParameteri GL12/GL_TEXTURE_3D GL11/GL_TEXTURE_WRAP_S GL11/GL_REPEAT)
938+
(GL11/glTexParameteri GL12/GL_TEXTURE_3D GL11/GL_TEXTURE_WRAP_T GL11/GL_REPEAT)
939+
(GL11/glTexParameteri GL12/GL_TEXTURE_3D GL12/GL_TEXTURE_WRAP_R GL11/GL_REPEAT)
940+
(GL12/glTexImage3D GL12/GL_TEXTURE_3D 0 GL30/GL_R32F size size size 0 GL11/GL_RED GL11/GL_FLOAT buffer)
941+
texture))
942+
943+
944+
(def noise3d (dfn/- (dfn/* 0.3 (perlin-noise (make-noise-params 32 4 3)))
945+
(dfn/* 0.7 (worley-noise (make-noise-params 32 4 3)))))
946+
(def noise-3d-norm (dfn/* (/ 1.0 (- (dfn/reduce-max noise3d) (dfn/reduce-min noise3d))) (dfn/- noise3d (dfn/reduce-min noise3d))))
947+
(def noise-texture (float-array->texture3d (dtype/->float-array noise-3d-norm) 32))
948+
949+
950+
(def noise-shader
951+
"#version 130
952+
uniform sampler3D noise3d;
953+
float cloud(vec3 idx)
954+
{
955+
return texture(noise3d, idx).r;
956+
}")
957+
958+
959+
(defn setup-noise-uniforms
960+
[program width height]
961+
(setup-fog-uniforms program width height)
962+
(GL20/glUniform1i (GL20/glGetUniformLocation program "noise3d") 0)
963+
(GL13/glActiveTexture GL13/GL_TEXTURE0)
964+
(GL11/glBindTexture GL12/GL_TEXTURE_3D noise-texture))
965+
966+
967+
(defn render-noise
968+
[width height]
969+
(let [fragment-sources [ray-box cloud-transfer noise-shader fragment-cloud]
970+
program (make-program-with-shaders [vertex-test] fragment-sources)
971+
vao (setup-quad-vao)
972+
texture (make-texture-2d width height)]
973+
(setup-point-attribute program)
974+
(framebuffer-render texture width height
975+
(setup-noise-uniforms program width height)
976+
(GL11/glDrawElements GL11/GL_QUADS 4 GL11/GL_UNSIGNED_INT 0))
977+
(let [result (read-texture-2d texture width height)]
887978
(GL11/glDeleteTextures texture)
888979
(teardown-vao vao)
889980
(GL20/glDeleteProgram program)
890981
result)))
891982

892983

893-
(def image (dfn/* 255 (tensor/select (tensor/reshape (tensor/->tensor (render-clouds 640 480)) [480 640 4]) :all :all [2 1 0])))
984+
(bufimg/tensor->image (rgba-array->bufimg (render-noise 640 480) 640 480))
894985

895-
(bufimg/tensor->image image)
986+
(GL11/glDeleteTextures noise-texture)
896987

897988
(GLFW/glfwDestroyWindow window)
898989

0 commit comments

Comments
 (0)