]> gitweb.ps.run Git - subsurface_scattering/blobdiff - src/main.cpp
fix build.sh
[subsurface_scattering] / src / main.cpp
index 8bdede62d035eab9802e464c63e55c5048a1c27e..b95cc972121437ecb2a77ce573129ff41b72450b 100644 (file)
 #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/Window.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
-const char *vertexShaderSource = R"(\r
-#version 330 core\r
+struct model {\r
+  std::vector<float> vertices;\r
+  std::vector<GLuint> indices;\r
 \r
-layout (location = 0) in vec3 pos;\r
-layout (location = 0) in vec3 normal;\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
-out vec3 FragPos;\r
-out vec3 Normal;\r
+private:\r
+  void initVAO() {\r
+    GLuint VBO;\r
+    glGenBuffers(1, &VBO);\r
 \r
-uniform mat4 model;\r
-uniform mat4 view;\r
-uniform mat4 projection;\r
+    GLuint EBO;\r
+    glGenBuffers(1, &EBO);\r
 \r
-void main()\r
-{\r
-  gl_Position = projection * view * model * vec4(pos, 1.0);\r
-  FragPos = vec3(model * vec4(pos, 1));\r
-  Normal = normal;\r
-}\r
-)";\r
+    glGenVertexArrays(1, &VAO);\r
 \r
-const char *fragmentShaderSource = R"(\r
-#version 330 core\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
-in vec3 FragPos;\r
-in vec3 Normal;\r
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(0));\r
+    glEnableVertexAttribArray(0);\r
+    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3));\r
+    glEnableVertexAttribArray(1);\r
 \r
-out vec4 FragColor;\r
+    glBindVertexArray(0);\r
+  }\r
+  GLuint VAO = 0;\r
+};\r
 \r
-uniform vec3 objectColor;\r
-uniform vec3 lightColor;\r
-uniform vec3 lightPos;\r
 \r
-void main()\r
-{\r
-  vec3 norm = normalize(Normal);\r
-  vec3 lightDir = normalize(lightPos - FragPos);\r
+struct freecam {\r
+  glm::vec3 pos = glm::vec3(0, 0, -1);\r
+  glm::vec2 rot = glm::vec2(0, 0);\r
 \r
-  float diff = max(dot(norm, lightDir), 0.0);\r
-  vec3 diffuse = diff * lightColor;\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
-  float ambientStrength = 0.1;\r
-  vec3 ambient = ambientStrength * lightColor;\r
+    rot.x += mouseDeltaX;\r
+    rot.y += mouseDeltaY;\r
 \r
-  vec3 result = (ambient + diffuse) * objectColor;\r
-  FragColor = vec4(result, 1.0f);\r
-}\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
+\r
+struct arccam {\r
+  glm::vec2 rot = glm::vec2(0, 0);\r
+  float radius = 1;\r
 \r
-std::vector<float> vertices;\r
-std::vector<GLuint> indices;\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
-glm::vec3 lightPos(1.2f, 0.5f, 2.0f);\r
+    rot.x += mouseDeltaX;\r
+    rot.y += mouseDeltaY;\r
 \r
-void load(const std::string &filename, std::vector<float> &vertices,\r
-          std::vector<GLuint> &indices) {\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::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
+\r
+std::string readFile(std::string filename) {\r
+  std::ifstream ifs(filename, std::ios::binary);\r
+  ifs.seekg(0, ifs.end);\r
+  long length = ifs.tellg();\r
+  ifs.seekg(0, ifs.beg);\r
+  char *buffer = (char*)malloc(length);\r
+  ifs.read(buffer, length);\r
+  ifs.close();\r
+  std::string result(buffer);\r
+  free(buffer);\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_GenNormals);\r
+                    aiProcess_SortByPType | aiProcess_GenSmoothNormals);\r
+\r
+  model result;\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
-    vertices.push_back(v.x);\r
-    vertices.push_back(v.y);\r
-    vertices.push_back(v.z);\r
-    vertices.push_back(n.x);\r
-    vertices.push_back(n.y);\r
-    vertices.push_back(n.z);\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
   }\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
-      indices.push_back(f.mIndices[j]);\r
+      result.indices.push_back(f.mIndices[j]);\r
     }\r
   }\r
-}\r
-\r
-int main() {\r
-  // Window Setup\r
-\r
-  sf::ContextSettings settings;\r
-  settings.depthBits = 24;\r
-  settings.antialiasingLevel = 0;\r
-  settings.majorVersion = 4;\r
-  settings.minorVersion = 6;\r
 \r
-  sf::Window window(sf::VideoMode(800, 600), "Subsurface Scattering",\r
-                    sf::Style::Default, settings);\r
-  window.setVerticalSyncEnabled(true);\r
-\r
-  window.setActive(true);\r
-\r
-  // Initialize GLEW\r
-\r
-  if (glewInit() != GLEW_OK) {\r
-  }\r
-\r
-  load("models/Isotrop-upperjaw.ply", vertices, indices);\r
-\r
-  // Compile Shaders\r
+  return result;\r
+}\r
 \r
-  GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);\r
-  glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);\r
-  glCompileShader(vertexShader);\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(vertexShader, GL_COMPILE_STATUS, &success);\r
+  glGetShaderiv(vertShader, GL_COMPILE_STATUS, &success);\r
   if (!success) {\r
-    glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);\r
+    glGetShaderInfoLog(vertShader, 512, NULL, infoLog);\r
     printf("Error compiling vertex shader: %s\n", infoLog);\r
   }\r
 \r
-  GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);\r
-  glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);\r
-  glCompileShader(fragmentShader);\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(fragmentShader, GL_COMPILE_STATUS, &success);\r
+  glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success);\r
   if (!success) {\r
-    glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);\r
+    glGetShaderInfoLog(fragShader, 512, NULL, infoLog);\r
     printf("Error compiling fragment shader: %s\n", infoLog);\r
   }\r
 \r
   // Link Shader Program\r
 \r
   GLuint shaderProgram = glCreateProgram();\r
-  glAttachShader(shaderProgram, vertexShader);\r
-  glAttachShader(shaderProgram, fragmentShader);\r
+  glAttachShader(shaderProgram, vertShader);\r
+  glAttachShader(shaderProgram, fragShader);\r
   glLinkProgram(shaderProgram);\r
 \r
   glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);\r
@@ -153,105 +241,176 @@ int main() {
     printf("Error linking shader program: %s\n", infoLog);\r
   }\r
 \r
-  glDeleteShader(vertexShader);\r
-  glDeleteShader(fragmentShader);\r
+  glDeleteShader(vertShader);\r
+  glDeleteShader(fragShader);\r
 \r
-  // Create VBO\r
+  return shaderProgram;\r
+}\r
 \r
-  GLuint VBO;\r
-  glGenBuffers(1, &VBO);\r
 \r
-  // Create EBO\r
+int main() {\r
+  // Window Setup\r
 \r
-  GLuint EBO;\r
-  glGenBuffers(1, &EBO);\r
+  sf::ContextSettings settings;\r
+  settings.depthBits = 24;\r
+  settings.antialiasingLevel = 0;\r
+  settings.majorVersion = 4;\r
+  settings.minorVersion = 6;\r
 \r
-  // Create VAO\r
+  sf::RenderWindow window(sf::VideoMode(1600, 900), "Subsurface Scattering",\r
+                    sf::Style::Default, settings);\r
+  window.setVerticalSyncEnabled(true);\r
 \r
-  GLuint VAO;\r
-  glGenVertexArrays(1, &VAO);\r
+  ImGui::SFML::Init(window);\r
 \r
-  glBindVertexArray(VAO);\r
+  // Initialize GLEW\r
 \r
-  glBindBuffer(GL_ARRAY_BUFFER, VBO);\r
-  glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(),\r
-               vertices.data(), GL_STATIC_DRAW);\r
+  if (glewInit() != GLEW_OK) {\r
+  }\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
+  GLuint shaderProgram = compileShaders("shaders/vert.glsl", "shaders/frag.glsl");\r
 \r
-  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)0);\r
-  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)3);\r
-  glEnableVertexAttribArray(0);\r
+  model m = loadModel("models/Isotrop-upperjaw.ply");\r
 \r
-  glBindVertexArray(0);\r
+  arccam arcCam;\r
+  freecam freeCam;\r
+      \r
+  glm::vec3 lightPos(1.2f, 5.0f, 2.0f);\r
 \r
-  // Perspective\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::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -3.0f));\r
+  glm::mat4 view;\r
+\r
+  glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f);\r
+\r
+  struct {\r
+    bool wireframe = false;\r
+    bool freecam = false;\r
+  } options;\r
 \r
-  glm::mat4 proj =\r
-      glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 1000.0f);\r
+  sf::Clock deltaClock;\r
 \r
-  bool wireframe = false;\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
-      if (event.type == sf::Event::Closed) {\r
+      ImGui::SFML::ProcessEvent(event);\r
+\r
+      if (event.type == sf::Event::EventType::Closed) {\r
         running = false;\r
-      } else if (event.type == sf::Event::Resized) {\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::KeyReleased) {\r
+      } else if (event.type == sf::Event::EventType::KeyReleased) {\r
         using keys = sf::Keyboard;\r
         switch (event.key.code) {\r
-        case keys::W:\r
-          wireframe = !wireframe;\r
-          break;\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\r
+\r
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
 \r
     glEnable(GL_DEPTH_TEST);\r
 \r
-    if (wireframe)\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(shaderProgram);\r
+    \r
+    if (options.freecam)\r
+      view = freeCam.getViewMatrix();\r
+    else\r
+      view = arcCam.getViewMatrix();\r
+    \r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgram, "model"),\r
+      1, GL_FALSE, glm::value_ptr(model));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgram, "view"),\r
+      1, GL_FALSE, glm::value_ptr(view));\r
+    glUniformMatrix4fv(\r
+      glGetUniformLocation(shaderProgram, "projection"),\r
+      1, GL_FALSE, glm::value_ptr(proj));\r
+\r
+    glUniform3f(\r
+      glGetUniformLocation(shaderProgram, "objectColor"),\r
+      1.0f, 0.5f, 0.31f);\r
+    glUniform3f(\r
+      glGetUniformLocation(shaderProgram, "lightColor"),\r
+      1.0f, 1.0f, 1.0f);\r
+    glUniform3fv(\r
+      glGetUniformLocation(shaderProgram, "lightPos"),\r
+      1, glm::value_ptr(lightPos));\r
+\r
+    m.draw();\r
+    \r
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\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
+    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
+      }\r
+    } else {\r
+      ImGui::LabelText("Rotation", "%f %f", arcCam.rot.x, arcCam.rot.y);\r
+      ImGui::InputFloat("Radius", &arcCam.radius);\r
+      if (ImGui::Button("Reset")) {\r
+        arcCam.rot = glm::vec2(0);\r
+        arcCam.radius = 1;\r
+      }\r
+    }\r
+    ImGui::End();\r
 \r
-    model = glm::rotate(model, glm::radians(0.2f), glm::vec3(0.0f, 1.0f, 0.0f));\r
-\r
-    glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1,\r
-                       GL_FALSE, glm::value_ptr(model));\r
-    glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE,\r
-                       glm::value_ptr(view));\r
-    glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1,\r
-                       GL_FALSE, glm::value_ptr(proj));\r
-\r
-    glUniform3f(glGetUniformLocation(shaderProgram, "objectColor"), 1.0f, 0.5f,\r
-                0.31f);\r
-    glUniform3f(glGetUniformLocation(shaderProgram, "lightColor"), 1.0f, 1.0f,\r
-                1.0f);\r
-    glUniform3fv(glGetUniformLocation(shaderProgram, "lightPos"), 1, glm::value_ptr(lightPos));\r
-\r
-    glBindVertexArray(VAO);\r
-    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);\r
-    glBindVertexArray(0);\r
+    ImGui::SFML::Render(window);\r
 \r
     window.display();\r
   }\r
 \r
   return 0;\r
-}
\ No newline at end of file
+}\r