Bubba-3D  0.9.0
Awesome game engine!
Renderer.cpp
1 /*
2  * This file is part of Bubba-3D.
3  *
4  * Bubba-3D is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Bubba-3D is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with Bubba-3D. If not, see http://www.gnu.org/licenses/.
16  */
17 #include "Renderer.h"
18 #include <sstream>
19 #include <Globals.h>
20 #include "ResourceManager.h"
21 #include "constants.h"
22 #include "GameObject.h"
23 #include "CubeMapTexture.h"
24 #include "Logger.h"
25 #include "Camera.h"
26 #include "Scene.h"
27 
28 
29 
30 
31 namespace patch
32 {
33  template < typename T > std::string to_string( const T& n )
34  {
35  std::ostringstream stm ;
36  stm << n ;
37  return stm.str() ;
38  }
39 }
40 
41 
42 Renderer::Renderer()
43 {
44 }
45 
46 Renderer::~Renderer()
47 {
48 }
49 
50 void Renderer::initRenderer(int width, int height) {
51  initGL();
52  resize(width, height);
53 
54  // clear the buffers
55  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
56 }
57 
58 void Renderer::resize(unsigned int width, unsigned int height) {
59  // adjust the viewport when the window is resized
60  glViewport(0, 0, width, height);
61 
62  postProcessFbo = createPostProcessFbo(width, height);
63  verticalBlurFbo = createPostProcessFbo(width, height);
64  horizontalBlurFbo = createPostProcessFbo(width, height);
65  cutOffFbo = createPostProcessFbo(width, height);
66 }
67 
68 void Renderer::drawModel(IDrawable &model, ShaderProgram* shaderProgram)
69 {
70  shaderProgram->use();
71  model.render();
72 }
73 
74 void Renderer::drawScene(Camera *camera, Scene *scene, float currentTime)
75 {
76  Renderer::currentTime = currentTime;
77 
78  chag::float4x4 viewMatrix = camera->getViewMatrix();
79  chag::float4x4 projectionMatrix = camera->getProjectionMatrix();
80  chag::float4x4 viewProjectionMatrix = projectionMatrix * viewMatrix;
81 
82 
83 
84  // enable back face culling.
85  glEnable(GL_CULL_FACE);
86 
87 
88  //*************************************************************************
89  // Render shadow map
90  //*************************************************************************
91  chag::float4x4 lightMatrix = chag::make_identity<chag::float4x4>();
92 
93  if (scene->shadowMapCamera != NULL) {
94  chag::float4x4 lightViewMatrix = scene->shadowMapCamera->getViewMatrix();
95  chag::float4x4 lightProjectionMatrix = scene->shadowMapCamera->getProjectionMatrix();
96  chag::float4x4 lightViewProjectionMatrix = lightProjectionMatrix * lightViewMatrix;
97 
98  lightMatrix = chag::make_translation(chag::make_vector( 0.5f, 0.5f, 0.5f ))
99  * chag::make_scale<chag::float4x4>(chag::make_vector(0.5f, 0.5f, 0.5f))
100  * lightViewProjectionMatrix
101  * inverse(viewMatrix);
102 
103  drawShadowMap(sbo, lightViewProjectionMatrix, scene);
104  }
105 
106  //*************************************************************************
107  // Render the scene from the cameras viewpoint, to the default framebuffer
108  //*************************************************************************
109  glBindFramebuffer(GL_FRAMEBUFFER, postProcessFbo.id);
110  glClearColor(0.2f, 0.2f, 0.8f, 1.0f);
111  glClearDepth(1.0f);
112  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
113  int w = Globals::get(Globals::Key::WINDOW_WIDTH);
114  int h = Globals::get(Globals::Key::WINDOW_HEIGHT);
115  glViewport(0, 0, w, h);
116  // Use shader and set up uniforms
117  shaderProgram->use();
118 
119  shaderProgram->setUniformBufferSubData( UNIFORM_BUFFER_OBJECT_MATRICES_NAME, 0 * sizeof(chag::float4x4), sizeof(chag::float4x4), &(viewMatrix.c1.x));
120  shaderProgram->setUniformBufferSubData( UNIFORM_BUFFER_OBJECT_MATRICES_NAME, 1 * sizeof(chag::float4x4), sizeof(chag::float4x4), &(projectionMatrix.c1.x));
121  shaderProgram->setUniformBufferSubData( UNIFORM_BUFFER_OBJECT_MATRICES_NAME, 2 * sizeof(chag::float4x4), sizeof(chag::float4x4), &(viewProjectionMatrix.c1.x));
122 
123  //Sets matrices
124  shaderProgram->setUniformMatrix4fv("lightMatrix", lightMatrix);
125  shaderProgram->setUniformMatrix4fv("inverseViewNormalMatrix", transpose(viewMatrix));
126  shaderProgram->setUniform3f("viewPosition", camera->getPosition());
127  shaderProgram->setUniformMatrix4fv("viewMatrix", viewMatrix);
128 
129  setLights(shaderProgram, scene);
130 
131  setFog(shaderProgram);
132 
133  //Set shadowmap
134  if (scene->shadowMapCamera != NULL) {
135  shaderProgram->setUniform1i("has_shadow_map", 1);
136  shaderProgram->setUniform1i("shadowMap", 1);
137  glActiveTexture(GL_TEXTURE1);
138  glBindTexture(GL_TEXTURE_2D, sbo.texture);
139  }
140 
141  //Set cube map
142  if (scene->cubeMap != nullptr) {
143  shaderProgram->setUniform1i("hasCubeMap", 1);
144  shaderProgram->setUniform1i("cubeMap", 2);
145  glActiveTexture(GL_TEXTURE2);
146  scene->cubeMap->bind(GL_TEXTURE2);
147  } else {
148  shaderProgram->setUniform1i("hasCubeMap", 0);
149  shaderProgram->setUniform1i("cubeMap", 2);
150  }
151 
152  drawShadowCasters(shaderProgram, scene);
153 
154  glEnable(GL_BLEND);
155  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
156  drawTransparent(shaderProgram, scene);
157  glDisable(GL_BLEND);
158 
159  renderPostProcess();
160 
161  //Cleanup
162  glUseProgram(0);
163 
164 }
165 
166 void Renderer::setLights(ShaderProgram* shaderProgram, Scene *scene) {
167  //set dirlights
168  shaderProgram->setUniform3f("directionalLight.colors.ambientColor", scene->directionalLight.ambientColor);
169  shaderProgram->setUniform3f("directionalLight.colors.diffuseColor", scene->directionalLight.diffuseColor);
170  shaderProgram->setUniform3f("directionalLight.colors.specularColor", scene->directionalLight.specularColor);
171  shaderProgram->setUniform3f("directionalLight.direction", scene->directionalLight.direction);
172 
173  //set pointLights
174 
175  shaderProgram->setUniform1i("nrPointLights", (int)scene->pointLights.size());
176  for (int i = 0; i < (int)scene->pointLights.size(); i++) {
177  std::string name = std::string("pointLights[") + patch::to_string(i).c_str() + "]";
178  shaderProgram->setUniform3f((name + ".position").c_str(), scene->pointLights[i].position);
179  shaderProgram->setUniform3f((name + ".colors.ambientColor").c_str(), scene->pointLights[i].ambientColor);
180  shaderProgram->setUniform3f((name + ".colors.diffuseColor").c_str(), scene->pointLights[i].diffuseColor);
181  shaderProgram->setUniform3f((name + ".colors.specularColor").c_str(), scene->pointLights[i].specularColor);
182  shaderProgram->setUniform1f((name + ".attenuation.constant").c_str(), scene->pointLights[i].attenuation.constant);
183  shaderProgram->setUniform1f((name + ".attenuation.linear").c_str(), scene->pointLights[i].attenuation.linear);
184  shaderProgram->setUniform1f((name + ".attenuation.exp").c_str(), scene->pointLights[i].attenuation.exp);
185  }
186 
187  //set spotLights
188  shaderProgram->setUniform1i("nrSpotLights", (int)scene->spotLights.size());
189  for (int i = 0; i < (int)scene->spotLights.size(); i++) {
190  std::string name = std::string("spotLights[") + patch::to_string(i).c_str() + "]";
191  shaderProgram->setUniform3f((name + ".position").c_str(), scene->spotLights[i].position);
192  shaderProgram->setUniform3f((name + ".colors.ambientColor").c_str(), scene->spotLights[i].ambientColor);
193  shaderProgram->setUniform3f((name + ".colors.diffuseColor").c_str(), scene->spotLights[i].diffuseColor);
194  shaderProgram->setUniform3f((name + ".colors.specularColor").c_str(), scene->spotLights[i].specularColor);
195  shaderProgram->setUniform1f((name + ".attenuation.constant").c_str(), scene->spotLights[i].attenuation.constant);
196  shaderProgram->setUniform1f((name + ".attenuation.linear").c_str(), scene->spotLights[i].attenuation.linear);
197  shaderProgram->setUniform1f((name + ".attenuation.exp").c_str(), scene->spotLights[i].attenuation.exp);
198  shaderProgram->setUniform3f((name + ".direction").c_str(), scene->spotLights[i].direction);
199  shaderProgram->setUniform1f((name + ".cutoff").c_str(), scene->spotLights[i].cutOff);
200  shaderProgram->setUniform1f((name + ".cutoffOuter").c_str(), scene->spotLights[i].outerCutOff);
201  }
202 }
203 
208 void Renderer::drawShadowCasters(ShaderProgram* shaderProgram, Scene *scene)
209 {
210  std::vector<GameObject*> shadowCasters = scene->getShadowCasters();
211  for (unsigned int i = 0; i < scene->getShadowCasters().size(); i++) {
212  shaderProgram->setUniform1f("object_reflectiveness", (*shadowCasters[i]).shininess);
213  drawModel(*shadowCasters[i], shaderProgram);
214  }
215 }
216 
217 void Renderer::drawTransparent(ShaderProgram* shaderProgram, Scene *scene)
218 {
219  std::vector<GameObject*> transparentObjects = scene->getTransparentObjects();
220  for (unsigned int i = 0; i < transparentObjects.size(); i++) {
221  shaderProgram->setUniform1f("object_reflectiveness", (*transparentObjects[i]).shininess);
222  drawModel(*transparentObjects[i], shaderProgram);
223  }
224 }
225 
226 void Renderer::drawShadowMap(Fbo sbo, chag::float4x4 viewProjectionMatrix, Scene *scene) {
227  glBindFramebuffer(GL_FRAMEBUFFER, sbo.id);
228  glViewport(0, 0, SHADOW_MAP_RESOLUTION, SHADOW_MAP_RESOLUTION);
229 
230  glClearColor(1.0, 1.0, 1.0, 1.0);
231  glClearDepth(1.0);
232  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
233 
234  glEnable(GL_POLYGON_OFFSET_FILL);
235  glPolygonOffset(2.5, 2.0);
236 
237  GLint currentProgram;
238  glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
239  sbo.shaderProgram->use();
240  sbo.shaderProgram->setUniformMatrix4fv("viewProjectionMatrix", viewProjectionMatrix);
241 
242  std::vector<GameObject*> shadowCasters = scene->getShadowCasters();
243  for (unsigned int i = 0; i < shadowCasters.size(); i++) {
244  sbo.shaderProgram->setUniform1f("object_reflectiveness", (*shadowCasters[i]).shininess);
245  (*shadowCasters[i]).renderShadow(sbo.shaderProgram);
246  }
247 
248  //CLEANUP
249  glDisable(GL_POLYGON_OFFSET_FILL);
250  glBindFramebuffer(GL_FRAMEBUFFER, 0);
251  glUseProgram(currentProgram);
252 }
253 
254 void Renderer::setFog(ShaderProgram* shaderProgram) {
255  shaderProgram->setUniform1i("fog.iEquation", effects.fog.fEquation);
256  shaderProgram->setUniform1f("fog.fDensity", effects.fog.fDensity);
257  shaderProgram->setUniform1f("fog.fEnd", effects.fog.fEnd);
258  shaderProgram->setUniform1f("fog.fStart", effects.fog.fStart);
259  shaderProgram->setUniform3f("fog.vColor", effects.fog.vColor);
260 }
261 
262 void Renderer::initGL()
263 {
264  /* Workaround for AMD. It might no longer be necessary, but I dunno if we
265  * are ever going to remove it. (Consider it a piece of living history.)
266  */
267  if (!glBindFragDataLocation)
268  {
269  glBindFragDataLocation = glBindFragDataLocationEXT;
270  }
271 
272  //*************************************************************************
273  // Load shaders
274  //*************************************************************************
275  ResourceManager::loadShader("shaders/simple.vert", "shaders/simple.frag", SIMPLE_SHADER_NAME);
276 
277  shaderProgram = ResourceManager::getShader(SIMPLE_SHADER_NAME);
278  shaderProgram->setUniformBufferObjectBinding(UNIFORM_BUFFER_OBJECT_MATRICES_NAME, UNIFORM_BUFFER_OBJECT_MATRICES_INDEX);
279  shaderProgram->initUniformBufferObject(UNIFORM_BUFFER_OBJECT_MATRICES_NAME, 3 * sizeof(chag::float4x4), UNIFORM_BUFFER_OBJECT_MATRICES_INDEX);
280 
281  CHECK_GL_ERROR();
282 
283 
284 
285  //*************************************************************************
286  // Generate shadow map frame buffer object
287  //*************************************************************************
288  Logger::logInfo("Generating OpenGL data.");
289 
290  ResourceManager::loadShader("shaders/shadowMap.vert", "shaders/shadowMap.frag", "SHADOW_SHADER");
291  sbo.shaderProgram = ResourceManager::getShader("SHADOW_SHADER");
292 
293  sbo.width = SHADOW_MAP_RESOLUTION;
294  sbo.height = SHADOW_MAP_RESOLUTION;
295 
296  glGenFramebuffers(1, &sbo.id);
297  glBindFramebuffer(GL_FRAMEBUFFER, sbo.id);
298 
299  glGenTextures(1, &sbo.texture);
300  glBindTexture(GL_TEXTURE_2D, sbo.texture);
301 
302  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOW_MAP_RESOLUTION, SHADOW_MAP_RESOLUTION, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
303 
304  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
305  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
306 
307  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
308  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
309 
310  chag::float4 zeros = { 1.0f, 1.0f, 1.0f, 1.0f };
311  glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, &zeros.x);
312 
313  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
314  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
315 
316  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, sbo.texture, 0);
317 
318  //Disable reading color buffer
319  glDrawBuffer(GL_NONE);
320  glReadBuffer(GL_NONE);
321 
322  //Cleanup
323  glBindFramebuffer(GL_FRAMEBUFFER, 0);
324  glBindTexture(GL_TEXTURE_2D, 0);
325 
326 
327  //*************************************************************************
328  // Create post process Fbo
329  //*************************************************************************
330 
331  std::string post_fx = "POST_FX_SHADER";
332  std::string vert_blur = "VERTICAL_BLUR_SHADER";
333  std::string hor_blur = "HORIZONTAL_BLUR_SHADER";
334  std::string cutoff = "CUTOFF_SHADER";
335 
336  ResourceManager::loadShader("shaders/postFx.vert", "shaders/postFx.frag", post_fx);
337  ResourceManager::loadShader("shaders/postFx.vert", "shaders/vertical_blur.frag", vert_blur);
338  ResourceManager::loadShader("shaders/postFx.vert", "shaders/horizontal_blur.frag", hor_blur);
339  ResourceManager::loadShader("shaders/postFx.vert", "shaders/cutoff.frag", cutoff);
340 
341  postFxShader = ResourceManager::getShader(post_fx);
342  verticalBlurShader = ResourceManager::getShader(vert_blur);
343  horizontalBlurShader = ResourceManager::getShader(hor_blur);
344  cutoffShader = ResourceManager::getShader(cutoff);
345 
346 
347  //Cleanup
348  glBindFramebuffer(GL_FRAMEBUFFER, 0);
349  glBindTexture(GL_TEXTURE_2D, 0);
350 
351  glEnable(GL_DEPTH_TEST);
352 
353  Logger::logInfo("Generating OpenGL data completed.");
354 }
355 
356 Fbo Renderer::createPostProcessFbo(int width, int height) {
357 
358  Fbo fbo;
359 
360  fbo.width = width;
361  fbo.height = height;
362 
363  glGenFramebuffers(1, &fbo.id);
364  glBindFramebuffer(GL_FRAMEBUFFER, fbo.id);
365 
366  glGenTextures(1, &fbo.texture);
367  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fbo.texture);
368 
369  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
370  glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
371  glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
372 
373 
374  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, fbo.texture, 0);
375 
376  glGenRenderbuffers(1, &fbo.depthbuffer);
377  glBindRenderbuffer(GL_RENDERBUFFER, fbo.depthbuffer);
378  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
379  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo.depthbuffer);
380 
381  return fbo;
382 }
383 
384 void Renderer::renderPostProcess() {
385 
386  int w = Globals::get(Globals::WINDOW_WIDTH);
387  int h = Globals::get(Globals::WINDOW_HEIGHT);
388 
389  blurImage();
390 
391  glBindFramebuffer(GL_FRAMEBUFFER, 0);
392  glViewport(0, 0, w, h);
393  glClearColor(0.6f, 0.0f, 0.0f, 1.0f);
394  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
395 
396  postFxShader->use();
397  postFxShader->setUniform1i("frameBufferTexture", 0);
398  postFxShader->setUniform1i("blurredFrameBufferTexture", 1);
399 
400  glActiveTexture(GL_TEXTURE0);
401  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, postProcessFbo.texture);
402 
403  glActiveTexture(GL_TEXTURE1);
404  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, verticalBlurFbo.texture);
405 
406  postFxShader->setUniform1f("time", currentTime);
407 
408  drawFullScreenQuad();
409 }
410 
411 void Renderer::blurImage() {
412  if (!effects.blur.active) { return; }
413  //CUTOFF
414 
415  int width = Globals::get(Globals::WINDOW_WIDTH);
416  int height = Globals::get(Globals::WINDOW_HEIGHT);
417  cutoffShader->use();
418  glBindFramebuffer(GL_FRAMEBUFFER, cutOffFbo.id);
419  glViewport(0, 0, width, height);
420  glClearColor(1.0, 1.0, 0.0, 1.0);
421  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
422 
423  cutoffShader->setUniform1f("cutAt", effects.blur.cutOff);
424  glActiveTexture(GL_TEXTURE0);
425  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, postProcessFbo.texture);
426 
427  drawFullScreenQuad();
428 
429  //HORIZONTAL
430  glBindFramebuffer(GL_FRAMEBUFFER, horizontalBlurFbo.id);
431  glClearColor(0.0, 0.0, 0.0, 1.0);
432  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
433 
434  horizontalBlurShader->use();
435 
436  horizontalBlurShader->setUniform1i("frameBufferTexture", 0);
437  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, cutOffFbo.texture);
438  drawFullScreenQuad();
439 
440  //VERTICAL
441  glBindFramebuffer(GL_FRAMEBUFFER, verticalBlurFbo.id);
442  glClearColor(0.0, 0.0, 0.0, 1.0);
443  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
444 
445  verticalBlurShader->use();
446 
447  verticalBlurShader->setUniform1i("frameBufferTexture", 0);
448  glBindTexture(GL_TEXTURE_RECTANGLE_ARB, horizontalBlurFbo.texture);
449  drawFullScreenQuad();
450 }
451 
452 void Renderer::drawFullScreenQuad()
453 {
454  static GLuint vertexArrayObject = 0;
455 
456  // do this initialization first time the function is called... somewhat dodgy, but works for demonstration purposes
457  if (vertexArrayObject == 0)
458  {
459  glGenVertexArrays(1, &vertexArrayObject);
460  static const chag::float2 positions[] = {{-1.0f, -1.0f},
461  { 1.0f, 1.0f},
462  {-1.0f, 1.0f},
463 
464  {-1.0f, -1.0f},
465  { 1.0f, -1.0f},
466  { 1.0f, 1.0f}};
467 
468  createAddAttribBuffer(vertexArrayObject, positions, sizeof(positions), 0, 2, GL_FLOAT);
469  GLuint pos_vbo;
470  glGenBuffers(1, &pos_vbo);
471  glBindBuffer(GL_ARRAY_BUFFER, pos_vbo);
472  glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
473 
474  glBindVertexArray(vertexArrayObject);
475  glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0 );
476  glEnableVertexAttribArray(0);
477  CHECK_GL_ERROR();
478  }
479 
480  glBindVertexArray(vertexArrayObject);
481  glDrawArrays(GL_TRIANGLES, 0, 6);
482 }
483 
Definition: Utils.h:29
Class for maintaining OpenGL shader programs.
Definition: ShaderProgram.h:39
Definition: Scene.h:29
Definition: Camera.h:26