Skip to content

Commit 4437935

Browse files
committed
added post cartoon v
1 parent c7f68d7 commit 4437935

File tree

7 files changed

+917
-9
lines changed

7 files changed

+917
-9
lines changed

post-cartoon-iv/post.js

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import {
77
RepeatWrapping,
88
HalfFloatType,
99
RGBAFormat,
10+
UnsignedByteType,
11+
Vector2,
1012
} from "../third_party/three.module.js";
1113
import { ShaderPass } from "../js/ShaderPass.js";
14+
import { ShaderPingPongPass } from "../js/ShaderPingPongPass.js";
1215
import { getFBO } from "../js/FBO.js";
1316
import { shader as orthoVs } from "../shaders/ortho-vs.js";
1417
import { shader as sobel } from "../shaders/sobel.js";
@@ -17,6 +20,7 @@ import { shader as luma } from "../shaders/luma.js";
1720
import { generateParams as generatePaperParams } from "../js/paper.js";
1821
import { shader as darken } from "../shaders/blend-darken.js";
1922
import { shader as screen } from "../shaders/blend-screen.js";
23+
import { blur5 } from "../shaders/fast-separable-gaussian-blur.js";
2024

2125
import {
2226
Material as ColorMaterial,
@@ -30,6 +34,23 @@ const loader = new TextureLoader();
3034
const noiseTexture = loader.load("../assets/noise1.png");
3135
noiseTexture.wrapS = noiseTexture.wrapT = RepeatWrapping;
3236

37+
const blurFragmentShader = `#version 300 es
38+
precision highp float;
39+
40+
uniform sampler2D inputTexture;
41+
uniform vec2 direction;
42+
43+
${blur5}
44+
45+
in vec2 vUv;
46+
out vec4 fragColor;
47+
48+
void main() {
49+
vec2 size = vec2(textureSize(inputTexture, 0));
50+
fragColor = blur5(inputTexture, vUv, size, direction);
51+
}
52+
`;
53+
3354
const componentFragmentShader = `#version 300 es
3455
precision highp float;
3556
@@ -288,7 +309,7 @@ void main() {
288309
fragColor.rgb = blendDarken(fragColor.rgb, darkInk/255., border*.25 * shade);
289310
fragColor.rgb = blendDarken(fragColor.rgb, darkInk/255., darkIntensity * (1.-shadeHatch));
290311
fragColor.rgb = blendScreen(fragColor.rgb, brightInk/255., brightIntensity * whiteHatch);
291-
312+
292313
fragColor.a = 1.;
293314
}
294315
`;
@@ -302,14 +323,15 @@ class Post {
302323
this.params = {
303324
roughness: 0.2,
304325
metalness: 0.1,
305-
colorScale: 0.25,
326+
colorScale: 0.07,
306327
colorOffset: 0.25,
307328
colorWidth: 0.5,
308329
scale: 0.32,
309330
angle: 0,
310331
thickness: 0.7,
311332
noisiness: 0.003,
312333
contour: 2,
334+
blur: 2,
313335
border: 0.5,
314336
fill: 1,
315337
stroke: 1,
@@ -318,7 +340,7 @@ class Post {
318340
yellow: 0.6,
319341
black: 0.1,
320342
darkIntensity: 0.75,
321-
brightIntensity: 0.25,
343+
brightIntensity: 1,
322344
darkInk: new Color(30, 30, 30),
323345
brightInk: new Color(230, 230, 230),
324346
};
@@ -336,6 +358,7 @@ class Post {
336358
thickness: { value: this.params.thickness },
337359
contour: { value: this.params.contour },
338360
border: { value: this.params.border },
361+
blur: { value: this.params.blur },
339362
stroke: { value: this.params.stroke },
340363
fill: { value: this.params.fill },
341364
darkIntensity: { value: this.params.darkIntensity },
@@ -346,10 +369,26 @@ class Post {
346369
vertexShader: orthoVs,
347370
fragmentShader,
348371
});
372+
const blurShader = new RawShaderMaterial({
373+
uniforms: {
374+
inputTexture: { value: this.colorFBO.texture },
375+
direction: { value: new Vector2() },
376+
},
377+
vertexShader: orthoVs,
378+
fragmentShader: blurFragmentShader,
379+
});
380+
this.blurPass = new ShaderPingPongPass(renderer, blurShader, {
381+
format: RGBAFormat,
382+
type: UnsignedByteType,
383+
});
384+
this.blurShadePass = new ShaderPingPongPass(renderer, blurShader, {
385+
format: RGBAFormat,
386+
type: UnsignedByteType,
387+
});
349388
this.renderPass = new ShaderPass(renderer, shader);
350389
const componentShader = new RawShaderMaterial({
351390
uniforms: {
352-
colorTexture: { value: this.colorFBO.texture },
391+
colorTexture: { value: null },
353392
cyan: { value: this.params.cyan },
354393
magenta: { value: this.params.magenta },
355394
yellow: { value: this.params.yellow },
@@ -371,6 +410,8 @@ class Post {
371410
this.shadeFBO.setSize(w, h);
372411
this.renderPass.setSize(w, h);
373412
this.componentPass.setSize(w, h);
413+
this.blurPass.setSize(w, h);
414+
this.blurShadePass.setSize(w, h);
374415
}
375416

376417
render(scene, camera) {
@@ -390,6 +431,46 @@ class Post {
390431
this.renderer.setRenderTarget(null);
391432
scene.overrideMaterial = null;
392433

434+
this.blurPass.shader.uniforms.inputTexture.value = this.colorFBO.texture;
435+
for (let i = 0; i < 6; i++) {
436+
if (i < this.params.blur) {
437+
var d = (i + 1) * 2;
438+
this.blurPass.shader.uniforms.direction.value.set(d, 0);
439+
this.blurPass.render();
440+
this.blurPass.shader.uniforms.inputTexture.value = this.blurPass.fbos[
441+
this.blurPass.currentFBO
442+
].texture;
443+
this.blurPass.shader.uniforms.direction.value.set(0, d);
444+
this.blurPass.render();
445+
this.blurPass.shader.uniforms.inputTexture.value = this.blurPass.fbos[
446+
this.blurPass.currentFBO
447+
].texture;
448+
}
449+
}
450+
this.componentPass.shader.uniforms.colorTexture.value = this.blurPass.shader.uniforms.inputTexture.value = this.blurPass.fbos[
451+
this.blurPass.currentFBO
452+
].texture;
453+
454+
this.blurShadePass.shader.uniforms.inputTexture.value = this.shadeFBO.texture;
455+
for (let i = 0; i < 6; i++) {
456+
if (i < this.params.blur) {
457+
var d = (i + 1) * 2;
458+
this.blurShadePass.shader.uniforms.direction.value.set(d, 0);
459+
this.blurShadePass.render();
460+
this.blurShadePass.shader.uniforms.inputTexture.value = this.blurShadePass.fbos[
461+
this.blurShadePass.currentFBO
462+
].texture;
463+
this.blurShadePass.shader.uniforms.direction.value.set(0, d);
464+
this.blurShadePass.render();
465+
this.blurShadePass.shader.uniforms.inputTexture.value = this.blurShadePass.fbos[
466+
this.blurShadePass.currentFBO
467+
].texture;
468+
}
469+
}
470+
this.renderPass.shader.uniforms.shadeTexture.value = this.blurShadePass.shader.uniforms.inputTexture.value = this.blurShadePass.fbos[
471+
this.blurShadePass.currentFBO
472+
].texture;
473+
393474
this.componentPass.render();
394475
this.renderPass.render(true);
395476
}
@@ -411,11 +492,7 @@ class Post {
411492
.onChange(async (v) => {
412493
colorMat.uniforms.width.value = v;
413494
});
414-
// controllers["metalness"] = gui
415-
// .add(this.params, "metalness", 0., 1)
416-
// .onChange(async (v) => {
417-
// this.renderPass.shader.uniforms.metalness.value = v;
418-
// });
495+
419496
controllers["scale"] = gui
420497
.add(this.params, "scale", 0.1, 1)
421498
.onChange(async (v) => {
@@ -426,6 +503,7 @@ class Post {
426503
.onChange(async (v) => {
427504
this.renderPass.shader.uniforms.thickness.value = v;
428505
});
506+
controllers["blur"] = gui.add(this.params, "blur", 0, 7);
429507
controllers["contour"] = gui
430508
.add(this.params, "contour", 0, 5)
431509
.onChange(async (v) => {

post-cartoon-v/ColorMaterial.js

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import {
2+
MeshBasicMaterial,
3+
Vector2,
4+
Color,
5+
} from "../third_party/three.module.js";
6+
7+
class Material extends MeshBasicMaterial {
8+
constructor(options) {
9+
super(options);
10+
11+
this.params = {
12+
scale: 0.25,
13+
offset: 0.25,
14+
width: 0.5,
15+
};
16+
17+
this.uniforms = {
18+
resolution: { value: new Vector2(1, 1) },
19+
paperTexture: { value: null },
20+
scale: { value: this.params.scale },
21+
offset: { value: this.params.offset },
22+
width: { value: this.params.width },
23+
};
24+
25+
this.onBeforeCompile = (shader, renderer) => {
26+
for (const uniformName of Object.keys(this.uniforms)) {
27+
shader.uniforms[uniformName] = this.uniforms[uniformName];
28+
}
29+
30+
shader.vertexShader = shader.vertexShader.replace(
31+
`#include <common>`,
32+
`#include <common>
33+
out vec2 vCoords;
34+
out vec3 vPosition;
35+
out vec4 vWorldPosition;`
36+
);
37+
shader.vertexShader = shader.vertexShader.replace(
38+
`#include <uv_vertex>`,
39+
`#include <uv_vertex>
40+
vCoords = uv;
41+
vPosition = position;
42+
vWorldPosition = modelMatrix * vec4(position, 1.);// + vec4(normal.xyz, 0.);`
43+
);
44+
45+
shader.fragmentShader = shader.fragmentShader.replace(
46+
`#include <common>`,
47+
`#include <common>
48+
uniform vec2 resolution;
49+
uniform sampler2D paperTexture;
50+
uniform float scale;
51+
uniform float offset;
52+
uniform float width;
53+
54+
in vec2 vCoords;
55+
in vec3 vPosition;
56+
in vec4 vWorldPosition;
57+
#define TAU 6.28318530718
58+
59+
// Classic Perlin 3D Noise
60+
// by Stefan Gustavson
61+
//
62+
vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
63+
vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
64+
vec3 fade(vec3 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}
65+
66+
float cnoise(vec3 P){
67+
vec3 Pi0 = floor(P); // Integer part for indexing
68+
vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
69+
Pi0 = mod(Pi0, 289.0);
70+
Pi1 = mod(Pi1, 289.0);
71+
vec3 Pf0 = fract(P); // Fractional part for interpolation
72+
vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
73+
vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
74+
vec4 iy = vec4(Pi0.yy, Pi1.yy);
75+
vec4 iz0 = Pi0.zzzz;
76+
vec4 iz1 = Pi1.zzzz;
77+
78+
vec4 ixy = permute(permute(ix) + iy);
79+
vec4 ixy0 = permute(ixy + iz0);
80+
vec4 ixy1 = permute(ixy + iz1);
81+
82+
vec4 gx0 = ixy0 / 7.0;
83+
vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5;
84+
gx0 = fract(gx0);
85+
vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
86+
vec4 sz0 = step(gz0, vec4(0.0));
87+
gx0 -= sz0 * (step(0.0, gx0) - 0.5);
88+
gy0 -= sz0 * (step(0.0, gy0) - 0.5);
89+
90+
vec4 gx1 = ixy1 / 7.0;
91+
vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5;
92+
gx1 = fract(gx1);
93+
vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
94+
vec4 sz1 = step(gz1, vec4(0.0));
95+
gx1 -= sz1 * (step(0.0, gx1) - 0.5);
96+
gy1 -= sz1 * (step(0.0, gy1) - 0.5);
97+
98+
vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
99+
vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
100+
vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
101+
vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
102+
vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
103+
vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
104+
vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
105+
vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
106+
107+
vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
108+
g000 *= norm0.x;
109+
g010 *= norm0.y;
110+
g100 *= norm0.z;
111+
g110 *= norm0.w;
112+
vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
113+
g001 *= norm1.x;
114+
g011 *= norm1.y;
115+
g101 *= norm1.z;
116+
g111 *= norm1.w;
117+
118+
float n000 = dot(g000, Pf0);
119+
float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
120+
float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
121+
float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
122+
float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
123+
float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
124+
float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
125+
float n111 = dot(g111, Pf1);
126+
127+
vec3 fade_xyz = fade(Pf0);
128+
vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
129+
vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
130+
float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
131+
return 2.2 * n_xyz;
132+
}
133+
134+
// from https://www.shadertoy.com/view/ltfXR4
135+
vec3 catmul_rom(vec3 p0, vec3 p1, vec3 p2, vec3 p3, float t)
136+
{
137+
return 0.5 * (
138+
(2.0 * p1) +
139+
(-p0 + p2) * t +
140+
(2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t * t +
141+
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t * t * t);
142+
}
143+
144+
vec3 color_spline(float t, bool wrap)
145+
{
146+
t = clamp(t, 0.0, 1.0);
147+
148+
const int s = 7;
149+
150+
vec3 p[s];
151+
p[0] = vec3(87,24,69) / 255.0;
152+
p[1] = vec3(144,13,62) / 255.0;
153+
p[2] = vec3(200,0,57) / 255.0;
154+
p[3] = vec3(255,86,51) / 255.0;
155+
p[4] = vec3(255,195,0) / 255.0;
156+
157+
p[s-2] = p[0];
158+
p[s-1] = p[1];
159+
160+
float m = wrap ? float(s - 2) : float(s - 3);
161+
float d = m * t;
162+
163+
int b = int(d);
164+
float dt = d - floor(d);
165+
166+
return catmul_rom(p[((b-1)+s)%s], p[b], p[b+1], p[(b+2)%s], dt);
167+
}
168+
169+
`
170+
);
171+
shader.fragmentShader = shader.fragmentShader.replace(
172+
"#include <dithering_fragment>",
173+
`#include <dithering_fragment>
174+
float n = smoothstep(.5-width, .5+width, .5 + .5 * cnoise(scale*vWorldPosition.xyz));
175+
gl_FragColor.rgb *= color_spline(n, true);
176+
gl_FragColor.rgb += offset;
177+
`
178+
);
179+
};
180+
}
181+
}
182+
183+
function generateParams(gui, material) {
184+
const params = material.params;
185+
gui
186+
.add(params, "scale", 0.1, 5)
187+
.onChange((v) => (material.uniforms.scale.value = v));
188+
//gui.add(params, "offset", 0, 1).onChange((v) => (material.metalness = v));
189+
}
190+
191+
export { Material, generateParams };

post-cartoon-v/Material.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {
2+
MeshStandardMaterial,
3+
Vector2,
4+
Color,
5+
} from "../third_party/three.module.js";
6+
7+
const Material = MeshStandardMaterial;
8+
9+
function generateParams(gui, material) {
10+
const params = material;
11+
gui.add(params, "roughness", 0, 1).onChange((v) => (material.roughness = v));
12+
gui.add(params, "metalness", 0, 1).onChange((v) => (material.metalness = v));
13+
}
14+
15+
export { Material, generateParams };

0 commit comments

Comments
 (0)