diff --git a/projects/bonus3/CMakeLists.txt b/projects/bonus3/CMakeLists.txt index b8d4061..4d3a25d 100644 --- a/projects/bonus3/CMakeLists.txt +++ b/projects/bonus3/CMakeLists.txt @@ -1,8 +1,9 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.20) project(bonus3) set(THIRD_PARTY_LIBRARY_PATH ${CMAKE_SOURCE_DIR}/external) +set(SHADER_TARGET_PATH ${CMAKE_BINARY_DIR}/media/shader/bonus3) include_directories(${THIRD_PARTY_LIBRARY_PATH}/glm) @@ -48,6 +49,14 @@ add_executable(bonus3 ${PROJECT_SRC} ${PROJECT_HDR} ${BASE_SRC} ${BASE_HDR} ${PR source_group("Shader Files" FILES ${PROJECT_SHADERS}) +add_custom_command( + TARGET bonus3 + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E + make_directory ${SHADER_TARGET_PATH} + COMMENT "make directory ${SHADER_TARGET_PATH}" +) + set(first True) foreach(shader ${PROJECT_SHADERS}) get_filename_component(name ${shader} NAME) diff --git a/projects/bonus3/blend_bloom_map.frag b/projects/bonus3/blend_bloom_map.frag index 737df47..ef8b1de 100644 --- a/projects/bonus3/blend_bloom_map.frag +++ b/projects/bonus3/blend_bloom_map.frag @@ -6,8 +6,7 @@ in vec2 screenTexCoord; uniform sampler2D scene; uniform sampler2D bloomBlur; -void main() -{ +void main() { vec3 sceneColor = texture(scene, screenTexCoord).rgb; vec3 bloomColor = texture(bloomBlur, screenTexCoord).rgb; FragColor = vec4(sceneColor + bloomColor, 1.0); diff --git a/projects/bonus3/extract_bright_color.frag b/projects/bonus3/extract_bright_color.frag index a3e1a85..1b1e0c1 100644 --- a/projects/bonus3/extract_bright_color.frag +++ b/projects/bonus3/extract_bright_color.frag @@ -6,6 +6,6 @@ uniform sampler2D sceneMap; in vec2 screenTexCoord; void main() { - // TODO + // TODO: extract the bright color with color components greater than 1.0 brightColorMap = vec4(0.0f, 0.0f, 0.0f, 1.0f); } diff --git a/projects/bonus3/gaussian_blur.frag b/projects/bonus3/gaussian_blur.frag index 2e6f28d..abe314f 100644 --- a/projects/bonus3/gaussian_blur.frag +++ b/projects/bonus3/gaussian_blur.frag @@ -6,10 +6,10 @@ in vec2 screenTexCoord; uniform sampler2D image; uniform bool horizontal; -uniform float weight[5] = float[] (0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162); +uniform float weight[5] = float[] ( + 0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162); -void main() -{ - // TODO - FragColor = vec4(texture(image, screenTexCoord).rgb, 1.0); +void main() { + // TODO: perform gaussian blur + FragColor = vec4(texture(image, screenTexCoord).rgb, 1.0); } \ No newline at end of file diff --git a/projects/bonus3/geometry.frag b/projects/bonus3/geometry.frag index 725cfa0..d16da3e 100644 --- a/projects/bonus3/geometry.frag +++ b/projects/bonus3/geometry.frag @@ -9,6 +9,6 @@ in vec2 texCoord; void main() { gPosition = position; - gNormal = normal; + gNormal = gl_FrontFacing ? normal : -normal; gAlbedo = vec3(0.95f); } \ No newline at end of file diff --git a/projects/bonus3/main.cpp b/projects/bonus3/main.cpp index f3aa87f..b307495 100644 --- a/projects/bonus3/main.cpp +++ b/projects/bonus3/main.cpp @@ -1,7 +1,7 @@ #include #include -#include "postprocessing.h" +#include "post_processing.h" Options getOptions(int argc, char* argv[]) { Options options; diff --git a/projects/bonus3/postprocessing.cpp b/projects/bonus3/post_processing.cpp similarity index 92% rename from projects/bonus3/postprocessing.cpp rename to projects/bonus3/post_processing.cpp index 0c7e98f..5729b9c 100644 --- a/projects/bonus3/postprocessing.cpp +++ b/projects/bonus3/post_processing.cpp @@ -1,11 +1,14 @@ +#include + #include #include #include -#include "postprocessing.h" +#include "post_processing.h" -const std::string ballRelPath = "obj/sphere.obj"; const std::string bunnyRelPath = "obj/bunny.obj"; +const std::string cubeRelPath = "obj/cube.obj"; +const std::string sphereRelPath = "obj/sphere.obj"; const std::string geometryVsRelPath = "shader/bonus3/geometry.vert"; const std::string geometryFsRelPath = "shader/bonus3/geometry.frag"; @@ -42,9 +45,11 @@ PostProcessing::PostProcessing(const Options& options) : Application(options) { _pointLight->kl = 0.0f; _pointLight->kq = 0.05f; - _ball.reset(new Model(getAssetFullPath(ballRelPath))); - - createGround(); + _sphere.reset(new Model(getAssetFullPath(sphereRelPath))); + + _cube.reset(new Model(getAssetFullPath(cubeRelPath))); + _cube->transform.position = glm::vec3(22.5659f, 25.1945f, 0.0f); + _cube->transform.scale = glm::vec3(50.0f); _screenQuad.reset(new FullscreenQuad); @@ -71,6 +76,10 @@ PostProcessing::~PostProcessing() { } void PostProcessing::handleInput() { + if (_input.keyboard.keyStates[GLFW_KEY_ESCAPE] != GLFW_RELEASE) { + glfwSetWindowShouldClose(_window, true); + return; + } } void PostProcessing::renderFrame() { @@ -146,10 +155,13 @@ void PostProcessing::initSSAOPassResources() { _ssaoBlurFBO->drawBuffer(GL_COLOR_ATTACHMENT0); _ssaoBlurFBO->unbind(); + std::default_random_engine e; + std::uniform_real_distribution u(0.0f, 1.0f); + for (unsigned int i = 0; i < 64; ++i) { - glm::vec3 sample(randomFloat() * 2.0f - 1.0f, randomFloat() * 2.0f - 1.0f, randomFloat()); + glm::vec3 sample(u(e) * 2.0f - 1.0f, u(e) * 2.0f - 1.0f, u(e)); sample = glm::normalize(sample); - sample *= randomFloat(); + sample *= u(e); float scale = float(i) / 64.0f; // scale samples s.t. they're more aligned to center of kernel @@ -161,7 +173,7 @@ void PostProcessing::initSSAOPassResources() { std::vector ssaoNoises; for (unsigned int i = 0; i < 16; i++) { // rotate around z-axis (in tangent space) - glm::vec3 noise(randomFloat() * 2.0f - 1.0f, randomFloat() * 2.0f - 1.0f, 0.0f); + glm::vec3 noise(u(e) * 2.0f - 1.0f, u(e) * 2.0f - 1.0f, 0.0f); ssaoNoises.push_back(noise); } @@ -173,6 +185,7 @@ void PostProcessing::initSSAOPassResources() { _ssaoNoise->setParamterInt(GL_TEXTURE_WRAP_T, GL_REPEAT); _ssaoNoise->unbind(); + // TODO: modify ssao.frag _ssaoShader.reset(new GLSLProgram); _ssaoShader->attachVertexShaderFromFile(getAssetFullPath(quadVsRelPath)); _ssaoShader->attachFragmentShaderFromFile(getAssetFullPath(ssaoFsRelPath)); @@ -183,6 +196,7 @@ void PostProcessing::initSSAOPassResources() { _ssaoBlurShader->attachFragmentShaderFromFile(getAssetFullPath(ssaoBlurFsRelPath)); _ssaoBlurShader->link(); + // TODO: modify ssao_lighting.frag _ssaoLightingShader.reset(new GLSLProgram); _ssaoLightingShader->attachVertexShaderFromFile(getAssetFullPath(quadVsRelPath)); _ssaoLightingShader->attachFragmentShaderFromFile(getAssetFullPath(ssaoLightingFsRelPath)); @@ -228,11 +242,13 @@ void PostProcessing::initBloomPassResources() { _lightShader->attachFragmentShaderFromFile(getAssetFullPath(lightFsRelPath)); _lightShader->link(); + // TODO: modify extract_bright_color.frag _brightColorShader.reset(new GLSLProgram); _brightColorShader->attachVertexShaderFromFile(getAssetFullPath(quadVsRelPath)); _brightColorShader->attachFragmentShaderFromFile(getAssetFullPath(brightColorFsRelPath)); _brightColorShader->link(); + // TODO: modify gaussian_blur.frag _blurShader.reset(new GLSLProgram); _blurShader->attachVertexShaderFromFile(getAssetFullPath(quadVsRelPath)); _blurShader->attachFragmentShaderFromFile(getAssetFullPath(gaussianBlurFsRelPath)); @@ -251,25 +267,6 @@ void PostProcessing::initShaders() { _drawScreenShader->link(); } -void PostProcessing::createGround() { - constexpr float groundWidth = 50.0f; - std::vector vertices(4); - for (size_t i = 0; i < vertices.size(); ++i) { - vertices[i].position.x = (i % 2) ? groundWidth : -groundWidth; - vertices[i].position.y = 0.0f; - vertices[i].position.z = (i > 1) ? groundWidth : -groundWidth; - vertices[i].normal = glm::vec3(0.0f, 1.0f, 0.0f); - vertices[i].texCoord.x = (i % 2) ? 1.0f : 0.0f; - vertices[i].texCoord.y = (i > 1) ? 1.0f : 0.0f; - }; - - std::vector indices = { - 0, 1, 2, 1, 2, 3 - }; - - _ground.reset(new Model(vertices, indices)); -} - void PostProcessing::renderScene() { glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearColor.a); // deferred rendering: geometry pass @@ -284,12 +281,9 @@ void PostProcessing::renderScene() { _gBufferShader->setUniformMat4("model", _bunny->transform.getLocalMatrix()); _bunny->draw(); - _gBufferShader->setUniformMat4("model", glm::mat4(1.0f)); - _ground->draw(); + _gBufferShader->setUniformMat4("model", _cube->transform.getLocalMatrix()); + _cube->draw(); - _gBufferShader->setUniformMat4("model", glm::translate(glm::mat4(1.0f), glm::vec3(-2.5f, 0.0f, 0.0f)) * - glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(0.0f, 0.0f, 1.0f))); - _ground->draw(); _gBufferFBO->unbind(); // deferred rendering: lighting passes @@ -338,6 +332,7 @@ void PostProcessing::renderScene() { _ssaoResult[0]->unbind(); } + // + bloom pass _bloomFBO->bind(); glDisable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT); @@ -371,7 +366,7 @@ void PostProcessing::renderScene() { _lightShader->setUniformVec3("lightColor", _pointLight->color); _lightShader->setUniformFloat("lightIntensity", _pointLight->intensity); - _ball->draw(); + _sphere->draw(); _bloomFBO->unbind(); @@ -400,7 +395,7 @@ void PostProcessing::renderUI() { if (!ImGui::Begin("Control Panel", nullptr, flags)) { ImGui::End(); } else { - ImGui::Text("render method"); + ImGui::Text("post processing technics"); ImGui::Separator(); ImGui::Checkbox("bloom", &_enableBloom); ImGui::Checkbox("ssao", &_enableSSAO); diff --git a/projects/bonus3/postprocessing.h b/projects/bonus3/post_processing.h similarity index 95% rename from projects/bonus3/postprocessing.h rename to projects/bonus3/post_processing.h index 632d950..b33b068 100644 --- a/projects/bonus3/postprocessing.h +++ b/projects/bonus3/post_processing.h @@ -8,7 +8,6 @@ #include "../base/light.h" #include "../base/framebuffer.h" #include "../base/fullscreen_quad.h" -#include "random.h" class PostProcessing : public Application { public: @@ -18,7 +17,7 @@ class PostProcessing : public Application { private: std::unique_ptr _bunny; - std::unique_ptr _ground; + std::unique_ptr _cube; std::unique_ptr _drawScreenShader; std::unique_ptr _screenQuad; @@ -26,7 +25,7 @@ class PostProcessing : public Application { std::unique_ptr _camera; std::unique_ptr _pointLight; - std::unique_ptr _ball; + std::unique_ptr _sphere; // deferred rendering: geometry pass resources std::unique_ptr _gBufferFBO; @@ -79,8 +78,6 @@ class PostProcessing : public Application { void initShaders(); - void createGround(); - void renderScene(); void renderUI(); diff --git a/projects/bonus3/random.h b/projects/bonus3/random.h deleted file mode 100644 index 965e1ee..0000000 --- a/projects/bonus3/random.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -inline float randomFloat() { - // Returns a random real in [0,1). - return float(rand() / (RAND_MAX + 1.0)); -} - -inline float randomFloat(float minVal, float maxVal) { - // Returns a random real in [min,max). - return minVal + (maxVal - minVal) * randomFloat(); -} - -inline glm::vec3 randomVec3() { - return glm::vec3(randomFloat(), randomFloat(), randomFloat()); -} - -inline glm::vec3 randomVec3(float minVal, float maxVal) { - return glm::vec3( - randomFloat(minVal, maxVal), - randomFloat(minVal, maxVal), - randomFloat(minVal, maxVal)); -} \ No newline at end of file diff --git a/projects/bonus3/ssao.frag b/projects/bonus3/ssao.frag index ed481ad..084cfae 100644 --- a/projects/bonus3/ssao.frag +++ b/projects/bonus3/ssao.frag @@ -15,6 +15,6 @@ uniform mat4 projection; in vec2 screenTexCoord; void main() { - // TODO + // TODO: perform SSAO ssaoResult = 1.0f; } \ No newline at end of file diff --git a/projects/bonus3/ssaoDrawLight.vert b/projects/bonus3/ssaoDrawLight.vert deleted file mode 100644 index 6fdf2ac..0000000 --- a/projects/bonus3/ssaoDrawLight.vert +++ /dev/null @@ -1,10 +0,0 @@ -#version 330 core -layout(location = 0) in vec3 aPosition; - -uniform mat4 projection; -uniform mat4 view; -uniform mat4 model; - -void main() { - gl_Position = projection * view * model * vec4(aPosition, 1.0f); -} \ No newline at end of file diff --git a/projects/bonus3/ssao_blur.frag b/projects/bonus3/ssao_blur.frag index 8df6621..95e3bc9 100644 --- a/projects/bonus3/ssao_blur.frag +++ b/projects/bonus3/ssao_blur.frag @@ -8,13 +8,12 @@ in vec2 screenTexCoord; void main() { vec2 texelSize = 1.0 / vec2(textureSize(ssaoResult, 0)); float result = 0.0; - for (int x = -2; x <= 2; ++x) - { - for (int y = -2; y <= 2; ++y) - { + for (int x = -2; x <= 2; ++x) { + for (int y = -2; y <= 2; ++y) { vec2 offset = vec2(float(x), float(y)) * texelSize; result += texture(ssaoResult, screenTexCoord + offset).r; } } + blurResult = result / (5.0 * 5.0); } \ No newline at end of file diff --git a/projects/bonus3/ssao_draw_light.frag b/projects/bonus3/ssao_draw_light.frag deleted file mode 100644 index 16c1dc9..0000000 --- a/projects/bonus3/ssao_draw_light.frag +++ /dev/null @@ -1,9 +0,0 @@ -#version 330 core -layout(location = 0) out vec4 fragColor; - -uniform vec3 lightColor; -uniform float lightIntensity; - -void main() { - fragColor = vec4(lightColor * lightIntensity, 1.0); -} \ No newline at end of file diff --git a/projects/bonus3/ssao_lighting.frag b/projects/bonus3/ssao_lighting.frag index 4414706..f240149 100644 --- a/projects/bonus3/ssao_lighting.frag +++ b/projects/bonus3/ssao_lighting.frag @@ -25,7 +25,6 @@ void main() { vec3 albedo = texture(gAlbedo, screenTexCoord).rgb; float occlusion = texture(ssaoResult, screenTexCoord).x; - //TODO - + //TODO: perform lambert shading fragColor = vec4(normal, 1.0f); } \ No newline at end of file diff --git a/projects/bonus5/aabb.h b/projects/bonus5/aabb.h index 029f441..f01198c 100644 --- a/projects/bonus5/aabb.h +++ b/projects/bonus5/aabb.h @@ -35,6 +35,24 @@ struct AABB { ); } + bool intersect(const Ray& ray, const glm::vec3& invDir, const int negDir[3]) const { + const auto& box = *this; + const auto& o = ray.o; + const auto& dir = ray.dir; + + float tMinX = (box[negDir[0]].x - o.x) * invDir.x; + float tMaxX = (box[1 - negDir[0]].x - o.x) * invDir.x; + float tMinY = (box[negDir[1]].y - o.y) * invDir.y; + float tMaxY = (box[1 - negDir[1]].y - o.y) * invDir.y; + float tMinZ = (box[negDir[2]].z - o.z) * invDir.z; + float tMaxZ = (box[1 - negDir[2]].z - o.z) * invDir.z; + + float tMin = std::max(tMinX, std::max(tMinY, tMinZ)); + float tMax = std::min(tMaxX, std::min(tMaxY, tMaxZ)); + + return tMin < tMax && tMin < ray.tMax && tMax > 0; + } + float surfaceArea() const { glm::vec3 diagonal = pMax - pMin; return 2 * (diagonal.x * diagonal.y + diagonal.x * diagonal.z + diagonal.y * diagonal.z); diff --git a/projects/bonus5/bvh.cpp b/projects/bonus5/bvh.cpp index 9fd2b9b..caa89d3 100644 --- a/projects/bonus5/bvh.cpp +++ b/projects/bonus5/bvh.cpp @@ -34,13 +34,80 @@ BVHBuildNode* BVH::recursiveBuild( node->initLeafNode(box, startId, nPrimitives); return node; } else { - // TODO : recursive build BVH + // TODO: recursive build BVH return node; } } int BVH::toLinearTree(BVHBuildNode* root, int* offset) { - return 0; + if (root == nullptr) { + return -1; + } + + int nodeIdx = *offset; + *offset += 1; + int leftIdx = toLinearTree(root->leftChild, offset); + int rightIdx = toLinearTree(root->rightChild, offset); + nodes[nodeIdx].box = root->bound; + if (leftIdx == -1 && rightIdx == -1) { + nodes[nodeIdx].type = BVHNode::Type::Leaf; + nodes[nodeIdx].startIndex = root->startIdx; + nodes[nodeIdx].nPrimitives = root->nPrimitives; + } else { + nodes[nodeIdx].type = BVHNode::Type::NonLeaf; + nodes[nodeIdx].leftChild = leftIdx; + nodes[nodeIdx].rightChild = rightIdx; + } + + return nodeIdx; +} + +bool BVH::intersect(const Ray& ray, Interaction& isect) { + bool hit = false; + glm::vec3 invDir = glm::vec3(1.0f / ray.dir.x, 1.0f / ray.dir.y, 1.0f / ray.dir.z); + int isDirNeg[3]; + isDirNeg[0] = ray.dir.x < 0 ? 1 : 0; + isDirNeg[1] = ray.dir.y < 0 ? 1 : 0; + isDirNeg[2] = ray.dir.z < 0 ? 1 : 0; + int currentNodeIndex = 0; + int toVisitOffset = 0; + int nodesToVisit[128]; + BVHNode node; + while (true) { + node = nodes[currentNodeIndex]; + if (node.box.intersect(ray, invDir, isDirNeg)) { + if (node.type == BVHNode::Type::Leaf) { + int firstIndex = node.startIndex; + int nPrimitives = node.nPrimitives; + + Primitive primitive; + for (int i = 0; i < nPrimitives; ++i) { + primitive = orderedPrimitives[firstIndex + i]; + if (intersectPrimitive(ray, primitive, isect)) { + hit = true; + } + } + + if (toVisitOffset == 0) { + break; + } + + currentNodeIndex = nodesToVisit[--toVisitOffset]; + } else { + int leftChild = node.leftChild; + int rightChild = node.rightChild; + nodesToVisit[toVisitOffset++] = rightChild; + currentNodeIndex = leftChild; + } + } else { + if (toVisitOffset == 0) { + break; + } + currentNodeIndex = nodesToVisit[--toVisitOffset]; + } + } + + return hit; } AABB BVH::getAABB(const Primitive& prim) { @@ -52,6 +119,15 @@ AABB BVH::getAABB(const Primitive& prim) { } } +bool BVH::intersectPrimitive(const Ray& ray, const Primitive& primitive, Interaction& isect) { + if (intersectSphere(ray, *primitive.sphere, isect)) { + isect.primitive = primitive; + return true; + } + + return false; +} + AABB BVH::getTriangleAABB(const Triangle& triangle) { const auto& p1 = triangle.vertices[triangle.v[0]].position; const auto& p2 = triangle.vertices[triangle.v[1]].position; @@ -62,4 +138,26 @@ AABB BVH::getTriangleAABB(const Triangle& triangle) { AABB BVH::getSphereAABB(const Sphere& sphere) { return AABB(sphere.position - glm::vec3(sphere.radius), sphere.position + glm::vec3(sphere.radius)); +} + +bool BVH::intersectSphere(const Ray& ray, const Sphere& sphere, Interaction& isect) { + float a = glm::dot(ray.dir, ray.dir); + float b = glm::dot(ray.dir, ray.o - sphere.position); + float c = glm::dot(ray.o - sphere.position, ray.o - sphere.position) - sphere.radius * sphere.radius; + float discriminant = b * b - a * c; + + if (discriminant >= 0) { + float t1 = (-b - std::sqrt(discriminant)) / a; + float t2 = (-b + std::sqrt(discriminant)) / a; + + if ((1e-3f <= t1 && t1 < ray.tMax) || (1e-3f <= t2 && t2 < ray.tMax)) { + float t = (1e-3f <= t1 && t1 < ray.tMax) ? t1 : t2; + ray.tMax = t; + isect.hitPoint.position = ray.o + t * ray.dir; + isect.hitPoint.normal = glm::normalize(isect.hitPoint.position - sphere.position); + return true; + } + } + + return false; } \ No newline at end of file diff --git a/projects/bonus5/bvh.h b/projects/bonus5/bvh.h index 2294dd4..7451fd4 100644 --- a/projects/bonus5/bvh.h +++ b/projects/bonus5/bvh.h @@ -125,4 +125,8 @@ class BVH { static AABB getTriangleAABB(const Triangle& triangle); static AABB getSphereAABB(const Sphere& sphere); + + static bool intersectPrimitive(const Ray& ray, const Primitive& primitive, Interaction& isect); + + static bool intersectSphere(const Ray& ray, const Sphere& sphere, Interaction& isect); }; \ No newline at end of file diff --git a/projects/bonus5/main.cpp b/projects/bonus5/main.cpp index 479c698..e5c3eac 100644 --- a/projects/bonus5/main.cpp +++ b/projects/bonus5/main.cpp @@ -7,8 +7,8 @@ Options getOptions(int argc, char* argv[]) { Options options; options.windowTitle = "RayTracing"; // TODO: change appropriate resolution for debugging - options.windowWidth = 1280; - options.windowHeight = 720; + options.windowWidth = 640; + options.windowHeight = 360; options.windowResizable = false; options.vSync = true; options.msaa = false; diff --git a/projects/bonus5/raytracing.cpp b/projects/bonus5/raytracing.cpp index b20bd1f..fa83173 100644 --- a/projects/bonus5/raytracing.cpp +++ b/projects/bonus5/raytracing.cpp @@ -2,6 +2,10 @@ #include #include +#include +#include +#include + #include #include @@ -19,7 +23,7 @@ const std::string quadFsRelPath = "shader/bonus5/quad.frag"; const std::string raytracingVsRelPath = "shader/bonus5/quad.vert"; const std::string raytracingFsRelPath = "shader/bonus5/raytracing.frag"; -const std::vector skyBoxTextureRelPaths = { +const std::vector skyboxTextureRelPaths = { "texture/skyboxrt/right.jpg", "texture/skyboxrt/left.jpg", "texture/skyboxrt/top.jpg", @@ -29,13 +33,13 @@ const std::vector skyBoxTextureRelPaths = { }; RayTracing::RayTracing(const Options& options): Application(options) { - lucy.reset(new Model(getAssetFullPath(lucyRelPath))); + _lucy.reset(new Model(getAssetFullPath(lucyRelPath))); std::vector skyBoxTexturePaths; - for (size_t i = 0; i < skyBoxTextureRelPaths.size(); ++i) { - skyBoxTexturePaths.push_back(getAssetFullPath(skyBoxTextureRelPaths[i])); + for (size_t i = 0; i < skyboxTextureRelPaths.size(); ++i) { + skyBoxTexturePaths.push_back(getAssetFullPath(skyboxTextureRelPaths[i])); } - skyBox.reset(new ImageTextureCubemap(skyBoxTexturePaths)); + _skybox.reset(new ImageTextureCubemap(skyBoxTexturePaths)); _camera.reset(new PerspectiveCamera( glm::radians(60.0f), static_cast(_windowWidth) / _windowHeight, 0.1f, 1000.0f)); @@ -60,7 +64,7 @@ RayTracing::RayTracing(const Options& options): Application(options) { _sampleFramebuffers[i].reset(new Framebuffer); _sampleFramebuffers[i]->bind(); _sampleFramebuffers[i]->drawBuffers({ GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }); - + _outFrames[i].reset(new Texture2D(GL_RGBA32F, _windowWidth, _windowHeight, GL_RGBA, GL_FLOAT)); _outFrames[i]->bind(); _outFrames[i]->setParamterInt(GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -83,13 +87,33 @@ RayTracing::RayTracing(const Options& options): Application(options) { _sampleFramebuffers[i]->unbind(); } - createScene1(); + createRenderScene(_renderSceneIndex); + + // init imGUI + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGui::StyleColorsDark(); + ImGui_ImplGlfw_InitForOpenGL(_window, true); + ImGui_ImplOpenGL3_Init(); +} + +RayTracing::~RayTracing() { + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); } void RayTracing::handleInput() { if (_input.keyboard.keyStates[GLFW_KEY_ESCAPE] != GLFW_RELEASE) { glfwSetWindowShouldClose(_window, true); - return ; + return; + } + + static int lastSceneIndex = _renderSceneIndex; + if (lastSceneIndex != _renderSceneIndex) { + createRenderScene(_renderSceneIndex); + lastSceneIndex = _renderSceneIndex; + _sampleCount = 0; } } @@ -97,74 +121,109 @@ void RayTracing::renderFrame() { showFpsInWindowTitle(); glDisable(GL_DEPTH_TEST); - + glm::mat4 cameraToWorld = glm::inverse(_camera->getViewMatrix()); glm::mat4 cameraToScreen = _camera->getProjectionMatrix(); glm::mat4 screenToRaster = glm::scale(glm::mat4(1.0f), glm::vec3(float(_windowWidth) / 2.0f, - float(_windowHeight) / 2.0f, 1.0f)) * - glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 1.0f, 0.0f)); - + float(_windowHeight) / 2.0f, 1.0f)) * + glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 1.0f, 0.0f)); + glm::mat4 rasterToScreen = glm::inverse(screenToRaster); glm::mat4 rasterToCamera = glm::inverse(cameraToScreen) * rasterToScreen; - - _sampleFramebuffers[currentWriteBufferID]->bind(); - raytracingProgram->use(); - raytracingProgram->setUniformUint("totalSamples", sampleCount); - raytracingProgram->setUniformMat4("camera.cameraToWorld", cameraToWorld); - raytracingProgram->setUniformMat4("camera.rasterToCamera", rasterToCamera); - - raytracingProgram->setUniformInt("sky", 0); - skyBox->bind(0); + + _sampleFramebuffers[_currentWriteBufferID]->bind(); + _raytracingShader->use(); + _raytracingShader->setUniformUint("totalSamples", _sampleCount); + _raytracingShader->setUniformMat4("camera.cameraToWorld", cameraToWorld); + _raytracingShader->setUniformMat4("camera.rasterToCamera", rasterToCamera); + + _raytracingShader->setUniformInt("sky", 0); + _skybox->bind(0); _sphereBuffer->bind(1); - raytracingProgram->setUniformInt("sphereBuffer", 1); + _raytracingShader->setUniformInt("sphereBuffer", 1); - raytracingProgram->setUniformInt("materialBuffer", 2); + _raytracingShader->setUniformInt("materialBuffer", 2); _materialBuffer->bind(2); - raytracingProgram->setUniformInt("primitiveBuffer", 3); + _raytracingShader->setUniformInt("primitiveBuffer", 3); _primitiveBuffer->bind(3); - raytracingProgram->setUniformInt("RTResult", 4); - _outFrames[currentReadBufferID]->bind(4); + _raytracingShader->setUniformInt("RTResult", 4); + _outFrames[_currentReadBufferID]->bind(4); - raytracingProgram->setUniformInt("oldRngState", 5); - _rngStates[currentReadBufferID]->bind(5); + _raytracingShader->setUniformInt("oldRngState", 5); + _rngStates[_currentReadBufferID]->bind(5); _indexBuffer->bind(6); - raytracingProgram->setUniformInt("triangleIndexBuffer", 6); + _raytracingShader->setUniformInt("triangleIndexBuffer", 6); _vertexBuffer->bind(7); - raytracingProgram->setUniformInt("vertexBuffer", 7); + _raytracingShader->setUniformInt("vertexBuffer", 7); _bvhBuffer->bind(8); - raytracingProgram->setUniformInt("bvh", 8); + _raytracingShader->setUniformInt("bvh", 8); _screenQuad->draw(); - _sampleFramebuffers[currentWriteBufferID]->unbind(); + _sampleFramebuffers[_currentWriteBufferID]->unbind(); // render the result to the screen - drawScreenProgram->use(); - drawScreenProgram->setUniformInt("frame", 0); + _drawScreenShader->use(); + _drawScreenShader->setUniformInt("frame", 0); - _outFrames[currentWriteBufferID]->bind(0); + _outFrames[_currentWriteBufferID]->bind(0); _screenQuad->draw(); // update - ++sampleCount; - std::swap(currentReadBufferID, currentWriteBufferID); + ++_sampleCount; + std::swap(_currentReadBufferID, _currentWriteBufferID); + + // render UI + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiCond_Once, ImVec2(0.0f, 0.0f)); + + const auto flags = + ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoSavedSettings; + + if (!ImGui::Begin("Control Panel", nullptr, flags)) { + ImGui::End(); + } else { + ImGui::Text("switch scenes"); + ImGui::Separator(); + static const char* scenes[] = { + "scene 1", "scene 2", "scene 3" + }; + + ImGui::Combo("##1", &_renderSceneIndex, scenes, IM_ARRAYSIZE(scenes)); + + ImGui::NewLine(); + + ImGui::Text("statistics"); + ImGui::Separator(); + ImGui::Text("samples: %u", _sampleCount); + + ImGui::End(); + } + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } void RayTracing::initShaders() { - raytracingProgram.reset(new GLSLProgram); - raytracingProgram->attachVertexShaderFromFile(getAssetFullPath(raytracingVsRelPath)); - raytracingProgram->attachFragmentShaderFromFile(getAssetFullPath(raytracingFsRelPath)); - raytracingProgram->link(); - - drawScreenProgram.reset(new GLSLProgram); - drawScreenProgram->attachVertexShaderFromFile(getAssetFullPath(quadVsRelPath)); - drawScreenProgram->attachFragmentShaderFromFile(getAssetFullPath(quadFsRelPath)); - drawScreenProgram->link(); + // TODO: modify raytracing.frag code to achieve raytracing + _raytracingShader.reset(new GLSLProgram); + _raytracingShader->attachVertexShaderFromFile(getAssetFullPath(raytracingVsRelPath)); + _raytracingShader->attachFragmentShaderFromFile(getAssetFullPath(raytracingFsRelPath)); + _raytracingShader->link(); + + _drawScreenShader.reset(new GLSLProgram); + _drawScreenShader->attachVertexShaderFromFile(getAssetFullPath(quadVsRelPath)); + _drawScreenShader->attachFragmentShaderFromFile(getAssetFullPath(quadFsRelPath)); + _drawScreenShader->link(); } int RayTracing::getBufferHeight(size_t nObjects, size_t objectSize, size_t texComponent) const { @@ -173,10 +232,10 @@ int RayTracing::getBufferHeight(size_t nObjects, size_t objectSize, size_t texCo } void RayTracing::createBalls() { - balls.push_back(Sphere(glm::vec3(0.0f, -1000.0f, 0.0f), 1000.0f)); - ballMaterials.push_back(Material(Material::Type::Lambertian, 1.0f, 0.0f, glm::vec3(0.5f, 0.5f, 0.5f))); - for (int a = -12; a < 12; a++) { - for (int b = -12; b < 12; b++) { + _balls.push_back(Sphere(glm::vec3(0.0f, -1000.0f, 0.0f), 1000.0f)); + _ballMaterials.push_back(Material(Material::Type::Lambertian, 1.0f, 0.0f, glm::vec3(0.5f, 0.5f, 0.5f))); + for (int a = -12; a < 12; ++a) { + for (int b = -12; b < 12; ++b) { auto chooseMat = randomFloat(); glm::vec3 center(a + 0.9f * randomFloat(), 0.2f, b + 0.9f * randomFloat()); @@ -202,21 +261,30 @@ void RayTracing::createBalls() { material.albedo = glm::vec3(1.0f, 1.0f, 1.0f); } - balls.push_back(Sphere(center, randomFloat(0.15f, 0.2f))); - ballMaterials.push_back(material); + _balls.push_back(Sphere(center, randomFloat(0.15f, 0.2f))); + _ballMaterials.push_back(material); } } } // init three big sphere - balls.push_back(Sphere(glm::vec3(4.0f, 1.0f, 5.0f), 1.0f)); - ballMaterials.push_back(Material(Material::Type::Dielectric, 1.5f, 0.0f, glm::vec3(1.0f, 1.0f, 1.0f))); + _balls.push_back(Sphere(glm::vec3(4.0f, 1.0f, 5.0f), 1.0f)); + _ballMaterials.push_back(Material(Material::Type::Dielectric, 1.5f, 0.0f, glm::vec3(1.0f, 1.0f, 1.0f))); - balls.push_back(Sphere(glm::vec3(-8.0f, 2.0f, 14.0f), 2.0f)); - ballMaterials.push_back(Material(Material::Type::Lambertian, 1.0f, 0.0f, glm::vec3(0.2f, 0.4f, 0.8f))); + _balls.push_back(Sphere(glm::vec3(-8.0f, 2.0f, 14.0f), 2.0f)); + _ballMaterials.push_back(Material(Material::Type::Lambertian, 1.0f, 0.0f, glm::vec3(0.2f, 0.4f, 0.8f))); - balls.push_back(Sphere(glm::vec3(3.0f, 3.0f, -8.0f), 2.0f)); - ballMaterials.push_back(Material(Material::Type::Metal, 1.0f, 0.0f, glm::vec3(0.7f, 0.6f, 0.5f))); + _balls.push_back(Sphere(glm::vec3(3.0f, 3.0f, -8.0f), 2.0f)); + _ballMaterials.push_back(Material(Material::Type::Metal, 1.0f, 0.0f, glm::vec3(0.7f, 0.6f, 0.5f))); +} + +void RayTracing::createRenderScene(int index) { + switch (index) { + case 0: createScene1(); break; + case 1: createScene2(); break; + case 2: createScene3(); break; + default: createScene3(); break; + } } void RayTracing::createPrimitiveBuffer(const std::vector& spheres, @@ -271,8 +339,7 @@ void RayTracing::createPrimitiveBuffer(const std::vector& spheres, _sphereBuffer->setParamterInt(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); _sphereBuffer->setParamterInt(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); _sphereBuffer->unbind(); - } - else { + } else { _sphereBuffer.reset(new Texture2D(GL_RGBA32F, BufferWidth, getBufferHeight(1, sizeof(Sphere), Sphere::getTexDataComponent()), GL_RGBA, GL_FLOAT, nullptr)); @@ -340,8 +407,7 @@ void RayTracing::createPrimitiveBuffer(const std::vector& spheres, _indexBuffer->setParamterInt(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); _indexBuffer->setParamterInt(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); _indexBuffer->unbind(); - } - else { + } else { _vertexBuffer.reset(new Texture2D( GL_RGBA32F, BufferWidth, getBufferHeight(1, sizeof(Vertex), Sphere::getTexDataComponent()), @@ -351,6 +417,7 @@ void RayTracing::createPrimitiveBuffer(const std::vector& spheres, getBufferHeight(1, sizeof(glm::ivec3), Triangle::getIndexTexDataComponent()), GL_RGB_INTEGER, GL_INT, nullptr)); } + if (!materials.empty()) { for (auto& material : materials) { material.type = static_cast(toFloatLayout(static_cast(material.type))); @@ -365,14 +432,14 @@ void RayTracing::createPrimitiveBuffer(const std::vector& spheres, _materialBuffer->setParamterInt(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); _materialBuffer->setParamterInt(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); _materialBuffer->unbind(); - } - else { + } else { _materialBuffer.reset(new Texture2D(GL_RGB32F, BufferWidth, getBufferHeight(1, sizeof(Material), Material::getTexDataComponent()), GL_RGB, GL_FLOAT, nullptr)); } + if (!primitives.empty()) { - if (!useBVH) { + if (!_useBVH) { std::vector orderedPrim(roundUp(primitives.size(), BufferWidth)); int primCnt = 0; for (const auto& prim : primitives) { @@ -391,11 +458,10 @@ void RayTracing::createPrimitiveBuffer(const std::vector& spheres, _primitiveBuffer->setParamterInt(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); _primitiveBuffer->setParamterInt(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); _primitiveBuffer->unbind(); - raytracingProgram->use(); - raytracingProgram->setUniformInt("nPrimitives", static_cast(primitives.size())); + _raytracingShader->use(); + _raytracingShader->setUniformInt("nPrimitives", static_cast(primitives.size())); - } - else { + } else { // build BVH BVH bvh(primitives); auto& linearBVH = bvh.nodes; @@ -437,7 +503,6 @@ void RayTracing::createPrimitiveBuffer(const std::vector& spheres, _primitiveBuffer->setParamterInt(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); _primitiveBuffer->unbind(); } - } std::cout << "Scene Statistics" << std::endl; @@ -451,7 +516,7 @@ void RayTracing::createScene1() { _camera->transform.position = glm::vec3(0.0f, 0.0f, 12.0f); _camera->transform.lookAt(glm::vec3(0.0f)); - useBVH = false; + _useBVH = false; createPrimitiveBuffer( { @@ -473,25 +538,28 @@ void RayTracing::createScene2() { _camera->transform.position = glm::vec3(15.0f, 3.0f, 4.0f); _camera->transform.lookAt(glm::vec3(0.0f)); - useBVH = true; + _useBVH = true; createPrimitiveBuffer( - balls, + _balls, {}, {}, - ballMaterials, + _ballMaterials, {}); } void RayTracing::createScene3() { + _camera->transform.position = glm::vec3(15.0f, 3.0f, 4.0f); + _camera->transform.lookAt(glm::vec3(0.0f)); + glm::mat4 scaleT = glm::scale(glm::mat4(1.0f), glm::vec3(0.6f, 0.6f, 0.6f)); glm::mat4 rotateT = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)); - useBVH = true; + _useBVH = true; std::vector transformations = { rotateT * scaleT, - glm::translate(glm::mat4(1.0f), glm::vec3( -4.0f, 0.0f, 2.0f)) * rotateT * scaleT, + glm::translate(glm::mat4(1.0f), glm::vec3(-4.0f, 0.0f, 2.0f)) * rotateT * scaleT, glm::translate(glm::mat4(1.0f), glm::vec3( 4.0f, 0.0f, -2.0f)) * rotateT * scaleT }; @@ -502,10 +570,10 @@ void RayTracing::createScene3() { }; createPrimitiveBuffer( - balls, - { lucy.get(), lucy.get(), lucy.get() }, + _balls, + { _lucy.get(), _lucy.get(), _lucy.get() }, transformations, - ballMaterials, + _ballMaterials, modelMaterials); } diff --git a/projects/bonus5/raytracing.frag b/projects/bonus5/raytracing.frag index 4a5f865..5079217 100644 --- a/projects/bonus5/raytracing.frag +++ b/projects/bonus5/raytracing.frag @@ -24,29 +24,11 @@ const float Epsilon = 1e-3f; const int windowWidth = 1200; const int maxTraceDepth = 16; -uniform sampler2D RTResult; -uniform usampler2D oldRngState; - -uniform uint totalSamples; -uniform int nPrimitives; -// Scene Config - -uniform samplerCube sky; -uniform sampler2D sphereBuffer; -uniform sampler2D vertexBuffer; -uniform isampler2D triangleIndexBuffer; -uniform sampler2D materialBuffer; -uniform isampler2D primitiveBuffer; -uniform sampler2D bvh; - - struct Camera { mat4 cameraToWorld; // the inverse matrix of view matrix mat4 rasterToCamera; }; -uniform Camera camera; - struct Ray { vec3 o; vec3 dir; @@ -105,152 +87,171 @@ struct Interaction { struct BVHNode { AABB box; int nodeType; - int firstVal; - int secondVal; - /* - union { - struct { - int leftChild; - int rightChild; - }; - struct { - int firstChildIndex; - int nPrimitives; - }; - }; - */ + int firstVal; // leftChild / firstChildIndex + int secondVal; // rightChild / nPrimitives }; + +uniform sampler2D RTResult; +uniform usampler2D oldRngState; + +uniform uint totalSamples; +uniform int nPrimitives; + +// Scene Config +uniform samplerCube sky; +uniform sampler2D sphereBuffer; +uniform sampler2D vertexBuffer; +uniform isampler2D triangleIndexBuffer; +uniform sampler2D materialBuffer; +uniform isampler2D primitiveBuffer; +uniform sampler2D bvh; + +uniform Camera camera; + // tracer -/* -*Summary: initialize the origin and direction of the ray of current pixel -*Parameters: -* u: random offset of the origin -*Return: the ray of current pixel -*/ +/** + * Summary: initialize the origin and direction of the ray of current pixel + * Parameters: + * u: random offset of the origin + * Return: the ray of current pixel + */ Ray generateRay(vec2 u); -/* -*Summary: get the hit point -*Parameters: -* ray: -* t : distance between the origin and the hit point -*Return: the hit point -*/ +/** + * Summary: get the hit point + * Parameters: + * ray: + * t : distance between the origin and the hit point + * Return: the hit point + */ vec3 getHitPoint(inout Ray ray, float t); -/* -*Summary: trace the ray in the scene and calculate the color of pixel -*Parameters: -* ray: the ray -*Return: the color of pixel -*/ +/** + * Summary: trace the ray in the scene and calculate the color of pixel + * Parameters: + * ray: the ray + * Return: the color of pixel + */ vec4 trace(inout Ray ray); + vec3 gammaCorrection(vec3 color); vec3 inverseGammaCorrection(vec3 color); void outputSample(vec4 color); + // intersect bool solveQuadraticEquation(float a, float b, float c, out float x1, out float x2); -/* -*Summary: check whether the ray hit something -*Parameters: -* ray: the ray -* isect: record the shape and material of the primitive -*Return: true if the ray hit something -*/ + +/** + * Summary: check whether the ray hit something + * Parameters: + * ray: the ray + * isect: record the shape and material of the primitive + * Return: true if the ray hit something + */ bool intersect(inout Ray ray, inout Interaction isect); -/* -*Summary: check whether the ray hit AABB -*Parameters: -* ray: the ray -* box: the AABB that will be checked -* isect: record the shape and material of the primitive -* invDir: vec3(1.0f / ray.dir.x, 1.0f / ray.dir.y, 1.0f / ray.dir.z) -*Return: true if the ray hit AABB -*/ + +/** + * Summary: check whether the ray hit AABB + * Parameters: + * ray: the ray + * box: the AABB that will be checked + * isect: record the shape and material of the primitive + * invDir: vec3(1.0f / ray.dir.x, 1.0f / ray.dir.y, 1.0f / ray.dir.z) + * Return: true if the ray hit AABB + */ bool intersectAABB(inout Ray ray, inout AABB box, inout vec3 invDir); -/* -*Summary: check whether the ray hit primitive -*Parameters: -* ray: the ray -* primitive: the primitive that will be checked -* isect: record the shape of the primitive -*Return: true if the ray hit primitive -*/ + +/** + * Summary: check whether the ray hit primitive + * Parameters: + * ray: the ray + * primitive: the primitive that will be checked + * isect: record the shape of the primitive + * Return: true if the ray hit primitive + */ bool intersectPrimitive(inout Ray ray, inout Primitive primitive, inout Interaction isect); -/* -*Summary: check whether the ray hit sphere and update ray -*Parameters: -* ray: the ray -* sphere: the sphere that will be checked -* isect: record the shape of the sphere -*Return: true if the ray hit sphere -*/ + +/** + * Summary: check whether the ray hit sphere + * Parameters: + * ray: the ray + * sphere: the sphere that will be checked + * isect: record the shape of the sphere + * Return: true if the ray hit sphere + */ + bool intersectSphere(inout Ray ray, inout Sphere sphere, inout Interaction isect); -/* -*Summary: check whether the ray hit triangle and update ray -*Parameters: -* ray: the ray -* mesh: the triangle that will be checked -* isect: record the shape of the triangle -*Return: true if the ray hit triangle -*/ + +/** + * Summary: check whether the ray hit triangle + * Parameters: + * ray: the ray + * mesh: the triangle that will be checked + * isect: record the shape of the triangle + * Return: true if the ray hit triangle + */ bool intersectTriangle(inout Ray ray, inout Triangle mesh, inout Interaction isect); // sample -/* +/** *Summary: uniform sample in the hemisphere *Parameters: -* u: random number vector +* u: random number vector *Return: the sample vector */ vec3 uniformSampleHemiSphere(vec2 u); -/* -*Summary: cosine-weighted sample in the hemisphere -*Parameters: -* u: random number vector -*Return: the sample vector -*/ + +/** + * Summary: cosine-weighted sample in the hemisphere + * Parameters: + * u: random number vector + * Return: the sample vector + */ vec3 cosineWeightedSampleHeimiSphere(vec2 u); -/* -*Summary: uniform sample in the sphere -*Parameters: -* u: random number vector -*Return: the sample vector -*/ + +/** + * Summary: uniform sample in the sphere + * Parameters: + * u: random number vector + * Return: the sample vector + */ vec3 uniformSampleSphere(vec2 u); // material -/* -*Summary: approximate the reflectance of dielectric material -*Parameters: -* cosTheta: cosine value between in vector and surface normal -* ior : index of refraction -*Return: the reflectance of dielectric material -*/ +/** + * Summary: approximate the reflectance of dielectric material + * Parameters: + * cosTheta: cosine value between in vector and surface normal + * ior : index of refraction + * Return: the reflectance of dielectric material + */ float fresnelSchlick(float cosTheta, float ior); -/* -*Summary: update the ray when hit lambertian material -*Parameters: -* ray: the ray -* isect : record the shape and material of the primitive -*Return: true if the ray continue bounce -*/ + +/** + * Summary: update the ray when hit lambertian material + * Parameters: + * ray: the ray + * isect : record the shape and material of the primitive + * Return: true if the ray continue bounce + */ bool lambertianScatterFunction(inout Ray ray, inout Interaction isect); -/* -*Summary: update the ray when hit metal material -*Parameters: -* ray: the ray -* isect : record the shape and material of the primitive -*Return: true if the ray continue bounce -*/ + +/** + * Summary: update the ray when hit metal material + * Parameters: + * ray: the ray + * isect : record the shape and material of the primitive + * Return: true if the ray continue bounce + */ bool metalScatterFunction(inout Ray ray, inout Interaction isect); -/* -*Summary: update the ray when hit dielectric material -*Parameters: -* ray: the ray -* isect : record the shape and material of the primitive -*/ + +/** + * Summary: update the ray when hit dielectric material + * Parameters: + * ray: the ray + * isect : record the shape and material of the primitive + */ void dielectricScatterFunction(inout Ray ray, inout Interaction isect); // random number generator @@ -258,15 +259,17 @@ uint rngState; void rngInit(); uint rngUpdateState(); uint rngXorShift(); -/* -*Summary: get random number in [0, 1) -*Return: the random number -*/ + +/** + * Summary: get random number in [0, 1) + * Return: the random number + */ float rngGetRandom1D(); -/* -*Summary: get random vector in [0, 1) -*Return: the random vector -*/ + +/** + * Summary: get random vector in [0, 1) + * Return: the random vector + */ vec2 rngGetRandom2D(); LocalCoord createLocalCoord(inout vec3 n); @@ -277,65 +280,71 @@ void swap(inout float a, inout float b); vec2 getSampleIdx(sampler2D data, int idx); void getVec3FromTexture(sampler2D data, vec2 texCoord, out vec3 v); void getVec4FromTexture(sampler2D data, vec2 texCoord, out vec4 v); -/* -*Summary: get material data -*Parameters: -* data: buffer of data -* idx : index of data -* material: store the data -*Return: the material data -*Usage: getMaterialData(materialBuffer, isect.primitive.materialIdx, isect.material) -*/ + +/** + * Summary: get material data + * Parameters: + * data: buffer of data + * idx : index of data + * material: store the data + * Return: the material data + * Usage: getMaterialData(materialBuffer, isect.primitive.materialIdx, isect.material) + */ void getMaterialData(sampler2D data, int idx, out Material material); -/* -*Summary: get sphere data -*Parameters: -* data: buffer of data -* idx : index of data -* sphere: store the data -*Return: the sphere data -*Usage: getSphereData(sphereBuffer, isect.primitive.shapeIdx, sphere) -*/ + +/** + * Summary: get sphere data + * Parameters: + * data: buffer of data + * idx : index of data + * sphere: store the data + * Return: the sphere data + * Usage: getSphereData(sphereBuffer, isect.primitive.shapeIdx, sphere) + */ void getSphereData(sampler2D data, int idx, out Sphere sphere); -/* -*Summary: get the vertex index data of triangle -*Parameters: -* data: buffer of data -* idx : index of data -* triIdx: store the data -*Return: the vertex index data of triangle -*Usage: getTriangleIndexData(triangleIndexBuffer, primitive.shapeIdx, idx) -*/ + +/** + * Summary: get the vertex index data of triangle + * Parameters: + * data: buffer of data + * idx : index of data + * triIdx: store the data + * Return: the vertex index data of triangle + * Usage: getTriangleIndexData(triangleIndexBuffer, primitive.shapeIdx, idx) + */ void getTriangleIndexData(isampler2D data, int idx, out TriangleIndex triIdx); -/* -*Summary: get the vertex data of triangle -*Parameters: -* data: buffer of data -* idx : index of data -* triIdx: store the data -*Return: the vertex data of triangle -*Usage: getTriangleData(vertexBuffer, triidx, triangle) -*/ + +/** + * Summary: get the vertex data of triangle + * Parameters: + * data: buffer of data + * idx : index of data + * triIdx: store the data + * Return: the vertex data of triangle + * Usage: getTriangleData(vertexBuffer, triidx, triangle) + */ void getTriangleData(sampler2D data, inout TriangleIndex idx, out Triangle triangle); -/* -*Summary: get primitive data -*Parameters: -* data: buffer of data -* idx : index of data -* triIdx: store the data -*Return: the get primitive data -*Usage: getPrimitiveData(primitiveBuffer, BVHNode.firstVal, primitive); -*/ + +/** + * Summary: get primitive data + * Parameters: + * data: buffer of data + * idx : index of data + * triIdx: store the data + * Return: the get primitive data + * Usage: getPrimitiveData(primitiveBuffer, BVHNode.firstVal, primitive); + */ void getPrimitiveData(isampler2D data, int idx, out Primitive primitive); -/* -*Summary: get BVHNode data -*Parameters: -* data: buffer of data -* idx : index of data -* triIdx: store the data -*Return: the get BVHNode data -*Usage: getBVHNodeData(bvh, BVHNode.firstVal or BVHNode.secondVal , node) -*/ + +/** + * Summary: get BVHNode data + * Parameters: + * data: buffer of data + * idx : index of data + * triIdx: store the data + * Return: the get BVHNode data + * Usage: getBVHNodeData(bvh, BVHNode.firstVal or BVHNode.secondVal , node) + */ void getBVHNodeData(sampler2D data, int idx, out BVHNode node); void main() { @@ -345,21 +354,22 @@ void main() { } Ray generateRay(vec2 u) { - // TODO + vec4 pixelPos = vec4(gl_FragCoord.x - 0.5f + u.x, gl_FragCoord.y - 0.5f + u.y, 0.0f, 1.0f); Ray ray; - ray.o = vec3(0.0f); - ray.dir = vec3(0.0f, 0.0f, 1.0f); + ray.o = vec3(camera.cameraToWorld * vec4(0.0f, 0.0f, 0.0f, 1.0f)); + vec3 localRayDir = (camera.rasterToCamera * pixelPos).xyz - vec3(0.0f, 0.0f, 0.0f); + ray.dir = normalize(vec3(camera.cameraToWorld * vec4(localRayDir.xyz, 0.0f))); + ray.tMax = INFINITY; return ray; } vec3 getHitPoint(inout Ray ray, float t) { - //TODO - return vec3(0.0f); + return ray.o + t * ray.dir; } vec4 trace(inout Ray ray) { - //TODO - return vec4(0.5f, 0.5f, 0.5f, 1.0f); + // TODO: change the code here to trace the ray through the scene + return vec4(texture(sky, ray.dir).rgb, 1.0f); } vec3 gammaCorrection(vec3 color) { @@ -378,12 +388,12 @@ void outputSample(vec4 color) { } bool intersect(inout Ray ray, inout Interaction isect) { - //TODO + // TODO: perform ray hit the primitive with bvh trasversal return false; } bool intersectAABB(inout Ray ray, inout AABB box, inout vec3 invDir) { - //TODO + // TODO: perform ray hit AABB return false; } @@ -408,17 +418,19 @@ bool solveQuadraticEquation(float a, float b, float c, out float x1, out float x } bool intersectPrimitive(inout Ray ray, inout Primitive primitive, inout Interaction isect) { - //TODO + // TODO: perform ray hit the primitive, the type of the primitive can be + // + sphere (use intersectSphere) + // + triangle (use intersectTriangle) return false; } bool intersectSphere(inout Ray ray, inout Sphere sphere, inout Interaction isect) { - // TODO + // TODO: perform ray hit the sphere return false; } bool intersectTriangle(inout Ray ray, inout Triangle mesh, inout Interaction isect) { - //TODO + // TODO: perform ray hit the triangle return false; } @@ -427,6 +439,7 @@ vec3 uniformSampleHemiSphere(vec2 u) { float z = 1 - u.x; float sinTheta = sqrt(max(0.0f, 1.0f - z * z)); float phi = 2 * Pi * u.y; + return vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, z); } @@ -434,6 +447,7 @@ vec3 cosineWeightedSampleHeimiSphere(vec2 u) { float sinTheta = sqrt(u.x); float cosTheta = sqrt(1 - sinTheta * sinTheta); float phi = 2 * Pi * u.y; + return vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); } @@ -441,27 +455,31 @@ vec3 uniformSampleSphere(vec2 u) { float cosTheta = 1 - 2 * u.x; float sinTheta = sqrt(max(0.0f, 1 - cosTheta * cosTheta)); float phi = 2 * Pi * u.y; + return vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); } // material float fresnelSchlick(float cosTheta, float ior) { - // TODO - return 0.0f; + float r0 = (1.0f - ior) / (1.0f + ior); + r0 = r0 * r0; + + return r0 + (1 - r0) * pow(1 - cosTheta, 5); } bool lambertianScatterFunction(inout Ray ray, inout Interaction isect) { - // TODO + // TODO: perform ray interact with the lambert material return false; } bool metalScatterFunction(inout Ray ray, inout Interaction isect) { - //TODO + // TODO: perform ray interact with the metallic material return false; } void dielectricScatterFunction(inout Ray ray, inout Interaction isect) { - // TODO + // TODO: perform ray interact with the dielectric material + return ; } void rngInit() { diff --git a/projects/bonus5/raytracing.h b/projects/bonus5/raytracing.h index 0b12df7..8b7a969 100644 --- a/projects/bonus5/raytracing.h +++ b/projects/bonus5/raytracing.h @@ -19,27 +19,27 @@ class RayTracing : public Application { public: RayTracing(const Options& options); - ~RayTracing() = default; + ~RayTracing(); private: - std::unique_ptr lucy; + std::unique_ptr _lucy; - std::vector balls; - std::vector ballMaterials; + std::vector _balls; + std::vector _ballMaterials; - std::unique_ptr skyBox; + std::unique_ptr _skybox; std::unique_ptr _screenQuad; std::unique_ptr _camera; - std::unique_ptr raytracingProgram; - std::unique_ptr drawScreenProgram; + std::unique_ptr _raytracingShader; + std::unique_ptr _drawScreenShader; std::unique_ptr _sampleFramebuffers[2]; - uint32_t currentReadBufferID = 0; - uint32_t currentWriteBufferID = 1; - uint32_t sampleCount = 0; + uint32_t _currentReadBufferID = 0; + uint32_t _currentWriteBufferID = 1; + uint32_t _sampleCount = 0; std::unique_ptr _outFrames[2]; std::unique_ptr _rngStates[2]; @@ -53,8 +53,10 @@ class RayTracing : public Application { std::unique_ptr _materialBuffer; std::unique_ptr _bvhBuffer; - bool hasSphere = false; - bool useBVH = true; + bool _hasSphere = false; + bool _useBVH = false; + + int _renderSceneIndex = 0; void handleInput() override; @@ -63,17 +65,21 @@ class RayTracing : public Application { void initShaders(); void createBalls(); - - void createPrimitiveBuffer(const std::vector& spheres, - const std::vector models, - const std::vector& transforms, - const std::vector& sphereMaterials, - const std::vector& triangleMaterials); + + void createRenderScene(int index); void createScene1(); + void createScene2(); + void createScene3(); + void createPrimitiveBuffer(const std::vector& spheres, + const std::vector models, + const std::vector& transforms, + const std::vector& sphereMaterials, + const std::vector& triangleMaterials); + int getBufferHeight(size_t nObjects, size_t objectSize, size_t texComponent) const; static int toFloatLayout(int v); diff --git a/projects/bonus5/triangle.h b/projects/bonus5/triangle.h index 5c43e8f..6881e5f 100644 --- a/projects/bonus5/triangle.h +++ b/projects/bonus5/triangle.h @@ -21,6 +21,47 @@ struct Triangle { v[2] = vi3; } + bool intersect(const Ray& ray) { + glm::vec3 o = ray.o; + glm::vec3 dir = ray.dir; + Vertex v1 = vertices[v[0]]; + Vertex v2 = vertices[v[1]]; + Vertex v3 = vertices[v[2]]; + + glm::vec3 p1 = v1.position; + glm::vec3 p2 = v2.position; + glm::vec3 p3 = v3.position; + glm::vec3 n1 = v1.normal; + glm::vec3 n2 = v2.normal; + glm::vec3 n3 = v3.normal; + + glm::vec3 e1 = p2 - p1; + glm::vec3 e2 = p3 - p1; + glm::vec3 n = glm::normalize(glm::cross(e1, e2)); + if (std::abs(glm::dot(n, dir)) < 1e-4f) { + return false; + } + + float d = glm::dot(n, p1); + float tHit = (d - glm::dot(n, o)) / glm::dot(n, dir); + if (tHit < 0 || tHit >= ray.tMax) { + return false; + } + + glm::vec3 q = o + tHit * dir; + float area = glm::dot(glm::cross(e1, e2), n); + float alpha = glm::dot(glm::cross(p3 - p2, q - p2), n) / area; + float beta = glm::dot(glm::cross(q - p1, p3 - p1), n) / area; + float gamma = glm::dot(glm::cross(p2 - p1, q - p1), n) / area; + + if (alpha >= 0 && beta >= 0 && gamma >= 0) { + ray.tMax = tHit; + return true; + } else { + return false; + } + } + static constexpr int getVertexTexDataComponent() noexcept { return 4; } diff --git a/readme.md b/readme.md index 7369e60..004cf6c 100644 --- a/readme.md +++ b/readme.md @@ -84,6 +84,11 @@ cd bin/Debug +##### Post Processing +
+ +
+ ##### Shadow Mapping
diff --git "a/reports/~$4_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" "b/reports/~$4_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" deleted file mode 100644 index 61d7c50..0000000 Binary files "a/reports/~$4_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" and /dev/null differ diff --git "a/reports/\351\242\235\345\244\2263_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" "b/reports/\351\242\235\345\244\2263_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" index a3dcc98..81d3221 100644 Binary files "a/reports/\351\242\235\345\244\2263_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" and "b/reports/\351\242\235\345\244\2263_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" differ diff --git "a/reports/\351\242\235\345\244\2265_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" "b/reports/\351\242\235\345\244\2265_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" index 16753a2..d74056c 100644 Binary files "a/reports/\351\242\235\345\244\2265_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" and "b/reports/\351\242\235\345\244\2265_\345\255\246\345\217\267_\345\247\223\345\220\215.doc" differ diff --git a/screenshots/bonus3.png b/screenshots/bonus3.png new file mode 100644 index 0000000..1053487 Binary files /dev/null and b/screenshots/bonus3.png differ diff --git a/screenshots/bonus5.png b/screenshots/bonus5.png index 9e87bdf..024912d 100644 Binary files a/screenshots/bonus5.png and b/screenshots/bonus5.png differ