Skip to content

Commit 1b7eb70

Browse files
committed
add video texture example
1 parent 8e73ac6 commit 1b7eb70

File tree

5 files changed

+376
-0
lines changed

5 files changed

+376
-0
lines changed

index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ <h2><a href="%(url)s">%(name)s</a></h2>
195195
name: 'Google I/O 2011 WebGL Techniques and Performance Samples',
196196
by: 'Greggman',
197197
},
198+
{ url: '/video/video.html',
199+
img: '/video/video.png',
200+
name: 'Video Texture',
201+
by: 'Greggman',
202+
},
198203

199204
].map(function(sample, ndx) {
200205
var col = ndx % 3;

js/twgl-full.min.js

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

video/start.svg

Lines changed: 9 additions & 0 deletions
Loading

video/video.html

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
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+
<title>twgl.js - video texture</title>
14+
<style>
15+
body {
16+
margin: 0;
17+
font-family: monospace;
18+
color: white;
19+
}
20+
canvas {
21+
display: block;
22+
width: 100vw;
23+
height: 100vh;
24+
}
25+
#b {
26+
position: absolute;
27+
top: 10px;
28+
width: 100%;
29+
text-align: center;
30+
z-index: 2;
31+
}
32+
a {
33+
color: red;
34+
}
35+
.fulldialog {
36+
display: flex;
37+
display: -webkit-flex;
38+
flex-flow: column;
39+
-webkit-flex-flow: column;
40+
justify-content: center;
41+
align-content: center;
42+
align-items: center;
43+
-webkit-justify-content: center;
44+
-webkit-align-content: center;
45+
-webkit-align-items: center;
46+
47+
position: absolute;
48+
z-index: 10;
49+
left: 0;
50+
top: 0;
51+
width: 100%;
52+
height: 100%;
53+
background-color: rgba(0,0,0,0.8);
54+
}
55+
.fulldialog > * {
56+
padding: 1em;
57+
background-color: rgba(0,0,0,0.8);
58+
border: 1px solid #666;
59+
border-radius: 0.5em;
60+
}
61+
#start {
62+
background-color: rgba(0,0,0,0.0);
63+
}
64+
#start>div {
65+
text-align: center;
66+
}
67+
#start>div>div {
68+
text-align: left;
69+
color: red;
70+
font-weight: bold;
71+
}
72+
#start img {
73+
display: inline-block;
74+
width: 10em;
75+
height: 10em;
76+
}
77+
#start:after {
78+
box-shadow: inset 0 0 10em rgba(0,0,0,0.9);
79+
position: absolute;
80+
top: 0;
81+
left: 0;
82+
width: 100%;
83+
height: 100%;
84+
z-index: 12;
85+
content: "";
86+
}
87+
</style>
88+
</head>
89+
<body>
90+
<canvas id="c"></canvas>
91+
<div id="b"><a href="http://twgljs.org">twgl.js</a> - video texture</div>
92+
<video id="vid" style="display: none;">
93+
<source src="../color-adjust/sample-video.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"' />
94+
<source src="../color-adjust/sample-video.theora.ogv" type='video/ogg; codecs="theora, vorbis"' />
95+
<source src="../color-adjust/sample-video.webmvp8.webm" type='video/webm; codecs="vp8, vorbis"' />
96+
</video>
97+
<div id="start" class="fulldialog" style="display: none;">
98+
<div>
99+
<img src="start.svg" />
100+
</div>
101+
</div>
102+
</body>
103+
<script id="one-point-vs" type="notjs">
104+
uniform mat4 u_worldViewProjection;
105+
uniform vec3 u_lightWorldPos;
106+
uniform mat4 u_world;
107+
uniform mat4 u_viewInverse;
108+
uniform mat4 u_worldInverseTranspose;
109+
110+
attribute vec4 a_position;
111+
attribute vec3 a_normal;
112+
attribute vec2 a_texcoord;
113+
114+
varying vec4 v_position;
115+
varying vec2 v_texCoord;
116+
varying vec3 v_normal;
117+
varying vec3 v_surfaceToLight;
118+
varying vec3 v_surfaceToView;
119+
120+
void main() {
121+
v_texCoord = a_texcoord;
122+
v_position = (u_worldViewProjection * a_position);
123+
v_normal = (u_worldInverseTranspose * vec4(a_normal, 0)).xyz;
124+
v_surfaceToLight = u_lightWorldPos - (u_world * a_position).xyz;
125+
v_surfaceToView = (u_viewInverse[3] - (u_world * a_position)).xyz;
126+
gl_Position = v_position;
127+
}
128+
</script>
129+
<script id="one-point-fs" type="notjs">
130+
precision mediump float;
131+
132+
varying vec4 v_position;
133+
varying vec2 v_texCoord;
134+
varying vec3 v_normal;
135+
varying vec3 v_surfaceToLight;
136+
varying vec3 v_surfaceToView;
137+
138+
uniform vec4 u_lightColor;
139+
uniform vec4 u_diffuseMult;
140+
uniform sampler2D u_diffuse;
141+
uniform vec4 u_specular;
142+
uniform float u_shininess;
143+
uniform float u_specularFactor;
144+
145+
vec4 lit(float l ,float h, float m) {
146+
return vec4(1.0,
147+
abs(l),//max(l, 0.0),
148+
(l > 0.0) ? pow(max(0.0, h), m) : 0.0,
149+
1.0);
150+
}
151+
152+
void main() {
153+
vec4 diffuseColor = texture2D(u_diffuse, v_texCoord) * u_diffuseMult;
154+
if (diffuseColor.a < 0.1) {
155+
discard;
156+
}
157+
vec3 a_normal = normalize(v_normal);
158+
vec3 surfaceToLight = normalize(v_surfaceToLight);
159+
vec3 surfaceToView = normalize(v_surfaceToView);
160+
vec3 halfVector = normalize(surfaceToLight + surfaceToView);
161+
vec4 litR = lit(dot(a_normal, surfaceToLight),
162+
dot(a_normal, halfVector), u_shininess);
163+
vec4 outColor = vec4((
164+
u_lightColor * (diffuseColor * litR.y +
165+
u_specular * litR.z * u_specularFactor)).rgb,
166+
diffuseColor.a);
167+
gl_FragColor = outColor;
168+
}
169+
</script>
170+
<script src="../js/twgl-full.min.js"></script>
171+
<script>
172+
"use strict";
173+
var isMobile = window.navigator.userAgent.match(/Android|iPhone|iPad|iPod|Windows Phone/i);
174+
var isiOS = window.navigator.userAgent.match(/iPhone|iPad|iPod/i);
175+
twgl.setDefaults({attribPrefix: "a_"});
176+
var m4 = twgl.m4;
177+
var gl = twgl.getWebGLContext(document.getElementById("c"));
178+
var onePointProgramInfo = twgl.createProgramInfo(gl, ["one-point-vs", "one-point-fs"]);
179+
180+
var shapes = [
181+
twgl.primitives.createCubeBufferInfo(gl, 2),
182+
twgl.primitives.createSphereBufferInfo(gl, 1, 24, 12),
183+
twgl.primitives.createPlaneBufferInfo(gl, 2, 2),
184+
twgl.primitives.createTruncatedConeBufferInfo(gl, 1, 0, 2, 24, 1),
185+
];
186+
187+
function rand(min, max) {
188+
if (max === undefined) {
189+
max = min;
190+
min = 0;
191+
}
192+
return min + Math.random() * (max - min);
193+
}
194+
195+
// Shared values
196+
var baseHue = rand(360);
197+
var lightWorldPosition = [1, 8, -10];
198+
var lightColor = [1, 1, 1, 1];
199+
var camera = m4.identity();
200+
var view = m4.identity();
201+
var viewProjection = m4.identity();
202+
203+
var texture = twgl.createTexture(gl, {
204+
src: [0, 0, 255],
205+
format: gl.RGB,
206+
min: gl.LINEAR,
207+
wrap: gl.CLAMP_TO_EDGE,
208+
});
209+
210+
var objects = [];
211+
var drawObjects = [];
212+
var numObjects = 100;
213+
for (var ii = 0; ii < numObjects; ++ii) {
214+
var uniforms;
215+
var programInfo;
216+
var shape = shapes[ii % shapes.length];
217+
var programInfo = onePointProgramInfo;
218+
var uniforms = {
219+
u_lightWorldPos: lightWorldPosition,
220+
u_lightColor: lightColor,
221+
u_diffuseMult: [1, 1, 1, 1],
222+
u_specular: [1, 1, 1, 1],
223+
u_shininess: 50,
224+
u_specularFactor: 1,
225+
u_diffuse: texture,
226+
u_viewInverse: camera,
227+
u_world: m4.identity(),
228+
u_worldInverseTranspose: m4.identity(),
229+
u_worldViewProjection: m4.identity(),
230+
};
231+
drawObjects.push({
232+
programInfo: programInfo,
233+
bufferInfo: shape,
234+
uniforms: uniforms,
235+
});
236+
objects.push({
237+
translation: [rand(-5, 5), rand(-5, 5), rand(-5, 5)],
238+
xSpeed: rand(0.01, 0.03),
239+
ySpeed: rand(0.01, 0.03),
240+
zSpeed: rand(0.01, 0.03),
241+
offset: rand(0, Math.PI * 2),
242+
uniforms: uniforms,
243+
});
244+
}
245+
246+
var audio;
247+
var copyVideo;
248+
var setVideo;
249+
var video = document.getElementById("vid");
250+
video.addEventListener("playing", function() {
251+
copyVideo = true;
252+
}, true);
253+
video.addEventListener("canplaythrough", function() {
254+
setVideo = true;
255+
}, true);
256+
video.addEventListener("ended", function() {
257+
if (!audio) {
258+
video.currentTime = 0;
259+
video.play();
260+
}
261+
}, true);
262+
video.addEventListener("error", function() {
263+
console.log("could not play video");
264+
}, true);
265+
266+
if (!isMobile) {
267+
// If it's desktop we can start the video automaically
268+
video.play();
269+
} else {
270+
// otherwise we need to start inside a touch event
271+
var start = document.querySelector("#start");
272+
start.style.display = "";
273+
start.addEventListener('touchstart', function() {
274+
start.style.display = "none";
275+
if (isiOS) {
276+
// iOS9 doesn't let us play video without going fullscreen :(
277+
// so a workaround, which I'm sure Apple will *fix* as in "make it not work"
278+
// is to create an audio tag using the same video
279+
// play the audio. DON'T PLAY THE VIDEO. Set the video's currentTime to match
280+
// the audio. I can't believe this works
281+
audio = document.createElement("audio");
282+
audio.src = "../color-adjust/sample-video.mp4";
283+
audio.addEventListener("ended", function() {
284+
audio.currentTime = 0;
285+
audio.play();
286+
});
287+
audio.play();
288+
video.load();
289+
} else {
290+
video.play();
291+
}
292+
});
293+
}
294+
295+
function render(time) {
296+
time *= 0.001;
297+
twgl.resizeCanvasToDisplaySize(gl.canvas);
298+
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
299+
300+
gl.enable(gl.DEPTH_TEST);
301+
gl.enable(gl.BLEND);
302+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
303+
gl.clearColor(0.1, 0.1, 0.1, 1);
304+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
305+
306+
var radius = 10;
307+
var orbitSpeed = time * 0.01;
308+
var projection = m4.perspective(30 * Math.PI / 180, gl.canvas.clientWidth / gl.canvas.clientHeight, 0.5, 100);
309+
var eye = [Math.cos(orbitSpeed) * radius, 4, Math.sin(orbitSpeed) * radius];
310+
var target = [0, 0, 0];
311+
var up = [0, 1, 0];
312+
313+
if (copyVideo || setVideo) {
314+
if (setVideo) {
315+
video.currentTime = audio.currentTime;
316+
}
317+
gl.bindTexture(gl.TEXTURE_2D, texture)
318+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, video);
319+
}
320+
321+
m4.lookAt(eye, target, up, camera);
322+
m4.inverse(camera, view);
323+
m4.multiply(view, projection, viewProjection);
324+
325+
objects.forEach(function(obj) {
326+
var uni = obj.uniforms;
327+
var world = uni.u_world;
328+
var t = time;
329+
m4.identity(world);
330+
m4.rotateY(world, t * obj.ySpeed + obj.offset, world);
331+
m4.rotateZ(world, t * obj.zSpeed + obj.offset, world);
332+
m4.translate(world, obj.translation, world);
333+
m4.rotateX(world, t * obj.xSpeed + obj.offset, world);
334+
m4.transpose(m4.inverse(world, uni.u_worldInverseTranspose), uni.u_worldInverseTranspose);
335+
m4.multiply(uni.u_world, viewProjection, uni.u_worldViewProjection);
336+
});
337+
338+
twgl.drawObjectList(gl, drawObjects);
339+
340+
requestAnimationFrame(render);
341+
}
342+
requestAnimationFrame(render);
343+
344+
</script>
345+
</html>
346+
347+
348+
349+
350+

video/video.png

107 KB
Loading

0 commit comments

Comments
 (0)