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
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
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" })
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
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)})]
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
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 )
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
547558in 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
668688float 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
740762vec2 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
848874uniform 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