X-Git-Url: https://gitweb.ps.run/subsurface_scattering/blobdiff_plain/357464ac8bd3bd04d886460b5ec1720520d22460..9d10826ccb5d1f8a3821d4d2f4242c401146d12d:/src/main.cpp?ds=sidebyside diff --git a/src/main.cpp b/src/main.cpp index 1b59749..41d5e76 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,214 +1,506 @@ #include +#include #include +#define GLM_ENABLE_EXPERIMENTAL + #include +#include #include #include #include -#include +#include + +#include +#include #include -#include #include +#include + +struct model { + std::vector vertices; + std::vector indices; + + void draw() { + if (VAO == 0) initVAO(); + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + } + +private: + void initVAO() { + GLuint VBO; + glGenBuffers(1, &VBO); + + GLuint EBO; + glGenBuffers(1, &EBO); + + glGenVertexArrays(1, &VAO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), + vertices.data(), GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), + indices.data(), GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(0)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3)); + + glBindVertexArray(0); + } + GLuint VAO = 0; +}; + + +struct freecam { + glm::vec3 pos = glm::vec3(0, 0, -1); + glm::vec2 rot = glm::vec2(0, 0); + + void update(sf::Window &window) { + int mouseDeltaX = sf::Mouse::getPosition(window).x - window.getSize().x / 2; + int mouseDeltaY = sf::Mouse::getPosition(window).y - window.getSize().y / 2; + + rot.x += mouseDeltaX; + rot.y += mouseDeltaY; + + forward = glm::rotate(glm::vec3(0, 0, 1), rot.y / angleFactor, glm::vec3(1, 0, 0)); + forward = glm::rotate(forward, -rot.x / angleFactor, glm::vec3(0, 1, 0)); + + glm::vec3 left = glm::rotate(glm::vec3(0, 0, 1), -rot.x / angleFactor + glm::radians(90.0f), glm::vec3(0, 1, 0)); + + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LShift)) + moveFactor = 200; + else + moveFactor = 20; + + if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) + pos += forward / moveFactor; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) + pos -= forward / moveFactor; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) + pos += left / moveFactor; + if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) + pos -= left / moveFactor; + + limit(); + } + + void limit() { + rot.x = fmod(rot.x, glm::radians(360.0f) * angleFactor); + rot.y = fmod(rot.y, glm::radians(360.0f) * angleFactor); + } + glm::mat4 getViewMatrix() { + forward = glm::rotate(glm::vec3(0, 0, 1), rot.y / angleFactor, glm::vec3(1, 0, 0)); + forward = glm::rotate(forward, -rot.x / angleFactor, glm::vec3(0, 1, 0)); + glm::mat4 result = glm::lookAt(pos, pos + forward, up); + return result; + } + +private: + glm::vec3 forward = glm::vec3(0, 0, 1); + glm::vec3 up = glm::vec3(0, 1, 0); + + const float angleFactor = 200; + float moveFactor = 20; +}; + + +struct arccam { + glm::vec2 rot = glm::vec2(0, 0); + float radius = 1; + + void update(sf::Window &window) { + int mouseDeltaX = sf::Mouse::getPosition(window).x - window.getSize().x / 2; + int mouseDeltaY = sf::Mouse::getPosition(window).y - window.getSize().y / 2; + + rot.x += mouseDeltaX; + rot.y += mouseDeltaY; + + limit(-89, 89); + } + + void limit(float minY, float maxY) { + float angleX = rot.x / angleFactor; + float angleY = rot.y / angleFactor; + + rot.x = fmod(rot.x, glm::radians(360.0f) * angleFactor); + + if (angleY > glm::radians(maxY)) + rot.y = glm::radians(maxY) * angleFactor; + if (angleY < glm::radians(minY)) + rot.y = glm::radians(minY) * angleFactor; + } + + glm::vec3 getPos() { + float angle = rot.y / angleFactor; + + float camY = sin(angle) * exp(radius); + float camZ = cos(angle) * exp(radius); + + glm::vec3 result(0.0, camY, camZ); + return glm::rotate(result, -rot.x / angleFactor, glm::vec3(0, 1, 0)); + } + + glm::mat4 getViewMatrix() { + float angle = rot.y / angleFactor; + + float camY = sin(angle) * exp(radius); + float camZ = cos(angle) * exp(radius); + glm::mat4 result = glm::lookAt(glm::vec3(0.0, camY, camZ), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); + result = glm::rotate(result, rot.x / angleFactor, glm::vec3(0, 1, 0)); + + return result; + } + +private: + const float angleFactor = 200; +}; + + +std::string readFile(std::string filename) { + std::ifstream ifs(filename, std::ios::binary); + std::string result, line; + while (std::getline(ifs, line)) + result += line + "\n"; -const char *vertexShaderSource = -"#version 330 core\n" -"layout (location = 0) in vec3 pos;\n" -"uniform mat4 model;\n" -"uniform mat4 view;\n" -"uniform mat4 projection;\n" -"\n" -"void main()\n" -"{\n" -" gl_Position = projection * view * model * vec4(pos, 1.0);\n" -"}\n"; - -const char *fragmentShaderSource = -"#version 330 core\n" -"out vec4 FragColor;\n" -"\n" -"void main()\n" -"{\n" -" FragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n" -"}\n"; - -std::vector vertices; -std::vector indices; - - -void load(const std::string &filename, std::vector &vertices, std::vector &indices) { + return result; +} + +model loadModel(const std::string &filename) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( - filename, - aiProcess_CalcTangentSpace | - aiProcess_Triangulate | - aiProcess_JoinIdenticalVertices | - aiProcess_SortByPType - ); + filename, aiProcess_CalcTangentSpace | aiProcess_Triangulate | + aiProcess_SortByPType | aiProcess_GenSmoothNormals); + + model result; for (int i = 0; i < scene->mMeshes[0]->mNumVertices; i++) { aiVector3D v = scene->mMeshes[0]->mVertices[i]; - vertices.push_back(v.x); - vertices.push_back(v.y); - vertices.push_back(v.z); + aiVector3D n = scene->mMeshes[0]->mNormals[i]; + result.vertices.push_back(v.x); + result.vertices.push_back(v.y); + result.vertices.push_back(v.z); + result.vertices.push_back(n.x); + result.vertices.push_back(n.y); + result.vertices.push_back(n.z); } for (int i = 0; i < scene->mMeshes[0]->mNumFaces; i++) { aiFace f = scene->mMeshes[0]->mFaces[i]; for (int j = 0; j < f.mNumIndices; j++) { - indices.push_back(f.mIndices[j]); + result.indices.push_back(f.mIndices[j]); } } + + return result; } +GLuint compileShaders(const char *vertFilename, const char *fragFilename) { + GLuint vertShader = glCreateShader(GL_VERTEX_SHADER); + std::string vertSource = readFile(vertFilename); + const char *vertAddr = vertSource.c_str(); + glShaderSource(vertShader, 1, &vertAddr, NULL); + glCompileShader(vertShader); + + int success; + char infoLog[512]; + glGetShaderiv(vertShader, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(vertShader, 512, NULL, infoLog); + printf("Error compiling vertex shader(%s): %s\n", vertFilename, infoLog); + } + + GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER); + std::string fragSource = readFile(fragFilename); + const char *fragAddr = fragSource.c_str(); + glShaderSource(fragShader, 1, &fragAddr, NULL); + glCompileShader(fragShader); + + glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(fragShader, 512, NULL, infoLog); + printf("Error compiling fragment shader(%s): %s\n", fragFilename, infoLog); + } + + // Link Shader Program + + GLuint shaderProgram = glCreateProgram(); + glAttachShader(shaderProgram, vertShader); + glAttachShader(shaderProgram, fragShader); + glLinkProgram(shaderProgram); + + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); + printf("Error linking shader program: %s\n", infoLog); + } + + glDeleteShader(vertShader); + glDeleteShader(fragShader); + + return shaderProgram; +} + + int main() { // Window Setup + const int width = 1600, height = 900; + sf::ContextSettings settings; settings.depthBits = 24; settings.antialiasingLevel = 0; settings.majorVersion = 4; settings.minorVersion = 6; - sf::Window window(sf::VideoMode(800, 600), "Subsurface Scattering", + sf::RenderWindow window(sf::VideoMode(1600, 900), "Subsurface Scattering", sf::Style::Default, settings); window.setVerticalSyncEnabled(true); - window.setActive(true); + ImGui::SFML::Init(window); // Initialize GLEW if (glewInit() != GLEW_OK) { - } - load("models/Isotrop-upperjaw.ply", vertices, indices); + GLuint shaderProgram = compileShaders("shaders/vert.glsl", "shaders/frag.glsl"); - // Compile Shaders + model m = loadModel("models/Isotrop-upperjaw.ply"); - GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); - glCompileShader(vertexShader); + arccam arcCam; + freecam freeCam; + + glm::vec3 lightPos(1.2f, 5.0f, 2.0f); - int success; - char infoLog[512]; - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); - if (!success) { - glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); - printf("Error compiling vertex shader: %s\n", infoLog); - } + // MVP - GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); - glCompileShader(fragmentShader); + glm::mat4 model = glm::scale(glm::mat4(1.0f), glm::vec3(0.01f, 0.01f, 0.01f)); - glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); - if (!success) { - glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); - printf("Error compiling fragment shader: %s\n", infoLog); - } + glm::mat4 view; - // Link Shader Program + glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f); - GLuint shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, vertexShader); - glAttachShader(shaderProgram, fragmentShader); - glLinkProgram(shaderProgram); + // Framebuffer + GLuint fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); - if (!success) { - glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); - printf("Error linking shader program: %s\n", infoLog); + GLuint renderTexture; + glGenTextures(1, &renderTexture); + glBindTexture(GL_TEXTURE_2D, renderTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + //glBindTexture(GL_TEXTURE_2D, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTexture, 0); + + GLuint rbo; + glGenRenderbuffers(1, &rbo); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + //glBindRenderbuffer(GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) { + printf("Successfully created framebuffer\n"); } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + GLuint screenShaderProgram = compileShaders("shaders/fbo_vert.glsl", "shaders/fbo_frag.glsl"); + glUseProgram(screenShaderProgram); + glUniform1i(glGetUniformLocation(screenShaderProgram, "screenTexture"), 0); - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - // Create VBO - - GLuint VBO; - glGenBuffers(1, &VBO); + // Screen VAO + + GLuint screenVBO; + glGenBuffers(1, &screenVBO); - // Create EBO + GLuint screenVAO; + glGenVertexArrays(1, &screenVAO); - GLuint EBO; - glGenBuffers(1, &EBO); - - // Create VAO + glBindVertexArray(screenVAO); - GLuint VAO; - glGenVertexArrays(1, &VAO); + float screenVerts[] = { + -1.0f, +1.0f, +0.0f, +1.0f, + -1.0f, -1.0f, +0.0f, +0.0f, + +1.0f, -1.0f, +1.0f, +0.0f, + + -1.0f, +1.0f, +0.0f, +1.0f, + +1.0f, -1.0f, +1.0f, +0.0f, + +1.0f, +1.0f, +1.0f, +1.0f, + }; - glBindVertexArray(VAO); - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(), GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, screenVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, + screenVerts, GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, NULL); glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)(0)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)(sizeof(float) * 2)); glBindVertexArray(0); - // Perspective - - glm::mat4 model = glm::mat4(1.0f); + // Config - glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -200.0f)); + struct { + bool wireframe = false; + bool freecam = false; + } options; - glm::mat4 proj = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 1000.0f); + sf::Clock deltaClock; - bool wireframe = false; + bool prevMouse = false; bool running = true; while (running) { + // Events + sf::Event event; while (window.pollEvent(event)) { - if (event.type == sf::Event::Closed) { + ImGui::SFML::ProcessEvent(event); + + if (event.type == sf::Event::EventType::Closed) { running = false; - } else if (event.type == sf::Event::Resized) { + } else if (event.type == sf::Event::EventType::Resized) { glViewport(0, 0, event.size.width, event.size.height); - } else if (event.type == sf::Event::KeyReleased) { + } else if (event.type == sf::Event::EventType::KeyReleased) { using keys = sf::Keyboard; switch (event.key.code) { - case keys::W: - wireframe = !wireframe; - break; case keys::Escape: running = false; break; } + } else if (event.type == sf::Event::EventType::MouseWheelScrolled) { + if (! options.freecam) { + arcCam.radius -= event.mouseWheelScroll.delta / 5.0f; + } } } - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // Update + + if (sf::Mouse::isButtonPressed(sf::Mouse::Right)) { + window.setMouseCursorVisible(false); + if (prevMouse) { + if (options.freecam) + freeCam.update(window); + else + arcCam.update(window); + } + + + sf::Mouse::setPosition(sf::Vector2i( + window.getSize().x / 2, + window.getSize().y / 2 + ), window); + } else { + window.setMouseCursorVisible(true); + } + + prevMouse = sf::Mouse::isButtonPressed(sf::Mouse::Right); + + // Render to fbo + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); - if (wireframe) + if (options.wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - model = glm::rotate(model, glm::radians(0.2f), glm::vec3(0.0f, 1.0f, 0.0f)); - - glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); - glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view)); - glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(proj)); - glUseProgram(shaderProgram); - glBindVertexArray(VAO); - glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); + + if (options.freecam) + view = freeCam.getViewMatrix(); + else + view = arcCam.getViewMatrix(); + + glUniformMatrix4fv( + glGetUniformLocation(shaderProgram, "model"), + 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv( + glGetUniformLocation(shaderProgram, "view"), + 1, GL_FALSE, glm::value_ptr(view)); + glUniformMatrix4fv( + glGetUniformLocation(shaderProgram, "projection"), + 1, GL_FALSE, glm::value_ptr(proj)); + + glUniform3f( + glGetUniformLocation(shaderProgram, "objectColor"), + 1.0f, 0.5f, 0.31f); + glUniform3f( + glGetUniformLocation(shaderProgram, "lightColor"), + 1.0f, 1.0f, 1.0f); + glUniform3fv( + glGetUniformLocation(shaderProgram, "lightPos"), + 1, glm::value_ptr(lightPos)); + glUniform3fv( + glGetUniformLocation(shaderProgram, "viewPos"), + 1, glm::value_ptr(options.freecam ? freeCam.pos : arcCam.getPos())); + + m.draw(); + + // Render fbo to screen + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDisable(GL_DEPTH_TEST); + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + glUseProgram(screenShaderProgram); + + glBindVertexArray(screenVAO); + glBindTexture(GL_TEXTURE_2D, renderTexture); + glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); + ImGui::SFML::Update(window, deltaClock.restart()); + + ImGui::Begin("Options"); + ImGui::Checkbox("Wireframe", &options.wireframe); + ImGui::Checkbox("Free Cam", &options.freecam); + if (options.freecam) { + ImGui::LabelText("Position", "%f %f %f", freeCam.pos.x, freeCam.pos.y, freeCam.pos.z); + ImGui::LabelText("Rotation", "%f %f", freeCam.rot.x, freeCam.rot.y); + if (ImGui::Button("Reset")) { + freeCam.pos = glm::vec3(0, 0, -1); + freeCam.rot = glm::vec2(0); + } + } else { + ImGui::LabelText("Rotation", "%f %f", arcCam.rot.x, arcCam.rot.y); + ImGui::DragFloat("Radius", &arcCam.radius, 0.01f, -1.0f, 1.0f); + if (ImGui::Button("Reset")) { + arcCam.rot = glm::vec2(0); + arcCam.radius = 1; + } + } + ImGui::End(); + + ImGui::SFML::Render(window); + window.display(); } + glDeleteFramebuffers(1, &fbo); + return 0; } \ No newline at end of file