renderer_.d 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. module three.rendererx;
  2. version(none) {
  3. import three.common;
  4. import three.scene;
  5. import three.camera;
  6. import three.renderTarget;
  7. import three.viewport;
  8. import std.string : toStringz;
  9. import std.exception : collectException;
  10. enum deferredRendererVertexShaderSource = "
  11. #version 420 core
  12. layout(location = 0) in vec3 in_position;
  13. layout(location = 1) in vec3 in_normal;
  14. layout(location = 2) in vec2 in_texcoord;
  15. layout(location = 3) in vec4 in_color;
  16. //==============
  17. out vec2 _normal;
  18. out vec2 _texture;
  19. out vec3 _color;
  20. //==============
  21. out gl_PerVertex
  22. {
  23. vec4 gl_Position;
  24. };
  25. vec2 encode(vec3 n)
  26. {
  27. float f = sqrt(8*n.z+8);
  28. return n.xy / f + 0.5;
  29. }
  30. void main()
  31. {
  32. gl_Position = vec4(0.005 * in_position.x, 0.005 * in_position.y, 0.005* in_position.z, 1.0);
  33. _normal = encode(in_normal);
  34. _texture = in_texcoord;
  35. _color = in_color.xyz;
  36. };
  37. ";
  38. enum deferredRendererFragmentShaderSource = "
  39. #version 420 core
  40. //==============
  41. in vec2 _normal;
  42. in vec2 _texture;
  43. in vec3 _color;
  44. //==============
  45. layout(location = 0) out float depth;
  46. layout(location = 1) out vec4 normal;
  47. layout(location = 2) out vec4 color;
  48. void main()
  49. {
  50. depth = gl_FragCoord.z;
  51. normal.xy = _normal.xy;
  52. color.xyz = _color;
  53. }
  54. ";
  55. struct GBuffer {
  56. uint width;
  57. uint height;
  58. GLuint texturePosition;
  59. GLuint textureNormal;
  60. GLuint textureColor;
  61. GLuint textureDepthStencil;
  62. GLuint fbo;
  63. }
  64. void construct(out GBuffer gBuffer, uint width, uint height) nothrow {
  65. gBuffer.width = width;
  66. gBuffer.height = height;
  67. glCheck!glGenTextures(1, &gBuffer.texturePosition);
  68. glCheck!glBindTexture(GL_TEXTURE_2D, gBuffer.texturePosition);
  69. glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  70. glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  71. // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  72. // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  73. // glCheck!glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
  74. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, width, height);
  75. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_FLOAT, null);
  76. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  77. glCheck!glGenTextures(1, &gBuffer.textureNormal);
  78. glCheck!glBindTexture(GL_TEXTURE_2D, gBuffer.textureNormal);
  79. glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  80. glCheck!glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  81. // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  82. // glCheck!glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  83. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB10_A2, width, height);
  84. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, null);
  85. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  86. glCheck!glGenTextures(1, &gBuffer.textureColor);
  87. glCheck!glBindTexture(GL_TEXTURE_2D, gBuffer.textureColor);
  88. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
  89. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, null);
  90. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  91. glCheck!glGenTextures(1, &gBuffer.textureDepthStencil);
  92. glCheck!glBindTexture(GL_TEXTURE_2D, gBuffer.textureDepthStencil);
  93. glCheck!glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, width, height);
  94. glCheck!glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null);
  95. glCheck!glBindTexture(GL_TEXTURE_2D, 0);
  96. glCheck!glGenFramebuffers(1, &gBuffer.fbo);
  97. glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gBuffer.fbo);
  98. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0, GL_TEXTURE_2D, gBuffer.texturePosition, 0);
  99. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 1, GL_TEXTURE_2D, gBuffer.textureNormal, 0);
  100. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 2, GL_TEXTURE_2D, gBuffer.textureColor, 0);
  101. glCheck!glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, gBuffer.textureDepthStencil, 0);
  102. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  103. }
  104. void destruct(ref GBuffer gBuffer) nothrow {
  105. glCheck!glDeleteFramebuffers(1, &gBuffer.fbo);
  106. glCheck!glDeleteTextures(1, &gBuffer.textureDepthStencil);
  107. glCheck!glDeleteTextures(1, &gBuffer.textureColor);
  108. glCheck!glDeleteTextures(1, &gBuffer.textureNormal);
  109. glCheck!glDeleteTextures(1, &gBuffer.texturePosition);
  110. gBuffer = GBuffer.init;
  111. }
  112. struct Pipeline {
  113. GLuint pipeline;
  114. GLuint vertexShaderGeometryPass;
  115. GLuint fragmentShaderGeometryPass;
  116. }
  117. void construct(out Pipeline pipeline) nothrow {
  118. glCheck!glGenProgramPipelines(1, &pipeline.pipeline);
  119. auto szVertexSource = [deferredRendererVertexShaderSource.toStringz()];
  120. pipeline.vertexShaderGeometryPass = glCheck!glCreateShaderProgramv(GL_VERTEX_SHADER, 1, szVertexSource.ptr);
  121. int len;
  122. glCheck!glGetProgramiv(pipeline.vertexShaderGeometryPass, GL_INFO_LOG_LENGTH , &len);
  123. if (len > 1) {
  124. char[] msg = new char[len];
  125. glCheck!glGetProgramInfoLog(pipeline.vertexShaderGeometryPass, len, null, cast(char*) msg);
  126. log(cast(string)msg).collectException;
  127. }
  128. auto szFragmentSource = [deferredRendererFragmentShaderSource.toStringz()];
  129. pipeline.fragmentShaderGeometryPass = glCheck!glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, szFragmentSource.ptr);
  130. // int len;
  131. glCheck!glGetProgramiv(pipeline.fragmentShaderGeometryPass, GL_INFO_LOG_LENGTH , &len);
  132. if (len > 1) {
  133. char[] msg = new char[len];
  134. glCheck!glGetProgramInfoLog(pipeline.fragmentShaderGeometryPass, len, null, cast(char*) msg);
  135. log(cast(string)msg).collectException;
  136. }
  137. glCheck!glUseProgramStages(pipeline.pipeline, GL_VERTEX_SHADER_BIT, pipeline.vertexShaderGeometryPass);
  138. glCheck!glUseProgramStages(pipeline.pipeline, GL_FRAGMENT_SHADER_BIT, pipeline.fragmentShaderGeometryPass);
  139. glCheck!glValidateProgramPipeline(pipeline.pipeline);
  140. GLint status;
  141. glCheck!glGetProgramPipelineiv(pipeline.pipeline, GL_VALIDATE_STATUS, &status);
  142. //TODO: add error handling
  143. assert(status != 0);
  144. }
  145. void destruct(ref Pipeline pipeline) nothrow {
  146. glDeleteProgramPipelines(1, &pipeline.pipeline);
  147. pipeline = Pipeline.init;
  148. }
  149. struct OpenGlTiledDeferredRenderer {
  150. GBuffer gBuffer;
  151. Pipeline pipeline;
  152. }
  153. void construct(out OpenGlTiledDeferredRenderer deferredRenderer, uint width, uint height) nothrow {
  154. deferredRenderer.gBuffer.construct(width, height);
  155. deferredRenderer.pipeline.construct();
  156. }
  157. void destruct(ref OpenGlTiledDeferredRenderer deferredRenderer) nothrow {
  158. deferredRenderer.pipeline.destruct();
  159. deferredRenderer.gBuffer.destruct();
  160. deferredRenderer = OpenGlTiledDeferredRenderer.init;
  161. }
  162. // draw the scene supersampled with renderer's with+height onto renderTarget at position+size of viewport
  163. void renderOneFrame(ref OpenGlTiledDeferredRenderer renderer, ref Scene scene, ref Camera camera, ref RenderTarget renderTarget, ref Viewport viewport) {
  164. // 1. Render the (opaque) geometry into the G-Buffers.
  165. // 2. Construct a screen space grid, covering the frame buffer, with some fixed tile
  166. // size, t = (x, y), e.g. 32 × 32 pixels.
  167. // 3. For each light: find the screen space extents of the light volume and append the
  168. // light ID to each affected grid cell.
  169. // 4. For each fragment in the frame buffer, with location f = (x, y).
  170. // (a) sample the G-Buffers at f.
  171. // (b) accumulate light contributions from all lights in tile at ⌊f /t⌋
  172. // (c) output total light contributions to frame buffer at f
  173. with(renderer.gBuffer) glCheck!glViewport(0, 0, width, height);
  174. //enable depth mask _before_ glClear ing the depth buffer!
  175. glCheck!glDepthMask(GL_TRUE); scope(exit) glCheck!glDepthMask(GL_FALSE);
  176. glCheck!glEnable(GL_DEPTH_TEST); scope(exit) glCheck!glDisable(GL_DEPTH_TEST);
  177. glCheck!glDepthFunc(GL_LEQUAL);
  178. //bind gBuffer
  179. glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, renderer.gBuffer.fbo); scope(exit) glCheck!glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  180. GLenum[] drawBuffers = [GL_COLOR_ATTACHMENT0 + 0, GL_COLOR_ATTACHMENT0 + 1, GL_COLOR_ATTACHMENT0 + 2];
  181. glCheck!glDrawBuffers(drawBuffers.length, drawBuffers.ptr); scope(exit) glCheck!glDrawBuffer(GL_NONE);
  182. glCheck!glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  183. // glCheck!glClearColor(0, 0, 0.3, 1);
  184. //bind pipeline
  185. glCheck!glBindProgramPipeline(renderer.pipeline.pipeline); scope(exit) glCheck!glBindProgramPipeline(0);
  186. {// Draw Geometry
  187. scope(exit) glCheck!glBindVertexArray(0);
  188. scope(exit) glCheck!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // TODO: GL_ELEMENT_ARRAY_BUFFER should be vao state, but bugs might make this necessary
  189. for(size_t meshIdx = 0; meshIdx < scene.mesh.cnt; ++meshIdx) {
  190. glCheck!glBindVertexArray(scene.mesh.vao[meshIdx]);
  191. glCheck!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, scene.mesh.vboIndices[meshIdx]); // TODO: GL_ELEMENT_ARRAY_BUFFER should be vao state, but bugs might make this necessary
  192. // DrawElementsIndirectCommand
  193. // glCheck!glcommand
  194. version(none) { //inefficient. use glMultiDrawElementsIndirect instead
  195. glCheck!glDrawElements(GL_TRIANGLES, scene.mesh.cntIndices[meshIdx], GL_UNSIGNED_INT, null);
  196. }
  197. }
  198. // glCheck!glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, null, scene.mesh.cnt, 0);
  199. }
  200. }
  201. debug {
  202. void blitGBufferToScreen(ref OpenGlTiledDeferredRenderer renderer) {
  203. glCheck!glBindFramebuffer(GL_READ_FRAMEBUFFER, renderer.gBuffer.fbo); scope(exit) glCheck!glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
  204. GLsizei width = renderer.gBuffer.width;
  205. GLsizei height = renderer.gBuffer.height;
  206. scope(exit) glCheck!glReadBuffer(GL_NONE);
  207. glCheck!glReadBuffer(GL_COLOR_ATTACHMENT0 + 0);
  208. glCheck!glBlitFramebuffer(0, 0, width, height, 0, height-300, 400, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  209. glCheck!glReadBuffer(GL_COLOR_ATTACHMENT0 + 1);
  210. glCheck!glBlitFramebuffer(0, 0, width, height, 0, 0, 400, 300, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  211. glCheck!glReadBuffer(GL_COLOR_ATTACHMENT0 + 2);
  212. glCheck!glBlitFramebuffer(0, 0, width, height, width-400, height-300, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  213. }
  214. }
  215. }