Skip to content

Commit bf44f7a

Browse files
committed
add stencil example
1 parent 07e932d commit bf44f7a

File tree

2 files changed

+334
-0
lines changed

2 files changed

+334
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ twgl.setUniforms(progInfo, {
446446
* [zoom-around](http://twgljs.org/examples/zoom-around.html)
447447
* [text](http://twgljs.org/examples/text.html)
448448
* [kaleidoscope](http://twgljs.org/examples/kaleidoscope.html)
449+
* [stencil](http://twgljs.org/examples/stencil.html)
449450
* [tunnel](http://twgljs.org/examples/tunnel.html)
450451
* [GPGPU particles](http://twgljs.org/examples/gpgpu-particles.html)
451452
* [item list](http://twgljs.org/examples/itemlist.html)

examples/stencil.html

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf8">
5+
<!--
6+
7+
@license twgl.js Copyright (c) 2015, Gregg Tavares All Rights Reserved.
8+
Available via the MIT license.
9+
see: http://github.com/greggman/twgl.js for details
10+
11+
-->
12+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
13+
<meta property="og:title" content="TWGL.js - stencil" />
14+
<meta property="og:type" content="website" />
15+
<meta property="og:image" content="http://twgljs.org/examples/screenshots/stencil.png" />
16+
<meta property="og:description" content="TWGL.js - stencil" />
17+
<meta property="og:url" content="http://twgljs.org" />
18+
19+
<meta name="twitter:card" content="summary_large_image">
20+
<meta name="twitter:site" content="@greggman">
21+
<meta name="twitter:creator" content="@greggman">
22+
<meta name="twitter:domain" content="twgljs.org">
23+
<meta name="twitter:title" content="TWGL.js - stencil">
24+
<meta name="twitter:url" content="http://twgljs.org/examples/primitives.html">
25+
<meta name="twitter:description" content="TWGL.js - stencil">
26+
<meta name="twitter:image:src" content="http://twgljs.org/examples/screenshots/stencil.png">
27+
28+
<link href="/resources/images/twgljs-icon.png" rel="shortcut icon" type="image/png">
29+
30+
<title>twgl.js - stencil</title>
31+
<style>
32+
body {
33+
margin: 0;
34+
font-family: monospace;
35+
}
36+
canvas {
37+
display: block;
38+
width: 100vw;
39+
height: 100vh;
40+
}
41+
#b {
42+
position: absolute;
43+
top: 10px;
44+
width: 100%;
45+
text-align: center;
46+
z-index: 2;
47+
}
48+
</style>
49+
</head>
50+
<body>
51+
<canvas id="c"></canvas>
52+
<div id="b"><a href="http://twgljs.org">twgl.js</a> - stencil</div>
53+
</body>
54+
<script id="vs" type="notjs">
55+
uniform mat4 u_worldViewProjection;
56+
uniform vec3 u_lightWorldPos;
57+
uniform mat4 u_world;
58+
uniform mat4 u_viewInverse;
59+
uniform mat4 u_worldInverseTranspose;
60+
61+
attribute vec4 a_position;
62+
attribute vec3 a_normal;
63+
attribute vec2 a_texcoord;
64+
65+
varying vec4 v_position;
66+
varying vec2 v_texCoord;
67+
varying vec3 v_normal;
68+
varying vec3 v_surfaceToLight;
69+
varying vec3 v_surfaceToView;
70+
71+
void main() {
72+
v_texCoord = a_texcoord;
73+
v_position = (u_worldViewProjection * a_position);
74+
v_normal = (u_worldInverseTranspose * vec4(a_normal, 0)).xyz;
75+
v_surfaceToLight = u_lightWorldPos - (u_world * a_position).xyz;
76+
v_surfaceToView = (u_viewInverse[3] - (u_world * a_position)).xyz;
77+
gl_Position = v_position;
78+
}
79+
</script>
80+
<script id="fs" type="notjs">
81+
precision mediump float;
82+
83+
varying vec4 v_position;
84+
varying vec2 v_texCoord;
85+
varying vec3 v_normal;
86+
varying vec3 v_surfaceToLight;
87+
varying vec3 v_surfaceToView;
88+
89+
uniform vec4 u_lightColor;
90+
uniform vec4 u_diffuseMult;
91+
uniform sampler2D u_diffuse;
92+
uniform vec4 u_specular;
93+
uniform float u_shininess;
94+
uniform float u_specularFactor;
95+
96+
vec4 lit(float l ,float h, float m) {
97+
return vec4(1.0,
98+
abs(l),//max(l, 0.0),
99+
(l > 0.0) ? pow(max(0.0, h), m) : 0.0,
100+
1.0);
101+
}
102+
103+
void main() {
104+
vec4 diffuseColor = texture2D(u_diffuse, v_texCoord) * u_diffuseMult;
105+
vec3 a_normal = normalize(v_normal);
106+
vec3 surfaceToLight = normalize(v_surfaceToLight);
107+
vec3 surfaceToView = normalize(v_surfaceToView);
108+
vec3 halfVector = normalize(surfaceToLight + surfaceToView);
109+
vec4 litR = lit(dot(a_normal, surfaceToLight),
110+
dot(a_normal, halfVector), u_shininess);
111+
vec4 outColor = vec4((
112+
u_lightColor * (diffuseColor * litR.y +
113+
u_specular * litR.z * u_specularFactor)).rgb,
114+
diffuseColor.a);
115+
gl_FragColor = outColor;
116+
}
117+
</script>
118+
<script src="../3rdparty/chroma.min.js"></script>
119+
<script type="module">
120+
import * as twgl from '../dist/7.x/twgl-full.module.js';
121+
twgl.setDefaults({attribPrefix: "a_"});
122+
const m4 = twgl.m4;
123+
const gl = document.querySelector("#c").getContext("webgl", { stencil: true });
124+
const programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
125+
126+
const shapes = [
127+
twgl.primitives.createPlaneBufferInfo(gl, 2, 2),
128+
twgl.primitives.createCubeBufferInfo(gl, 2),
129+
twgl.primitives.createSphereBufferInfo(gl, 1, 24, 12),
130+
twgl.primitives.createTruncatedConeBufferInfo(gl, 1, 0, 2, 24, 1),
131+
twgl.primitives.createCresentBufferInfo(gl, 1, 1, 0.5, 0.1, 24),
132+
twgl.primitives.createCylinderBufferInfo(gl, 1, 2, 24, 2),
133+
twgl.primitives.createTorusBufferInfo(gl, 1, 0.4, 24, 12),
134+
twgl.primitives.createSphereBufferInfo(gl, 1, 4, 3),
135+
];
136+
137+
function rand(min, max) {
138+
return min + Math.random() * (max - min);
139+
}
140+
141+
// Shared values
142+
const lightWorldPosition = [1, 8, -10];
143+
const lightColor = [1, 1, 1, 1];
144+
const camera = m4.identity();
145+
const view = m4.identity();
146+
const viewProjection = m4.identity();
147+
148+
const tex = twgl.createTexture(gl, {
149+
min: gl.NEAREST,
150+
mag: gl.NEAREST,
151+
src: [
152+
255, 255, 255, 255,
153+
192, 192, 192, 255,
154+
192, 192, 192, 255,
155+
255, 255, 255, 255,
156+
],
157+
});
158+
159+
const whiteTex = twgl.createTexture(gl, {
160+
min: gl.NEAREST,
161+
mag: gl.NEAREST,
162+
src: [
163+
255, 255, 255, 255,
164+
],
165+
});
166+
167+
const worlds = [];
168+
for (let w = 1; w < shapes.length; ++w) {
169+
const objects = [];
170+
const drawObjects = [];
171+
const numObjects = 100;
172+
const baseHue = w * 50;
173+
for (let ii = 0; ii < numObjects; ++ii) {
174+
const uniforms = {
175+
u_lightWorldPos: lightWorldPosition,
176+
u_lightColor: lightColor,
177+
u_diffuseMult: chroma.hsv((baseHue + rand(0, 40)) % 360, 0.4, 0.8).gl(),
178+
u_specular: [1, 1, 1, 1],
179+
u_shininess: 50,
180+
u_specularFactor: 1,
181+
u_diffuse: tex,
182+
u_viewInverse: camera,
183+
u_world: m4.identity(),
184+
u_worldInverseTranspose: m4.identity(),
185+
u_worldViewProjection: m4.identity(),
186+
};
187+
drawObjects.push({
188+
programInfo: programInfo,
189+
bufferInfo: shapes[w],
190+
uniforms: uniforms,
191+
});
192+
objects.push({
193+
translation: [rand(-10, 10), rand(-10, 10), rand(-10, 10)],
194+
ySpeed: rand(0.05, 0.1),
195+
zSpeed: rand(0.05, 0.1),
196+
timeOffset: rand(0, 100),
197+
uniforms: uniforms,
198+
});
199+
}
200+
worlds.push({
201+
objects,
202+
drawObjects,
203+
});
204+
}
205+
206+
const directions = [
207+
[-1, 0, 0],
208+
[ 1, 0, 0],
209+
[ 0, -1, 0],
210+
[ 0, 1, 0],
211+
[ 0, 0, -1],
212+
[ 0, 0, 1],
213+
];
214+
215+
function render(time) {
216+
time *= 0.001;
217+
twgl.resizeCanvasToDisplaySize(gl.canvas);
218+
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
219+
220+
gl.enable(gl.DEPTH_TEST);
221+
gl.enable(gl.STENCIL_TEST);
222+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
223+
224+
const projection = m4.perspective(30 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.5, 100);
225+
const eye = [1, 4, -20];
226+
const target = [0, 0, 0];
227+
const up = [0, 1, 0];
228+
229+
m4.lookAt(eye, target, up, camera);
230+
m4.inverse(camera, view);
231+
m4.multiply(projection, view, viewProjection);
232+
233+
gl.stencilOp(
234+
gl.KEEP, // what to do if the stencil test fails
235+
gl.KEEP, // what to do if the depth test fails
236+
gl.REPLACE, // what to do if both tests pass
237+
);
238+
gl.useProgram(programInfo.program);
239+
240+
twgl.setBuffersAndAttributes(gl, programInfo, shapes[0]);
241+
directions.forEach((direction, i) => {
242+
gl.stencilFunc(
243+
gl.ALWAYS, // the test
244+
i + 1, // reference value
245+
0xFF, // mask
246+
);
247+
const u_world = m4.identity();
248+
m4.rotateY(u_world, time * -0.1, u_world);
249+
m4.rotateZ(u_world, time * 0.2, u_world);
250+
m4.scale(u_world, [3, 3, 3], u_world);
251+
m4.translate(u_world, direction, u_world);
252+
m4.rotateZ(u_world, direction[0] * Math.PI * 0.5, u_world);
253+
if (direction[1]) {
254+
m4.rotateX(u_world, (direction[1] * 0.5 + 0.5) * Math.PI, u_world);
255+
}
256+
m4.rotateX(u_world, direction[2] * Math.PI * 0.5, u_world);
257+
const u_worldInverseTranspose = m4.transpose(m4.inverse(u_world));
258+
const u_worldViewProjection = m4.multiply(viewProjection, u_world);
259+
twgl.setUniforms(programInfo, {
260+
u_lightWorldPos: [0, 0, -10],
261+
u_lightColor: [1, 1, 1, 1],
262+
u_diffuseMult: [1, 1, 1, 1],
263+
u_specular: [0, 0, 0, 1],
264+
u_shininess: 1,
265+
u_specularFactor: 1,
266+
u_diffuse: tex,
267+
u_world,
268+
u_viewInverse: camera,
269+
u_worldInverseTranspose,
270+
u_worldViewProjection,
271+
});
272+
twgl.drawBufferInfo(gl, shapes[0]);
273+
});
274+
275+
gl.stencilOp(
276+
gl.KEEP, // what to do if the stencil test fails
277+
gl.KEEP, // what to do if the depth test fails
278+
gl.KEEP, // what to do if both tests pass
279+
);
280+
281+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
282+
worlds.forEach(({ objects, drawObjects }, i) => {
283+
gl.stencilFunc(
284+
gl.EQUAL, // the test
285+
i, // reference value
286+
0xFF, // mask
287+
);
288+
gl.disable(gl.DEPTH_TEST);
289+
290+
gl.useProgram(programInfo.program);
291+
twgl.setBuffersAndAttributes(gl, programInfo, shapes[1]);
292+
twgl.setUniforms(programInfo, {
293+
u_lightWorldPos: [0, 0, -10],
294+
u_lightColor: [1, 1, 1, 1],
295+
u_diffuseMult: chroma.hsv((i * 50 + 180) % 360, 0.4, 0.8).gl(),
296+
u_specular: [0, 0, 0, 1],
297+
u_shininess: 1,
298+
u_specularFactor: 1,
299+
u_diffuse: whiteTex,
300+
u_world: m4.translate(m4.rotationX(Math.PI * -0.5), [0, 0, 0.5]),
301+
u_viewInverse: m4.identity(),
302+
u_worldInverseTranspose: m4.identity(),
303+
u_worldViewProjection: m4.identity(),
304+
});
305+
twgl.drawBufferInfo(gl, shapes[1]);
306+
307+
gl.enable(gl.DEPTH_TEST);
308+
gl.clear(gl.DEPTH_BUFFER_BIT);
309+
310+
objects.forEach(function(obj) {
311+
const uni = obj.uniforms;
312+
const world = uni.u_world;
313+
m4.identity(world);
314+
m4.rotateY(world, time * obj.ySpeed + obj.timeOffset, world);
315+
m4.rotateZ(world, time * obj.zSpeed + obj.timeOffset, world);
316+
m4.translate(world, obj.translation, world);
317+
m4.rotateX(world, time * 0.2 + obj.timeOffset, world);
318+
m4.transpose(m4.inverse(world, uni.u_worldInverseTranspose), uni.u_worldInverseTranspose);
319+
m4.multiply(viewProjection, uni.u_world, uni.u_worldViewProjection);
320+
});
321+
322+
twgl.drawObjectList(gl, drawObjects);
323+
});
324+
325+
requestAnimationFrame(render);
326+
}
327+
requestAnimationFrame(render);
328+
329+
</script>
330+
</html>
331+
332+
333+

0 commit comments

Comments
 (0)