About
Applying for Ph.D.
diff --git a/Airbrush/index.html b/Airbrush/index.html index 08bd303..4a4e04f 100644 --- a/Airbrush/index.html +++ b/Airbrush/index.html @@ -3,42 +3,105 @@ -Airbrush
Airbrush is special. -An airbrush stroke looks like a solid vanilla stroke. -The main difference is its transparency gradient from middle axis to rim, as the figure shows.
-When artists draw 2D anime style illustrations or animations, airbrush has special usages. -Airbrush is mostly used for coloring, shading or highlighting, -while other brushes are mostly used for drawing outlines.
-Therefore, airbrush strokes commonly cover large areas of pixels comparing to outline strokes. -Optimizing airbrush strokes rendering algorithm can effectively improve the rendering performance. -In this tutorial, I will introduce how to render regular airbrush strokes, and a fancy theory to optimize it.
+Airbrush
An airbrush stroke looks like a solid vanilla stroke. +The main difference is its transparency gradient from middle axis to rim.
Technologically, traditional airbrush is a special type of stamp brush whose footprint is a transparent dot. When the footprints are very close and blend each other, they form an airbrush stroke with the transparency gradient, as the figure shows. If you've learned the previous chapter, rendering an airbrush is nothing more than creating a transparent dot as footprint.
-To get a desirable result like the above figure shows, stamp interval should be very small. -A pixel on the stroke samples the footprint more than 30 times at maximum, which hurts the rendering performance. -To address the issue, we want to model this process with calculus, let the stamp interval infinite small, and derive a mathematically continuous stroke.
++
+When artists draw illustrations or animations, airbrush has special uses. +It is commonly used for coloring, shading, or highlighting, while other brushes are typically used for drawing outlines.
+ +Therefore, airbrush strokes typically cover larger areas of pixels compared to outline strokes. +Optimizing airbrush stroke rendering algorithms can significantly improve rendering performance. +In this tutorial, I will present a fancy but efficient way for optimization and explain the theory behind it.
+Theory
+If we render airbrush strokes as a regular stamp strokes, stamp interval should be extremely small, as shown in the above GIF images. +A pixel on the stroke samples the footprint more than 30 times at maximum, which can significantly impact rendering performance. +To address the issue, we can model this process using calculus. +Let's assume the stamp interval is infinitely small, and derive a mathematically continuous stroke.
Imagine there are infinite number of stamps on an edge whose length is . The number of stamps is denoted with , and the interval between stamps is . For each pixel whose position is invoked by the edge, its alpha value is equal to blend all the alpha values from all the stamps on the edge. -The is the vector from stamp and current pixel.
+The is the vector from stamp and the current pixel.We define "alpha density" value, denoted with small alpha . -And let , whose is called alpha density field and define by the footprint. -Hopefully, the notations remind you of the probability density and probability values (or uniformly distributed charge on a bar). -They are following the same idea. -Replace the and we get:
+Let , is called alpha density field and defined by the footprint. +Hopefully, the notations remind you of the probability density and probability values +(or uniformly distributed charge on a bar, and we are calculating its electric field). +Replace the and we get:
+So, given any footprint defines a function (2D field), +we can calculate the stamp strokes' continuous form by substituting the footprint function into the formula.
We use the old local coordinate. Origin at , X and Y axes align to the tangent and normal direction. So and in the coordinate. The is the X position of stamp i. As and , and apply product integral (Volterra Integral) on the formula.
-If you know the Minkowski sum, it feels like that we are calculating Minkowski sum of a dot and a polyline. +But the dot is transparent, and we need to know the alpha value associated with each vector in the final vector set.
+Special Alpha Density
+To get a clearer comprehension of the theory, let's examine a special case. +Consider the alpha density value to be a point with a constant value, +indicating that a stamp stroke's footprint is a consistently transparent dot, defined by the function
+ +where is the constant alpha value within the radius , +and is the distance to dot's center.
+Substituting the into the allows us to partition the integral into two parts based on the value of :
+ +The second integral does not contribute to the expression and can be omitted for simplicity. +The first integral represents the integral over the segment of the edge that stamps can cover the current pixel. +The segment is marked with thick solid line in the figure below.
+ +The figure is exactly the same as the one when learning stamp strokes. +We denote the segment's length as , then the integral simplifies to a multiplication:
+ +In practice, the segment's length can be calculated with the two roots of the equation. +We are following the same idea as the vanilla or stamp stroke, rendering an edge correctly +Here is the implementation:
+ + +- fragment.glsl
As I mentioned above, airbrush's most important characteristic is its transparency gradient. +Let's derive this gradient function. +For simplicity, we assume stroke radius is a constant value . +It's not hard to deduce that in the bone area. +After substitution,
+ +So, the alpha value of a pixel in the bone area is independent of its x position. +This independence applies to any other footprints or alpha density fields as long as they are constrained within a dot. +Additionally, pixels in the bone area with the same y position always integral over the same length of a segment, therefore they have the same alpha value.
Pre-introduction to Vector Fill
You may have learned how to render brush strokes on polyline curves. diff --git a/Basics/Basics/index.html b/Basics/Basics/index.html index a5666ce..9751726 100644 --- a/Basics/Basics/index.html +++ b/Basics/Basics/index.html @@ -4,8 +4,8 @@
Basics
Brush strokes
diff --git a/Basics/Stamp/index.html b/Basics/Stamp/index.html index f705d3e..a39a3a0 100644 --- a/Basics/Stamp/index.html +++ b/Basics/Stamp/index.html @@ -4,8 +4,8 @@Stamp
Intro
@@ -87,12 +87,14 @@Loop
- vertex.glsl
- fragment.glsl
Loading... Loading...
-- vertex.glsl
- fragment.glsl
You can use RGBA values sampled from footprints directly, like what I did. +
You can use RGBA values sampled from footprints directly, like what I did here.
But for the most common scenario,
we set RGB values with users' brush setting and sample alpha values from a monochrome texture,
whose pixel's gray scale determines the opacity.
-Then apply random rotation and noise on each footprint to further stylize the stroke.
-The stamp index values currIndex
are helpful to generate consistent random numbers as seed values.
uniform vec3 RGB; // Users' brush setting
void main(){
float A = 0.0;
for each stamp
{
// Only sample opacity value from the footprint.
float opacity = texture(footprint, textureCoordinate);
// Apply alpha compositing to get the final alpha value.
A = A * (1.0-opacity) + opacity;
}
outColor = vec4(RGB, A);
}
Furthermore, we can apply random rotation or noise on each footprint to stylize the stroke.
+The stamp index values currIndex
are very helpful to generate consistent random numbers as seed values.
Square footprint
I introduce the brush rendering with the assumption that footprints are constrained within a dot area, which is the most common case in practice. @@ -116,6 +118,6 @@
Square foot
- vertex.glsl
- fragment.glsl
Loading... Loading...
-
- vertex.glsl
- fragment.glsl
I basically cannot perceive the deformation caused by the trick at the first glance.
I cannot perceive the deformation caused by the trick without careful investigation.