]> gitweb.ps.run Git - subsurface_scattering/commitdiff
fix translucency, add gaussian blur to shader
authorPatrick <patrick.schoenberger@posteo.de>
Tue, 23 Mar 2021 18:28:28 +0000 (19:28 +0100)
committerPatrick <patrick.schoenberger@posteo.de>
Tue, 23 Mar 2021 18:28:28 +0000 (19:28 +0100)
build.sh
shaders/fbo_frag.glsl
shaders/frag_irradiance.glsl
shaders/frag_shadowmap.glsl
shaders/vert_irradiance.glsl [new file with mode: 0644]
shaders/vert_shadowmap.glsl [moved from shaders/vert.glsl with 63% similarity]
src/main.cpp
src/main2.cpp [new file with mode: 0644]

index a0654330aa0a9f2b5561b03c1bbd19f89ef5f8c5..8d878f588c669bbd6532a62e0ceae5256a26aa9a 100644 (file)
--- a/build.sh
+++ b/build.sh
@@ -1,2 +1,4 @@
-# g++ -c ~/cpp/libs/imgui/*.cpp ~/cpp/libs/imgui-sfml/*.cpp -I ~/cpp/libs/imgui -I ~/cpp/libs/imgui-sfml/
-g++ src/main.cpp ./*.o -o main -I ~/cpp/libs/imgui -I ~/cpp/libs/imgui-sfml -lsfml-system -lsfml-window -lsfml-graphics -lGLEW -lGL -lassimp
+#!/bin/sh
+
+# g++ -c C:/prg/cpp/libs/imgui/*.cpp C:/prg/cpp/libs/imgui-sfml/*.cpp -I C:/prg/cpp/libs/imgui -I C:/prg/cpp/libs/imgui-sfml -I C:/prg/cpp/libs/SFML-2.5.1/include
+g++ src/main.cpp ./bin/*.o -o main -I C:/prg/cpp/libs/SFML-2.5.1/include -I C:/prg/cpp/libs/assimp-5.0.1/include -I C:/prg/cpp/libs/assimp-5.0.1/build/include -I C:/prg/cpp/libs/glew-2.1.0/include -I C:/prg/cpp/libs/glm -I C:/prg/cpp/libs/imgui -I C:/prg/cpp/libs/imgui-sfml -L "C:/prg/cpp/libs/SFML-2.5.1/build/lib/Release" -L "C:/prg/cpp/libs/assimp-5.0.1/build/code/Release" -L "C:/prg/cpp/libs/glew-2.1.0/lib/Release/x64" -lsfml-system -lsfml-window -lsfml-graphics -lGLEW -lGL -lassimp
index 7463fc858a87636ff57917867bbc5494ca366956..11029923d8555e7017f756de2f733484597f0acc 100644 (file)
@@ -11,24 +11,51 @@ uniform int renderState;
 uniform vec2 samplePositions[13];\r
 uniform vec3 sampleWeights[13];\r
 \r
+vec4 blur(sampler2D tex, vec2 uv, vec2 res) {\r
+  float Pi = 6.28318530718; // Pi*2\r
+    \r
+  // GAUSSIAN BLUR SETTINGS {{{\r
+  float Directions = 16.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower)\r
+  float Quality = 4.0; // BLUR QUALITY (Default 4.0 - More is better but slower)\r
+  float Size = 8.0; // BLUR SIZE (Radius)\r
+  // GAUSSIAN BLUR SETTINGS }}}\r
+  \r
+  vec2 Radius = Size/res;\r
+  \r
+  // Pixel colour\r
+  vec4 Color = texture(tex, uv);\r
+  \r
+  // Blur calculations\r
+  for( float d=0.0; d<Pi; d+=Pi/Directions) {\r
+    for(float i=1.0/Quality; i<=1.0; i+=1.0/Quality) {\r
+      Color += texture( tex, uv+vec2(cos(d),sin(d))*Radius*i);         \r
+    }\r
+  }\r
+  \r
+  // Output to screen\r
+  Color /= Quality * Directions - 15.0;\r
+  return Color;\r
+}\r
+\r
 void main()\r
 {\r
     if (renderState == 0) {\r
-        FragColor = texture(shadowmapTexture, TexCoords);\r
+        FragColor = blur(shadowmapTexture, TexCoords, vec2(screenWidth, screenHeight));\r
     }\r
-    // stencil buffer\r
     else if (renderState == 1) {\r
-        FragColor = texture(irradianceTexture, TexCoords);\r
+        FragColor = texture(shadowmapTexture, TexCoords);\r
     }\r
+    // stencil buffer\r
     else if (renderState == 2) {\r
-        FragColor = texture(shadowmapTexture, TexCoords) * texture(irradianceTexture, TexCoords);\r
+        FragColor = texture(irradianceTexture, TexCoords);\r
     }\r
     else if (renderState == 3) {\r
         vec4 result = vec4(0, 0, 0, 1);\r
         for (int i = 0; i < 13; i++) {\r
             vec2 sampleCoords = TexCoords + samplePositions[i] * vec2(1.0/screenWidth, 1.0/screenHeight);\r
-            vec4 sample = texture(irradianceTexture, sampleCoords)\r
-                        * texture(shadowmapTexture, sampleCoords);\r
+            //vec4 sample = texture(irradianceTexture, sampleCoords)\r
+            //            * texture(shadowmapTexture, sampleCoords);\r
+            vec4 sample = texture(irradianceTexture, sampleCoords);\r
             vec4 weight = vec4(sampleWeights[i], 1);\r
             result += sample * weight;\r
         }\r
index 9e14ebe2e2da8dd07e31d4cb92b71abe40cfdd6f..497bdf07adc643c2bdcaebda5989ff38ffa21e63 100644 (file)
@@ -1,16 +1,21 @@
 #version 330 core\r
 \r
 in vec3 FragPos;\r
+in vec3 LocalPos;\r
+in vec3 Backside;\r
+in float BacksideIrradiance;\r
 in vec3 Normal;\r
 \r
 out vec4 FragColor;\r
 \r
-uniform sampler2D shadowmapTexture;\r
-\r
 uniform vec3 objectColor;\r
 uniform vec3 lightColor;\r
 uniform vec3 lightPos;\r
 uniform vec3 viewPos;\r
+uniform float transmittanceScale;\r
+uniform int renderState;\r
+uniform float powBase;\r
+uniform float powFactor;\r
 \r
 void main()\r
 {\r
@@ -29,6 +34,22 @@ void main()
   float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);\r
   vec3 specular = specularStrength * spec * lightColor;\r
 \r
+  //float distanceToBackside = length(clamp(FragPos - Backside, vec3(0), vec3(1000)));\r
+  float distanceToBackside = length(FragPos - Backside);\r
+  //distanceToBackside = distance(Backside, LocalPos);\r
   vec3 result = (ambient + diffuse + specular) * objectColor;\r
+\r
+  if (renderState == 3)\r
+    if (distanceToBackside != 0)\r
+      //result += objectColor * pow(powBase, -pow(distanceToBackside, 2)) * transmittanceScale * (1 - diff);\r
+      result += objectColor * pow(powBase, powFactor / pow(distanceToBackside, 0.6)) * transmittanceScale * (1 - diff);\r
+  // if (renderState == 3) {\r
+  //   //result = Backside;\r
+  //   //result = LocalPos;\r
+  //   result = vec3(distanceToBackside);\r
+  // }\r
+\r
+    \r
   FragColor = vec4(result, 1.0f);\r
+  //FragColor = vec4(vec3(distanceToBackside), 1);\r
 }\r
index 6d6dab61b4723d93ac5ec396efa3ec93a0e12193..9a15c7a5d949da97bcacbce9b54b66adc9b824b0 100644 (file)
@@ -2,6 +2,7 @@
 #version 330 core\r
 \r
 in vec3 FragPos;\r
+in vec3 LocalPos;\r
 \r
 out vec4 FragColor;\r
 \r
@@ -9,6 +10,10 @@ uniform vec3 lightPos;
 \r
 void main()\r
 {\r
-  float lightDist = 1 - (length(lightPos - FragPos) - 5.5);\r
-  FragColor = vec4(vec3(lightDist), 1);\r
+  float lightDist = length(lightPos - FragPos);\r
+  float c1 = mod(lightDist, 10);\r
+  float c2 = mod(lightDist/10, 10);\r
+  float c3 = mod(lightDist/100, 10);\r
+  FragColor = vec4(c1, c2, c3, 1);\r
+  //FragColor = vec4(LocalPos/10, 1);\r
 }\r
diff --git a/shaders/vert_irradiance.glsl b/shaders/vert_irradiance.glsl
new file mode 100644 (file)
index 0000000..25770f6
--- /dev/null
@@ -0,0 +1,77 @@
+#version 330 core\r
+\r
+layout (location = 0) in vec3 pos;\r
+layout (location = 1) in vec3 normal;\r
+\r
+out vec3 FragPos;\r
+out vec3 LocalPos;\r
+out vec3 Backside;\r
+out float BacksideIrradiance;\r
+out vec3 Normal;\r
+\r
+uniform sampler2D shadowmapTexture;\r
+uniform vec3 lightPos;\r
+uniform vec2 samplePositions[13];\r
+uniform vec3 sampleWeights[13];\r
+uniform int screenWidth;\r
+uniform int screenHeight;\r
+\r
+uniform mat4 model;\r
+uniform mat4 view;\r
+uniform mat4 lightView;\r
+uniform mat4 lightViewInv;\r
+uniform mat4 projection;\r
+uniform mat4 lightProjection;\r
+\r
+vec4 blur(sampler2D tex, vec2 uv, vec2 res) {\r
+  float Pi = 6.28318530718; // Pi*2\r
+    \r
+  // GAUSSIAN BLUR SETTINGS {{{\r
+  float Directions = 16.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower)\r
+  float Quality = 4.0; // BLUR QUALITY (Default 4.0 - More is better but slower)\r
+  float Size = 8.0; // BLUR SIZE (Radius)\r
+  // GAUSSIAN BLUR SETTINGS }}}\r
+  \r
+  vec2 Radius = Size/res;\r
+  \r
+  // Pixel colour\r
+  vec4 Color = texture(tex, uv);\r
+  \r
+  // Blur calculations\r
+  for( float d=0.0; d<Pi; d+=Pi/Directions) {\r
+    for(float i=1.0/Quality; i<=1.0; i+=1.0/Quality) {\r
+      Color += texture( tex, uv+vec2(cos(d),sin(d))*Radius*i);         \r
+    }\r
+  }\r
+  \r
+  // Output to screen\r
+  Color /= Quality * Directions - 15.0;\r
+  return Color;\r
+}\r
+\r
+void main()\r
+{\r
+  gl_Position = projection * view * model * vec4(pos, 1.0);\r
+  FragPos = vec3(model * vec4(pos, 1));\r
+  LocalPos = pos;\r
+  Normal = normal;\r
+  \r
+  vec4 lightSpace = lightProjection * lightView * model * vec4(pos, 1.0);\r
+  lightSpace = lightSpace / lightSpace.w;\r
+  vec2 shadowmapCoords = lightSpace.xy;\r
+  shadowmapCoords = vec2(\r
+    (shadowmapCoords.x * 0.99 + 1) / 2,\r
+    (shadowmapCoords.y * 0.99 + 1) / 2\r
+  );\r
+\r
+\r
+  // blur\r
+  vec4 t = texture(shadowmapTexture, shadowmapCoords);\r
+  //vec4 t = blur(shadowmapTexture, shadowmapCoords, vec2(screenWidth, screenHeight));\r
+\r
+  BacksideIrradiance = t.r + t.g*10 + t.b*100;\r
+  \r
+  vec3 lightDir = (vec3(0, 0, 0) - lightPos);\r
+  Backside = (lightPos + (lightDir * BacksideIrradiance));\r
+  //Backside = texture(shadowmapTexture, shadowmapCoords).xyz*10;\r
+}\r
similarity index 63%
rename from shaders/vert.glsl
rename to shaders/vert_shadowmap.glsl
index 6f485734d62eab44c88ed1c2e6650ebb2006958d..50847bbd0a7ab279b5e0e97bb8ae72893e014156 100644 (file)
@@ -4,15 +4,17 @@ layout (location = 0) in vec3 pos;
 layout (location = 1) in vec3 normal;\r
 \r
 out vec3 FragPos;\r
+out vec3 LocalPos;\r
 out vec3 Normal;\r
 \r
 uniform mat4 model;\r
-uniform mat4 view;\r
+uniform mat4 lightView;\r
 uniform mat4 projection;\r
 \r
 void main()\r
 {\r
-  gl_Position = projection * view * model * vec4(pos, 1.0);\r
+  gl_Position = projection * lightView * model * vec4(pos, 1.0);\r
   FragPos = vec3(model * vec4(pos, 1));\r
+  LocalPos = pos;\r
   Normal = normal;\r
 }\r
index dde29ec662014deda3e1e65e5b605902eeaa91eb..24a39cc85510f5b5896a50e236028e4e21cdac90 100644 (file)
 /*\r
 \r
 TODO:\r
-- ShadowMap to fbo\r
 - Save Depth to fbo\r
+- Stencil Buffer\r
+- LightDist > 1\r
+  - 1 - distanceToBackside in frag_irradiance\r
+- ShadowMap Perspective (no projection?)\r
+- (Implement Gaussian Blur)\r
+- LightDir nicht immer zu 0 0 0\r
 \r
 */\r
 \r
@@ -101,7 +106,6 @@ private:
   GLuint VAO = 0;\r
 };\r
 \r
-\r
 struct freecam {\r
   glm::vec3 pos = glm::vec3(0, 0, -1);\r
   glm::vec2 rot = glm::vec2(0, 0);\r
@@ -155,7 +159,6 @@ private:
   float moveFactor = 20;\r
 };\r
 \r
-\r
 struct arccam {\r
   glm::vec2 rot = glm::vec2(0, 0);\r
   float radius = 1;\r
@@ -207,7 +210,6 @@ private:
   const float angleFactor = 200;\r
 };\r
 \r
-\r
 std::string readFile(std::string filename) {\r
   std::ifstream ifs(filename, std::ios::binary);\r
   std::string result, line;\r
@@ -222,19 +224,22 @@ model loadModel(const std::string &filename) {
 \r
   const aiScene *scene = importer.ReadFile(\r
       filename, aiProcess_CalcTangentSpace | aiProcess_Triangulate |\r
-                    aiProcess_SortByPType | aiProcess_GenSmoothNormals);\r
+                    aiProcess_SortByPType | aiProcess_GenSmoothNormals |\r
+                    aiProcess_GenUVCoords);\r
 \r
   model result;\r
 \r
+  printf("uv channels: %d\n", scene->mMeshes[0]->GetNumUVChannels());\r
+\r
   for (int i = 0; i < scene->mMeshes[0]->mNumVertices; i++) {\r
     aiVector3D v = scene->mMeshes[0]->mVertices[i];\r
     aiVector3D n = scene->mMeshes[0]->mNormals[i];\r
-    result.vertices.push_back(v.x);\r
-    result.vertices.push_back(v.y);\r
-    result.vertices.push_back(v.z);\r
-    result.vertices.push_back(n.x);\r
-    result.vertices.push_back(n.y);\r
-    result.vertices.push_back(n.z);\r
+    result.vertices.push_back(v.x * 100);\r
+    result.vertices.push_back(v.y * 100);\r
+    result.vertices.push_back(v.z * 100);\r
+    result.vertices.push_back(n.x * 100);\r
+    result.vertices.push_back(n.y * 100);\r
+    result.vertices.push_back(n.z * 100);\r
   }\r
 \r
   for (int i = 0; i < scene->mMeshes[0]->mNumFaces; i++) {\r
@@ -293,7 +298,6 @@ GLuint compileShaders(const char *vertFilename, const char *fragFilename) {
   return shaderProgram;\r
 }\r
 \r
-\r
 struct framebuffer {\r
   framebuffer(const char *vertFilename, const char *fragFilename, int width, int height) {\r
     glGenFramebuffers(1, &fbo);\r
@@ -387,23 +391,23 @@ int main() {
   if (glewInit() != GLEW_OK) {\r
   }\r
 \r
-  GLuint shaderProgramShadowmap = compileShaders("shaders/vert.glsl", "shaders/frag_shadowmap.glsl");\r
-  GLuint shaderProgramIrradiance = compileShaders("shaders/vert.glsl", "shaders/frag_irradiance.glsl");\r
+  GLuint shaderProgramShadowmap = compileShaders("shaders/vert_shadowmap.glsl", "shaders/frag_shadowmap.glsl");\r
+  GLuint shaderProgramIrradiance = compileShaders("shaders/vert_irradiance.glsl", "shaders/frag_irradiance.glsl");\r
 \r
-  model m = loadModel("models/Isotrop-upperjaw.ply");\r
+  //model m = loadModel("models/Isotrop-upperjaw.ply");\r
+  model m = loadModel("models/african_head/african_head.obj");\r
 \r
   arccam arcCam;\r
   freecam freeCam;\r
-      \r
-  glm::vec3 lightPos(1.2f, 5.0f, 2.0f);\r
 \r
   // MVP\r
 \r
   glm::mat4 model = glm::scale(glm::mat4(1.0f), glm::vec3(0.01f, 0.01f, 0.01f));\r
 \r
-  glm::mat4 view;\r
+  glm::mat4 view, lightView;\r
 \r
   glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f);\r
+  glm::mat4 lightProj = glm::perspective(glm::radians(90.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f);\r
 \r
   // Framebuffer\r
   framebuffer fb_shadowmap("shaders/fbo_vert.glsl", "shaders/fbo_frag.glsl", width, height);\r
@@ -411,12 +415,18 @@ int main() {
 \r
   // Config\r
 \r
-  struct {\r
+  const struct {\r
     bool wireframe = false;\r
     bool freecam = false;\r
-    int renderState = 0;\r
+    int renderState = 2;\r
     float color[3] = { 0.7f, 0.4f, 0.4f };\r
-  } options;\r
+    glm::vec3 lightPos = glm::vec3(0.0f, 0.04f, -0.08f);\r
+    float transmittanceScale = 0.005f;\r
+    float powBase = 2.718;\r
+    float powFactor = 1;\r
+  } DefaultOptions;\r
+\r
+  auto options = DefaultOptions;\r
 \r
   sf::Clock deltaClock;\r
 \r
@@ -473,6 +483,10 @@ int main() {
 \r
     // Render Shadowmap\r
 \r
+    glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE);\r
+    glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE);\r
+    glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);\r
+\r
     glBindFramebuffer(GL_FRAMEBUFFER, fb_shadowmap.fbo);\r
     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);\r
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
@@ -490,19 +504,21 @@ int main() {
     else\r
       view = arcCam.getViewMatrix();\r
     \r
+    lightView = glm::lookAt(options.lightPos, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));\r
+    \r
     glUniformMatrix4fv(\r
       glGetUniformLocation(shaderProgramShadowmap, "model"),\r
       1, GL_FALSE, glm::value_ptr(model));\r
     glUniformMatrix4fv(\r
-      glGetUniformLocation(shaderProgramShadowmap, "view"),\r
-      1, GL_FALSE, glm::value_ptr(view));\r
+      glGetUniformLocation(shaderProgramShadowmap, "lightView"),\r
+      1, GL_FALSE, glm::value_ptr(lightView));\r
     glUniformMatrix4fv(\r
       glGetUniformLocation(shaderProgramShadowmap, "projection"),\r
-      1, GL_FALSE, glm::value_ptr(proj));\r
+      1, GL_FALSE, glm::value_ptr(lightProj));\r
 \r
     glUniform3fv(\r
       glGetUniformLocation(shaderProgramShadowmap, "lightPos"),\r
-      1, glm::value_ptr(lightPos));\r
+      1, glm::value_ptr(options.lightPos));\r
 \r
     m.draw();\r
 \r
@@ -520,20 +536,41 @@ int main() {
 \r
     glUseProgram(shaderProgramIrradiance);\r
     \r
-    if (options.freecam)\r
-      view = freeCam.getViewMatrix();\r
-    else\r
-      view = arcCam.getViewMatrix();\r
-    \r
     glUniformMatrix4fv(\r
       glGetUniformLocation(shaderProgramIrradiance, "model"),\r
       1, GL_FALSE, glm::value_ptr(model));\r
     glUniformMatrix4fv(\r
       glGetUniformLocation(shaderProgramIrradiance, "view"),\r
       1, GL_FALSE, glm::value_ptr(view));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "lightView"),\r
+      1, GL_FALSE, glm::value_ptr(lightView));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "lightViewInv"),\r
+      1, GL_FALSE, glm::value_ptr(glm::inverse(lightView)));\r
     glUniformMatrix4fv(\r
       glGetUniformLocation(shaderProgramIrradiance, "projection"),\r
       1, GL_FALSE, glm::value_ptr(proj));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "lightProjection"),\r
+      1, GL_FALSE, glm::value_ptr(lightProj));\r
+    glUniform1i(glGetUniformLocation(shaderProgramIrradiance, "screenWidth"), window.getSize().x);\r
+    glUniform1i(glGetUniformLocation(shaderProgramIrradiance, "screenHeight"), window.getSize().y);\r
+    glUniform2fv(glGetUniformLocation(shaderProgramIrradiance, "samplePositions"), 13, samplePositions);\r
+    glUniform3fv(glGetUniformLocation(shaderProgramIrradiance, "sampleWeights"), 13, sampleWeights);\r
+\r
+    glUniform1f(\r
+      glGetUniformLocation(shaderProgramIrradiance, "transmittanceScale"),\r
+      options.transmittanceScale);\r
+    glUniform1i(\r
+      glGetUniformLocation(shaderProgramIrradiance, "renderState"),\r
+      options.renderState);\r
+    glUniform1f(\r
+      glGetUniformLocation(shaderProgramIrradiance, "powBase"),\r
+      options.powBase);\r
+    glUniform1f(\r
+      glGetUniformLocation(shaderProgramIrradiance, "powFactor"),\r
+      options.powFactor);\r
 \r
     glUniform3fv(\r
       glGetUniformLocation(shaderProgramIrradiance, "objectColor"),\r
@@ -543,7 +580,7 @@ int main() {
       1.0f, 1.0f, 1.0f);\r
     glUniform3fv(\r
       glGetUniformLocation(shaderProgramIrradiance, "lightPos"),\r
-      1, glm::value_ptr(lightPos));\r
+      1, glm::value_ptr(options.lightPos));\r
     glUniform3fv(\r
       glGetUniformLocation(shaderProgramIrradiance, "viewPos"),\r
       1, glm::value_ptr(options.freecam ? freeCam.pos : arcCam.getPos()));\r
@@ -586,13 +623,18 @@ int main() {
     ImGui::Checkbox("Wireframe", &options.wireframe);\r
     ImGui::Checkbox("Free Cam", &options.freecam);\r
     ImGui::InputInt("Render State", &options.renderState);\r
-    ImGui::InputFloat3("Color", options.color, 2);\r
+    ImGui::DragFloat3("Color", options.color, 0.01, 0, 1);\r
+    ImGui::DragFloat("Transmittance Scale", &options.transmittanceScale, 0.0001f, 0, 0.3);\r
+    ImGui::DragFloat("Pow Base", &options.powBase, 0.01f, 0, 4);\r
+    ImGui::DragFloat("Pow Factor", &options.powFactor, 0.01f, 0, 3);\r
+    ImGui::DragFloat3("Light Pos", glm::value_ptr(options.lightPos), 0.01, -5, 5);\r
     if (options.freecam) {\r
       ImGui::LabelText("Position", "%f %f %f", freeCam.pos.x, freeCam.pos.y, freeCam.pos.z);\r
       ImGui::LabelText("Rotation", "%f %f", freeCam.rot.x, freeCam.rot.y);\r
       if (ImGui::Button("Reset")) {\r
         freeCam.pos = glm::vec3(0, 0, -1);\r
         freeCam.rot = glm::vec2(0);\r
+        options = DefaultOptions;\r
       }\r
     } else {\r
       ImGui::LabelText("Rotation", "%f %f", arcCam.rot.x, arcCam.rot.y);\r
@@ -600,6 +642,7 @@ int main() {
       if (ImGui::Button("Reset")) {\r
         arcCam.rot = glm::vec2(0);\r
         arcCam.radius = 1;\r
+        options = DefaultOptions;\r
       }\r
     }\r
     ImGui::End();\r
diff --git a/src/main2.cpp b/src/main2.cpp
new file mode 100644 (file)
index 0000000..24a39cc
--- /dev/null
@@ -0,0 +1,656 @@
+#include <stdio.h>\r
+#include <fstream>\r
+\r
+#include <GL/glew.h>\r
+\r
+#define GLM_ENABLE_EXPERIMENTAL\r
+\r
+#include <glm/glm.hpp>\r
+#include <glm/gtx/rotate_vector.hpp>\r
+#include <glm/gtc/matrix_transform.hpp>\r
+#include <glm/gtc/type_ptr.hpp>\r
+\r
+#include <SFML/OpenGL.hpp>\r
+#include <SFML/Graphics.hpp>\r
+\r
+#include <imgui.h>\r
+#include <imgui-SFML.h>\r
+\r
+#include <assimp/Importer.hpp>\r
+#include <assimp/postprocess.h>\r
+#include <assimp/scene.h>\r
+\r
+/*\r
+\r
+TODO:\r
+- Save Depth to fbo\r
+- Stencil Buffer\r
+- LightDist > 1\r
+  - 1 - distanceToBackside in frag_irradiance\r
+- ShadowMap Perspective (no projection?)\r
+- (Implement Gaussian Blur)\r
+- LightDir nicht immer zu 0 0 0\r
+\r
+*/\r
+\r
+float samplePositions[] = {\r
+  0.000000f,  0.000000f,\r
+  1.633992f,  0.036795f,\r
+  0.177801f,  1.717593f,\r
+  -0.194906f,  0.091094f,\r
+  -0.239737f, -0.220217f,\r
+  -0.003530f, -0.118219f,\r
+  1.320107f, -0.181542f,\r
+  5.970690f,  0.253378f,\r
+  -1.089250f,  4.958349f,\r
+  -4.015465f,  4.156699f,\r
+  -4.063099f, -4.110150f,\r
+  -0.638605f, -6.297663f,\r
+  2.542348f, -3.245901f\r
+};\r
+\r
+float sampleWeights[] = {\r
+  0.220441f,  0.487000f, 0.635000f,\r
+  0.076356f,  0.064487f, 0.039097f,\r
+  0.116515f,  0.103222f, 0.064912f,\r
+  0.064844f,  0.086388f, 0.062272f,\r
+  0.131798f,  0.151695f, 0.103676f,\r
+  0.025690f,  0.042728f, 0.033003f,\r
+  0.048593f,  0.064740f, 0.046131f,\r
+  0.048092f,  0.003042f, 0.000400f,\r
+  0.048845f,  0.005406f, 0.001222f,\r
+  0.051322f,  0.006034f, 0.001420f,\r
+  0.061428f,  0.009152f, 0.002511f,\r
+  0.030936f,  0.002868f, 0.000652f,\r
+  0.073580f,  0.023239f, 0.009703f\r
+};\r
+\r
+struct model {\r
+  std::vector<float> vertices;\r
+  std::vector<GLuint> indices;\r
+\r
+  void draw() {\r
+    if (VAO == 0) initVAO();\r
+    glBindVertexArray(VAO);\r
+    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);\r
+    glBindVertexArray(0);\r
+  }\r
+\r
+private:\r
+  void initVAO() {\r
+    GLuint VBO;\r
+    glGenBuffers(1, &VBO);\r
+\r
+    GLuint EBO;\r
+    glGenBuffers(1, &EBO);\r
+\r
+    glGenVertexArrays(1, &VAO);\r
+\r
+    glBindVertexArray(VAO);\r
+\r
+    glBindBuffer(GL_ARRAY_BUFFER, VBO);\r
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(),\r
+                vertices.data(), GL_STATIC_DRAW);\r
+\r
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);\r
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(),\r
+                indices.data(), GL_STATIC_DRAW);\r
+\r
+    glEnableVertexAttribArray(0);\r
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(0));\r
+    glEnableVertexAttribArray(1);\r
+    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3));\r
+\r
+    glBindVertexArray(0);\r
+  }\r
+  GLuint VAO = 0;\r
+};\r
+\r
+struct freecam {\r
+  glm::vec3 pos = glm::vec3(0, 0, -1);\r
+  glm::vec2 rot = glm::vec2(0, 0);\r
+\r
+  void update(sf::Window &window) {\r
+    int mouseDeltaX = sf::Mouse::getPosition(window).x - window.getSize().x / 2;\r
+    int mouseDeltaY = sf::Mouse::getPosition(window).y - window.getSize().y / 2;\r
+\r
+    rot.x += mouseDeltaX;\r
+    rot.y += mouseDeltaY;\r
+\r
+    forward = glm::rotate(glm::vec3(0, 0, 1), rot.y / angleFactor, glm::vec3(1, 0, 0));\r
+    forward = glm::rotate(forward, -rot.x / angleFactor, glm::vec3(0, 1, 0));\r
+\r
+    glm::vec3 left = glm::rotate(glm::vec3(0, 0, 1), -rot.x / angleFactor + glm::radians(90.0f), glm::vec3(0, 1, 0));\r
+\r
+    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LShift))\r
+      moveFactor = 200;\r
+    else\r
+      moveFactor = 20;\r
+\r
+    if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))\r
+      pos += forward / moveFactor;\r
+    if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))\r
+      pos -= forward / moveFactor;\r
+    if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))\r
+      pos += left / moveFactor;\r
+    if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))\r
+      pos -= left / moveFactor;\r
+\r
+    limit();\r
+  }\r
+\r
+  void limit() {\r
+    rot.x = fmod(rot.x, glm::radians(360.0f) * angleFactor);\r
+    rot.y = fmod(rot.y, glm::radians(360.0f) * angleFactor);\r
+  }\r
+\r
+  glm::mat4 getViewMatrix() {\r
+    forward = glm::rotate(glm::vec3(0, 0, 1), rot.y / angleFactor, glm::vec3(1, 0, 0));\r
+    forward = glm::rotate(forward, -rot.x / angleFactor, glm::vec3(0, 1, 0));\r
+    glm::mat4 result = glm::lookAt(pos, pos + forward, up);\r
+    return result;\r
+  }\r
+\r
+private:\r
+  glm::vec3 forward = glm::vec3(0, 0, 1);\r
+  glm::vec3 up = glm::vec3(0, 1, 0);\r
+\r
+  const float angleFactor = 200;\r
+  float moveFactor = 20;\r
+};\r
+\r
+struct arccam {\r
+  glm::vec2 rot = glm::vec2(0, 0);\r
+  float radius = 1;\r
+\r
+  void update(sf::Window &window) {\r
+    int mouseDeltaX = sf::Mouse::getPosition(window).x - window.getSize().x / 2;\r
+    int mouseDeltaY = sf::Mouse::getPosition(window).y - window.getSize().y / 2;\r
+\r
+    rot.x += mouseDeltaX;\r
+    rot.y += mouseDeltaY;\r
+\r
+    limit(-89, 89);\r
+  }\r
+\r
+  void limit(float minY, float maxY) {\r
+    float angleX = rot.x / angleFactor;\r
+    float angleY = rot.y / angleFactor;\r
+\r
+    rot.x = fmod(rot.x, glm::radians(360.0f) * angleFactor);\r
+\r
+    if (angleY > glm::radians(maxY))\r
+      rot.y = glm::radians(maxY) * angleFactor;\r
+    if (angleY < glm::radians(minY))\r
+      rot.y = glm::radians(minY) * angleFactor;\r
+  }\r
+\r
+  glm::vec3 getPos() {\r
+    float angle = rot.y / angleFactor;\r
+  \r
+    float camY = sin(angle) * exp(radius);\r
+    float camZ = cos(angle) * exp(radius);\r
+\r
+    glm::vec3 result(0.0, camY, camZ);\r
+    return glm::rotate(result, -rot.x / angleFactor, glm::vec3(0, 1, 0));\r
+  }\r
+\r
+  glm::mat4 getViewMatrix() {\r
+    float angle = rot.y / angleFactor;\r
+  \r
+    float camY = sin(angle) * exp(radius);\r
+    float camZ = cos(angle) * exp(radius);\r
+    glm::mat4 result = glm::lookAt(glm::vec3(0.0, camY, camZ), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));\r
+    result = glm::rotate(result, rot.x / angleFactor, glm::vec3(0, 1, 0));\r
+\r
+    return result;\r
+  }\r
+\r
+private:\r
+  const float angleFactor = 200;\r
+};\r
+\r
+std::string readFile(std::string filename) {\r
+  std::ifstream ifs(filename, std::ios::binary);\r
+  std::string result, line;\r
+  while (std::getline(ifs, line))\r
+    result += line + "\n";\r
+\r
+  return result;\r
+}\r
+\r
+model loadModel(const std::string &filename) {\r
+  Assimp::Importer importer;\r
+\r
+  const aiScene *scene = importer.ReadFile(\r
+      filename, aiProcess_CalcTangentSpace | aiProcess_Triangulate |\r
+                    aiProcess_SortByPType | aiProcess_GenSmoothNormals |\r
+                    aiProcess_GenUVCoords);\r
+\r
+  model result;\r
+\r
+  printf("uv channels: %d\n", scene->mMeshes[0]->GetNumUVChannels());\r
+\r
+  for (int i = 0; i < scene->mMeshes[0]->mNumVertices; i++) {\r
+    aiVector3D v = scene->mMeshes[0]->mVertices[i];\r
+    aiVector3D n = scene->mMeshes[0]->mNormals[i];\r
+    result.vertices.push_back(v.x * 100);\r
+    result.vertices.push_back(v.y * 100);\r
+    result.vertices.push_back(v.z * 100);\r
+    result.vertices.push_back(n.x * 100);\r
+    result.vertices.push_back(n.y * 100);\r
+    result.vertices.push_back(n.z * 100);\r
+  }\r
+\r
+  for (int i = 0; i < scene->mMeshes[0]->mNumFaces; i++) {\r
+    aiFace f = scene->mMeshes[0]->mFaces[i];\r
+    for (int j = 0; j < f.mNumIndices; j++) {\r
+      result.indices.push_back(f.mIndices[j]);\r
+    }\r
+  }\r
+\r
+  return result;\r
+}\r
+\r
+GLuint compileShaders(const char *vertFilename, const char *fragFilename) {\r
+  GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);\r
+  std::string vertSource = readFile(vertFilename);\r
+  const char *vertAddr = vertSource.c_str();\r
+  glShaderSource(vertShader, 1, &vertAddr, NULL);\r
+  glCompileShader(vertShader);\r
+\r
+  int success;\r
+  char infoLog[512];\r
+  glGetShaderiv(vertShader, GL_COMPILE_STATUS, &success);\r
+  if (!success) {\r
+    glGetShaderInfoLog(vertShader, 512, NULL, infoLog);\r
+    printf("Error compiling vertex shader(%s): %s\n", vertFilename, infoLog);\r
+  }\r
+\r
+  GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);\r
+  std::string fragSource = readFile(fragFilename);\r
+  const char *fragAddr = fragSource.c_str();\r
+  glShaderSource(fragShader, 1, &fragAddr, NULL);\r
+  glCompileShader(fragShader);\r
+\r
+  glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success);\r
+  if (!success) {\r
+    glGetShaderInfoLog(fragShader, 512, NULL, infoLog);\r
+    printf("Error compiling fragment shader(%s): %s\n", fragFilename, infoLog);\r
+  }\r
+\r
+  // Link Shader Program\r
+\r
+  GLuint shaderProgram = glCreateProgram();\r
+  glAttachShader(shaderProgram, vertShader);\r
+  glAttachShader(shaderProgram, fragShader);\r
+  glLinkProgram(shaderProgram);\r
+\r
+  glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);\r
+  if (!success) {\r
+    glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);\r
+    printf("Error linking shader program: %s\n", infoLog);\r
+  }\r
+\r
+  glDeleteShader(vertShader);\r
+  glDeleteShader(fragShader);\r
+\r
+  return shaderProgram;\r
+}\r
+\r
+struct framebuffer {\r
+  framebuffer(const char *vertFilename, const char *fragFilename, int width, int height) {\r
+    glGenFramebuffers(1, &fbo);\r
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);\r
+    \r
+    glGenTextures(1, &renderTexture);\r
+    glBindTexture(GL_TEXTURE_2D, renderTexture);\r
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);\r
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\r
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\r
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\r
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\r
+    //glBindTexture(GL_TEXTURE_2D, 0);\r
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTexture, 0);\r
+\r
+    glGenRenderbuffers(1, &rbo);\r
+    glBindRenderbuffer(GL_RENDERBUFFER, rbo);\r
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);\r
+    //glBindRenderbuffer(GL_RENDERBUFFER, 0);\r
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);\r
+\r
+    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {\r
+      printf("Successfully created framebuffer\n");\r
+    }\r
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);\r
+    \r
+    screenShaderProgram = compileShaders(vertFilename, fragFilename);\r
+    glUseProgram(screenShaderProgram);\r
+    glUniform1i(glGetUniformLocation(screenShaderProgram, "screenTexture"), 0);\r
+\r
+    // Screen VAO\r
+    \r
+    glGenBuffers(1, &screenVBO);\r
+\r
+    glGenVertexArrays(1, &screenVAO);\r
+\r
+    glBindVertexArray(screenVAO);\r
+\r
+    float screenVerts[] = {\r
+      -1.0f, +1.0f, +0.0f, +1.0f,\r
+      -1.0f, -1.0f, +0.0f, +0.0f,\r
+      +1.0f, -1.0f, +1.0f, +0.0f,\r
+  \r
+      -1.0f, +1.0f, +0.0f, +1.0f,\r
+      +1.0f, -1.0f, +1.0f, +0.0f,\r
+      +1.0f, +1.0f, +1.0f, +1.0f,\r
+    };\r
+\r
+    glBindBuffer(GL_ARRAY_BUFFER, screenVBO);\r
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4,\r
+                screenVerts, GL_STATIC_DRAW);\r
+\r
+    glEnableVertexAttribArray(0);\r
+    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)(0));\r
+    glEnableVertexAttribArray(1);\r
+    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)(sizeof(float) * 2));\r
+\r
+    glBindVertexArray(0);\r
+  }\r
+  ~framebuffer() {\r
+    glDeleteFramebuffers(1, &fbo);\r
+  }\r
+  \r
+  GLuint fbo;\r
+  GLuint renderTexture;\r
+  GLuint rbo;\r
+  GLuint screenShaderProgram;\r
+  GLuint screenVBO;\r
+  GLuint screenVAO;\r
+};\r
+\r
+int main() {\r
+  // Window Setup\r
+\r
+  const int width = 1600, height = 900;\r
+\r
+  sf::ContextSettings settings;\r
+  settings.depthBits = 24;\r
+  settings.antialiasingLevel = 0;\r
+  settings.majorVersion = 4;\r
+  settings.minorVersion = 6;\r
+\r
+  sf::RenderWindow window(sf::VideoMode(1600, 900), "Subsurface Scattering",\r
+                    sf::Style::Default, settings);\r
+  window.setVerticalSyncEnabled(true);\r
+\r
+  ImGui::SFML::Init(window);\r
+\r
+  // Initialize GLEW\r
+\r
+  if (glewInit() != GLEW_OK) {\r
+  }\r
+\r
+  GLuint shaderProgramShadowmap = compileShaders("shaders/vert_shadowmap.glsl", "shaders/frag_shadowmap.glsl");\r
+  GLuint shaderProgramIrradiance = compileShaders("shaders/vert_irradiance.glsl", "shaders/frag_irradiance.glsl");\r
+\r
+  //model m = loadModel("models/Isotrop-upperjaw.ply");\r
+  model m = loadModel("models/african_head/african_head.obj");\r
+\r
+  arccam arcCam;\r
+  freecam freeCam;\r
+\r
+  // MVP\r
+\r
+  glm::mat4 model = glm::scale(glm::mat4(1.0f), glm::vec3(0.01f, 0.01f, 0.01f));\r
+\r
+  glm::mat4 view, lightView;\r
+\r
+  glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f);\r
+  glm::mat4 lightProj = glm::perspective(glm::radians(90.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f);\r
+\r
+  // Framebuffer\r
+  framebuffer fb_shadowmap("shaders/fbo_vert.glsl", "shaders/fbo_frag.glsl", width, height);\r
+  framebuffer fb_irradiance("shaders/fbo_vert.glsl", "shaders/fbo_frag.glsl", width, height);\r
+\r
+  // Config\r
+\r
+  const struct {\r
+    bool wireframe = false;\r
+    bool freecam = false;\r
+    int renderState = 2;\r
+    float color[3] = { 0.7f, 0.4f, 0.4f };\r
+    glm::vec3 lightPos = glm::vec3(0.0f, 0.04f, -0.08f);\r
+    float transmittanceScale = 0.005f;\r
+    float powBase = 2.718;\r
+    float powFactor = 1;\r
+  } DefaultOptions;\r
+\r
+  auto options = DefaultOptions;\r
+\r
+  sf::Clock deltaClock;\r
+\r
+  bool prevMouse = false;\r
+\r
+  bool running = true;\r
+  while (running) {\r
+    // Events\r
+\r
+    sf::Event event;\r
+    while (window.pollEvent(event)) {\r
+      ImGui::SFML::ProcessEvent(event);\r
+\r
+      if (event.type == sf::Event::EventType::Closed) {\r
+        running = false;\r
+      } else if (event.type == sf::Event::EventType::Resized) {\r
+        glViewport(0, 0, event.size.width, event.size.height);\r
+      } else if (event.type == sf::Event::EventType::KeyReleased) {\r
+        using keys = sf::Keyboard;\r
+        switch (event.key.code) {\r
+        case keys::Escape:\r
+          running = false;\r
+          break;\r
+        }\r
+      } else if (event.type == sf::Event::EventType::MouseWheelScrolled) {\r
+        if (! options.freecam) {\r
+          arcCam.radius -= event.mouseWheelScroll.delta / 5.0f;\r
+        }\r
+      }\r
+    }\r
+\r
+    // Update\r
+\r
+    if (sf::Mouse::isButtonPressed(sf::Mouse::Right)) {\r
+      window.setMouseCursorVisible(false);\r
+\r
+      if (prevMouse) {\r
+        if (options.freecam)\r
+          freeCam.update(window);\r
+        else\r
+          arcCam.update(window);\r
+      }\r
+\r
+\r
+      sf::Mouse::setPosition(sf::Vector2i(\r
+          window.getSize().x / 2,\r
+          window.getSize().y / 2\r
+        ), window);  \r
+    } else {\r
+      window.setMouseCursorVisible(true);\r
+    }\r
+\r
+    prevMouse = sf::Mouse::isButtonPressed(sf::Mouse::Right);\r
+\r
+    // Render Shadowmap\r
+\r
+    glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE);\r
+    glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE);\r
+    glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);\r
+\r
+    glBindFramebuffer(GL_FRAMEBUFFER, fb_shadowmap.fbo);\r
+    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);\r
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
+    glEnable(GL_DEPTH_TEST);\r
+\r
+    if (options.wireframe)\r
+      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\r
+    else\r
+      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\r
+\r
+    glUseProgram(shaderProgramShadowmap);\r
+    \r
+    if (options.freecam)\r
+      view = freeCam.getViewMatrix();\r
+    else\r
+      view = arcCam.getViewMatrix();\r
+    \r
+    lightView = glm::lookAt(options.lightPos, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));\r
+    \r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramShadowmap, "model"),\r
+      1, GL_FALSE, glm::value_ptr(model));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramShadowmap, "lightView"),\r
+      1, GL_FALSE, glm::value_ptr(lightView));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramShadowmap, "projection"),\r
+      1, GL_FALSE, glm::value_ptr(lightProj));\r
+\r
+    glUniform3fv(\r
+      glGetUniformLocation(shaderProgramShadowmap, "lightPos"),\r
+      1, glm::value_ptr(options.lightPos));\r
+\r
+    m.draw();\r
+\r
+    // Render irradiance\r
+\r
+    glBindFramebuffer(GL_FRAMEBUFFER, fb_irradiance.fbo);\r
+    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);\r
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
+    glEnable(GL_DEPTH_TEST);\r
+\r
+    if (options.wireframe)\r
+      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\r
+    else\r
+      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\r
+\r
+    glUseProgram(shaderProgramIrradiance);\r
+    \r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "model"),\r
+      1, GL_FALSE, glm::value_ptr(model));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "view"),\r
+      1, GL_FALSE, glm::value_ptr(view));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "lightView"),\r
+      1, GL_FALSE, glm::value_ptr(lightView));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "lightViewInv"),\r
+      1, GL_FALSE, glm::value_ptr(glm::inverse(lightView)));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "projection"),\r
+      1, GL_FALSE, glm::value_ptr(proj));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "lightProjection"),\r
+      1, GL_FALSE, glm::value_ptr(lightProj));\r
+    glUniform1i(glGetUniformLocation(shaderProgramIrradiance, "screenWidth"), window.getSize().x);\r
+    glUniform1i(glGetUniformLocation(shaderProgramIrradiance, "screenHeight"), window.getSize().y);\r
+    glUniform2fv(glGetUniformLocation(shaderProgramIrradiance, "samplePositions"), 13, samplePositions);\r
+    glUniform3fv(glGetUniformLocation(shaderProgramIrradiance, "sampleWeights"), 13, sampleWeights);\r
+\r
+    glUniform1f(\r
+      glGetUniformLocation(shaderProgramIrradiance, "transmittanceScale"),\r
+      options.transmittanceScale);\r
+    glUniform1i(\r
+      glGetUniformLocation(shaderProgramIrradiance, "renderState"),\r
+      options.renderState);\r
+    glUniform1f(\r
+      glGetUniformLocation(shaderProgramIrradiance, "powBase"),\r
+      options.powBase);\r
+    glUniform1f(\r
+      glGetUniformLocation(shaderProgramIrradiance, "powFactor"),\r
+      options.powFactor);\r
+\r
+    glUniform3fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "objectColor"),\r
+      1, options.color);\r
+    glUniform3f(\r
+      glGetUniformLocation(shaderProgramIrradiance, "lightColor"),\r
+      1.0f, 1.0f, 1.0f);\r
+    glUniform3fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "lightPos"),\r
+      1, glm::value_ptr(options.lightPos));\r
+    glUniform3fv(\r
+      glGetUniformLocation(shaderProgramIrradiance, "viewPos"),\r
+      1, glm::value_ptr(options.freecam ? freeCam.pos : arcCam.getPos()));\r
+      \r
+    glUniform1i(glGetUniformLocation(shaderProgramIrradiance, "shadowmapTexture"), 0);\r
+    glActiveTexture(GL_TEXTURE0 + 0);\r
+    glBindTexture(GL_TEXTURE_2D, fb_shadowmap.renderTexture);\r
+\r
+    m.draw();\r
+\r
+    // Render fbo to screen\r
+    \r
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\r
+\r
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);\r
+    glDisable(GL_DEPTH_TEST);\r
+    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);\r
+    glClear(GL_COLOR_BUFFER_BIT);\r
+    glUseProgram(fb_irradiance.screenShaderProgram);\r
+\r
+    glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "screenWidth"), window.getSize().x);\r
+    glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "screenHeight"), window.getSize().y);\r
+    glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "renderState"), options.renderState);\r
+    glUniform2fv(glGetUniformLocation(fb_irradiance.screenShaderProgram, "samplePositions"), 13, samplePositions);\r
+    glUniform3fv(glGetUniformLocation(fb_irradiance.screenShaderProgram, "sampleWeights"), 13, sampleWeights);\r
+\r
+    glBindVertexArray(fb_irradiance.screenVAO);\r
+    glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "shadowmapTexture"), 0);\r
+    glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "irradianceTexture"), 1);\r
+    glActiveTexture(GL_TEXTURE0 + 0);\r
+    glBindTexture(GL_TEXTURE_2D, fb_shadowmap.renderTexture);\r
+    glActiveTexture(GL_TEXTURE0 + 1);\r
+    glBindTexture(GL_TEXTURE_2D, fb_irradiance.renderTexture);\r
+    glDrawArrays(GL_TRIANGLES, 0, 6);\r
+    glBindVertexArray(0);\r
+\r
+    ImGui::SFML::Update(window, deltaClock.restart());\r
+\r
+    ImGui::Begin("Options");\r
+    ImGui::Checkbox("Wireframe", &options.wireframe);\r
+    ImGui::Checkbox("Free Cam", &options.freecam);\r
+    ImGui::InputInt("Render State", &options.renderState);\r
+    ImGui::DragFloat3("Color", options.color, 0.01, 0, 1);\r
+    ImGui::DragFloat("Transmittance Scale", &options.transmittanceScale, 0.0001f, 0, 0.3);\r
+    ImGui::DragFloat("Pow Base", &options.powBase, 0.01f, 0, 4);\r
+    ImGui::DragFloat("Pow Factor", &options.powFactor, 0.01f, 0, 3);\r
+    ImGui::DragFloat3("Light Pos", glm::value_ptr(options.lightPos), 0.01, -5, 5);\r
+    if (options.freecam) {\r
+      ImGui::LabelText("Position", "%f %f %f", freeCam.pos.x, freeCam.pos.y, freeCam.pos.z);\r
+      ImGui::LabelText("Rotation", "%f %f", freeCam.rot.x, freeCam.rot.y);\r
+      if (ImGui::Button("Reset")) {\r
+        freeCam.pos = glm::vec3(0, 0, -1);\r
+        freeCam.rot = glm::vec2(0);\r
+        options = DefaultOptions;\r
+      }\r
+    } else {\r
+      ImGui::LabelText("Rotation", "%f %f", arcCam.rot.x, arcCam.rot.y);\r
+      ImGui::DragFloat("Radius", &arcCam.radius, 0.01f, -1.0f, 1.0f);\r
+      if (ImGui::Button("Reset")) {\r
+        arcCam.rot = glm::vec2(0);\r
+        arcCam.radius = 1;\r
+        options = DefaultOptions;\r
+      }\r
+    }\r
+    ImGui::End();\r
+\r
+    ImGui::SFML::Render(window);\r
+\r
+    window.display();\r
+  }\r
+\r
+  return 0;\r
+}\r