|
@@ -2,46 +2,174 @@
|
|
|
* @author meatbags / xavierburrow.com, github/meatbags
|
|
|
*
|
|
|
* Colour halftone shader
|
|
|
+ * Shape uniform (1 = circle, 2 = euclidean dot, 3 = ellipse, 4 = line, 5 = square)
|
|
|
+ * Blending mode (1 = linear, 2 = add, 3 = multiply, 4 = lighter colour, 5 = darker colour)
|
|
|
*/
|
|
|
|
|
|
THREE.HalftoneShader = {
|
|
|
uniforms: {
|
|
|
+ "shape": {value: 1},
|
|
|
"tDiffuse": {value: null},
|
|
|
"radius": {value: 5},
|
|
|
"rC": {value: Math.PI * 0.25},
|
|
|
"rM": {value: Math.PI * 0.33},
|
|
|
"rY": {value: Math.PI * 0.66},
|
|
|
- "shape": {value: 1},
|
|
|
"width": {value: 1},
|
|
|
- "height": {value: 1}
|
|
|
+ "height": {value: 1},
|
|
|
+ "blending": {value: 0},
|
|
|
+ "blendingMode": {value: 1},
|
|
|
+ "greyscale": {value: false},
|
|
|
+ "disable": {value: false}
|
|
|
},
|
|
|
vertexShader: `
|
|
|
- varying vec2 vUv;
|
|
|
+ varying vec2 vUV;
|
|
|
|
|
|
void main() {
|
|
|
- vUv = uv;
|
|
|
+ vUV = uv;
|
|
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
|
}`,
|
|
|
fragmentShader: `
|
|
|
- varying vec2 vUv;
|
|
|
+ #define SQRT2 1.41421356
|
|
|
+ #define SQRT2_HALF 0.70710678
|
|
|
+ #define SQRT2_MINUS_ONE 0.41421356
|
|
|
+ #define SQRT2_HALF_MINUS_ONE 0.20710678
|
|
|
+
|
|
|
uniform sampler2D tDiffuse;
|
|
|
uniform float radius;
|
|
|
uniform float rC;
|
|
|
- uniform float rY;
|
|
|
uniform float rM;
|
|
|
+ uniform float rY;
|
|
|
uniform float width;
|
|
|
uniform float height;
|
|
|
+ uniform int shape;
|
|
|
+ uniform bool disable;
|
|
|
+ uniform float blending;
|
|
|
+ uniform int blendingMode;
|
|
|
+ uniform bool greyscale;
|
|
|
+
|
|
|
+ varying vec2 vUV;
|
|
|
|
|
|
- float rand(vec2 seed){
|
|
|
- return fract(sin(dot(seed.xy, vec2(12.9898,78.233))) * 43758.5453);
|
|
|
+ float blend(float a, float b, float t) {
|
|
|
+ return a * (1.0 - t) + b * t;
|
|
|
}
|
|
|
|
|
|
- vec2 gridReference(vec2 coord, float step, float rotation) {
|
|
|
- return vec2(0, 0);
|
|
|
+ float blendColour(float a, float b, float t) {
|
|
|
+ if (blendingMode == 1) {
|
|
|
+ return blend(a, b, t);
|
|
|
+ } else if (blendingMode == 2) {
|
|
|
+ return blend(a, min(1.0, a + b), t);
|
|
|
+ } else if (blendingMode == 3) {
|
|
|
+ return blend(a, max(0.0, a * b), t);
|
|
|
+ } else if (blendingMode == 4) {
|
|
|
+ return blend(a, max(a, b), t);
|
|
|
+ } else {
|
|
|
+ return blend(a, min(a, b), t);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ float hypot(float x, float y) {
|
|
|
+ return sqrt(x * x + y * y);
|
|
|
+ }
|
|
|
+
|
|
|
+ float distanceTo(vec2 a, vec2 b) {
|
|
|
+ return hypot(b.x - a.x, b.y - a.y);
|
|
|
+ }
|
|
|
+
|
|
|
+ float shapeDistance(vec2 p, vec2 coord, vec2 n) {
|
|
|
+ float d = distanceTo(p, coord);
|
|
|
+
|
|
|
+ if (shape == 3) {
|
|
|
+ // ellipse
|
|
|
+ if (d != 0.0) {
|
|
|
+ float dp = abs((p.x - coord.x) / d * n.x + (p.y - coord.y) / d * n.y);
|
|
|
+ d = (d * (1.0 - SQRT2_HALF_MINUS_ONE)) + dp * d * SQRT2_MINUS_ONE;
|
|
|
+ }
|
|
|
+ } else if (shape == 4) {
|
|
|
+ // line
|
|
|
+ float dp = (p.x - coord.x) * n.x + (p.y - coord.y) * n.y;
|
|
|
+ d = hypot(n.x * dp, n.y * dp);
|
|
|
+ }
|
|
|
+
|
|
|
+ return d;
|
|
|
+ }
|
|
|
+
|
|
|
+ float shapeRadius(float r, vec2 p, vec2 coord) {
|
|
|
+ float theta = atan(p.y - coord.y, p.x - coord.x);
|
|
|
+ float sin_t = abs(sin(theta));
|
|
|
+ float cos_t = abs(cos(theta));
|
|
|
+
|
|
|
+ if (shape == 2) {
|
|
|
+ // euclidean dot
|
|
|
+ float square = r + ((sin_t > cos_t) ? r - sin_t * r : r - cos_t * r);
|
|
|
+ if (r <= 0.5) {
|
|
|
+ r = blend(r, square, r * 2.0);
|
|
|
+ } else {
|
|
|
+ float max_r = r + 2.0 * ((sin_t > cos_t) ? r - sin_t * r : r - cos_t * r);
|
|
|
+ r = blend(square, max_r, pow(abs((r - 0.5) * 2.0), 0.4));
|
|
|
+ }
|
|
|
+ } else if (shape == 5) {
|
|
|
+ // square
|
|
|
+ r += (sin_t > cos_t) ? r - sin_t * r : r - cos_t * r;
|
|
|
+ }
|
|
|
+
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+
|
|
|
+ vec2 gridReference(vec2 p, vec2 origin, vec2 n, float step, float aspect) {
|
|
|
+ // get nearest grid reference (rotated grid)
|
|
|
+ float dot_normal = n.x * (p.x - origin.x) + n.y * (p.y - origin.y);
|
|
|
+ float dot_line = -n.y * (p.x - origin.x) + n.x * (p.y - origin.y);
|
|
|
+ vec2 offset = vec2(n.x * dot_normal, n.y * dot_normal);
|
|
|
+ float offset_normal = mod(hypot(offset.x, offset.y), step);
|
|
|
+ float normal_scale = ((offset_normal < step * 0.5) ? -offset_normal : step - offset_normal) * ((dot_normal < 0.0) ? 1.0 : -1.0);
|
|
|
+ float offset_line = mod(hypot((p.x - offset.x) - origin.x, (p.y - offset.y) - origin.y), step);
|
|
|
+ float line_scale = ((offset_line < step * 0.5) ? -offset_line : step - offset_line) * ((dot_line < 0.0) ? 1.0 : -1.0);
|
|
|
+
|
|
|
+ return vec2(
|
|
|
+ p.x - n.x * normal_scale + n.y * line_scale,
|
|
|
+ p.y - n.y * normal_scale * aspect - n.x * line_scale
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
void main() {
|
|
|
- vec4 color = texture2D(tDiffuse, vUv);
|
|
|
- gl_FragColor = color;
|
|
|
+ if (!disable) {
|
|
|
+ vec2 origin = vec2(0, 0);
|
|
|
+ float step = radius / width;
|
|
|
+ float radius_max = step;
|
|
|
+ float aspect = height / width;
|
|
|
+ float aa = (step < 1.0 / width) ? step * 0.5 : 1.0 / width;
|
|
|
+ vec2 normC = vec2(cos(rC), sin(rC));
|
|
|
+ vec2 normM = vec2(cos(rM), sin(rM));
|
|
|
+ vec2 normY = vec2(cos(rY), sin(rY));
|
|
|
+
|
|
|
+ // sampling
|
|
|
+ vec2 coordC = gridReference(vUV, origin, normC, step, aspect);
|
|
|
+ vec2 coordM = gridReference(vUV, origin, normM, step, aspect);
|
|
|
+ vec2 coordY = gridReference(vUV, origin, normY, step, aspect);
|
|
|
+ float distC = shapeRadius(texture2D(tDiffuse, coordC).r, vUV, coordC) * radius_max - shapeDistance(vUV, coordC, normC);
|
|
|
+ float distM = shapeRadius(texture2D(tDiffuse, coordM).g, vUV, coordM) * radius_max - shapeDistance(vUV, coordM, normM);
|
|
|
+ float distY = shapeRadius(texture2D(tDiffuse, coordY).b, vUV, coordY) * radius_max - shapeDistance(vUV, coordY, normY);
|
|
|
+ float r = (distC > 0.0) ? clamp(0.0, 1.0, distC / aa) : 0.0;
|
|
|
+ float g = (distM > 0.0) ? clamp(0.0, 1.0, distM / aa) : 0.0;
|
|
|
+ float b = (distY > 0.0) ? clamp(0.0, 1.0, distY / aa) : 0.0;
|
|
|
+
|
|
|
+ if (blending != 0.0) {
|
|
|
+ vec4 colour = texture2D(tDiffuse, vUV);
|
|
|
+ r = blendColour(r, colour.r, blending);
|
|
|
+ g = blendColour(g, colour.g, blending);
|
|
|
+ b = blendColour(b, colour.b, blending);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (greyscale) {
|
|
|
+ r = (r + b + g) / 3.0;
|
|
|
+ g = r;
|
|
|
+ b = r;
|
|
|
+ }
|
|
|
+
|
|
|
+ // write
|
|
|
+ gl_FragColor = vec4(r, g, b, 1.0);
|
|
|
+ } else {
|
|
|
+ gl_FragColor = texture2D(tDiffuse, vUV);
|
|
|
+ }
|
|
|
}`
|
|
|
};
|