From 4588120ce7f7e3067b10b85e14b2690ce7dc2464 Mon Sep 17 00:00:00 2001 From: Nobuyuki Date: Mon, 13 May 2024 09:11:39 +0900 Subject: [PATCH] added task04 --- .github/workflows/ubuntu.yml | 20 ++++---- .github/workflows/windows.yml | 14 +++--- CMakeLists.txt | 2 +- README.md | 9 ++-- task04/CMakeLists.txt | 53 ++++++++++++++++++++ task04/README.md | 48 ++++++++++++++++++ task04/main.cpp | 92 ++++++++++++++++++++++++++++++++++ task04/problem1.png | Bin 0 -> 6640 bytes task04/problem2.png | Bin 0 -> 12051 bytes task04/shader.frag | 9 ++++ task04/shader.vert | 36 +++++++++++++ 11 files changed, 262 insertions(+), 21 deletions(-) create mode 100644 task04/CMakeLists.txt create mode 100644 task04/README.md create mode 100644 task04/main.cpp create mode 100644 task04/problem1.png create mode 100644 task04/problem2.png create mode 100644 task04/shader.frag create mode 100644 task04/shader.vert diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 4e1ec4d..d7c2eca 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -16,16 +16,16 @@ jobs: steps: - uses: actions/checkout@v2 - #- name: install glfw - # run: | - # sudo apt install -y \ - # libwayland-dev libxkbcommon-dev wayland-protocols extra-cmake-modules \ - # libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev - # git submodule update --init -- external/glfw - # cmake -S external/glfw -B external/glfwbuild - # cd external/glfwbuild - # cmake --build . --config Release - # cmake --install . --prefix ../glfwlib + - name: install glfw + run: | + sudo apt install -y \ + libwayland-dev libxkbcommon-dev wayland-protocols extra-cmake-modules \ + libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev + git submodule update --init -- external/glfw + cmake -S external/glfw -B external/glfwbuild + cd external/glfwbuild + cmake --build . --config Release + cmake --install . --prefix ../glfwlib - name: install eigen run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index bb0aaab..acbaa29 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -17,13 +17,13 @@ jobs: - uses: actions/checkout@v2 - #- name: install glfw - # run: | - # git submodule update --init -- external/glfw - # cmake -S external/glfw -B external/glfwbuild - # cd external/glfwbuild - # cmake --build . --config Release - # cmake --install . --prefix ../glfwlib + - name: install glfw + run: | + git submodule update --init -- external/glfw + cmake -S external/glfw -B external/glfwbuild + cd external/glfwbuild + cmake --build . --config Release + cmake --install . --prefix ../glfwlib - name: get eigen run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index a3b3b3f..8c1f04d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(tasks) add_subdirectory(task01) add_subdirectory(task02) add_subdirectory(task03) -# add_subdirectory(task04) +add_subdirectory(task04) # add_subdirectory(task05) # add_subdirectory(task06) # add_subdirectory(task07) diff --git a/README.md b/README.md index b888bbe..c51b5f7 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Topics: |(2)
Apr. 15| **Parametric curves / surfaces**
**Rasterization in 2D**, Digital Differential Analyzer | [task01](task01) | [[5]](http://nobuyuki-umetani.com/acg2024s/rasterization_2d.pdf) [[6]](http://nobuyuki-umetani.com/acg2024s/barycentric_coordinates.pdf) | |(3)
Apr. 22| **Parametric representation**
Bézier curve, polynominal | [task02](task02) | [[7] ](http://nobuyuki-umetani.com/acg2024s/parametric_curve.pdf) [[8]](http://nobuyuki-umetani.com/acg2024s/polynominal.pdf) | |(5)
May 7| **Coordinate transformation**
Affine, homography transformation | [task03](task03) | [[9]](http://nobuyuki-umetani.com/acg2024s/transformation.pdf) [[10]](http://nobuyuki-umetani.com/acg2024s/transformation_homogeneous_2d.pdf) [[11]](http://nobuyuki-umetani.com/acg2024s/transformation_homogeneous_3d.pdf) | -|(4)
May 13| **Graphics pipeline**
depth buffer method, shading, shadow, anti aliasing | task04 | | +|(4)
May 13| **Graphics pipeline**
depth buffer method, shading, shadow, anti aliasing | [task04](task04) | [[12]](http://nobuyuki-umetani.com/acg2024s/rasterization_3d.pdf)[[13]](http://nobuyuki-umetani.com/acg2024s/graphics_pipeline.pdf)[[14]](http://nobuyuki-umetani.com/acg2024s/shading.pdf) | |(6)
May 20| **Ray Casting 1**
spatial data structure | task05 | | |(7)
May 27| **Ray Casting 2**
Rendering equation, Monte Carlo integration | task06 | | |(8)
June 3| **Character animation**
Linear blend skinning | task07 | | @@ -81,7 +81,7 @@ Look at the following document. | [task01](task01) | **Rasterization of lines and polygons**
DDA, winding number | | | [task02](task02) | **Rasterization of parametric curves**
Quadratic Bézier curve, root of polynominal | | | [task03](task03) | **Perspectively-correct texture mapping**
rasterization of triangle, barycentric coordinate | | -| task04 | **Vertex shader practice**
Rendering pipeline, mirror reflection, OpenGL | | +| [task04](task04) | **Vertex shader practice**
Rendering pipeline, mirror reflection, OpenGL | | | task05 | **Fragment shader practice**
Ray marching method, CSG modeling, implicit modeling | | | task06 | **Monte Carlo integration**
Multiple importance sampling, path tracing, rendering equation | | | task07 | TBD | | @@ -110,7 +110,10 @@ Look at the following document. - [[9] Coordinate Transformation](http://nobuyuki-umetani.com/acg2024s/transformation.pdf) - [[10] 2D Homogeneous Transformation](http://nobuyuki-umetani.com/acg2024s/transformation_homogeneous_2d.pdf) - [[11] 3D Homogeneous Transformation](http://nobuyuki-umetani.com/acg2024s/transformation_homogeneous_3d.pdf) -- [[11] 3D Rasterization](http://nobuyuki-umetani.com/acg2024s/rasterization_3d.pdf) +- [[12] 3D Rasterization](http://nobuyuki-umetani.com/acg2024s/rasterization_3d.pdf) +- [[13] Graphics Pipeline](http://nobuyuki-umetani.com/acg2024s/graphics_pipeline.pdf) +- [[14] Shading](http://nobuyuki-umetani.com/acg2024s/shading.pdf) + ## Reading Material diff --git a/task04/CMakeLists.txt b/task04/CMakeLists.txt new file mode 100644 index 0000000..5ccc545 --- /dev/null +++ b/task04/CMakeLists.txt @@ -0,0 +1,53 @@ +cmake_minimum_required(VERSION 3.10) + +############################# +# set C++ detail +enable_language(CXX) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + +############################# + +# set project name +project(task04) + +# define a macro to get absolute path in C++ +add_definitions(-DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}") + +############################# +# specifying libraries to use + +# use opengl +find_package(OpenGL REQUIRED) + +# use glfw +set(CMAKE_PREFIX_PATH ${PROJECT_SOURCE_DIR}/../external/glfwlib) +find_package(glfw3 REQUIRED) + +######################## +# include, build, & link + +include_directories(${PROJECT_NAME} + ${PROJECT_SOURCE_DIR}/../external + ${PROJECT_SOURCE_DIR}/../external/glad3/include + ${PROJECT_SOURCE_DIR}/../external/eigen +) + +add_executable(${PROJECT_NAME} + main.cpp + ${PROJECT_SOURCE_DIR}/../external/glad3/src/glad.c +) + +# https://stackoverflow.com/questions/33678965/need-to-link-cmake-project-to-dl-library +target_link_libraries(${PROJECT_NAME} + OpenGL::GL + glfw + ${CMAKE_DL_LIBS} +) + +############################# +# showing status of libraries + +GET_TARGET_PROPERTY(GLFW_INCLUDE_DIR + glfw INTERFACE_INCLUDE_DIRECTORIES) +message(STATUS "task04 glfw include directory: ${GLFW_INCLUDE_DIR}") \ No newline at end of file diff --git a/task04/README.md b/task04/README.md new file mode 100644 index 0000000..befbbb0 --- /dev/null +++ b/task04/README.md @@ -0,0 +1,48 @@ +# Task04: Vertex Shader Practice (Mirror Reflection) + +![preview](preview.png) + +**Deadline: May 16th (Thu) at 15:00pm** + +---- + +## Before Doing Assignment + +If you have not done the [task01](../task01), [task02](../task02) do it first to set up the C++ development environment. + +Follow [this document](../doc/submit.md) to submit the assignment, In a nutshell, before doing the assignment, +- make sure you synchronized the `main ` branch of your local repository to that of remote repository. +- make sure you created branch `task04` from `main` branch. +- make sure you are currently in the `task04` branch (use `git branch -a` command). + +Additionally, you need to install `glfw` library. +Follow [this document](../doc/setup_glfw.md) to install glfw. + +Now you are ready to go! + +--- + +## Problem 1 + +1. Build the code using cmake +2. Run the code +3. Take a screenshot image (looks like image at the top) +4. Save the screenshot image overwriting `task04/problem1.png` + +![problem1](problem1.png) + + +## Problem 2 + +Write some code (about 5 ~ 10 lines) around `line #29` in `shader.vert` +to define the coordinate transformation for mirror reflection. +Read the instruction in the `shader.vert` for more information. + +Save the screenshot image overwriting `task04/problem2.png` + +![problem2](problem2.png) + + +## After Doing the Assignment + +After modify the code, push the code and submit a pull request. diff --git a/task04/main.cpp b/task04/main.cpp new file mode 100644 index 0000000..cc83753 --- /dev/null +++ b/task04/main.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#define GL_SILENCE_DEPRECATION +#include +// +#include "../src/util_opengl.h" +#include "../src/util_triangle_mesh.h" + +/*** + * draw triangle mesh + * @param tri2vtx triangle index + * @param vtx2xyz vertex coordinates + * @param vtx2normal vertex normals + */ +void draw( + const Eigen::Matrix &tri2vtx, + const Eigen::Matrix3Xf &vtx2xyz, + const Eigen::Matrix3Xf &vtx2normal) { + ::glBegin(GL_TRIANGLES); + for (auto i_tri = 0; i_tri < tri2vtx.cols(); ++i_tri) { + const auto i0 = tri2vtx(0, i_tri); + const auto i1 = tri2vtx(1, i_tri); + const auto i2 = tri2vtx(2, i_tri); + ::glNormal3fv(vtx2normal.data() + i0 * 3); + ::glVertex3fv(vtx2xyz.data() + i0 * 3); + ::glNormal3fv(vtx2normal.data() + i1 * 3); + ::glVertex3fv(vtx2xyz.data() + i1 * 3); + ::glNormal3fv(vtx2normal.data() + i2 * 3); + ::glVertex3fv(vtx2xyz.data() + i2 * 3); + } + ::glEnd(); +} + +int main() { + const auto file_path = std::filesystem::path(PROJECT_SOURCE_DIR) / ".." / "asset" / "armadillo.obj"; + auto[tri2vtx, vtx2xyz] = acg::read_wavefrontobj_as_3d_triangle_mesh(file_path); + // bounding box + auto aabb_max = vtx2xyz.rowwise().maxCoeff(); + auto aabb_min = vtx2xyz.rowwise().minCoeff(); + auto aabb_center = (aabb_min + aabb_max) * 0.5f; // center of the bounding box + auto aabb_size = (aabb_max - aabb_min).maxCoeff(); // size of the bounding box + // normalize coordinate + vtx2xyz = (vtx2xyz.colwise() - aabb_center) / aabb_size * 1.3; + vtx2xyz = Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()).matrix() * vtx2xyz; + vtx2xyz = vtx2xyz.colwise() + Eigen::Vector3f(0.2, 0.0, 0.0); + // compute normals at vertices + const auto vtx2normal = acg::vertex_normals_of_triangle_mesh(tri2vtx, vtx2xyz); + + if (!glfwInit()) { exit(EXIT_FAILURE); } + // set OpenGL's version (note: ver. 2.1 is very old, but I chose because it's simple) + ::glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + ::glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + // open window + GLFWwindow *window = ::glfwCreateWindow(500, 500, "task04", nullptr, nullptr); + if (!window) { // exit if failed to create window + ::glfwTerminate(); + exit(EXIT_FAILURE); + } + ::glfwMakeContextCurrent(window); // working on this window + if (!gladLoadGL()) { // glad: load all OpenGL function pointers + std::cout << "Something went wrong in loading OpenGL functions!\n" << std::endl; + exit(-1); + } + + int shaderProgram; + { // compile shader program + std::string vrt_path = std::filesystem::path(PROJECT_SOURCE_DIR) / "shader.vert"; + std::string frg_path = std::filesystem::path(PROJECT_SOURCE_DIR) / "shader.frag"; + std::string vrt = acg::load_file_as_string(vrt_path); // read source code of vertex shader program + std::string frg = acg::load_file_as_string(frg_path); // read source code of fragment shader program + shaderProgram = acg::create_shader_program(vrt, frg); // compile the shader on GPU + } + ::glUseProgram(shaderProgram); // use the shader program + GLint iloc = glGetUniformLocation(shaderProgram, "is_reflection"); // shader program variable + + ::glClearColor(1, 1, 1, 1); // set the color to fill the frame buffer when glClear is called. + ::glEnable(GL_DEPTH_TEST); + while (!::glfwWindowShouldClose(window)) { + ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + ::glUniform1i(iloc, true); // set value to the shader program (draw reflection of the triangle mesh) + draw(tri2vtx, vtx2xyz, vtx2normal); + ::glUniform1i(iloc, false); // set value to the shader program (draw triangle mesh) + draw(tri2vtx, vtx2xyz, vtx2normal); + + ::glfwSwapBuffers(window); + ::glfwPollEvents(); + } + ::glfwDestroyWindow(window); + ::glfwTerminate(); + exit(EXIT_SUCCESS); +} diff --git a/task04/problem1.png b/task04/problem1.png new file mode 100644 index 0000000000000000000000000000000000000000..2bbe6479c9ba77dd46d0112e765047df26058ce0 GIT binary patch literal 6640 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 literal 0 HcmV?d00001 diff --git a/task04/shader.frag b/task04/shader.frag new file mode 100644 index 0000000..226233a --- /dev/null +++ b/task04/shader.frag @@ -0,0 +1,9 @@ +#version 120 + +varying vec3 normal; // normal interpolated using baricentric coordinate + +void main() +{ + // draw normal + gl_FragColor = vec4(0.5*normal+0.5,1); +} diff --git a/task04/shader.vert b/task04/shader.vert new file mode 100644 index 0000000..e0e50d5 --- /dev/null +++ b/task04/shader.vert @@ -0,0 +1,36 @@ +#version 120 + +// see the GLSL 1.2 specification: +// https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.1.20.pdf + +uniform bool is_reflection; // variable of the program +varying vec3 normal; // normal vector pass to the rasterizer and fragment shader + +void main() +{ + normal = vec3(gl_Normal);// set normal and pass it to fragment shader + + // "gl_Vertex" is the *input* vertex coordinate of triangle. + // "gl_Vertex" has type of "vec4", which is homogeneious coordinate + float x0 = gl_Vertex.x/gl_Vertex.w;// x-coord + float y0 = gl_Vertex.y/gl_Vertex.w;// y-coord + float z0 = gl_Vertex.z/gl_Vertex.w;// z-coord + if (is_reflection) { + vec3 nrm = normalize(vec3(0.4, 0.0, 1.0)); // normal of the mirror + vec3 org = vec3(-0.3, 0.0, -0.5); // point on the mirror + // wite code to change the input position (x0,y0,z0). + // the transformed position (x0, y0, z0) should be drawn as the mirror reflection. + // + // make sure the occlusion is correctly computed. + // the mirror is behind the armadillo, so the reflected image should be behind the armadillo. + // furthermore, make sure the occlusion is correctly computed for the reflected image. + //x0 = ??? + //y0 = ??? + //z0 = ??? + } + // do not edit below + + // "gl_Position" is the *output* vertex coordinate in the + // "canonical view volume (i.e.. [-1,+1]^3)" pass to the rasterizer. + gl_Position = vec4(x0, y0, -z0, 1);// opengl actually draw a pixel with *maximum* depth. so invert z +}