624624; ; #### OpenGL setup
625625; ;
626626; ; In order to render the clouds we create a window and an OpenGL context.
627+ ; ; Note that we need to create an invisible window to get an OpenGL context, even though we are not going to draw to the window
627628(GLFW/glfwInit )
628629
629630(def window-width 640 )
647648 (throw (Exception. (GL20/glGetShaderInfoLog shader 1024 ))))
648649 shader))
649650
650-
651+ ; ; The different shaders are then linked to become a shader program using the following method.
651652(defn make-program [& shaders]
652653 (let [program (GL20/glCreateProgram )]
653654 (doseq [shader shaders]
658659 (throw (Exception. (GL20/glGetProgramInfoLog program 1024 ))))
659660 program))
660661
661-
662+ ; ; This method is used to perform both compilation and linking of vertex shaders and fragment shaders.
662663(defn make-program-with-shaders
663664 [vertex-sources fragment-sources]
664665 (let [vertex-shaders (map #(make-shader % GL20/GL_VERTEX_SHADER) vertex-sources)
665666 fragment-shaders (map #(make-shader % GL20/GL_FRAGMENT_SHADER) fragment-sources)
666667 program (apply make-program (concat vertex-shaders fragment-shaders))]
667668 program))
668669
669-
670- (def vertex-test
670+ ; ; We are going to use this simple vertex shader to simply pass a vertex through without any transformations.
671+ (def vertex-passthrough
671672" #version 130
672673in vec3 point;
673674void main()
674675{
675676 gl_Position = vec4(point, 1);
676677}" )
677678
678-
679+ ; ; The following fragment shader is used to test rendering white pixels.
679680(def fragment-test
680681" #version 130
681682out vec4 fragColor;
@@ -684,18 +685,20 @@ void main()
684685 fragColor = vec4(1, 1, 1, 1);
685686}" )
686687
687-
688+ ; ; In order to pass data to LWJGL methods, we need to be able to convert arrays to Java buffer objects.
688689(defmacro def-make-buffer [method create-buffer]
689690 `(defn ~method [data#]
690691 (let [buffer# (~create-buffer (count data#))]
691692 (.put buffer# data#)
692693 (.flip buffer#)
693694 buffer#)))
694695
696+ ; ; Above macro is used to define methods for creating float, int, and byte buffer objects.
695697(def-make-buffer make-float-buffer BufferUtils /createFloatBuffer )
696698(def-make-buffer make-int-buffer BufferUtils /createIntBuffer )
697699(def-make-buffer make-byte-buffer BufferUtils /createByteBuffer )
698700
701+ ; ; We implement a method to create a vertex array object with a vertex buffer object and an index buffer object.
699702(defn setup-vao [vertices indices]
700703 (let [vao (GL30/glGenVertexArrays )
701704 vbo (GL15/glGenBuffers )
@@ -709,7 +712,7 @@ void main()
709712 GL15/GL_STATIC_DRAW)
710713 {:vao vao :vbo vbo :ibo ibo}))
711714
712-
715+ ; ; We also define the corresponding destructor for the vertex data.
713716(defn teardown-vao [{:keys [vao vbo ibo]}]
714717 (GL15/glBindBuffer GL15/GL_ELEMENT_ARRAY_BUFFER 0 )
715718 (GL15/glDeleteBuffers ibo)
@@ -718,16 +721,9 @@ void main()
718721 (GL30/glBindVertexArray 0 )
719722 (GL15/glDeleteBuffers vao))
720723
721-
722- (defn float-buffer->array
723- " Convert float buffer to flaot array"
724- [buffer]
725- (let [result (float-array (.limit buffer))]
726- (.get buffer result)
727- (.flip buffer)
728- result))
729-
730-
724+ ; ; #### Offscreen rendering to a texture
725+ ; ;
726+ ; ; The following method is used to create an empty 2D RGBA floating point texture
731727(defn make-texture-2d
732728 [width height]
733729 (let [texture (GL11/glGenTextures )]
@@ -739,15 +735,24 @@ void main()
739735 (GL42/glTexStorage2D GL11/GL_TEXTURE_2D 1 GL30/GL_RGBA32F width height)
740736 texture))
741737
738+ ; ; We define a method to convert a Java buffer object to a floating point array.
739+ (defn float-buffer->array
740+ " Convert float buffer to float array"
741+ [buffer]
742+ (let [result (float-array (.limit buffer))]
743+ (.get buffer result)
744+ (.flip buffer)
745+ result))
742746
747+ ; ; The following method reads texture data into a Java buffer and then converts it to a floating point array.
743748(defn read-texture-2d
744749 [texture width height]
745750 (let [buffer (BufferUtils/createFloatBuffer (* height width 4 ))]
746751 (GL11/glBindTexture GL11/GL_TEXTURE_2D texture)
747752 (GL11/glGetTexImage GL11/GL_TEXTURE_2D 0 GL12/GL_RGBA GL11/GL_FLOAT buffer)
748753 (float-buffer->array buffer)))
749754
750-
755+ ; ; This method sets up rendering to a specified texture of specified size and then executes the body.
751756(defmacro framebuffer-render
752757 [texture width height & body]
753758 `(let [fbo# (GL30/glGenFramebuffers )]
@@ -764,7 +769,8 @@ void main()
764769 (GL30/glBindFramebuffer GL30/GL_FRAMEBUFFER 0 )
765770 (GL30/glDeleteFramebuffers fbo#)))))
766771
767-
772+ ; ; We also create a method to set up the layout of the vertex buffer.
773+ ; ; Our vertex data is only going to be 3D coordinates of points.
768774(defn setup-point-attribute
769775 [program]
770776 (let [point-attribute (GL20/glGetAttribLocation program " point" )]
@@ -804,7 +810,7 @@ void main()
804810 (GL20/glDeleteProgram program)))))
805811
806812
807- (render-pixel [vertex-test ] [fragment-test])
813+ (render-pixel [vertex-passthrough ] [fragment-test])
808814
809815
810816; ; ## Noise octaves shader
@@ -830,7 +836,7 @@ void main()
830836
831837
832838(tabular " Test noise mock"
833- (fact (nth (render-pixel [vertex-test ] [noise-mock (noise-probe ?x ?y ?z)]) 0 )
839+ (fact (nth (render-pixel [vertex-passthrough ] [noise-mock (noise-probe ?x ?y ?z)]) 0 )
834840 => ?result)
835841 ?x ?y ?z ?result
836842 0 0 0 0.0
@@ -871,7 +877,7 @@ void main()
871877
872878
873879(tabular " Test octaves of noise"
874- (fact (first (render-pixel [vertex-test ]
880+ (fact (first (render-pixel [vertex-passthrough ]
875881 [noise-mock (noise-octaves ?octaves)
876882 (octaves-probe ?x ?y ?z)]))
877883 => ?result)
@@ -921,7 +927,7 @@ void main()
921927
922928(tabular " Test intersection of ray with box"
923929 (fact ((juxt first second)
924- (render-pixel [vertex-test ]
930+ (render-pixel [vertex-passthrough ]
925931 [ray-box (ray-box-probe ?ox ?oy ?oz ?dx ?dy ?dz)]))
926932 => ?result)
927933 ?ox ?oy ?oz ?dx ?dy ?dz ?result
@@ -1010,7 +1016,7 @@ void main()
10101016
10111017
10121018(tabular " Test cloud transfer"
1013- (fact (seq (render-pixel [vertex-test ]
1019+ (fact (seq (render-pixel [vertex-passthrough ]
10141020 [(fog ?density) constant-scatter no-shadow
10151021 (cloud-transfer " fog" ?step)
10161022 (cloud-transfer-probe ?a ?b)]))
@@ -1065,7 +1071,7 @@ void main()
10651071 [width height]
10661072 (let [fragment-sources [ray-box constant-scatter no-shadow (cloud-transfer " fog" 0.01 )
10671073 (fog 1.0 ) fragment-cloud]
1068- program (make-program-with-shaders [vertex-test ] fragment-sources)
1074+ program (make-program-with-shaders [vertex-passthrough ] fragment-sources)
10691075 vao (setup-quad-vao )]
10701076 (setup-point-attribute program)
10711077 (try
@@ -1131,7 +1137,7 @@ float noise(vec3 idx)
11311137(defn render-noise
11321138 [width height & cloud-shaders]
11331139 (let [fragment-sources (concat cloud-shaders [ray-box fragment-cloud])
1134- program (make-program-with-shaders [vertex-test ] fragment-sources)
1140+ program (make-program-with-shaders [vertex-passthrough ] fragment-sources)
11351141 vao (setup-quad-vao )]
11361142 (try
11371143 (setup-point-attribute program)
@@ -1174,7 +1180,7 @@ void main()
11741180
11751181(tabular " Remap and clamp input parameter values"
11761182 (fact (first (render-pixel
1177- [vertex-test ]
1183+ [vertex-passthrough ]
11781184 [remap-clamp (remap-probe ?value ?low1 ?high1 ?low2 ?high2)]))
11791185 => ?expected)
11801186 ?value ?low1 ?high1 ?low2 ?high2 ?expected
@@ -1253,7 +1259,7 @@ void main()
12531259
12541260
12551261(tabular " Shader function for scattering phase function"
1256- (fact (first (render-pixel [vertex-test ] [(mie-scatter ?g) (mie-probe ?mu)]))
1262+ (fact (first (render-pixel [vertex-passthrough ] [(mie-scatter ?g) (mie-probe ?mu)]))
12571263 => (roughly ?result 1e-6 ))
12581264 ?g ?mu ?result
12591265 0 0 (/ 3 (* 16 PI))
@@ -1264,7 +1270,7 @@ void main()
12641270
12651271
12661272(defn scatter-amount [theta]
1267- (first (render-pixel [vertex-test ] [(mie-scatter 0.76 ) (mie-probe (cos theta))])))
1273+ (first (render-pixel [vertex-passthrough ] [(mie-scatter 0.76 ) (mie-probe (cos theta))])))
12681274
12691275
12701276(let [scatter
0 commit comments