Filed Under Art

Hatching Shaders

visits: 904 | score: 0 posted by sysrpl on Sunday August 10, 2008 11:58 AM posted byon Sunday August 10, 2008 11:58 AM

Video: Halftone Comic Kid

Video: Hatch Style Shaders

Diagonal lines

Wavy horizontal lines

Hexagonal grid of circles

Unhatched scene to show surface diffusion

uniform float ambient; uniform vec3 diffuse; uniform float ring; uniform float shininess; uniform float specular; uniform int lights; uniform int style; varying vec3 eye; varying vec3 normal; varying vec3 vertex; uniform float thickness; float balance(float sample, float weight) { if (weight < 1.0) weight = sample + weight; return clamp(pow(weight, 5.0), 0.0, 1.0); } float diagonal(float sample) { vec2 pixel = floor(vec2(gl_FragCoord)); float a = 1.0; float b = mod(pixel.x - pixel.y, thickness); float c = thickness / 2.0; if (b < thickness) a = abs(b - c) / c; return balance(sample, a); } float waves(float sample) { vec2 pixel = floor(vec2(gl_FragCoord)); float a = 1.0; float b = mod(pixel.y + sin(pixel.x / 10.0) * 4.0, thickness); float c = thickness / 2.0; if (b < thickness) a = abs(b - c) / c; return balance(sample, a); } float circles(float sample) { vec2 pixel = floor(vec2(gl_FragCoord)); float b = thickness / 2.0; if (mod((pixel.y), thickness * 2.0) > thickness) pixel.x += b; pixel = mod(pixel, vec2(thickness)); float a = distance(pixel, vec2(b)) / (thickness * 0.65); return balance(sample, a); } vec3 shade(int index, vec3 eye, vec3 normal, vec3 color) { vec3 light = gl_LightSource[index].position.xyz + eye; vec3 c = gl_LightSource[index].diffuse.rgb; float w = gl_LightSource[index].position.w; vec3 l = normalize(light); float b = dot(normal, l) * w; if (b > 0.0) { color += diffuse * b * c; vec3 r = reflect(-l, normal); float s = pow(max(dot(r, eye), 0.0), shininess) * w; s = smoothstep(ring, 1.0, s); color += s * specular; } return color; } void main(void) { vec3 color = diffuse * ambient; vec3 e = normalize(eye); vec3 n = normalize(normal); for (int i = 0; i < lights; i++) color = shade(i, e, n, color); float hatch; float scale = color.r; if (style == 0) hatch = diagonal(scale); else if (style == 1) hatch = waves(scale); else if (style == 2) hatch = circles(scale); else hatch = 1.0; if (hatch > 0.25) color = vec3(1.0); gl_FragColor = vec4(color * hatch, 1); }

Rate this article

was playing around writing some realtime glsl shaders ideas and decided to implement a hatching shader. In my opinion the end result is somewhat nice. Below are some screen caps. You can judge for yourself.These shaders would be a nice enhancement to programmers and artists who use cel shading. You know how hand drawn comics sometimes use hatching for shading, this can be used to simulate that same look.As far as the details of how it's implemented, I'll say this: It's all done in one pass, and the style, waviness, and thickness of lines are controlled by variables passed to the shader.Here are some examples using different style parameters.Here is the glsl fragment shader I wrote that output all the above examples.