Skip to content

Commit

Permalink
added task02
Browse files Browse the repository at this point in the history
  • Loading branch information
nobuyuki83 committed Apr 22, 2024
1 parent 41d8ce7 commit b50236d
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 4 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ Topics:

| Day | Topic | Assignment | Slide |
|:----|:---|:---|:---|
|(1)<br>Apr. 8| **Introduction**<br>**Rasterization in 2D**, Digital Differential Analyzer | | [[1]](http://nobuyuki-umetani.com/acg2024s/introduction.pdf), [[4]](http://nobuyuki-umetani.com/acg2024s/digital_image.pdf) |
|(2)<br>Apr. 15| **Parametric curves / surfaces** <br/>Bézier curve, polynominal | [task01](task01) | [[5]](http://nobuyuki-umetani.com/acg2024s/rasterization_2d.pdf) [[6]](http://nobuyuki-umetani.com/acg2024s/barycentric_coordinates.pdf) |
|(3)<br>Apr. 22| **Coordinate transfrormation**<br/>Affine, homography transformation | task02 | |
|(1)<br>Apr. 8| **Introduction**<br>Didigital image | | [[1]](http://nobuyuki-umetani.com/acg2024s/introduction.pdf), [[4]](http://nobuyuki-umetani.com/acg2024s/digital_image.pdf) |
|(2)<br>Apr. 15| **Parametric curves / surfaces** <br/>**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)<br>Apr. 22| **Coordinate transfrormation**<br/>Bézier curve, polynominal, Affine, homography transformation | [task02](task02) | [[7] ](http://nobuyuki-umetani.com/acg2024s/parametric_curve.pdf) [[8]](http://nobuyuki-umetani.com/acg2024s/polynominal.pdf) |
|(5)<br>May 7| **Graphics Pipeline 1**<br>depth buffer method, shading | task03 | |
|(4)<br>May 13| **Graphics Pipeline 2**<br>shadow, anti aliasing | task04 | |
|(6)<br>May 20| **Ray Casting 1**<br/>spatial data structure | task05 | |
Expand Down Expand Up @@ -79,7 +79,7 @@ Look at the following document.
| Task ID | Title | Thumbnail |
|:---|:---|:---|
| [task01](task01) | **Rasterization of lines and polygons**<br>DDA, winding number | <img src="task01/preview.png" width=100px> |
| task02 | **Rasterization of parametric curves**<br> Quadratic Bézier curve, root of polynominal | <img src="task02/preview.png" width=100px> |
| [task02](task02) | **Rasterization of parametric curves**<br> Quadratic Bézier curve, root of polynominal | <img src="task02/preview.png" width=100px> |
| task03 | **Perspectively-correct texture mapping**<br>rasterization of triangle, barycentric coordinate | <img src="task03/preview.png" width=100px> |
| task04 | **Vertex shader practice** <br>Rendering pipeline, mirror reflection, OpenGL | <img src="task04/preview.png" width=100px> |
| task05 | **Fragment shader practice**<br>Ray marching method, CSG modeling, implicit modeling | <img src="task05/preview.png" width=100px> |
Expand All @@ -106,6 +106,8 @@ Look at the following document.
- [[5] Rasterization in 2D](http://nobuyuki-umetani.com/acg2024s/rasterization_2d.pdf)
- [[6] Barycentric Coordinates](http://nobuyuki-umetani.com/acg2024s/barycentric_coordinates.pdf)
- [[7] Parametric Curve](http://nobuyuki-umetani.com/acg2024s/parametric_curve.pdf)
- [[8] Polynominal Root finding](http://nobuyuki-umetani.com/acg2024s/polynominal.pdf)
- [[9] Coordinate Transformation](http://nobuyuki-umetani.com/acg2024s/transformation.pdf)


## Reading Material
Expand Down
36 changes: 36 additions & 0 deletions task02/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.10) # specify the version of cmake

#############################
# set C++ detail
enable_language(CXX) # we are using C++
set(CMAKE_CXX_STANDARD 17) # we are using C++ 17
set(CMAKE_CXX_STANDARD_REQUIRED TRUE) # we are using STL library

#############################
# set project name

project(task02)

#############################
# define macro
add_definitions(-DPROJECT_SOURCE_DIR="${PROJECT_SOURCE_DIR}")

#############################
# specifying libraries to use

########################
# include, build, and link

include_directories(
${PROJECT_SOURCE_DIR}/../external
${PROJECT_SOURCE_DIR}/../external/eigen
${PROJECT_SOURCE_DIR}/../src
)

add_executable(${PROJECT_NAME}
main.cpp
)

target_link_libraries(${PROJECT_NAME}
# stdc++fs # uncomment here if <filesystem> cannot be included
)
148 changes: 148 additions & 0 deletions task02/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Task01: Rasterization of parametric curves

**Deadline: April 25st (Thu) at 15:00pm**


This is the blurred preview of the expected result:

![preview](preview.png)

When you execute the program, it will output an PNG image file (`output.png`) replacing the image below. Try making the image below and the image above look similar after doing the assignment.

![preview](output.png)

----

## Instruction

Please follow this instruction to prepare the environment to do the assignment

If you did not do the [task01](../task01) assignment, you need to prepare **git**, **cmake**, and **C++ compiler** in your computer to complete this assignment.
Read the following document to install these.

[How to Set Up C++ Programming Environment](../doc/setup_env.md)

If you had some trouble with `git` in the local repository in the previous assignment, `clone` your remote repository again to avoid trouble.

```bash
$ git clone https://github.com/ACG-2024S/acg-<username>.git
```


Go to the top of the local repository

```bash
$ cd acg-<username> # go to the local repository
```

### Update Local Repository

Update the local repository on your computer

```bash
$ git checkout main # set main branch as the current branch
$ git fetch origin main # download the main branch from remote repository
$ git reset --hard origin/main # reset the local main branch same as remote repository
```

After this command, you will see the local repository is synced with the remote repository at `https://github.com/ACG-2024S/acg-<username>`

### Create a Branch

To do this assignment, you need to be in the branch `task02`.
You can always check your the current branch by

```bash
$ git branch -a # list all branches, showing the current branch
```

You are probably in the `main` branch. Let's create the `task02` branch and set it as the current branch.

```bash
$ git branch task02 # create task0 branch
$ git checkout task02 # switch into the task02 branch
$ git branch -a # make sure you are in the task02 branch
```

The environment is ready.

## Problem1

Install eigen under `acg-<username>/external` by the following command

```bash
$ pwd # make sure you are in acg-<username> directory
$ git submodule update --init external/eigen # clone the "eigen" repository (this may take one or two minutes)
```

Make sure you have a header file `Dense` at
```
acg-<username>/external/eigen/Eigen/Dense
```

Eigen can be used as a header-only library. You do not need to compile it to do this task.

Next, compile the code with **out-of-source** build by making a new directory for build `task02/build` and compile inside that directory
```bash
$ cd task02 # you are in "acg-<username>/task02" directory
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release .. # configure Release mode for fast execution
$ cmake --build .
```

Now you will see the `output.png` is updated. The `output.png` will show an angular shape of the letter **R**. Now let's write a program to make the font shape smooth as the original one.


## Problem2

The code you compiled above uses the ***Jordan's curve theorem** to find whether the center of a pixel is inside or outside the character.The code counts the number of intersections of a ray against the boundary.
The boundary of the letter is represented by sequences of line segments and quadratic Bézier curves. The Problem1's output was angular because the Bézier curve was approximated as a line segment.

Modify the code `main.cpp` around line #65 to compute the number of intersections of a ray against the Bézier curve. The output will be the letter ***R*** with smooth boundary.


### Submit

Finally, you submit the document by pushing to the `task02` branch of the remote repository.

```bash
cd acg-<username> # go to the top of the repository
git status # check the changes
git add . # stage the changes
git status # check the staged changes
git commit -m "task02 finished" # the comment can be anything
git push --set-upstream origin task02 # update the task02 branch of the remote repository
```

got to the GitHub webpage `https://github.com/ACG-2024S/acg-<username>`.
If everything looks good on this page, make a pull request.

![](../doc/pullrequest.png)


----

## Trouble Shooting

If you have trouble with `#include <filesystem>`, your C++ compilar is very old. Try update one. Following command may work tos specify which compilar to use on linux & Mac

```
export CC=/usr/local/bin/gcc-8
export CXX=/usr/local/bin/g++-8
cmake ..
```




----

## Reference

- Coding Adventure: Rendering Text
: https://www.youtube.com/watch?v=SO83KQuuZvg

- SIGGRAPH 2022 Talk - A Fast & Robust Solution for Cubic & Higher-Order Polynomials by Cem Yuksel: https://www.youtube.com/watch?v=ok0EZ0fBCMA

- True Type: https://en.wikipedia.org/wiki/TrueType
105 changes: 105 additions & 0 deletions task02/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include <filesystem>
// #include <experimental/filesystem> // uncomment here if the <filesystem> cannot be included above
//
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#include "Eigen/Core"
//
#include "parse_svg.h"

/***
* signed area of a triangle connecting points (p0, p1, p2) in counter-clockwise order.
* @param p0 1st point xy-coordinate
* @param p1 2nd point xy-coordinate
* @param p2 3rd point xy-coordinate
* @return signed area (float)
*/
float area(
const Eigen::Vector2f &p0,
const Eigen::Vector2f &p1,
const Eigen::Vector2f &p2) {
const auto v01 = p1 - p0;
const auto v02 = p2 - p0;
// return 0.5f * (v01[0] * v02[1] - v01[1] * v02[0]); // right handed coordinate
return 0.5f * (v01[1] * v02[0] - v01[0] * v02[1]); // left-handed coordinate (because pixel y-coordinate is going down)
}


/***
* compute number of intersection of a ray against a line segment
* @param org ray origin
* @param dir ray direction (unit normal)
* @param ps one of the two end points
* @param pe the other end point
* @return number of intersection
*/
int number_of_intersection_ray_against_edge(
const Eigen::Vector2f &org,
const Eigen::Vector2f &dir,
const Eigen::Vector2f &ps,
const Eigen::Vector2f &pe) {
auto a = area(org, org + dir, ps);
auto b = area(org, pe, org + dir);
auto c = area(org, ps, pe);
auto d = area(org + dir, ps, pe);
if (a * b > 0.f && d * c > 0.f && fabs(d) > fabs(c)) { return 1; }
return 0;
}

/***
*
* @param org ray origin
* @param dir ray direction (unit vector)
* @param ps one of the two end points
* @param pc control point
* @param pe the other end point
* @return the number of intersections
*/
int number_of_intersection_ray_against_quadratic_bezier(
const Eigen::Vector2f &org,
const Eigen::Vector2f &dir,
const Eigen::Vector2f &ps,
const Eigen::Vector2f &pc,
const Eigen::Vector2f &pe) {
// comment out below to do the assignment
return number_of_intersection_ray_against_edge(org, dir, ps, pe);
// write some code below to find the intersection between ray and the quadratic
}

int main() {
const auto input_file_path = std::filesystem::path(PROJECT_SOURCE_DIR) / ".." / "asset" / "r.svg";
const auto [width, height, shape] = acg::svg_get_image_size_and_shape(input_file_path);
if (width == 0) { // something went wrong in loading the function
std::cout << "file open failure" << std::endl;
abort();
}
const std::vector<std::string> outline_path = acg::svg_outline_path_from_shape(shape);
const std::vector<std::vector<acg::Edge>> loops = acg::svg_loops_from_outline_path(outline_path);
//
std::vector<unsigned char> img_data(width * height, 255); // grayscale image initialized white
for (unsigned int ih = 0; ih < height; ++ih) {
for (unsigned int iw = 0; iw < width; ++iw) {
const auto org = Eigen::Vector2f(iw + 0.5, ih + 0.5); // pixel center
const auto dir = Eigen::Vector2f(60., 20.); // search direction
int count_cross = 0;
for (const auto &loop: loops) { // loop over loop (letter R have internal/external loops)
for (const auto &edge: loop) { // loop over edge in the loop
if (edge.is_bezier) { // in case the edge is a quadratic Bézier
count_cross += number_of_intersection_ray_against_quadratic_bezier(
org, dir,
edge.ps, edge.pc, edge.pe);
} else { // in case the edge is a line segment
count_cross += number_of_intersection_ray_against_edge(
org, dir,
edge.ps, edge.pe);
}
}
}
if (count_cross % 2 == 1) { // Jordan's curve theory
img_data[ih * width + iw] = 0; // paint black if it is inside
}
}
}
const auto output_file_path = std::filesystem::path(PROJECT_SOURCE_DIR) / "output.png";
stbi_write_png(output_file_path.string().c_str(), width, height, 1, img_data.data(), width);
}
Binary file added task02/output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b50236d

Please sign in to comment.