Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ShenCiao committed Sep 17, 2023
0 parents commit dd87325
Show file tree
Hide file tree
Showing 20 changed files with 8,382 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Dependencies
/node_modules

# Production
/build

# Generated files
.docusaurus
.cache-loader

# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

.idea/
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Brush Stroke Tutorial

This is the code repository for "Brush Stroke Tutorial," powered by [Docusaurus](https://docusaurus.io/).
We may change the host and domain. Remember to star this code repository instead of bookmark the website.

The website will be WIP for a long time since rendering brush strokes with GPU is a newly emerged research topic.
Shen Ciao continuously update tutorial-style articles on (potentially) influential research works.

## Be critical
Most contents come from the research *[Ciallo: The next generation vector paint program][Ciallo]*.
It's impossible to create a perfect tutorial in the first place, so we eagerly need critiques and suggestions.
We would be grateful for creating issues or pull requests to fix typos, correct facto mistakes, and revise terrible terminology naming in this tutorial.

## Build and Develop
Follow the guidance in [Docusaurus's documentation](https://docusaurus.io/docs/installation).

The textual contents on the website are written in markdown, you can easily modify them without extra knowledge about web development.

The project is built with javascript libraries include:
- React
- Threejs: WebGL wrapper
- React-codemirror: Code editor

While creating this tutorial, shen has just started learning these JavaScript libraries.
If you are familiar with these libraries and have some engineering suggestions, please raise them in the issue.
Welcome any helps to improve the code editor.

## Citation
@inproceedings{Ciallo,
author = {Ciao, Shen and Wei, Li-Yi},
title = {Ciallo: The next-Generation Vector Paint Program},
year = {2023},
isbn = {9798400701436},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3587421.3595418},
doi = {10.1145/3587421.3595418},
booktitle = {ACM SIGGRAPH 2023 Talks},
articleno = {67},
numpages = {2},
keywords = {Digital painting, stylized stroke, arrangement, vector graphics. coloring, graphics processing unit (GPU)},
location = {Los Angeles, CA, USA},
series = {SIGGRAPH '23}
}

## License
Shield: [![CC BY-SA 4.0][cc-by-sa-shield]][cc-by-sa]

This work is licensed under a
[Creative Commons Attribution-ShareAlike 4.0 International License][cc-by-sa].

[![CC BY-SA 4.0][cc-by-sa-image]][cc-by-sa]

[cc-by-sa]: http://creativecommons.org/licenses/by-sa/4.0/
[cc-by-sa-image]: https://licensebuttons.net/l/by-sa/4.0/88x31.png
[cc-by-sa-shield]: https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg

Feel free to use the code, algorithms and demo images in your academic or commercial project, but you cannot state them are original.

The project will change into a copyleft license after updating the content about the 3D stroke.

[Ciallo]: https://github.com/ShenCiao/Ciallo
3 changes: 3 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
35 changes: 35 additions & 0 deletions docs/Appendix/Vector-fill/Vector-fill.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
title: Pre-introduction to Vector Fill
sidebar_label: Vector Fill
---

You may have learned how to render brush strokes on polyline curves.
If you want to develop a basic paint program like what I did, the next logical step is to learn how to fill color.

![VectorFill](./vector-fill.gif)

_Vector fill demo_

We've found that filling color is precisely the _2D Arrangement_ and _Point Location_ problem in computational geometry (plus rendering a polygon).
Basically all textbooks about computational geometry cover these problems and the corresponding algorithms to solve them.
It's very straightforward how to apply once you've learned about them.
But before you delve into the intricate details in a textbook, I will offer a brief overview to provide a general understanding.

We are given a set of 2D polylines (our vector drawings) and a query point,
the problem is to find the region enclosed by polylines and contains the query point.
To achieve this, we need first construct a 2D arrangement object whose official definition is:
A subdivision of the plane induced by the curves into vertices, edges, and faces,
which is typically stored in a doubly-connected edge list (DCEL) data structure.

![Arrangement2D](./arrangement.png)

Hopefully, it sounds familiar and reminds you of the data structure to store a 3D mesh.
In fact, a naive 2D arrangement is nothing more than a 2D polygon mesh (or meshes).
And to locate a query point, a native solution is to iterate through all faces from the mesh and test if the query point is inside.

From an introductory-level textbook, you will learn how to construct a polygon mesh (the arrangement object) from line segments and
algorithms to locate a point better than the naive solution.
To dive deeper, you may try using the [CGAL 2D arrangement library](https://doc.cgal.org/latest/Arrangement_on_surface_2/index.html)
and learn the arrangement constructed from 2D polylines, which is slightly different with a naive polygon mesh.

I hope the "2D mesh metaphor" will help you better understand the problems and solutions. Wish you happy learning!
Binary file added docs/Appendix/Vector-fill/arrangement.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Appendix/Vector-fill/vector-fill.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions docs/Appendix/_category_.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
position: 20
collapsible: true
collapsed: true
link:
type: generated-index
customProps:
description: This description can be used in the swizzled DocCard
3 changes: 3 additions & 0 deletions docs/Basics/Vanilla.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
position: 1
---
9 changes: 9 additions & 0 deletions docs/Basics/_category_.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
position: 3
label: 'Basics'
collapsible: false
collapsed: false
className: red
link:
type: generated-index
customProps:
description: This description can be used in the swizzled DocCard
117 changes: 117 additions & 0 deletions docs/Introduction/Introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
title: Introduction
sidebar_position: 2
---

This tutorial series will teach you how to use the **modern GPU** graphics pipeline to render **brush strokes** on **vector curves**.
The contents mainly come from my research work [Ciallo: The next generation vector paint program][Ciallo].
I will introduce this tutorial from the three aspects above.

## Modern GPU

![sketchpad](./sketchpad.gif)

_Draw lines in Ivan Sutherland's Sketchpad._

Drawing lines or rendering strokes is one of the oldest topics in Computer Graphics.
You can easily find a lot of pioneering works, for example, [Bresenham's line algorithm](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm).
They emerged from an era with certain conditions:

- Programs ran without the benefit of parallelization.
- Programs could access framebuffer directly without significant performance penalty.

But time has changed, now we have modern GPU hardware crafted for graphics and parallel computing,
and directly accessing a GPU framebuffer from a CPU can significantly hurt the performance.
So old algorithms may not satisfy your needs for real-time rendering.

In this tutorial, you will learn about the stroke rendering algorithms designed for the GPU graphics pipeline.
We (I and my mentor [Liyi-Wei](https://www.liyiwei.org/)) name these algorithms as _Articulated_ in our paper (mainly because they look like drawing an articulated arm).
I assume you are familiar with a graphics API like OpenGL or D3D.
This tutorial will concentrate more on the high-level algorithms than the implementation details.

Although graphics APIs provide us line primitives, including `LINES`, `LINE_STRIP`, and `LINE_LOOP`,
there are several well-known issues when using these primitives directly.
Check out Matt Deslauries' article [Drawing Lines is Hard](https://mattdesl.svbtle.com/drawing-lines-is-hard#line-primitives_1) if you know nothing about them.
As for us, the most significant issue is the limitation on the maximum line width or stroke radius.
We must be able to fully control the radius values when rendering brush strokes.

## Brush Strokes

Brush strokes refer to strokes drawn with the paint tool in graphics software such as Photoshop or Krita.
Artists configure their digital brushes to control stroke properties like radius or stylization,
then stroke on the canvas with dedicated input devices: Tablet and Stylus.
If you're unfamiliar with tablets and styluses, you can watch the video below for more information:

[![Tablet](https://img.youtube.com/vi/83BRMfjJXIk/maxresdefault.jpg)](https://www.youtube.com/watch?app=desktop&v=83BRMfjJXIk)

While you may recognize a brush stroke by its stylization, another crucial property could be ignored: the varying radius along the stroke.
The radii are typically generated from the pressure values as a stylus presses and moves on a tablet.
For experienced artists, one of the highest priorities is to configure the mapping function from pen pressure to brush radius after installing a painting program.

In this tutorial, you will learn to render a stroke with mutable radius, and the most popular way to stylize it called "Stamp."
You cannot find them elsewhere since they come from our own research.
Additionally, GPU brush stroke rendering a newly emerged topic.
Researchers will develop more novel methods in the future.
So I will continuously update this tutorial series to teach them.
Make sure to star our [code repository] for easy access to the latest updates.

## Vector Curves

Mutable radius is imperative for the most artists when working on digital painting,
but it's not defined in public vector standards like SVG.
This limitation is one of the primary reasons why lots of digital artists don't use vector workflow.
(Another one is filling color.)

To support the mutable radius, we will render a unique type of vector curve:
An ordered list of points (polyline) with radius values assigned to each point.
As a stylus is pressed and moved on a tablet, the program generate a sequence of points to record the trace of movement.
Additionally, the pen pressure is transformed into the radius value assigned to each point.

We can approximate any type of curve by increasing the number of points in a polyline, whether freehand-drawn or mathematically defined.

## Structure

Although the algorithms are very straightforward, I know how hard it could be to learn and replicate a research work.
That's why I created this tutorial, designed with a smooth learning curve and providing seamless coding environments.

Start with the Basic part, which covers the basics of the rendering methods.
Please read the articles in the Basic part in order, or you may miss something important.
Next, select your favorite topics to learn.
I will list the extra prerequisites at the very beginning of the articles.

Wish you happy learning!

## Cite

```
@inproceedings{Ciallo2023,
author = {Ciao, Shen and Wei, Li-Yi},
title = {Ciallo: The next-Generation Vector Paint Program},
year = {2023},
isbn = {9798400701436},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3587421.3595418},
doi = {10.1145/3587421.3595418},
booktitle = {ACM SIGGRAPH 2023 Talks},
articleno = {67},
numpages = {2},
keywords = {Digital painting, stylized stroke, arrangement, vector graphics. coloring, graphics processing unit (GPU)},
location = {Los Angeles, CA, USA},
series = {SIGGRAPH '23}
}
```

:::note Research Tip

To demonstrate your research work, select vector drawings have mutable radius or pen pressure data.
Regular vector drawing datasets don't contain them.

- Zeyu Wang's work: [paper](https://dl.acm.org/doi/10.1145/3450626.3459819)
- [Blender Grease Pencil](https://cloud.blender.org/p/gallery/5b642e25bf419c1042056fc6)
- Tell me more...

:::

[code repository]: https://github.com/ShenCiao/BrushStrokeTutorial
[Ciallo]: https://github.com/ShenCiao/Ciallo
Binary file added docs/Introduction/sketchpad.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions docs/toc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: Table of Contents
sidebar_position: 1
slug: /
---

This tutorial will teach you how to render brush strokes with the modern GPU graphics pipeline.

If you like this tutorial, please star the [code repository] instead of bookmark the website since the domain might be changed.

## Contents

- [Introduction](./introduction)
- Basics
- Vanilla
- Vanilla with mutable radius
- Stamp
- Stamp with mutable radius 1
- Stamp with mutable radius 2
- An interleave

## In Progress

Telling a good story is as hard as inventing a novel method and teaching it.

### Airbrush

Airbrush is a special type of stamp brush.
Learn the mathematical derivation from discrete to continuous stamp to get a "continuous airbrush".

### Stamp Density and "Ratio-distance"

Control stamp density along the polyline and render a critical stamp placing pattern called ratio-distance.
Very important for a serious project.

### 3D Stroke

Learn how to extend the rendering methods to 3D space.

I'm integrating it into the Blender Grease Pencil:

<iframe width="100%" height="500" src="https://www.youtube.com/embed/Q7_3IhgHOZM?start=30"
title="Blender Grease Pencil Stamp Brush Demo"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen>
</iframe>

[code repository]: https://github.com/ShenCiao/BrushStrokeTutorial
Loading

0 comments on commit dd87325

Please sign in to comment.