X-Git-Url: https://gitweb.ps.run/subsurface_scattering/blobdiff_plain/d231a4a0d3eca45bb1129f8fa5f9d093f3eff480..8107e994b24112c5bce75a8ae57d0680e5f9161a:/src/main.cpp diff --git a/src/main.cpp b/src/main.cpp index 564560d..1440f04 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -19,140 +20,219 @@ #include #include -const char *vertexShaderSource = R"( -#version 330 core +struct model { + std::vector vertices; + std::vector indices; -layout (location = 0) in vec3 pos; -layout (location = 1) in vec3 normal; + void draw() { + if (VAO == 0) initVAO(); + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + } -out vec3 FragPos; -out vec3 Normal; +private: + void initVAO() { + GLuint VBO; + glGenBuffers(1, &VBO); -uniform mat4 model; -uniform mat4 view; -uniform mat4 projection; + GLuint EBO; + glGenBuffers(1, &EBO); -void main() -{ - gl_Position = projection * view * model * vec4(pos, 1.0); - FragPos = vec3(model * vec4(pos, 1)); - Normal = normal; -} -)"; + glGenVertexArrays(1, &VAO); -const char *fragmentShaderSource = R"( -#version 330 core + glBindVertexArray(VAO); -in vec3 FragPos; -in vec3 Normal; + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), + vertices.data(), GL_STATIC_DRAW); -out vec4 FragColor; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), + indices.data(), GL_STATIC_DRAW); -uniform vec3 objectColor; -uniform vec3 lightColor; -uniform vec3 lightPos; + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(0)); + glEnableVertexAttribArray(0); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3)); + glEnableVertexAttribArray(1); -void main() -{ - vec3 norm = normalize(Normal); - vec3 lightDir = normalize(lightPos - FragPos); + glBindVertexArray(0); + } + GLuint VAO = 0; +}; - float diff = max(dot(norm, lightDir), 0.0); - vec3 diffuse = diff * lightColor; - float ambientStrength = 0.1; - vec3 ambient = ambientStrength * lightColor; +struct freecam { + glm::vec3 pos = glm::vec3(0, 0, -1); + glm::vec2 rot = glm::vec2(0, 0); - vec3 result = (ambient + diffuse) * objectColor; - FragColor = vec4(result, 1.0f); -} -)"; + 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; +}; -std::vector vertices; -std::vector indices; -glm::vec3 lightPos(1.2f, 5.0f, 2.0f); +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; -void load(const std::string &filename, std::vector &vertices, - std::vector &indices) { + 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::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); + ifs.seekg(0, ifs.end); + long length = ifs.tellg(); + ifs.seekg(0, ifs.beg); + char *buffer = (char*)malloc(length); + ifs.read(buffer, length); + ifs.close(); + std::string result(buffer); + free(buffer); + return result; +} + +model loadModel(const std::string &filename) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( 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]; aiVector3D n = scene->mMeshes[0]->mNormals[i]; - vertices.push_back(v.x); - vertices.push_back(v.y); - vertices.push_back(v.z); - vertices.push_back(n.x); - vertices.push_back(n.y); - vertices.push_back(n.z); + 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]); } } -} -int main() { - // Window Setup - - sf::ContextSettings settings; - settings.depthBits = 24; - settings.antialiasingLevel = 0; - settings.majorVersion = 4; - settings.minorVersion = 6; - - sf::RenderWindow window(sf::VideoMode(1600, 900), "Subsurface Scattering", - sf::Style::Default, settings); - window.setVerticalSyncEnabled(true); - window.setMouseCursorGrabbed(true); - window.setMouseCursorVisible(false); - - ImGui::SFML::Init(window); - - // Initialize GLEW - - if (glewInit() != GLEW_OK) { - } - - load("models/Isotrop-upperjaw.ply", vertices, indices); - - // Compile Shaders + return result; +} - GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); - glCompileShader(vertexShader); +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(vertexShader, GL_COMPILE_STATUS, &success); + glGetShaderiv(vertShader, GL_COMPILE_STATUS, &success); if (!success) { - glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); + glGetShaderInfoLog(vertShader, 512, NULL, infoLog); printf("Error compiling vertex shader: %s\n", infoLog); } - GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); - glCompileShader(fragmentShader); + 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(fragmentShader, GL_COMPILE_STATUS, &success); + glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success); if (!success) { - glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); + glGetShaderInfoLog(fragShader, 512, NULL, infoLog); printf("Error compiling fragment shader: %s\n", infoLog); } // Link Shader Program GLuint shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, vertexShader); - glAttachShader(shaderProgram, fragmentShader); + glAttachShader(shaderProgram, vertShader); + glAttachShader(shaderProgram, fragShader); glLinkProgram(shaderProgram); glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); @@ -161,78 +241,63 @@ int main() { printf("Error linking shader program: %s\n", infoLog); } - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); + glDeleteShader(vertShader); + glDeleteShader(fragShader); - // Create VBO + return shaderProgram; +} - GLuint VBO; - glGenBuffers(1, &VBO); - // Create EBO +int main() { + // Window Setup - GLuint EBO; - glGenBuffers(1, &EBO); + sf::ContextSettings settings; + settings.depthBits = 24; + settings.antialiasingLevel = 0; + settings.majorVersion = 4; + settings.minorVersion = 6; - // Create VAO + sf::RenderWindow window(sf::VideoMode(1600, 900), "Subsurface Scattering", + sf::Style::Default, settings); + window.setVerticalSyncEnabled(true); - GLuint VAO; - glGenVertexArrays(1, &VAO); + ImGui::SFML::Init(window); - glBindVertexArray(VAO); + // Initialize GLEW - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), - vertices.data(), GL_STATIC_DRAW); + if (glewInit() != GLEW_OK) { + } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), - indices.data(), GL_STATIC_DRAW); + GLuint shaderProgram = compileShaders("shaders/vert.glsl", "shaders/frag.glsl"); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(0)); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3)); - glEnableVertexAttribArray(1); + model m = loadModel("models/Isotrop-upperjaw.ply"); - glBindVertexArray(0); + arccam arcCam; + freecam freeCam; + + glm::vec3 lightPos(1.2f, 5.0f, 2.0f); - // Perspective + // MVP glm::mat4 model = glm::scale(glm::mat4(1.0f), glm::vec3(0.01f, 0.01f, 0.01f)); - struct { - float camX = 0; - float camZ = -5; - int mouseX = 0; - int mouseY = 0; - } arcball; - - struct { - int mouseX = 0; - int mouseY = 0; - } freecam; - - glm::vec3 camPos = glm::vec3(0, 0, -3); - glm::vec3 camForward = glm::vec3(0, 0, 1); - glm::vec3 camUp = glm::vec3(0, 1, 0); + glm::mat4 view; - glm::mat4 view = - glm::lookAt(glm::vec3(arcball.camX, 0.0, arcball.camZ), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); - - glm::mat4 proj = - glm::perspective(glm::radians(45.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f); + glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f); struct { - bool catchMouse = false; bool wireframe = false; bool freecam = false; - float radius = 1.0f; } options; sf::Clock deltaClock; + bool prevMouse = false; + bool running = true; while (running) { + // Events + sf::Event event; while (window.pollEvent(event)) { ImGui::SFML::ProcessEvent(event); @@ -247,57 +312,38 @@ int main() { case keys::Escape: running = false; break; - case keys::C: - options.catchMouse = !options.catchMouse; - break; - case keys::R: - freecam.mouseX = freecam.mouseY = 0; - break; } } else if (event.type == sf::Event::EventType::MouseWheelScrolled) { - options.radius -= event.mouseWheelScroll.delta / 5.0f; + if (! options.freecam) { + arcCam.radius -= event.mouseWheelScroll.delta / 5.0f; + } } } - int mouseDeltaX = sf::Mouse::getPosition(window).x - window.getSize().x / 2; - int mouseDeltaY = sf::Mouse::getPosition(window).y - window.getSize().y / 2; + // Update - if (options.catchMouse) { - sf::Mouse::setPosition(sf::Vector2i( - window.getSize().x / 2, - window.getSize().y / 2 - ), window); + if (sf::Mouse::isButtonPressed(sf::Mouse::Right)) { + window.setMouseCursorVisible(false); - if (options.freecam) { - freecam.mouseX += mouseDeltaX; - freecam.mouseY += mouseDeltaY; + if (prevMouse) { + if (options.freecam) + freeCam.update(window); + else + arcCam.update(window); + } - camForward = glm::rotate(glm::vec3(0, 0, 1), freecam.mouseY / 500.0f, glm::vec3(1, 0, 0)); - camForward = glm::rotate(camForward, -freecam.mouseX / 500.0f, glm::vec3(0, 1, 0)); - if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) { - camPos += camForward / 20.0f; - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) { - camPos -= camForward / 20.0f; - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) { - glm::vec3 camLeft = glm::rotate(glm::vec3(0, 0, 1), -freecam.mouseX / 500.0f + glm::radians(90.0f), glm::vec3(0, 1, 0)); - camPos += camLeft / 20.0f; - } - if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) { - glm::vec3 camRight = glm::rotate(glm::vec3(0, 0, 1), -freecam.mouseX / 500.0f - glm::radians(90.0f), glm::vec3(0, 1, 0)); - camPos += camRight / 20.0f; - } - } else { - if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) { - arcball.mouseX += mouseDeltaX; - arcball.mouseY += mouseDeltaY; - } - } + 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 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -309,60 +355,55 @@ int main() { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glUseProgram(shaderProgram); - - //rotate - //model = glm::rotate(model, glm::radians(0.2f), glm::vec3(0.0f, 1.0f, 0.0f)); - - if (options.freecam) { - view = glm::lookAt(camPos, camPos + camForward, camUp); - } else { - float angle = arcball.mouseY / 200.0f; - if (angle > glm::radians(89.0f)) { - angle = glm::radians(89.0f); - arcball.mouseY = angle * 200.0f; - } - if (angle < glm::radians(-89.0f)) { - angle = glm::radians(-89.0f); - arcball.mouseY = angle * 200.0f; - } - arcball.camX = sin(angle) * exp(options.radius); - arcball.camZ = cos(angle) * exp(options.radius); - view = glm::lookAt(glm::vec3(0.0, arcball.camX, arcball.camZ), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); - view = glm::rotate(view, arcball.mouseX / 100.0f, glm::vec3(0, 1, 0)); - } - - 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)); - - glBindVertexArray(VAO); - glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); - glBindVertexArray(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)); + + m.draw(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); ImGui::SFML::Update(window, deltaClock.restart()); ImGui::Begin("Options"); - ImGui::LabelText("Cursor Locked", "%d", options.catchMouse); ImGui::Checkbox("Wireframe", &options.wireframe); - ImGui::Checkbox("Free Cam", &options.freecam); + ImGui::Checkbox("Free Cam (F)", &options.freecam); if (options.freecam) { - ImGui::LabelText("Position", "%f %f %f", camPos.x, camPos.y, camPos.z); - ImGui::LabelText("Forward", "%f %f %f", camForward.x, camForward.y, camForward.z); - ImGui::LabelText("Mouse", "%d %d", freecam.mouseX, freecam.mouseY); + 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", arcball.camX, arcball.camZ); - ImGui::InputFloat("Radius", &options.radius); + ImGui::LabelText("Rotation", "%f %f", arcCam.rot.x, arcCam.rot.y); + ImGui::InputFloat("Radius", &arcCam.radius); + if (ImGui::Button("Reset")) { + arcCam.rot = glm::vec2(0); + arcCam.radius = 1; + } } ImGui::End();