X-Git-Url: https://gitweb.ps.run/subsurface_scattering/blobdiff_plain/451e872ddbe6db8bd8d6aa54ca0bf744dc5405e5..54a47a42ce3f6f05eafd62305552ee48dc08913f:/src/main.cpp diff --git a/src/main.cpp b/src/main.cpp index 4168c50..4f18e10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,6 +20,42 @@ #include #include + +// sample positions and weights for a Gaussian kernel from +// Hable, John ; Borshukov, George ; Hejl, Jim: Fast Skin Shading. In: ShaderX7, ShaderX : Charles River Media, 2009, S. 161–173 + +float samplePositions[] = { + 0.000000f, 0.000000f, + 1.633992f, 0.036795f, + 0.177801f, 1.717593f, + -0.194906f, 0.091094f, + -0.239737f, -0.220217f, + -0.003530f, -0.118219f, + 1.320107f, -0.181542f, + 5.970690f, 0.253378f, + -1.089250f, 4.958349f, + -4.015465f, 4.156699f, + -4.063099f, -4.110150f, + -0.638605f, -6.297663f, + 2.542348f, -3.245901f +}; + +float sampleWeights[] = { + 0.220441f, 0.487000f, 0.635000f, + 0.076356f, 0.064487f, 0.039097f, + 0.116515f, 0.103222f, 0.064912f, + 0.064844f, 0.086388f, 0.062272f, + 0.131798f, 0.151695f, 0.103676f, + 0.025690f, 0.042728f, 0.033003f, + 0.048593f, 0.064740f, 0.046131f, + 0.048092f, 0.003042f, 0.000400f, + 0.048845f, 0.005406f, 0.001222f, + 0.051322f, 0.006034f, 0.001420f, + 0.061428f, 0.009152f, 0.002511f, + 0.030936f, 0.002868f, 0.000652f, + 0.073580f, 0.023239f, 0.009703f +}; + struct model { std::vector vertices; std::vector indices; @@ -61,7 +97,6 @@ private: GLuint VAO = 0; }; - struct freecam { glm::vec3 pos = glm::vec3(0, 0, -1); glm::vec2 rot = glm::vec2(0, 0); @@ -115,7 +150,6 @@ private: float moveFactor = 20; }; - struct arccam { glm::vec2 rot = glm::vec2(0, 0); float radius = 1; @@ -167,7 +201,6 @@ private: const float angleFactor = 200; }; - std::string readFile(std::string filename) { std::ifstream ifs(filename, std::ios::binary); std::string result, line; @@ -182,10 +215,13 @@ model loadModel(const std::string &filename) { const aiScene *scene = importer.ReadFile( filename, aiProcess_CalcTangentSpace | aiProcess_Triangulate | - aiProcess_SortByPType | aiProcess_GenSmoothNormals); + aiProcess_SortByPType | aiProcess_GenSmoothNormals | + aiProcess_GenUVCoords); model result; + printf("uv channels: %d\n", scene->mMeshes[0]->GetNumUVChannels()); + for (int i = 0; i < scene->mMeshes[0]->mNumVertices; i++) { aiVector3D v = scene->mMeshes[0]->mVertices[i]; aiVector3D n = scene->mMeshes[0]->mNormals[i]; @@ -253,6 +289,76 @@ GLuint compileShaders(const char *vertFilename, const char *fragFilename) { return shaderProgram; } +struct framebuffer { + framebuffer(const char *vertFilename, const char *fragFilename, int width, int height) { + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + 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); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + //glBindTexture(GL_TEXTURE_2D, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTexture, 0); + + 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); + + screenShaderProgram = compileShaders(vertFilename, fragFilename); + glUseProgram(screenShaderProgram); + glUniform1i(glGetUniformLocation(screenShaderProgram, "screenTexture"), 0); + + // Screen VAO + + glGenBuffers(1, &screenVBO); + + glGenVertexArrays(1, &screenVAO); + + glBindVertexArray(screenVAO); + + 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, + }; + + glBindBuffer(GL_ARRAY_BUFFER, screenVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, + screenVerts, GL_STATIC_DRAW); + + 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); + } + ~framebuffer() { + glDeleteFramebuffers(1, &fbo); + } + + GLuint fbo; + GLuint renderTexture; + GLuint rbo; + GLuint screenShaderProgram; + GLuint screenVBO; + GLuint screenVAO; +}; int main() { // Window Setup @@ -276,94 +382,42 @@ int main() { if (glewInit() != GLEW_OK) { } - GLuint shaderProgram = compileShaders("shaders/vert.glsl", "shaders/frag.glsl"); + GLuint shaderProgramShadowmap = compileShaders("shaders/vert_shadowmap.glsl", "shaders/frag_shadowmap.glsl"); + GLuint shaderProgramIrradiance = compileShaders("shaders/vert_irradiance.glsl", "shaders/frag_irradiance.glsl"); model m = loadModel("models/Isotrop-upperjaw.ply"); - + arccam arcCam; freecam freeCam; - - glm::vec3 lightPos(1.2f, 5.0f, 2.0f); // MVP glm::mat4 model = glm::scale(glm::mat4(1.0f), glm::vec3(0.01f, 0.01f, 0.01f)); - glm::mat4 view; + glm::mat4 view, lightView; glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f); + glm::mat4 lightProj = glm::perspective(glm::radians(90.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f); // Framebuffer - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - 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); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - //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); - // Screen VAO - - GLuint screenVBO; - glGenBuffers(1, &screenVBO); - - GLuint screenVAO; - glGenVertexArrays(1, &screenVAO); - - glBindVertexArray(screenVAO); - - 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, - }; - - glBindBuffer(GL_ARRAY_BUFFER, screenVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, - screenVerts, GL_STATIC_DRAW); - - 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); + framebuffer fb_shadowmap("shaders/fbo_vert.glsl", "shaders/fbo_frag.glsl", width, height); + framebuffer fb_irradiance("shaders/fbo_vert.glsl", "shaders/fbo_frag.glsl", width, height); // Config - struct { + const struct { bool wireframe = false; bool freecam = false; - bool sssss = false; - int N = 2; - } options; + int renderState = 2; + float color[3] = { 0.7f, 0.4f, 0.4f }; + glm::vec3 lightPos = glm::vec3(0.0f, 0.0f, 0.03f); + float transmittanceScale = 0.025f; + float powBase = 2; + float powFactor = 1.5; + } DefaultOptions; + + auto options = DefaultOptions; sf::Clock deltaClock; @@ -395,7 +449,7 @@ int main() { } } - // Update + // Update Camera if (sf::Mouse::isButtonPressed(sf::Mouse::Right)) { window.setMouseCursorVisible(false); @@ -418,10 +472,14 @@ int main() { prevMouse = sf::Mouse::isButtonPressed(sf::Mouse::Right); - // Render to fbo + // Render Shadowmap to fbo - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE); + glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE); + glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE); + + glBindFramebuffer(GL_FRAMEBUFFER, fb_shadowmap.fbo); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); @@ -430,39 +488,102 @@ int main() { else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glUseProgram(shaderProgram); + glUseProgram(shaderProgramShadowmap); if (options.freecam) view = freeCam.getViewMatrix(); else view = arcCam.getViewMatrix(); + lightView = glm::lookAt(options.lightPos, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); + + glUniformMatrix4fv( + glGetUniformLocation(shaderProgramShadowmap, "model"), + 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv( + glGetUniformLocation(shaderProgramShadowmap, "lightView"), + 1, GL_FALSE, glm::value_ptr(lightView)); + glUniformMatrix4fv( + glGetUniformLocation(shaderProgramShadowmap, "projection"), + 1, GL_FALSE, glm::value_ptr(lightProj)); + + glUniform3fv( + glGetUniformLocation(shaderProgramShadowmap, "lightPos"), + 1, glm::value_ptr(options.lightPos)); + + m.draw(); + + // Render irradiance map to fbo + + glBindFramebuffer(GL_FRAMEBUFFER, fb_irradiance.fbo); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + + if (options.wireframe) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + else + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glUseProgram(shaderProgramIrradiance); + glUniformMatrix4fv( - glGetUniformLocation(shaderProgram, "model"), + glGetUniformLocation(shaderProgramIrradiance, "model"), 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv( - glGetUniformLocation(shaderProgram, "view"), + glGetUniformLocation(shaderProgramIrradiance, "view"), 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv( - glGetUniformLocation(shaderProgram, "projection"), + glGetUniformLocation(shaderProgramIrradiance, "lightView"), + 1, GL_FALSE, glm::value_ptr(lightView)); + glUniformMatrix4fv( + glGetUniformLocation(shaderProgramIrradiance, "lightViewInv"), + 1, GL_FALSE, glm::value_ptr(glm::inverse(lightView))); + glUniformMatrix4fv( + glGetUniformLocation(shaderProgramIrradiance, "projection"), 1, GL_FALSE, glm::value_ptr(proj)); + glUniformMatrix4fv( + glGetUniformLocation(shaderProgramIrradiance, "lightProjection"), + 1, GL_FALSE, glm::value_ptr(lightProj)); + glUniform1i(glGetUniformLocation(shaderProgramIrradiance, "screenWidth"), window.getSize().x); + glUniform1i(glGetUniformLocation(shaderProgramIrradiance, "screenHeight"), window.getSize().y); + glUniform1fv(glGetUniformLocation(shaderProgramIrradiance, "samplePositions"), 13, samplePositions); + glUniform3fv(glGetUniformLocation(shaderProgramIrradiance, "sampleWeights"), 13, sampleWeights); + + glUniform1f( + glGetUniformLocation(shaderProgramIrradiance, "transmittanceScale"), + options.transmittanceScale); + glUniform1i( + glGetUniformLocation(shaderProgramIrradiance, "renderState"), + options.renderState); + glUniform1f( + glGetUniformLocation(shaderProgramIrradiance, "powBase"), + options.powBase); + glUniform1f( + glGetUniformLocation(shaderProgramIrradiance, "powFactor"), + options.powFactor); + glUniform3fv( + glGetUniformLocation(shaderProgramIrradiance, "objectColor"), + 1, options.color); glUniform3f( - glGetUniformLocation(shaderProgram, "objectColor"), - 1.0f, 0.5f, 0.31f); - glUniform3f( - glGetUniformLocation(shaderProgram, "lightColor"), + glGetUniformLocation(shaderProgramIrradiance, "lightColor"), 1.0f, 1.0f, 1.0f); glUniform3fv( - glGetUniformLocation(shaderProgram, "lightPos"), - 1, glm::value_ptr(lightPos)); + glGetUniformLocation(shaderProgramIrradiance, "lightPos"), + 1, glm::value_ptr(options.lightPos)); glUniform3fv( - glGetUniformLocation(shaderProgram, "viewPos"), + glGetUniformLocation(shaderProgramIrradiance, "viewPos"), 1, glm::value_ptr(options.freecam ? freeCam.pos : arcCam.getPos())); + + + glUniform1i(glGetUniformLocation(shaderProgramIrradiance, "shadowmapTexture"), 0); + glActiveTexture(GL_TEXTURE0 + 0); + glBindTexture(GL_TEXTURE_2D, fb_shadowmap.renderTexture); m.draw(); - // Render fbo to screen + // Render fbos to screen and calculate light spread/translucency in shader glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); @@ -470,31 +591,41 @@ int main() { glDisable(GL_DEPTH_TEST); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); - glUseProgram(screenShaderProgram); - - glUniform1i(glGetUniformLocation(screenShaderProgram, "applySSSSS"), options.sssss); - glUniform1i(glGetUniformLocation(screenShaderProgram, "N"), options.N); - - glBindVertexArray(screenVAO); - glBindTexture(GL_TEXTURE_2D, renderTexture); + glUseProgram(fb_irradiance.screenShaderProgram); + + glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "screenWidth"), window.getSize().x); + glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "screenHeight"), window.getSize().y); + glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "renderState"), options.renderState); + glUniform2fv(glGetUniformLocation(fb_irradiance.screenShaderProgram, "samplePositions"), 13, samplePositions); + glUniform3fv(glGetUniformLocation(fb_irradiance.screenShaderProgram, "sampleWeights"), 13, sampleWeights); + + glBindVertexArray(fb_irradiance.screenVAO); + glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "shadowmapTexture"), 0); + glUniform1i(glGetUniformLocation(fb_irradiance.screenShaderProgram, "irradianceTexture"), 1); + glActiveTexture(GL_TEXTURE0 + 0); + glBindTexture(GL_TEXTURE_2D, fb_shadowmap.renderTexture); + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, fb_irradiance.renderTexture); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); + // menu + ImGui::SFML::Update(window, deltaClock.restart()); ImGui::Begin("Options"); ImGui::Checkbox("Wireframe", &options.wireframe); ImGui::Checkbox("Free Cam", &options.freecam); - ImGui::Checkbox("SSSSS", &options.sssss); - if (options.sssss) { - ImGui::DragInt("N", &options.N, 0.05f, 1, 16); - } + ImGui::DragFloat3("Color", options.color, 0.01, 0, 1); + ImGui::DragFloat("Transmittance Scale", &options.transmittanceScale, 0.0001f, 0, 0.3); + ImGui::DragFloat3("Light Pos", glm::value_ptr(options.lightPos), 0.01, -5, 5); 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); + options = DefaultOptions; } } else { ImGui::LabelText("Rotation", "%f %f", arcCam.rot.x, arcCam.rot.y); @@ -502,6 +633,7 @@ int main() { if (ImGui::Button("Reset")) { arcCam.rot = glm::vec2(0); arcCam.radius = 1; + options = DefaultOptions; } } ImGui::End(); @@ -511,7 +643,5 @@ int main() { window.display(); } - glDeleteFramebuffers(1, &fbo); - return 0; -} \ No newline at end of file +}