├── README.md
└── webgl-examples
├── README.md
└── tutorial
├── sample1
├── index.html
└── webgl.css
├── sample2
├── index.html
├── webgl-demo.js
└── webgl.css
├── sample3
├── index.html
├── webgl-demo.js
└── webgl.css
├── sample4
├── index.html
├── webgl-demo.js
└── webgl.css
├── sample5
├── index.html
├── webgl-demo.js
└── webgl.css
├── sample6
├── cubetexture.png
├── index.html
├── webgl-demo.js
└── webgl.css
├── sample7
├── cubetexture.png
├── index.html
├── webgl-demo.js
└── webgl.css
├── sample8
├── Firefox.mp4
├── index.html
├── webgl-demo.js
└── webgl.css
└── tetrahedron
├── index.html
└── webgl-demo.js
/README.md:
--------------------------------------------------------------------------------
1 | # MDN WebGL examples
2 |
3 | NOTE: This repository is archived and moved into the MDN Web Docs [dom-examples](https://github.com/mdn/dom-examples/tree/main/webgl-examples) repo.
4 |
--------------------------------------------------------------------------------
/webgl-examples/README.md:
--------------------------------------------------------------------------------
1 | # MDN WebGL examples
2 |
3 | NOTE: This repository is archived and moved into the MDN Web Docs [dom-examples](https://github.com/mdn/dom-examples/tree/master/webgl-examples) repo.
4 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample1/webgl.css:
--------------------------------------------------------------------------------
1 | canvas {
2 | border: 2px solid black;
3 | background-color: black;
4 | }
5 | video {
6 | display: none;
7 | }
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Demo
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample2/webgl-demo.js:
--------------------------------------------------------------------------------
1 | main();
2 |
3 | //
4 | // Start here
5 | //
6 | function main() {
7 | const canvas = document.querySelector('#glcanvas');
8 | const gl = canvas.getContext('webgl');
9 |
10 | // If we don't have a GL context, give up now
11 |
12 | if (!gl) {
13 | alert('Unable to initialize WebGL. Your browser or machine may not support it.');
14 | return;
15 | }
16 |
17 | // Vertex shader program
18 |
19 | const vsSource = `
20 | attribute vec4 aVertexPosition;
21 |
22 | uniform mat4 uModelViewMatrix;
23 | uniform mat4 uProjectionMatrix;
24 |
25 | void main() {
26 | gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
27 | }
28 | `;
29 |
30 | // Fragment shader program
31 |
32 | const fsSource = `
33 | void main() {
34 | gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
35 | }
36 | `;
37 |
38 | // Initialize a shader program; this is where all the lighting
39 | // for the vertices and so forth is established.
40 | const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
41 |
42 | // Collect all the info needed to use the shader program.
43 | // Look up which attribute our shader program is using
44 | // for aVertexPosition and look up uniform locations.
45 | const programInfo = {
46 | program: shaderProgram,
47 | attribLocations: {
48 | vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
49 | },
50 | uniformLocations: {
51 | projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
52 | modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
53 | },
54 | };
55 |
56 | // Here's where we call the routine that builds all the
57 | // objects we'll be drawing.
58 | const buffers = initBuffers(gl);
59 |
60 | // Draw the scene
61 | drawScene(gl, programInfo, buffers);
62 | }
63 |
64 | //
65 | // initBuffers
66 | //
67 | // Initialize the buffers we'll need. For this demo, we just
68 | // have one object -- a simple two-dimensional square.
69 | //
70 | function initBuffers(gl) {
71 |
72 | // Create a buffer for the square's positions.
73 |
74 | const positionBuffer = gl.createBuffer();
75 |
76 | // Select the positionBuffer as the one to apply buffer
77 | // operations to from here out.
78 |
79 | gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
80 |
81 | // Now create an array of positions for the square.
82 |
83 | const positions = [
84 | 1.0, 1.0,
85 | -1.0, 1.0,
86 | 1.0, -1.0,
87 | -1.0, -1.0,
88 | ];
89 |
90 | // Now pass the list of positions into WebGL to build the
91 | // shape. We do this by creating a Float32Array from the
92 | // JavaScript array, then use it to fill the current buffer.
93 |
94 | gl.bufferData(gl.ARRAY_BUFFER,
95 | new Float32Array(positions),
96 | gl.STATIC_DRAW);
97 |
98 | return {
99 | position: positionBuffer,
100 | };
101 | }
102 |
103 | //
104 | // Draw the scene.
105 | //
106 | function drawScene(gl, programInfo, buffers) {
107 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
108 | gl.clearDepth(1.0); // Clear everything
109 | gl.enable(gl.DEPTH_TEST); // Enable depth testing
110 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things
111 |
112 | // Clear the canvas before we start drawing on it.
113 |
114 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
115 |
116 | // Create a perspective matrix, a special matrix that is
117 | // used to simulate the distortion of perspective in a camera.
118 | // Our field of view is 45 degrees, with a width/height
119 | // ratio that matches the display size of the canvas
120 | // and we only want to see objects between 0.1 units
121 | // and 100 units away from the camera.
122 |
123 | const fieldOfView = 45 * Math.PI / 180; // in radians
124 | const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
125 | const zNear = 0.1;
126 | const zFar = 100.0;
127 | const projectionMatrix = mat4.create();
128 |
129 | // note: glmatrix.js always has the first argument
130 | // as the destination to receive the result.
131 | mat4.perspective(projectionMatrix,
132 | fieldOfView,
133 | aspect,
134 | zNear,
135 | zFar);
136 |
137 | // Set the drawing position to the "identity" point, which is
138 | // the center of the scene.
139 | const modelViewMatrix = mat4.create();
140 |
141 | // Now move the drawing position a bit to where we want to
142 | // start drawing the square.
143 |
144 | mat4.translate(modelViewMatrix, // destination matrix
145 | modelViewMatrix, // matrix to translate
146 | [-0.0, 0.0, -6.0]); // amount to translate
147 |
148 | // Tell WebGL how to pull out the positions from the position
149 | // buffer into the vertexPosition attribute.
150 | {
151 | const numComponents = 2;
152 | const type = gl.FLOAT;
153 | const normalize = false;
154 | const stride = 0;
155 | const offset = 0;
156 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
157 | gl.vertexAttribPointer(
158 | programInfo.attribLocations.vertexPosition,
159 | numComponents,
160 | type,
161 | normalize,
162 | stride,
163 | offset);
164 | gl.enableVertexAttribArray(
165 | programInfo.attribLocations.vertexPosition);
166 | }
167 |
168 | // Tell WebGL to use our program when drawing
169 |
170 | gl.useProgram(programInfo.program);
171 |
172 | // Set the shader uniforms
173 |
174 | gl.uniformMatrix4fv(
175 | programInfo.uniformLocations.projectionMatrix,
176 | false,
177 | projectionMatrix);
178 | gl.uniformMatrix4fv(
179 | programInfo.uniformLocations.modelViewMatrix,
180 | false,
181 | modelViewMatrix);
182 |
183 | {
184 | const offset = 0;
185 | const vertexCount = 4;
186 | gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
187 | }
188 | }
189 |
190 | //
191 | // Initialize a shader program, so WebGL knows how to draw our data
192 | //
193 | function initShaderProgram(gl, vsSource, fsSource) {
194 | const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
195 | const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
196 |
197 | // Create the shader program
198 |
199 | const shaderProgram = gl.createProgram();
200 | gl.attachShader(shaderProgram, vertexShader);
201 | gl.attachShader(shaderProgram, fragmentShader);
202 | gl.linkProgram(shaderProgram);
203 |
204 | // If creating the shader program failed, alert
205 |
206 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
207 | alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
208 | return null;
209 | }
210 |
211 | return shaderProgram;
212 | }
213 |
214 | //
215 | // creates a shader of the given type, uploads the source and
216 | // compiles it.
217 | //
218 | function loadShader(gl, type, source) {
219 | const shader = gl.createShader(type);
220 |
221 | // Send the source to the shader object
222 |
223 | gl.shaderSource(shader, source);
224 |
225 | // Compile the shader program
226 |
227 | gl.compileShader(shader);
228 |
229 | // See if it compiled successfully
230 |
231 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
232 | alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
233 | gl.deleteShader(shader);
234 | return null;
235 | }
236 |
237 | return shader;
238 | }
239 |
240 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample2/webgl.css:
--------------------------------------------------------------------------------
1 | canvas {
2 | border: 2px solid black;
3 | background-color: black;
4 | }
5 | video {
6 | display: none;
7 | }
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Demo
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample3/webgl-demo.js:
--------------------------------------------------------------------------------
1 | main();
2 |
3 | //
4 | // Start here
5 | //
6 | function main() {
7 | const canvas = document.querySelector('#glcanvas');
8 | const gl = canvas.getContext('webgl');
9 |
10 | // If we don't have a GL context, give up now
11 |
12 | if (!gl) {
13 | alert('Unable to initialize WebGL. Your browser or machine may not support it.');
14 | return;
15 | }
16 |
17 | // Vertex shader program
18 |
19 | const vsSource = `
20 | attribute vec4 aVertexPosition;
21 | attribute vec4 aVertexColor;
22 |
23 | uniform mat4 uModelViewMatrix;
24 | uniform mat4 uProjectionMatrix;
25 |
26 | varying lowp vec4 vColor;
27 |
28 | void main(void) {
29 | gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
30 | vColor = aVertexColor;
31 | }
32 | `;
33 |
34 | // Fragment shader program
35 |
36 | const fsSource = `
37 | varying lowp vec4 vColor;
38 |
39 | void main(void) {
40 | gl_FragColor = vColor;
41 | }
42 | `;
43 |
44 | // Initialize a shader program; this is where all the lighting
45 | // for the vertices and so forth is established.
46 | const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
47 |
48 | // Collect all the info needed to use the shader program.
49 | // Look up which attributes our shader program is using
50 | // for aVertexPosition, aVertexColor and also
51 | // look up uniform locations.
52 | const programInfo = {
53 | program: shaderProgram,
54 | attribLocations: {
55 | vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
56 | vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
57 | },
58 | uniformLocations: {
59 | projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
60 | modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
61 | },
62 | };
63 |
64 | // Here's where we call the routine that builds all the
65 | // objects we'll be drawing.
66 | const buffers = initBuffers(gl);
67 |
68 | // Draw the scene
69 | drawScene(gl, programInfo, buffers);
70 | }
71 |
72 | //
73 | // initBuffers
74 | //
75 | // Initialize the buffers we'll need. For this demo, we just
76 | // have one object -- a simple two-dimensional square.
77 | //
78 | function initBuffers(gl) {
79 |
80 | // Create a buffer for the square's positions.
81 |
82 | const positionBuffer = gl.createBuffer();
83 |
84 | // Select the positionBuffer as the one to apply buffer
85 | // operations to from here out.
86 |
87 | gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
88 |
89 | // Now create an array of positions for the square.
90 |
91 | const positions = [
92 | 1.0, 1.0,
93 | -1.0, 1.0,
94 | 1.0, -1.0,
95 | -1.0, -1.0,
96 | ];
97 |
98 | // Now pass the list of positions into WebGL to build the
99 | // shape. We do this by creating a Float32Array from the
100 | // JavaScript array, then use it to fill the current buffer.
101 |
102 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
103 |
104 | // Now set up the colors for the vertices
105 |
106 | var colors = [
107 | 1.0, 1.0, 1.0, 1.0, // white
108 | 1.0, 0.0, 0.0, 1.0, // red
109 | 0.0, 1.0, 0.0, 1.0, // green
110 | 0.0, 0.0, 1.0, 1.0, // blue
111 | ];
112 |
113 | const colorBuffer = gl.createBuffer();
114 | gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
115 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
116 |
117 | return {
118 | position: positionBuffer,
119 | color: colorBuffer,
120 | };
121 | }
122 |
123 | //
124 | // Draw the scene.
125 | //
126 | function drawScene(gl, programInfo, buffers) {
127 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
128 | gl.clearDepth(1.0); // Clear everything
129 | gl.enable(gl.DEPTH_TEST); // Enable depth testing
130 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things
131 |
132 | // Clear the canvas before we start drawing on it.
133 |
134 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
135 |
136 | // Create a perspective matrix, a special matrix that is
137 | // used to simulate the distortion of perspective in a camera.
138 | // Our field of view is 45 degrees, with a width/height
139 | // ratio that matches the display size of the canvas
140 | // and we only want to see objects between 0.1 units
141 | // and 100 units away from the camera.
142 |
143 | const fieldOfView = 45 * Math.PI / 180; // in radians
144 | const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
145 | const zNear = 0.1;
146 | const zFar = 100.0;
147 | const projectionMatrix = mat4.create();
148 |
149 | // note: glmatrix.js always has the first argument
150 | // as the destination to receive the result.
151 | mat4.perspective(projectionMatrix,
152 | fieldOfView,
153 | aspect,
154 | zNear,
155 | zFar);
156 |
157 | // Set the drawing position to the "identity" point, which is
158 | // the center of the scene.
159 | const modelViewMatrix = mat4.create();
160 |
161 | // Now move the drawing position a bit to where we want to
162 | // start drawing the square.
163 |
164 | mat4.translate(modelViewMatrix, // destination matrix
165 | modelViewMatrix, // matrix to translate
166 | [-0.0, 0.0, -6.0]); // amount to translate
167 |
168 | // Tell WebGL how to pull out the positions from the position
169 | // buffer into the vertexPosition attribute
170 | {
171 | const numComponents = 2;
172 | const type = gl.FLOAT;
173 | const normalize = false;
174 | const stride = 0;
175 | const offset = 0;
176 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
177 | gl.vertexAttribPointer(
178 | programInfo.attribLocations.vertexPosition,
179 | numComponents,
180 | type,
181 | normalize,
182 | stride,
183 | offset);
184 | gl.enableVertexAttribArray(
185 | programInfo.attribLocations.vertexPosition);
186 | }
187 |
188 | // Tell WebGL how to pull out the colors from the color buffer
189 | // into the vertexColor attribute.
190 | {
191 | const numComponents = 4;
192 | const type = gl.FLOAT;
193 | const normalize = false;
194 | const stride = 0;
195 | const offset = 0;
196 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
197 | gl.vertexAttribPointer(
198 | programInfo.attribLocations.vertexColor,
199 | numComponents,
200 | type,
201 | normalize,
202 | stride,
203 | offset);
204 | gl.enableVertexAttribArray(
205 | programInfo.attribLocations.vertexColor);
206 | }
207 |
208 | // Tell WebGL to use our program when drawing
209 |
210 | gl.useProgram(programInfo.program);
211 |
212 | // Set the shader uniforms
213 |
214 | gl.uniformMatrix4fv(
215 | programInfo.uniformLocations.projectionMatrix,
216 | false,
217 | projectionMatrix);
218 | gl.uniformMatrix4fv(
219 | programInfo.uniformLocations.modelViewMatrix,
220 | false,
221 | modelViewMatrix);
222 |
223 | {
224 | const offset = 0;
225 | const vertexCount = 4;
226 | gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
227 | }
228 | }
229 |
230 | //
231 | // Initialize a shader program, so WebGL knows how to draw our data
232 | //
233 | function initShaderProgram(gl, vsSource, fsSource) {
234 | const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
235 | const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
236 |
237 | // Create the shader program
238 |
239 | const shaderProgram = gl.createProgram();
240 | gl.attachShader(shaderProgram, vertexShader);
241 | gl.attachShader(shaderProgram, fragmentShader);
242 | gl.linkProgram(shaderProgram);
243 |
244 | // If creating the shader program failed, alert
245 |
246 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
247 | alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
248 | return null;
249 | }
250 |
251 | return shaderProgram;
252 | }
253 |
254 | //
255 | // creates a shader of the given type, uploads the source and
256 | // compiles it.
257 | //
258 | function loadShader(gl, type, source) {
259 | const shader = gl.createShader(type);
260 |
261 | // Send the source to the shader object
262 |
263 | gl.shaderSource(shader, source);
264 |
265 | // Compile the shader program
266 |
267 | gl.compileShader(shader);
268 |
269 | // See if it compiled successfully
270 |
271 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
272 | alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
273 | gl.deleteShader(shader);
274 | return null;
275 | }
276 |
277 | return shader;
278 | }
279 |
280 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample3/webgl.css:
--------------------------------------------------------------------------------
1 | canvas {
2 | border: 2px solid black;
3 | background-color: black;
4 | }
5 | video {
6 | display: none;
7 | }
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample4/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Demo
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample4/webgl-demo.js:
--------------------------------------------------------------------------------
1 | var squareRotation = 0.0;
2 |
3 | main();
4 |
5 | //
6 | // Start here
7 | //
8 | function main() {
9 | const canvas = document.querySelector('#glcanvas');
10 | const gl = canvas.getContext('webgl');
11 |
12 | // If we don't have a GL context, give up now
13 |
14 | if (!gl) {
15 | alert('Unable to initialize WebGL. Your browser or machine may not support it.');
16 | return;
17 | }
18 |
19 | // Vertex shader program
20 |
21 | const vsSource = `
22 | attribute vec4 aVertexPosition;
23 | attribute vec4 aVertexColor;
24 |
25 | uniform mat4 uModelViewMatrix;
26 | uniform mat4 uProjectionMatrix;
27 |
28 | varying lowp vec4 vColor;
29 |
30 | void main(void) {
31 | gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
32 | vColor = aVertexColor;
33 | }
34 | `;
35 |
36 | // Fragment shader program
37 |
38 | const fsSource = `
39 | varying lowp vec4 vColor;
40 |
41 | void main(void) {
42 | gl_FragColor = vColor;
43 | }
44 | `;
45 |
46 | // Initialize a shader program; this is where all the lighting
47 | // for the vertices and so forth is established.
48 | const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
49 |
50 | // Collect all the info needed to use the shader program.
51 | // Look up which attributes our shader program is using
52 | // for aVertexPosition, aVertexColor and also
53 | // look up uniform locations.
54 | const programInfo = {
55 | program: shaderProgram,
56 | attribLocations: {
57 | vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
58 | vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
59 | },
60 | uniformLocations: {
61 | projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
62 | modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
63 | },
64 | };
65 |
66 | // Here's where we call the routine that builds all the
67 | // objects we'll be drawing.
68 | const buffers = initBuffers(gl);
69 |
70 | var then = 0;
71 |
72 | // Draw the scene repeatedly
73 | function render(now) {
74 | now *= 0.001; // convert to seconds
75 | const deltaTime = now - then;
76 | then = now;
77 |
78 | drawScene(gl, programInfo, buffers, deltaTime);
79 |
80 | requestAnimationFrame(render);
81 | }
82 | requestAnimationFrame(render);
83 | }
84 |
85 | //
86 | // initBuffers
87 | //
88 | // Initialize the buffers we'll need. For this demo, we just
89 | // have one object -- a simple two-dimensional square.
90 | //
91 | function initBuffers(gl) {
92 |
93 | // Create a buffer for the square's positions.
94 |
95 | const positionBuffer = gl.createBuffer();
96 |
97 | // Select the positionBuffer as the one to apply buffer
98 | // operations to from here out.
99 |
100 | gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
101 |
102 | // Now create an array of positions for the square.
103 |
104 | const positions = [
105 | 1.0, 1.0,
106 | -1.0, 1.0,
107 | 1.0, -1.0,
108 | -1.0, -1.0,
109 | ];
110 |
111 | // Now pass the list of positions into WebGL to build the
112 | // shape. We do this by creating a Float32Array from the
113 | // JavaScript array, then use it to fill the current buffer.
114 |
115 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
116 |
117 | // Now set up the colors for the vertices
118 |
119 | const colors = [
120 | 1.0, 1.0, 1.0, 1.0, // white
121 | 1.0, 0.0, 0.0, 1.0, // red
122 | 0.0, 1.0, 0.0, 1.0, // green
123 | 0.0, 0.0, 1.0, 1.0, // blue
124 | ];
125 |
126 | const colorBuffer = gl.createBuffer();
127 | gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
128 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
129 |
130 | return {
131 | position: positionBuffer,
132 | color: colorBuffer,
133 | };
134 | }
135 |
136 | //
137 | // Draw the scene.
138 | //
139 | function drawScene(gl, programInfo, buffers, deltaTime) {
140 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
141 | gl.clearDepth(1.0); // Clear everything
142 | gl.enable(gl.DEPTH_TEST); // Enable depth testing
143 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things
144 |
145 | // Clear the canvas before we start drawing on it.
146 |
147 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
148 |
149 | // Create a perspective matrix, a special matrix that is
150 | // used to simulate the distortion of perspective in a camera.
151 | // Our field of view is 45 degrees, with a width/height
152 | // ratio that matches the display size of the canvas
153 | // and we only want to see objects between 0.1 units
154 | // and 100 units away from the camera.
155 |
156 | const fieldOfView = 45 * Math.PI / 180; // in radians
157 | const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
158 | const zNear = 0.1;
159 | const zFar = 100.0;
160 | const projectionMatrix = mat4.create();
161 |
162 | // note: glmatrix.js always has the first argument
163 | // as the destination to receive the result.
164 | mat4.perspective(projectionMatrix,
165 | fieldOfView,
166 | aspect,
167 | zNear,
168 | zFar);
169 |
170 | // Set the drawing position to the "identity" point, which is
171 | // the center of the scene.
172 | const modelViewMatrix = mat4.create();
173 |
174 | // Now move the drawing position a bit to where we want to
175 | // start drawing the square.
176 |
177 | mat4.translate(modelViewMatrix, // destination matrix
178 | modelViewMatrix, // matrix to translate
179 | [-0.0, 0.0, -6.0]); // amount to translate
180 | mat4.rotate(modelViewMatrix, // destination matrix
181 | modelViewMatrix, // matrix to rotate
182 | squareRotation, // amount to rotate in radians
183 | [0, 0, 1]); // axis to rotate around
184 |
185 | // Tell WebGL how to pull out the positions from the position
186 | // buffer into the vertexPosition attribute
187 | {
188 | const numComponents = 2;
189 | const type = gl.FLOAT;
190 | const normalize = false;
191 | const stride = 0;
192 | const offset = 0;
193 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
194 | gl.vertexAttribPointer(
195 | programInfo.attribLocations.vertexPosition,
196 | numComponents,
197 | type,
198 | normalize,
199 | stride,
200 | offset);
201 | gl.enableVertexAttribArray(
202 | programInfo.attribLocations.vertexPosition);
203 | }
204 |
205 | // Tell WebGL how to pull out the colors from the color buffer
206 | // into the vertexColor attribute.
207 | {
208 | const numComponents = 4;
209 | const type = gl.FLOAT;
210 | const normalize = false;
211 | const stride = 0;
212 | const offset = 0;
213 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
214 | gl.vertexAttribPointer(
215 | programInfo.attribLocations.vertexColor,
216 | numComponents,
217 | type,
218 | normalize,
219 | stride,
220 | offset);
221 | gl.enableVertexAttribArray(
222 | programInfo.attribLocations.vertexColor);
223 | }
224 |
225 | // Tell WebGL to use our program when drawing
226 |
227 | gl.useProgram(programInfo.program);
228 |
229 | // Set the shader uniforms
230 |
231 | gl.uniformMatrix4fv(
232 | programInfo.uniformLocations.projectionMatrix,
233 | false,
234 | projectionMatrix);
235 | gl.uniformMatrix4fv(
236 | programInfo.uniformLocations.modelViewMatrix,
237 | false,
238 | modelViewMatrix);
239 |
240 | {
241 | const offset = 0;
242 | const vertexCount = 4;
243 | gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
244 | }
245 |
246 | // Update the rotation for the next draw
247 |
248 | squareRotation += deltaTime;
249 | }
250 |
251 | //
252 | // Initialize a shader program, so WebGL knows how to draw our data
253 | //
254 | function initShaderProgram(gl, vsSource, fsSource) {
255 | const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
256 | const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
257 |
258 | // Create the shader program
259 |
260 | const shaderProgram = gl.createProgram();
261 | gl.attachShader(shaderProgram, vertexShader);
262 | gl.attachShader(shaderProgram, fragmentShader);
263 | gl.linkProgram(shaderProgram);
264 |
265 | // If creating the shader program failed, alert
266 |
267 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
268 | alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
269 | return null;
270 | }
271 |
272 | return shaderProgram;
273 | }
274 |
275 | //
276 | // creates a shader of the given type, uploads the source and
277 | // compiles it.
278 | //
279 | function loadShader(gl, type, source) {
280 | const shader = gl.createShader(type);
281 |
282 | // Send the source to the shader object
283 |
284 | gl.shaderSource(shader, source);
285 |
286 | // Compile the shader program
287 |
288 | gl.compileShader(shader);
289 |
290 | // See if it compiled successfully
291 |
292 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
293 | alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
294 | gl.deleteShader(shader);
295 | return null;
296 | }
297 |
298 | return shader;
299 | }
300 |
301 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample4/webgl.css:
--------------------------------------------------------------------------------
1 | canvas {
2 | border: 2px solid black;
3 | background-color: black;
4 | }
5 | video {
6 | display: none;
7 | }
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample5/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Demo
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample5/webgl-demo.js:
--------------------------------------------------------------------------------
1 | var cubeRotation = 0.0;
2 |
3 | main();
4 |
5 | //
6 | // Start here
7 | //
8 | function main() {
9 | const canvas = document.querySelector('#glcanvas');
10 | const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
11 |
12 | // If we don't have a GL context, give up now
13 |
14 | if (!gl) {
15 | alert('Unable to initialize WebGL. Your browser or machine may not support it.');
16 | return;
17 | }
18 |
19 | // Vertex shader program
20 |
21 | const vsSource = `
22 | attribute vec4 aVertexPosition;
23 | attribute vec4 aVertexColor;
24 |
25 | uniform mat4 uModelViewMatrix;
26 | uniform mat4 uProjectionMatrix;
27 |
28 | varying lowp vec4 vColor;
29 |
30 | void main(void) {
31 | gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
32 | vColor = aVertexColor;
33 | }
34 | `;
35 |
36 | // Fragment shader program
37 |
38 | const fsSource = `
39 | varying lowp vec4 vColor;
40 |
41 | void main(void) {
42 | gl_FragColor = vColor;
43 | }
44 | `;
45 |
46 | // Initialize a shader program; this is where all the lighting
47 | // for the vertices and so forth is established.
48 | const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
49 |
50 | // Collect all the info needed to use the shader program.
51 | // Look up which attributes our shader program is using
52 | // for aVertexPosition, aVertexColor and also
53 | // look up uniform locations.
54 | const programInfo = {
55 | program: shaderProgram,
56 | attribLocations: {
57 | vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
58 | vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
59 | },
60 | uniformLocations: {
61 | projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
62 | modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
63 | }
64 | };
65 |
66 | // Here's where we call the routine that builds all the
67 | // objects we'll be drawing.
68 | const buffers = initBuffers(gl);
69 |
70 | var then = 0;
71 |
72 | // Draw the scene repeatedly
73 | function render(now) {
74 | now *= 0.001; // convert to seconds
75 | const deltaTime = now - then;
76 | then = now;
77 |
78 | drawScene(gl, programInfo, buffers, deltaTime);
79 |
80 | requestAnimationFrame(render);
81 | }
82 | requestAnimationFrame(render);
83 | }
84 |
85 | //
86 | // initBuffers
87 | //
88 | // Initialize the buffers we'll need. For this demo, we just
89 | // have one object -- a simple three-dimensional cube.
90 | //
91 | function initBuffers(gl) {
92 |
93 | // Create a buffer for the cube's vertex positions.
94 |
95 | const positionBuffer = gl.createBuffer();
96 |
97 | // Select the positionBuffer as the one to apply buffer
98 | // operations to from here out.
99 |
100 | gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
101 |
102 | // Now create an array of positions for the cube.
103 |
104 | const positions = [
105 | // Front face
106 | -1.0, -1.0, 1.0,
107 | 1.0, -1.0, 1.0,
108 | 1.0, 1.0, 1.0,
109 | -1.0, 1.0, 1.0,
110 |
111 | // Back face
112 | -1.0, -1.0, -1.0,
113 | -1.0, 1.0, -1.0,
114 | 1.0, 1.0, -1.0,
115 | 1.0, -1.0, -1.0,
116 |
117 | // Top face
118 | -1.0, 1.0, -1.0,
119 | -1.0, 1.0, 1.0,
120 | 1.0, 1.0, 1.0,
121 | 1.0, 1.0, -1.0,
122 |
123 | // Bottom face
124 | -1.0, -1.0, -1.0,
125 | 1.0, -1.0, -1.0,
126 | 1.0, -1.0, 1.0,
127 | -1.0, -1.0, 1.0,
128 |
129 | // Right face
130 | 1.0, -1.0, -1.0,
131 | 1.0, 1.0, -1.0,
132 | 1.0, 1.0, 1.0,
133 | 1.0, -1.0, 1.0,
134 |
135 | // Left face
136 | -1.0, -1.0, -1.0,
137 | -1.0, -1.0, 1.0,
138 | -1.0, 1.0, 1.0,
139 | -1.0, 1.0, -1.0,
140 | ];
141 |
142 | // Now pass the list of positions into WebGL to build the
143 | // shape. We do this by creating a Float32Array from the
144 | // JavaScript array, then use it to fill the current buffer.
145 |
146 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
147 |
148 | // Now set up the colors for the faces. We'll use solid colors
149 | // for each face.
150 |
151 | const faceColors = [
152 | [1.0, 1.0, 1.0, 1.0], // Front face: white
153 | [1.0, 0.0, 0.0, 1.0], // Back face: red
154 | [0.0, 1.0, 0.0, 1.0], // Top face: green
155 | [0.0, 0.0, 1.0, 1.0], // Bottom face: blue
156 | [1.0, 1.0, 0.0, 1.0], // Right face: yellow
157 | [1.0, 0.0, 1.0, 1.0], // Left face: purple
158 | ];
159 |
160 | // Convert the array of colors into a table for all the vertices.
161 |
162 | var colors = [];
163 |
164 | for (var j = 0; j < faceColors.length; ++j) {
165 | const c = faceColors[j];
166 |
167 | // Repeat each color four times for the four vertices of the face
168 | colors = colors.concat(c, c, c, c);
169 | }
170 |
171 | const colorBuffer = gl.createBuffer();
172 | gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
173 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
174 |
175 | // Build the element array buffer; this specifies the indices
176 | // into the vertex arrays for each face's vertices.
177 |
178 | const indexBuffer = gl.createBuffer();
179 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
180 |
181 | // This array defines each face as two triangles, using the
182 | // indices into the vertex array to specify each triangle's
183 | // position.
184 |
185 | const indices = [
186 | 0, 1, 2, 0, 2, 3, // front
187 | 4, 5, 6, 4, 6, 7, // back
188 | 8, 9, 10, 8, 10, 11, // top
189 | 12, 13, 14, 12, 14, 15, // bottom
190 | 16, 17, 18, 16, 18, 19, // right
191 | 20, 21, 22, 20, 22, 23, // left
192 | ];
193 |
194 | // Now send the element array to GL
195 |
196 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
197 | new Uint16Array(indices), gl.STATIC_DRAW);
198 |
199 | return {
200 | position: positionBuffer,
201 | color: colorBuffer,
202 | indices: indexBuffer,
203 | };
204 | }
205 |
206 | //
207 | // Draw the scene.
208 | //
209 | function drawScene(gl, programInfo, buffers, deltaTime) {
210 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
211 | gl.clearDepth(1.0); // Clear everything
212 | gl.enable(gl.DEPTH_TEST); // Enable depth testing
213 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things
214 |
215 | // Clear the canvas before we start drawing on it.
216 |
217 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
218 |
219 | // Create a perspective matrix, a special matrix that is
220 | // used to simulate the distortion of perspective in a camera.
221 | // Our field of view is 45 degrees, with a width/height
222 | // ratio that matches the display size of the canvas
223 | // and we only want to see objects between 0.1 units
224 | // and 100 units away from the camera.
225 |
226 | const fieldOfView = 45 * Math.PI / 180; // in radians
227 | const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
228 | const zNear = 0.1;
229 | const zFar = 100.0;
230 | const projectionMatrix = mat4.create();
231 |
232 | // note: glmatrix.js always has the first argument
233 | // as the destination to receive the result.
234 | mat4.perspective(projectionMatrix,
235 | fieldOfView,
236 | aspect,
237 | zNear,
238 | zFar);
239 |
240 | // Set the drawing position to the "identity" point, which is
241 | // the center of the scene.
242 | const modelViewMatrix = mat4.create();
243 |
244 | // Now move the drawing position a bit to where we want to
245 | // start drawing the square.
246 |
247 | mat4.translate(modelViewMatrix, // destination matrix
248 | modelViewMatrix, // matrix to translate
249 | [-0.0, 0.0, -6.0]); // amount to translate
250 | mat4.rotate(modelViewMatrix, // destination matrix
251 | modelViewMatrix, // matrix to rotate
252 | cubeRotation, // amount to rotate in radians
253 | [0, 0, 1]); // axis to rotate around (Z)
254 | mat4.rotate(modelViewMatrix, // destination matrix
255 | modelViewMatrix, // matrix to rotate
256 | cubeRotation * .7,// amount to rotate in radians
257 | [0, 1, 0]); // axis to rotate around (Y)
258 | mat4.rotate(modelViewMatrix, // destination matrix
259 | modelViewMatrix, // matrix to rotate
260 | cubeRotation * .3,// amount to rotate in radians
261 | [1, 0, 0]); // axis to rotate around (X)
262 |
263 | // Tell WebGL how to pull out the positions from the position
264 | // buffer into the vertexPosition attribute
265 | {
266 | const numComponents = 3;
267 | const type = gl.FLOAT;
268 | const normalize = false;
269 | const stride = 0;
270 | const offset = 0;
271 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
272 | gl.vertexAttribPointer(
273 | programInfo.attribLocations.vertexPosition,
274 | numComponents,
275 | type,
276 | normalize,
277 | stride,
278 | offset);
279 | gl.enableVertexAttribArray(
280 | programInfo.attribLocations.vertexPosition);
281 | }
282 |
283 | // Tell WebGL how to pull out the colors from the color buffer
284 | // into the vertexColor attribute.
285 | {
286 | const numComponents = 4;
287 | const type = gl.FLOAT;
288 | const normalize = false;
289 | const stride = 0;
290 | const offset = 0;
291 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
292 | gl.vertexAttribPointer(
293 | programInfo.attribLocations.vertexColor,
294 | numComponents,
295 | type,
296 | normalize,
297 | stride,
298 | offset);
299 | gl.enableVertexAttribArray(
300 | programInfo.attribLocations.vertexColor);
301 | }
302 |
303 | // Tell WebGL which indices to use to index the vertices
304 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
305 |
306 | // Tell WebGL to use our program when drawing
307 |
308 | gl.useProgram(programInfo.program);
309 |
310 | // Set the shader uniforms
311 |
312 | gl.uniformMatrix4fv(
313 | programInfo.uniformLocations.projectionMatrix,
314 | false,
315 | projectionMatrix);
316 | gl.uniformMatrix4fv(
317 | programInfo.uniformLocations.modelViewMatrix,
318 | false,
319 | modelViewMatrix);
320 |
321 | {
322 | const vertexCount = 36;
323 | const type = gl.UNSIGNED_SHORT;
324 | const offset = 0;
325 | gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
326 | }
327 |
328 | // Update the rotation for the next draw
329 |
330 | cubeRotation += deltaTime;
331 | }
332 |
333 | //
334 | // Initialize a shader program, so WebGL knows how to draw our data
335 | //
336 | function initShaderProgram(gl, vsSource, fsSource) {
337 | const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
338 | const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
339 |
340 | // Create the shader program
341 |
342 | const shaderProgram = gl.createProgram();
343 | gl.attachShader(shaderProgram, vertexShader);
344 | gl.attachShader(shaderProgram, fragmentShader);
345 | gl.linkProgram(shaderProgram);
346 |
347 | // If creating the shader program failed, alert
348 |
349 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
350 | alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
351 | return null;
352 | }
353 |
354 | return shaderProgram;
355 | }
356 |
357 | //
358 | // creates a shader of the given type, uploads the source and
359 | // compiles it.
360 | //
361 | function loadShader(gl, type, source) {
362 | const shader = gl.createShader(type);
363 |
364 | // Send the source to the shader object
365 |
366 | gl.shaderSource(shader, source);
367 |
368 | // Compile the shader program
369 |
370 | gl.compileShader(shader);
371 |
372 | // See if it compiled successfully
373 |
374 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
375 | alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
376 | gl.deleteShader(shader);
377 | return null;
378 | }
379 |
380 | return shader;
381 | }
382 |
383 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample5/webgl.css:
--------------------------------------------------------------------------------
1 | canvas {
2 | border: 2px solid black;
3 | background-color: black;
4 | }
5 | video {
6 | display: none;
7 | }
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample6/cubetexture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/webgl-examples/17a7484b5bb5cddee1dce3eb93c8d48925453557/webgl-examples/tutorial/sample6/cubetexture.png
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample6/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Demo
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample6/webgl-demo.js:
--------------------------------------------------------------------------------
1 | var cubeRotation = 0.0;
2 |
3 | main();
4 |
5 | //
6 | // Start here
7 | //
8 | function main() {
9 | const canvas = document.querySelector('#glcanvas');
10 | const gl = canvas.getContext('webgl');
11 |
12 | // If we don't have a GL context, give up now
13 |
14 | if (!gl) {
15 | alert('Unable to initialize WebGL. Your browser or machine may not support it.');
16 | return;
17 | }
18 |
19 | // Vertex shader program
20 |
21 | const vsSource = `
22 | attribute vec4 aVertexPosition;
23 | attribute vec2 aTextureCoord;
24 |
25 | uniform mat4 uModelViewMatrix;
26 | uniform mat4 uProjectionMatrix;
27 |
28 | varying highp vec2 vTextureCoord;
29 |
30 | void main(void) {
31 | gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
32 | vTextureCoord = aTextureCoord;
33 | }
34 | `;
35 |
36 | // Fragment shader program
37 |
38 | const fsSource = `
39 | varying highp vec2 vTextureCoord;
40 |
41 | uniform sampler2D uSampler;
42 |
43 | void main(void) {
44 | gl_FragColor = texture2D(uSampler, vTextureCoord);
45 | }
46 | `;
47 |
48 | // Initialize a shader program; this is where all the lighting
49 | // for the vertices and so forth is established.
50 | const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
51 |
52 | // Collect all the info needed to use the shader program.
53 | // Look up which attributes our shader program is using
54 | // for aVertexPosition, aTextureCoord and also
55 | // look up uniform locations.
56 | const programInfo = {
57 | program: shaderProgram,
58 | attribLocations: {
59 | vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
60 | textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
61 | },
62 | uniformLocations: {
63 | projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
64 | modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
65 | uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
66 | }
67 | };
68 |
69 | // Here's where we call the routine that builds all the
70 | // objects we'll be drawing.
71 | const buffers = initBuffers(gl);
72 |
73 | const texture = loadTexture(gl, 'cubetexture.png');
74 |
75 | var then = 0;
76 |
77 | // Draw the scene repeatedly
78 | function render(now) {
79 | now *= 0.001; // convert to seconds
80 | const deltaTime = now - then;
81 | then = now;
82 |
83 | drawScene(gl, programInfo, buffers, texture, deltaTime);
84 |
85 | requestAnimationFrame(render);
86 | }
87 | requestAnimationFrame(render);
88 | }
89 |
90 | //
91 | // initBuffers
92 | //
93 | // Initialize the buffers we'll need. For this demo, we just
94 | // have one object -- a simple three-dimensional cube.
95 | //
96 | function initBuffers(gl) {
97 |
98 | // Create a buffer for the cube's vertex positions.
99 |
100 | const positionBuffer = gl.createBuffer();
101 |
102 | // Select the positionBuffer as the one to apply buffer
103 | // operations to from here out.
104 |
105 | gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
106 |
107 | // Now create an array of positions for the cube.
108 |
109 | const positions = [
110 | // Front face
111 | -1.0, -1.0, 1.0,
112 | 1.0, -1.0, 1.0,
113 | 1.0, 1.0, 1.0,
114 | -1.0, 1.0, 1.0,
115 |
116 | // Back face
117 | -1.0, -1.0, -1.0,
118 | -1.0, 1.0, -1.0,
119 | 1.0, 1.0, -1.0,
120 | 1.0, -1.0, -1.0,
121 |
122 | // Top face
123 | -1.0, 1.0, -1.0,
124 | -1.0, 1.0, 1.0,
125 | 1.0, 1.0, 1.0,
126 | 1.0, 1.0, -1.0,
127 |
128 | // Bottom face
129 | -1.0, -1.0, -1.0,
130 | 1.0, -1.0, -1.0,
131 | 1.0, -1.0, 1.0,
132 | -1.0, -1.0, 1.0,
133 |
134 | // Right face
135 | 1.0, -1.0, -1.0,
136 | 1.0, 1.0, -1.0,
137 | 1.0, 1.0, 1.0,
138 | 1.0, -1.0, 1.0,
139 |
140 | // Left face
141 | -1.0, -1.0, -1.0,
142 | -1.0, -1.0, 1.0,
143 | -1.0, 1.0, 1.0,
144 | -1.0, 1.0, -1.0,
145 | ];
146 |
147 | // Now pass the list of positions into WebGL to build the
148 | // shape. We do this by creating a Float32Array from the
149 | // JavaScript array, then use it to fill the current buffer.
150 |
151 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
152 |
153 | // Now set up the texture coordinates for the faces.
154 |
155 | const textureCoordBuffer = gl.createBuffer();
156 | gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
157 |
158 | const textureCoordinates = [
159 | // Front
160 | 0.0, 0.0,
161 | 1.0, 0.0,
162 | 1.0, 1.0,
163 | 0.0, 1.0,
164 | // Back
165 | 0.0, 0.0,
166 | 1.0, 0.0,
167 | 1.0, 1.0,
168 | 0.0, 1.0,
169 | // Top
170 | 0.0, 0.0,
171 | 1.0, 0.0,
172 | 1.0, 1.0,
173 | 0.0, 1.0,
174 | // Bottom
175 | 0.0, 0.0,
176 | 1.0, 0.0,
177 | 1.0, 1.0,
178 | 0.0, 1.0,
179 | // Right
180 | 0.0, 0.0,
181 | 1.0, 0.0,
182 | 1.0, 1.0,
183 | 0.0, 1.0,
184 | // Left
185 | 0.0, 0.0,
186 | 1.0, 0.0,
187 | 1.0, 1.0,
188 | 0.0, 1.0,
189 | ];
190 |
191 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),
192 | gl.STATIC_DRAW);
193 |
194 | // Build the element array buffer; this specifies the indices
195 | // into the vertex arrays for each face's vertices.
196 |
197 | const indexBuffer = gl.createBuffer();
198 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
199 |
200 | // This array defines each face as two triangles, using the
201 | // indices into the vertex array to specify each triangle's
202 | // position.
203 |
204 | const indices = [
205 | 0, 1, 2, 0, 2, 3, // front
206 | 4, 5, 6, 4, 6, 7, // back
207 | 8, 9, 10, 8, 10, 11, // top
208 | 12, 13, 14, 12, 14, 15, // bottom
209 | 16, 17, 18, 16, 18, 19, // right
210 | 20, 21, 22, 20, 22, 23, // left
211 | ];
212 |
213 | // Now send the element array to GL
214 |
215 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
216 | new Uint16Array(indices), gl.STATIC_DRAW);
217 |
218 | return {
219 | position: positionBuffer,
220 | textureCoord: textureCoordBuffer,
221 | indices: indexBuffer,
222 | };
223 | }
224 |
225 | //
226 | // Initialize a texture and load an image.
227 | // When the image finished loading copy it into the texture.
228 | //
229 | function loadTexture(gl, url) {
230 | const texture = gl.createTexture();
231 | gl.bindTexture(gl.TEXTURE_2D, texture);
232 |
233 | // Because images have to be download over the internet
234 | // they might take a moment until they are ready.
235 | // Until then put a single pixel in the texture so we can
236 | // use it immediately. When the image has finished downloading
237 | // we'll update the texture with the contents of the image.
238 | const level = 0;
239 | const internalFormat = gl.RGBA;
240 | const width = 1;
241 | const height = 1;
242 | const border = 0;
243 | const srcFormat = gl.RGBA;
244 | const srcType = gl.UNSIGNED_BYTE;
245 | const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
246 | gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
247 | width, height, border, srcFormat, srcType,
248 | pixel);
249 |
250 | const image = new Image();
251 | image.onload = function() {
252 | gl.bindTexture(gl.TEXTURE_2D, texture);
253 | gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
254 | srcFormat, srcType, image);
255 |
256 | // WebGL1 has different requirements for power of 2 images
257 | // vs non power of 2 images so check if the image is a
258 | // power of 2 in both dimensions.
259 | if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
260 | // Yes, it's a power of 2. Generate mips.
261 | gl.generateMipmap(gl.TEXTURE_2D);
262 | } else {
263 | // No, it's not a power of 2. Turn of mips and set
264 | // wrapping to clamp to edge
265 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
266 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
267 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
268 | }
269 | };
270 | image.src = url;
271 |
272 | return texture;
273 | }
274 |
275 | function isPowerOf2(value) {
276 | return (value & (value - 1)) == 0;
277 | }
278 |
279 | //
280 | // Draw the scene.
281 | //
282 | function drawScene(gl, programInfo, buffers, texture, deltaTime) {
283 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
284 | gl.clearDepth(1.0); // Clear everything
285 | gl.enable(gl.DEPTH_TEST); // Enable depth testing
286 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things
287 |
288 | // Clear the canvas before we start drawing on it.
289 |
290 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
291 |
292 | // Create a perspective matrix, a special matrix that is
293 | // used to simulate the distortion of perspective in a camera.
294 | // Our field of view is 45 degrees, with a width/height
295 | // ratio that matches the display size of the canvas
296 | // and we only want to see objects between 0.1 units
297 | // and 100 units away from the camera.
298 |
299 | const fieldOfView = 45 * Math.PI / 180; // in radians
300 | const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
301 | const zNear = 0.1;
302 | const zFar = 100.0;
303 | const projectionMatrix = mat4.create();
304 |
305 | // note: glmatrix.js always has the first argument
306 | // as the destination to receive the result.
307 | mat4.perspective(projectionMatrix,
308 | fieldOfView,
309 | aspect,
310 | zNear,
311 | zFar);
312 |
313 | // Set the drawing position to the "identity" point, which is
314 | // the center of the scene.
315 | const modelViewMatrix = mat4.create();
316 |
317 | // Now move the drawing position a bit to where we want to
318 | // start drawing the square.
319 |
320 | mat4.translate(modelViewMatrix, // destination matrix
321 | modelViewMatrix, // matrix to translate
322 | [-0.0, 0.0, -6.0]); // amount to translate
323 | mat4.rotate(modelViewMatrix, // destination matrix
324 | modelViewMatrix, // matrix to rotate
325 | cubeRotation, // amount to rotate in radians
326 | [0, 0, 1]); // axis to rotate around (Z)
327 | mat4.rotate(modelViewMatrix, // destination matrix
328 | modelViewMatrix, // matrix to rotate
329 | cubeRotation * .7,// amount to rotate in radians
330 | [0, 1, 0]); // axis to rotate around (X)
331 |
332 | // Tell WebGL how to pull out the positions from the position
333 | // buffer into the vertexPosition attribute
334 | {
335 | const numComponents = 3;
336 | const type = gl.FLOAT;
337 | const normalize = false;
338 | const stride = 0;
339 | const offset = 0;
340 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
341 | gl.vertexAttribPointer(
342 | programInfo.attribLocations.vertexPosition,
343 | numComponents,
344 | type,
345 | normalize,
346 | stride,
347 | offset);
348 | gl.enableVertexAttribArray(
349 | programInfo.attribLocations.vertexPosition);
350 | }
351 |
352 | // Tell WebGL how to pull out the texture coordinates from
353 | // the texture coordinate buffer into the textureCoord attribute.
354 | {
355 | const numComponents = 2;
356 | const type = gl.FLOAT;
357 | const normalize = false;
358 | const stride = 0;
359 | const offset = 0;
360 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
361 | gl.vertexAttribPointer(
362 | programInfo.attribLocations.textureCoord,
363 | numComponents,
364 | type,
365 | normalize,
366 | stride,
367 | offset);
368 | gl.enableVertexAttribArray(
369 | programInfo.attribLocations.textureCoord);
370 | }
371 |
372 | // Tell WebGL which indices to use to index the vertices
373 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
374 |
375 | // Tell WebGL to use our program when drawing
376 |
377 | gl.useProgram(programInfo.program);
378 |
379 | // Set the shader uniforms
380 |
381 | gl.uniformMatrix4fv(
382 | programInfo.uniformLocations.projectionMatrix,
383 | false,
384 | projectionMatrix);
385 | gl.uniformMatrix4fv(
386 | programInfo.uniformLocations.modelViewMatrix,
387 | false,
388 | modelViewMatrix);
389 |
390 | // Specify the texture to map onto the faces.
391 |
392 | // Tell WebGL we want to affect texture unit 0
393 | gl.activeTexture(gl.TEXTURE0);
394 |
395 | // Bind the texture to texture unit 0
396 | gl.bindTexture(gl.TEXTURE_2D, texture);
397 |
398 | // Tell the shader we bound the texture to texture unit 0
399 | gl.uniform1i(programInfo.uniformLocations.uSampler, 0);
400 |
401 | {
402 | const vertexCount = 36;
403 | const type = gl.UNSIGNED_SHORT;
404 | const offset = 0;
405 | gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
406 | }
407 |
408 | // Update the rotation for the next draw
409 |
410 | cubeRotation += deltaTime;
411 | }
412 |
413 | //
414 | // Initialize a shader program, so WebGL knows how to draw our data
415 | //
416 | function initShaderProgram(gl, vsSource, fsSource) {
417 | const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
418 | const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
419 |
420 | // Create the shader program
421 |
422 | const shaderProgram = gl.createProgram();
423 | gl.attachShader(shaderProgram, vertexShader);
424 | gl.attachShader(shaderProgram, fragmentShader);
425 | gl.linkProgram(shaderProgram);
426 |
427 | // If creating the shader program failed, alert
428 |
429 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
430 | alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
431 | return null;
432 | }
433 |
434 | return shaderProgram;
435 | }
436 |
437 | //
438 | // creates a shader of the given type, uploads the source and
439 | // compiles it.
440 | //
441 | function loadShader(gl, type, source) {
442 | const shader = gl.createShader(type);
443 |
444 | // Send the source to the shader object
445 |
446 | gl.shaderSource(shader, source);
447 |
448 | // Compile the shader program
449 |
450 | gl.compileShader(shader);
451 |
452 | // See if it compiled successfully
453 |
454 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
455 | alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
456 | gl.deleteShader(shader);
457 | return null;
458 | }
459 |
460 | return shader;
461 | }
462 |
463 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample6/webgl.css:
--------------------------------------------------------------------------------
1 | canvas {
2 | border: 2px solid black;
3 | background-color: black;
4 | }
5 | video {
6 | display: none;
7 | }
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample7/cubetexture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/webgl-examples/17a7484b5bb5cddee1dce3eb93c8d48925453557/webgl-examples/tutorial/sample7/cubetexture.png
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample7/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Demo
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample7/webgl-demo.js:
--------------------------------------------------------------------------------
1 | var cubeRotation = 0.0;
2 |
3 | main();
4 |
5 | //
6 | // Start here
7 | //
8 | function main() {
9 | const canvas = document.querySelector('#glcanvas');
10 | const gl = canvas.getContext('webgl');
11 |
12 | // If we don't have a GL context, give up now
13 |
14 | if (!gl) {
15 | alert('Unable to initialize WebGL. Your browser or machine may not support it.');
16 | return;
17 | }
18 |
19 | // Vertex shader program
20 |
21 | const vsSource = `
22 | attribute vec4 aVertexPosition;
23 | attribute vec3 aVertexNormal;
24 | attribute vec2 aTextureCoord;
25 |
26 | uniform mat4 uNormalMatrix;
27 | uniform mat4 uModelViewMatrix;
28 | uniform mat4 uProjectionMatrix;
29 |
30 | varying highp vec2 vTextureCoord;
31 | varying highp vec3 vLighting;
32 |
33 | void main(void) {
34 | gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
35 | vTextureCoord = aTextureCoord;
36 |
37 | // Apply lighting effect
38 |
39 | highp vec3 ambientLight = vec3(0.3, 0.3, 0.3);
40 | highp vec3 directionalLightColor = vec3(1, 1, 1);
41 | highp vec3 directionalVector = normalize(vec3(0.85, 0.8, 0.75));
42 |
43 | highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
44 |
45 | highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
46 | vLighting = ambientLight + (directionalLightColor * directional);
47 | }
48 | `;
49 |
50 | // Fragment shader program
51 |
52 | const fsSource = `
53 | varying highp vec2 vTextureCoord;
54 | varying highp vec3 vLighting;
55 |
56 | uniform sampler2D uSampler;
57 |
58 | void main(void) {
59 | highp vec4 texelColor = texture2D(uSampler, vTextureCoord);
60 |
61 | gl_FragColor = vec4(texelColor.rgb * vLighting, texelColor.a);
62 | }
63 | `;
64 |
65 | // Initialize a shader program; this is where all the lighting
66 | // for the vertices and so forth is established.
67 | const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
68 |
69 | // Collect all the info needed to use the shader program.
70 | // Look up which attributes our shader program is using
71 | // for aVertexPosition, aVertexNormal, aTextureCoord,
72 | // and look up uniform locations.
73 | const programInfo = {
74 | program: shaderProgram,
75 | attribLocations: {
76 | vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
77 | vertexNormal: gl.getAttribLocation(shaderProgram, 'aVertexNormal'),
78 | textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
79 | },
80 | uniformLocations: {
81 | projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
82 | modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
83 | normalMatrix: gl.getUniformLocation(shaderProgram, 'uNormalMatrix'),
84 | uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
85 | }
86 | };
87 |
88 | // Here's where we call the routine that builds all the
89 | // objects we'll be drawing.
90 | const buffers = initBuffers(gl);
91 |
92 | const texture = loadTexture(gl, 'cubetexture.png');
93 |
94 | var then = 0;
95 |
96 | // Draw the scene repeatedly
97 | function render(now) {
98 | now *= 0.001; // convert to seconds
99 | const deltaTime = now - then;
100 | then = now;
101 |
102 | drawScene(gl, programInfo, buffers, texture, deltaTime);
103 |
104 | requestAnimationFrame(render);
105 | }
106 | requestAnimationFrame(render);
107 | }
108 |
109 | //
110 | // initBuffers
111 | //
112 | // Initialize the buffers we'll need. For this demo, we just
113 | // have one object -- a simple three-dimensional cube.
114 | //
115 | function initBuffers(gl) {
116 |
117 | // Create a buffer for the cube's vertex positions.
118 |
119 | const positionBuffer = gl.createBuffer();
120 |
121 | // Select the positionBuffer as the one to apply buffer
122 | // operations to from here out.
123 |
124 | gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
125 |
126 | // Now create an array of positions for the cube.
127 |
128 | const positions = [
129 | // Front face
130 | -1.0, -1.0, 1.0,
131 | 1.0, -1.0, 1.0,
132 | 1.0, 1.0, 1.0,
133 | -1.0, 1.0, 1.0,
134 |
135 | // Back face
136 | -1.0, -1.0, -1.0,
137 | -1.0, 1.0, -1.0,
138 | 1.0, 1.0, -1.0,
139 | 1.0, -1.0, -1.0,
140 |
141 | // Top face
142 | -1.0, 1.0, -1.0,
143 | -1.0, 1.0, 1.0,
144 | 1.0, 1.0, 1.0,
145 | 1.0, 1.0, -1.0,
146 |
147 | // Bottom face
148 | -1.0, -1.0, -1.0,
149 | 1.0, -1.0, -1.0,
150 | 1.0, -1.0, 1.0,
151 | -1.0, -1.0, 1.0,
152 |
153 | // Right face
154 | 1.0, -1.0, -1.0,
155 | 1.0, 1.0, -1.0,
156 | 1.0, 1.0, 1.0,
157 | 1.0, -1.0, 1.0,
158 |
159 | // Left face
160 | -1.0, -1.0, -1.0,
161 | -1.0, -1.0, 1.0,
162 | -1.0, 1.0, 1.0,
163 | -1.0, 1.0, -1.0,
164 | ];
165 |
166 | // Now pass the list of positions into WebGL to build the
167 | // shape. We do this by creating a Float32Array from the
168 | // JavaScript array, then use it to fill the current buffer.
169 |
170 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
171 |
172 | // Set up the normals for the vertices, so that we can compute lighting.
173 |
174 | const normalBuffer = gl.createBuffer();
175 | gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
176 |
177 | const vertexNormals = [
178 | // Front
179 | 0.0, 0.0, 1.0,
180 | 0.0, 0.0, 1.0,
181 | 0.0, 0.0, 1.0,
182 | 0.0, 0.0, 1.0,
183 |
184 | // Back
185 | 0.0, 0.0, -1.0,
186 | 0.0, 0.0, -1.0,
187 | 0.0, 0.0, -1.0,
188 | 0.0, 0.0, -1.0,
189 |
190 | // Top
191 | 0.0, 1.0, 0.0,
192 | 0.0, 1.0, 0.0,
193 | 0.0, 1.0, 0.0,
194 | 0.0, 1.0, 0.0,
195 |
196 | // Bottom
197 | 0.0, -1.0, 0.0,
198 | 0.0, -1.0, 0.0,
199 | 0.0, -1.0, 0.0,
200 | 0.0, -1.0, 0.0,
201 |
202 | // Right
203 | 1.0, 0.0, 0.0,
204 | 1.0, 0.0, 0.0,
205 | 1.0, 0.0, 0.0,
206 | 1.0, 0.0, 0.0,
207 |
208 | // Left
209 | -1.0, 0.0, 0.0,
210 | -1.0, 0.0, 0.0,
211 | -1.0, 0.0, 0.0,
212 | -1.0, 0.0, 0.0
213 | ];
214 |
215 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals),
216 | gl.STATIC_DRAW);
217 |
218 | // Now set up the texture coordinates for the faces.
219 |
220 | const textureCoordBuffer = gl.createBuffer();
221 | gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
222 |
223 | const textureCoordinates = [
224 | // Front
225 | 0.0, 0.0,
226 | 1.0, 0.0,
227 | 1.0, 1.0,
228 | 0.0, 1.0,
229 | // Back
230 | 0.0, 0.0,
231 | 1.0, 0.0,
232 | 1.0, 1.0,
233 | 0.0, 1.0,
234 | // Top
235 | 0.0, 0.0,
236 | 1.0, 0.0,
237 | 1.0, 1.0,
238 | 0.0, 1.0,
239 | // Bottom
240 | 0.0, 0.0,
241 | 1.0, 0.0,
242 | 1.0, 1.0,
243 | 0.0, 1.0,
244 | // Right
245 | 0.0, 0.0,
246 | 1.0, 0.0,
247 | 1.0, 1.0,
248 | 0.0, 1.0,
249 | // Left
250 | 0.0, 0.0,
251 | 1.0, 0.0,
252 | 1.0, 1.0,
253 | 0.0, 1.0,
254 | ];
255 |
256 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),
257 | gl.STATIC_DRAW);
258 |
259 | // Build the element array buffer; this specifies the indices
260 | // into the vertex arrays for each face's vertices.
261 |
262 | const indexBuffer = gl.createBuffer();
263 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
264 |
265 | // This array defines each face as two triangles, using the
266 | // indices into the vertex array to specify each triangle's
267 | // position.
268 |
269 | const indices = [
270 | 0, 1, 2, 0, 2, 3, // front
271 | 4, 5, 6, 4, 6, 7, // back
272 | 8, 9, 10, 8, 10, 11, // top
273 | 12, 13, 14, 12, 14, 15, // bottom
274 | 16, 17, 18, 16, 18, 19, // right
275 | 20, 21, 22, 20, 22, 23, // left
276 | ];
277 |
278 | // Now send the element array to GL
279 |
280 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
281 | new Uint16Array(indices), gl.STATIC_DRAW);
282 |
283 | return {
284 | position: positionBuffer,
285 | normal: normalBuffer,
286 | textureCoord: textureCoordBuffer,
287 | indices: indexBuffer,
288 | };
289 | }
290 |
291 | //
292 | // Initialize a texture and load an image.
293 | // When the image finished loading copy it into the texture.
294 | //
295 | function loadTexture(gl, url) {
296 | const texture = gl.createTexture();
297 | gl.bindTexture(gl.TEXTURE_2D, texture);
298 |
299 | // Because images have to be download over the internet
300 | // they might take a moment until they are ready.
301 | // Until then put a single pixel in the texture so we can
302 | // use it immediately. When the image has finished downloading
303 | // we'll update the texture with the contents of the image.
304 | const level = 0;
305 | const internalFormat = gl.RGBA;
306 | const width = 1;
307 | const height = 1;
308 | const border = 0;
309 | const srcFormat = gl.RGBA;
310 | const srcType = gl.UNSIGNED_BYTE;
311 | const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
312 | gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
313 | width, height, border, srcFormat, srcType,
314 | pixel);
315 |
316 | const image = new Image();
317 | image.onload = function() {
318 | gl.bindTexture(gl.TEXTURE_2D, texture);
319 | gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
320 | srcFormat, srcType, image);
321 |
322 | // WebGL1 has different requirements for power of 2 images
323 | // vs non power of 2 images so check if the image is a
324 | // power of 2 in both dimensions.
325 | if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
326 | // Yes, it's a power of 2. Generate mips.
327 | gl.generateMipmap(gl.TEXTURE_2D);
328 | } else {
329 | // No, it's not a power of 2. Turn of mips and set
330 | // wrapping to clamp to edge
331 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
332 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
333 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
334 | }
335 | };
336 | image.src = url;
337 |
338 | return texture;
339 | }
340 |
341 | function isPowerOf2(value) {
342 | return (value & (value - 1)) == 0;
343 | }
344 |
345 | //
346 | // Draw the scene.
347 | //
348 | function drawScene(gl, programInfo, buffers, texture, deltaTime) {
349 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
350 | gl.clearDepth(1.0); // Clear everything
351 | gl.enable(gl.DEPTH_TEST); // Enable depth testing
352 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things
353 |
354 | // Clear the canvas before we start drawing on it.
355 |
356 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
357 |
358 | // Create a perspective matrix, a special matrix that is
359 | // used to simulate the distortion of perspective in a camera.
360 | // Our field of view is 45 degrees, with a width/height
361 | // ratio that matches the display size of the canvas
362 | // and we only want to see objects between 0.1 units
363 | // and 100 units away from the camera.
364 |
365 | const fieldOfView = 45 * Math.PI / 180; // in radians
366 | const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
367 | const zNear = 0.1;
368 | const zFar = 100.0;
369 | const projectionMatrix = mat4.create();
370 |
371 | // note: glmatrix.js always has the first argument
372 | // as the destination to receive the result.
373 | mat4.perspective(projectionMatrix,
374 | fieldOfView,
375 | aspect,
376 | zNear,
377 | zFar);
378 |
379 | // Set the drawing position to the "identity" point, which is
380 | // the center of the scene.
381 | const modelViewMatrix = mat4.create();
382 |
383 | // Now move the drawing position a bit to where we want to
384 | // start drawing the square.
385 |
386 | mat4.translate(modelViewMatrix, // destination matrix
387 | modelViewMatrix, // matrix to translate
388 | [-0.0, 0.0, -6.0]); // amount to translate
389 | mat4.rotate(modelViewMatrix, // destination matrix
390 | modelViewMatrix, // matrix to rotate
391 | cubeRotation, // amount to rotate in radians
392 | [0, 0, 1]); // axis to rotate around (Z)
393 | mat4.rotate(modelViewMatrix, // destination matrix
394 | modelViewMatrix, // matrix to rotate
395 | cubeRotation * .7,// amount to rotate in radians
396 | [0, 1, 0]); // axis to rotate around (X)
397 |
398 | const normalMatrix = mat4.create();
399 | mat4.invert(normalMatrix, modelViewMatrix);
400 | mat4.transpose(normalMatrix, normalMatrix);
401 |
402 | // Tell WebGL how to pull out the positions from the position
403 | // buffer into the vertexPosition attribute
404 | {
405 | const numComponents = 3;
406 | const type = gl.FLOAT;
407 | const normalize = false;
408 | const stride = 0;
409 | const offset = 0;
410 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
411 | gl.vertexAttribPointer(
412 | programInfo.attribLocations.vertexPosition,
413 | numComponents,
414 | type,
415 | normalize,
416 | stride,
417 | offset);
418 | gl.enableVertexAttribArray(
419 | programInfo.attribLocations.vertexPosition);
420 | }
421 |
422 | // Tell WebGL how to pull out the texture coordinates from
423 | // the texture coordinate buffer into the textureCoord attribute.
424 | {
425 | const numComponents = 2;
426 | const type = gl.FLOAT;
427 | const normalize = false;
428 | const stride = 0;
429 | const offset = 0;
430 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
431 | gl.vertexAttribPointer(
432 | programInfo.attribLocations.textureCoord,
433 | numComponents,
434 | type,
435 | normalize,
436 | stride,
437 | offset);
438 | gl.enableVertexAttribArray(
439 | programInfo.attribLocations.textureCoord);
440 | }
441 |
442 | // Tell WebGL how to pull out the normals from
443 | // the normal buffer into the vertexNormal attribute.
444 | {
445 | const numComponents = 3;
446 | const type = gl.FLOAT;
447 | const normalize = false;
448 | const stride = 0;
449 | const offset = 0;
450 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normal);
451 | gl.vertexAttribPointer(
452 | programInfo.attribLocations.vertexNormal,
453 | numComponents,
454 | type,
455 | normalize,
456 | stride,
457 | offset);
458 | gl.enableVertexAttribArray(
459 | programInfo.attribLocations.vertexNormal);
460 | }
461 |
462 | // Tell WebGL which indices to use to index the vertices
463 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
464 |
465 | // Tell WebGL to use our program when drawing
466 |
467 | gl.useProgram(programInfo.program);
468 |
469 | // Set the shader uniforms
470 |
471 | gl.uniformMatrix4fv(
472 | programInfo.uniformLocations.projectionMatrix,
473 | false,
474 | projectionMatrix);
475 | gl.uniformMatrix4fv(
476 | programInfo.uniformLocations.modelViewMatrix,
477 | false,
478 | modelViewMatrix);
479 | gl.uniformMatrix4fv(
480 | programInfo.uniformLocations.normalMatrix,
481 | false,
482 | normalMatrix);
483 |
484 | // Specify the texture to map onto the faces.
485 |
486 | // Tell WebGL we want to affect texture unit 0
487 | gl.activeTexture(gl.TEXTURE0);
488 |
489 | // Bind the texture to texture unit 0
490 | gl.bindTexture(gl.TEXTURE_2D, texture);
491 |
492 | // Tell the shader we bound the texture to texture unit 0
493 | gl.uniform1i(programInfo.uniformLocations.uSampler, 0);
494 |
495 | {
496 | const vertexCount = 36;
497 | const type = gl.UNSIGNED_SHORT;
498 | const offset = 0;
499 | gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
500 | }
501 |
502 | // Update the rotation for the next draw
503 |
504 | cubeRotation += deltaTime;
505 | }
506 |
507 | //
508 | // Initialize a shader program, so WebGL knows how to draw our data
509 | //
510 | function initShaderProgram(gl, vsSource, fsSource) {
511 | const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
512 | const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
513 |
514 | // Create the shader program
515 |
516 | const shaderProgram = gl.createProgram();
517 | gl.attachShader(shaderProgram, vertexShader);
518 | gl.attachShader(shaderProgram, fragmentShader);
519 | gl.linkProgram(shaderProgram);
520 |
521 | // If creating the shader program failed, alert
522 |
523 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
524 | alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
525 | return null;
526 | }
527 |
528 | return shaderProgram;
529 | }
530 |
531 | //
532 | // creates a shader of the given type, uploads the source and
533 | // compiles it.
534 | //
535 | function loadShader(gl, type, source) {
536 | const shader = gl.createShader(type);
537 |
538 | // Send the source to the shader object
539 |
540 | gl.shaderSource(shader, source);
541 |
542 | // Compile the shader program
543 |
544 | gl.compileShader(shader);
545 |
546 | // See if it compiled successfully
547 |
548 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
549 | alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
550 | gl.deleteShader(shader);
551 | return null;
552 | }
553 |
554 | return shader;
555 | }
556 |
557 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample7/webgl.css:
--------------------------------------------------------------------------------
1 | canvas {
2 | border: 2px solid black;
3 | background-color: black;
4 | }
5 | video {
6 | display: none;
7 | }
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample8/Firefox.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mdn/webgl-examples/17a7484b5bb5cddee1dce3eb93c8d48925453557/webgl-examples/tutorial/sample8/Firefox.mp4
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample8/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Demo
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample8/webgl-demo.js:
--------------------------------------------------------------------------------
1 | var cubeRotation = 0.0;
2 | // will set to true when video can be copied to texture
3 | var copyVideo = false;
4 |
5 | main();
6 |
7 | //
8 | // Start here
9 | //
10 | function main() {
11 | const canvas = document.querySelector('#glcanvas');
12 | const gl = canvas.getContext('webgl');
13 |
14 | // If we don't have a GL context, give up now
15 |
16 | if (!gl) {
17 | alert('Unable to initialize WebGL. Your browser or machine may not support it.');
18 | return;
19 | }
20 |
21 | // Vertex shader program
22 |
23 | const vsSource = `
24 | attribute vec4 aVertexPosition;
25 | attribute vec3 aVertexNormal;
26 | attribute vec2 aTextureCoord;
27 |
28 | uniform mat4 uNormalMatrix;
29 | uniform mat4 uModelViewMatrix;
30 | uniform mat4 uProjectionMatrix;
31 |
32 | varying highp vec2 vTextureCoord;
33 | varying highp vec3 vLighting;
34 |
35 | void main(void) {
36 | gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
37 | vTextureCoord = aTextureCoord;
38 |
39 | // Apply lighting effect
40 |
41 | highp vec3 ambientLight = vec3(0.3, 0.3, 0.3);
42 | highp vec3 directionalLightColor = vec3(1, 1, 1);
43 | highp vec3 directionalVector = normalize(vec3(0.85, 0.8, 0.75));
44 |
45 | highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
46 |
47 | highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
48 | vLighting = ambientLight + (directionalLightColor * directional);
49 | }
50 | `;
51 |
52 | // Fragment shader program
53 |
54 | const fsSource = `
55 | varying highp vec2 vTextureCoord;
56 | varying highp vec3 vLighting;
57 |
58 | uniform sampler2D uSampler;
59 |
60 | void main(void) {
61 | highp vec4 texelColor = texture2D(uSampler, vTextureCoord);
62 |
63 | gl_FragColor = vec4(texelColor.rgb * vLighting, texelColor.a);
64 | }
65 | `;
66 |
67 | // Initialize a shader program; this is where all the lighting
68 | // for the vertices and so forth is established.
69 | const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
70 |
71 | // Collect all the info needed to use the shader program.
72 | // Look up which attributes our shader program is using
73 | // for aVertexPosition, aVertexNormal, aTextureCoord,
74 | // and look up uniform locations.
75 | const programInfo = {
76 | program: shaderProgram,
77 | attribLocations: {
78 | vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
79 | vertexNormal: gl.getAttribLocation(shaderProgram, 'aVertexNormal'),
80 | textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
81 | },
82 | uniformLocations: {
83 | projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
84 | modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
85 | normalMatrix: gl.getUniformLocation(shaderProgram, 'uNormalMatrix'),
86 | uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
87 | }
88 | };
89 |
90 | // Here's where we call the routine that builds all the
91 | // objects we'll be drawing.
92 | const buffers = initBuffers(gl);
93 |
94 | const texture = initTexture(gl);
95 |
96 | const video = setupVideo('Firefox.mp4');
97 |
98 | var then = 0;
99 |
100 | // Draw the scene repeatedly
101 | function render(now) {
102 | now *= 0.001; // convert to seconds
103 | const deltaTime = now - then;
104 | then = now;
105 |
106 | if (copyVideo) {
107 | updateTexture(gl, texture, video);
108 | }
109 |
110 | drawScene(gl, programInfo, buffers, texture, deltaTime);
111 |
112 | requestAnimationFrame(render);
113 | }
114 | requestAnimationFrame(render);
115 | }
116 |
117 | function setupVideo(url) {
118 | const video = document.createElement('video');
119 |
120 | var playing = false;
121 | var timeupdate = false;
122 |
123 | video.autoplay = true;
124 | video.muted = true;
125 | video.loop = true;
126 |
127 | // Waiting for these 2 events ensures
128 | // there is data in the video
129 |
130 | video.addEventListener('playing', function() {
131 | playing = true;
132 | checkReady();
133 | }, true);
134 |
135 | video.addEventListener('timeupdate', function() {
136 | timeupdate = true;
137 | checkReady();
138 | }, true);
139 |
140 | video.src = url;
141 | video.play();
142 |
143 | function checkReady() {
144 | if (playing && timeupdate) {
145 | copyVideo = true;
146 | }
147 | }
148 |
149 | return video;
150 | }
151 |
152 | //
153 | // initBuffers
154 | //
155 | // Initialize the buffers we'll need. For this demo, we just
156 | // have one object -- a simple three-dimensional cube.
157 | //
158 | function initBuffers(gl) {
159 |
160 | // Create a buffer for the cube's vertex positions.
161 |
162 | const positionBuffer = gl.createBuffer();
163 |
164 | // Select the positionBuffer as the one to apply buffer
165 | // operations to from here out.
166 |
167 | gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
168 |
169 | // Now create an array of positions for the cube.
170 |
171 | const positions = [
172 | // Front face
173 | -1.0, -1.0, 1.0,
174 | 1.0, -1.0, 1.0,
175 | 1.0, 1.0, 1.0,
176 | -1.0, 1.0, 1.0,
177 |
178 | // Back face
179 | -1.0, -1.0, -1.0,
180 | -1.0, 1.0, -1.0,
181 | 1.0, 1.0, -1.0,
182 | 1.0, -1.0, -1.0,
183 |
184 | // Top face
185 | -1.0, 1.0, -1.0,
186 | -1.0, 1.0, 1.0,
187 | 1.0, 1.0, 1.0,
188 | 1.0, 1.0, -1.0,
189 |
190 | // Bottom face
191 | -1.0, -1.0, -1.0,
192 | 1.0, -1.0, -1.0,
193 | 1.0, -1.0, 1.0,
194 | -1.0, -1.0, 1.0,
195 |
196 | // Right face
197 | 1.0, -1.0, -1.0,
198 | 1.0, 1.0, -1.0,
199 | 1.0, 1.0, 1.0,
200 | 1.0, -1.0, 1.0,
201 |
202 | // Left face
203 | -1.0, -1.0, -1.0,
204 | -1.0, -1.0, 1.0,
205 | -1.0, 1.0, 1.0,
206 | -1.0, 1.0, -1.0,
207 | ];
208 |
209 | // Now pass the list of positions into WebGL to build the
210 | // shape. We do this by creating a Float32Array from the
211 | // JavaScript array, then use it to fill the current buffer.
212 |
213 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
214 |
215 | // Set up the normals for the vertices, so that we can compute lighting.
216 |
217 | const normalBuffer = gl.createBuffer();
218 | gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
219 |
220 | const vertexNormals = [
221 | // Front
222 | 0.0, 0.0, 1.0,
223 | 0.0, 0.0, 1.0,
224 | 0.0, 0.0, 1.0,
225 | 0.0, 0.0, 1.0,
226 |
227 | // Back
228 | 0.0, 0.0, -1.0,
229 | 0.0, 0.0, -1.0,
230 | 0.0, 0.0, -1.0,
231 | 0.0, 0.0, -1.0,
232 |
233 | // Top
234 | 0.0, 1.0, 0.0,
235 | 0.0, 1.0, 0.0,
236 | 0.0, 1.0, 0.0,
237 | 0.0, 1.0, 0.0,
238 |
239 | // Bottom
240 | 0.0, -1.0, 0.0,
241 | 0.0, -1.0, 0.0,
242 | 0.0, -1.0, 0.0,
243 | 0.0, -1.0, 0.0,
244 |
245 | // Right
246 | 1.0, 0.0, 0.0,
247 | 1.0, 0.0, 0.0,
248 | 1.0, 0.0, 0.0,
249 | 1.0, 0.0, 0.0,
250 |
251 | // Left
252 | -1.0, 0.0, 0.0,
253 | -1.0, 0.0, 0.0,
254 | -1.0, 0.0, 0.0,
255 | -1.0, 0.0, 0.0,
256 | ];
257 |
258 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexNormals),
259 | gl.STATIC_DRAW);
260 |
261 | // Now set up the texture coordinates for the faces.
262 |
263 | const textureCoordBuffer = gl.createBuffer();
264 | gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
265 |
266 | const textureCoordinates = [
267 | // Front
268 | 0.0, 0.0,
269 | 1.0, 0.0,
270 | 1.0, 1.0,
271 | 0.0, 1.0,
272 | // Back
273 | 0.0, 0.0,
274 | 1.0, 0.0,
275 | 1.0, 1.0,
276 | 0.0, 1.0,
277 | // Top
278 | 0.0, 0.0,
279 | 1.0, 0.0,
280 | 1.0, 1.0,
281 | 0.0, 1.0,
282 | // Bottom
283 | 0.0, 0.0,
284 | 1.0, 0.0,
285 | 1.0, 1.0,
286 | 0.0, 1.0,
287 | // Right
288 | 0.0, 0.0,
289 | 1.0, 0.0,
290 | 1.0, 1.0,
291 | 0.0, 1.0,
292 | // Left
293 | 0.0, 0.0,
294 | 1.0, 0.0,
295 | 1.0, 1.0,
296 | 0.0, 1.0,
297 | ];
298 |
299 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),
300 | gl.STATIC_DRAW);
301 |
302 | // Build the element array buffer; this specifies the indices
303 | // into the vertex arrays for each face's vertices.
304 |
305 | const indexBuffer = gl.createBuffer();
306 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
307 |
308 | // This array defines each face as two triangles, using the
309 | // indices into the vertex array to specify each triangle's
310 | // position.
311 |
312 | const indices = [
313 | 0, 1, 2, 0, 2, 3, // front
314 | 4, 5, 6, 4, 6, 7, // back
315 | 8, 9, 10, 8, 10, 11, // top
316 | 12, 13, 14, 12, 14, 15, // bottom
317 | 16, 17, 18, 16, 18, 19, // right
318 | 20, 21, 22, 20, 22, 23, // left
319 | ];
320 |
321 | // Now send the element array to GL
322 |
323 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
324 | new Uint16Array(indices), gl.STATIC_DRAW);
325 |
326 | return {
327 | position: positionBuffer,
328 | normal: normalBuffer,
329 | textureCoord: textureCoordBuffer,
330 | indices: indexBuffer,
331 | };
332 | }
333 |
334 | //
335 | // Initialize a texture.
336 | //
337 | function initTexture(gl, url) {
338 | const texture = gl.createTexture();
339 | gl.bindTexture(gl.TEXTURE_2D, texture);
340 |
341 | // Because video havs to be download over the internet
342 | // they might take a moment until it's ready so
343 | // put a single pixel in the texture so we can
344 | // use it immediately.
345 | const level = 0;
346 | const internalFormat = gl.RGBA;
347 | const width = 1;
348 | const height = 1;
349 | const border = 0;
350 | const srcFormat = gl.RGBA;
351 | const srcType = gl.UNSIGNED_BYTE;
352 | const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
353 | gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
354 | width, height, border, srcFormat, srcType,
355 | pixel);
356 |
357 | // Turn off mips and set wrapping to clamp to edge so it
358 | // will work regardless of the dimensions of the video.
359 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
360 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
361 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
362 |
363 | return texture;
364 | }
365 |
366 | //
367 | // copy the video texture
368 | //
369 | function updateTexture(gl, texture, video) {
370 | const level = 0;
371 | const internalFormat = gl.RGBA;
372 | const srcFormat = gl.RGBA;
373 | const srcType = gl.UNSIGNED_BYTE;
374 | gl.bindTexture(gl.TEXTURE_2D, texture);
375 | gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
376 | srcFormat, srcType, video);
377 | }
378 |
379 | function isPowerOf2(value) {
380 | return (value & (value - 1)) == 0;
381 | }
382 |
383 | //
384 | // Draw the scene.
385 | //
386 | function drawScene(gl, programInfo, buffers, texture, deltaTime) {
387 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
388 | gl.clearDepth(1.0); // Clear everything
389 | gl.enable(gl.DEPTH_TEST); // Enable depth testing
390 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things
391 |
392 | // Clear the canvas before we start drawing on it.
393 |
394 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
395 |
396 | // Create a perspective matrix, a special matrix that is
397 | // used to simulate the distortion of perspective in a camera.
398 | // Our field of view is 45 degrees, with a width/height
399 | // ratio that matches the display size of the canvas
400 | // and we only want to see objects between 0.1 units
401 | // and 100 units away from the camera.
402 |
403 | const fieldOfView = 45 * Math.PI / 180; // in radians
404 | const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
405 | const zNear = 0.1;
406 | const zFar = 100.0;
407 | const projectionMatrix = mat4.create();
408 |
409 | // note: glmatrix.js always has the first argument
410 | // as the destination to receive the result.
411 | mat4.perspective(projectionMatrix,
412 | fieldOfView,
413 | aspect,
414 | zNear,
415 | zFar);
416 |
417 | // Set the drawing position to the "identity" point, which is
418 | // the center of the scene.
419 | const modelViewMatrix = mat4.create();
420 |
421 | // Now move the drawing position a bit to where we want to
422 | // start drawing the square.
423 |
424 | mat4.translate(modelViewMatrix, // destination matrix
425 | modelViewMatrix, // matrix to translate
426 | [-0.0, 0.0, -6.0]); // amount to translate
427 | mat4.rotate(modelViewMatrix, // destination matrix
428 | modelViewMatrix, // matrix to rotate
429 | cubeRotation, // amount to rotate in radians
430 | [0, 0, 1]); // axis to rotate around (Z)
431 | mat4.rotate(modelViewMatrix, // destination matrix
432 | modelViewMatrix, // matrix to rotate
433 | cubeRotation * .7,// amount to rotate in radians
434 | [0, 1, 0]); // axis to rotate around (X)
435 |
436 | const normalMatrix = mat4.create();
437 | mat4.invert(normalMatrix, modelViewMatrix);
438 | mat4.transpose(normalMatrix, normalMatrix);
439 |
440 | // Tell WebGL how to pull out the positions from the position
441 | // buffer into the vertexPosition attribute
442 | {
443 | const numComponents = 3;
444 | const type = gl.FLOAT;
445 | const normalize = false;
446 | const stride = 0;
447 | const offset = 0;
448 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
449 | gl.vertexAttribPointer(
450 | programInfo.attribLocations.vertexPosition,
451 | numComponents,
452 | type,
453 | normalize,
454 | stride,
455 | offset);
456 | gl.enableVertexAttribArray(
457 | programInfo.attribLocations.vertexPosition);
458 | }
459 |
460 | // Tell WebGL how to pull out the texture coordinates from
461 | // the texture coordinate buffer into the textureCoord attribute.
462 | {
463 | const numComponents = 2;
464 | const type = gl.FLOAT;
465 | const normalize = false;
466 | const stride = 0;
467 | const offset = 0;
468 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
469 | gl.vertexAttribPointer(
470 | programInfo.attribLocations.textureCoord,
471 | numComponents,
472 | type,
473 | normalize,
474 | stride,
475 | offset);
476 | gl.enableVertexAttribArray(
477 | programInfo.attribLocations.textureCoord);
478 | }
479 |
480 | // Tell WebGL how to pull out the normals from
481 | // the normal buffer into the vertexNormal attribute.
482 | {
483 | const numComponents = 3;
484 | const type = gl.FLOAT;
485 | const normalize = false;
486 | const stride = 0;
487 | const offset = 0;
488 | gl.bindBuffer(gl.ARRAY_BUFFER, buffers.normal);
489 | gl.vertexAttribPointer(
490 | programInfo.attribLocations.vertexNormal,
491 | numComponents,
492 | type,
493 | normalize,
494 | stride,
495 | offset);
496 | gl.enableVertexAttribArray(
497 | programInfo.attribLocations.vertexNormal);
498 | }
499 |
500 | // Tell WebGL which indices to use to index the vertices
501 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
502 |
503 | // Tell WebGL to use our program when drawing
504 |
505 | gl.useProgram(programInfo.program);
506 |
507 | // Set the shader uniforms
508 |
509 | gl.uniformMatrix4fv(
510 | programInfo.uniformLocations.projectionMatrix,
511 | false,
512 | projectionMatrix);
513 | gl.uniformMatrix4fv(
514 | programInfo.uniformLocations.modelViewMatrix,
515 | false,
516 | modelViewMatrix);
517 | gl.uniformMatrix4fv(
518 | programInfo.uniformLocations.normalMatrix,
519 | false,
520 | normalMatrix);
521 |
522 | // Specify the texture to map onto the faces.
523 |
524 | // Tell WebGL we want to affect texture unit 0
525 | gl.activeTexture(gl.TEXTURE0);
526 |
527 | // Bind the texture to texture unit 0
528 | gl.bindTexture(gl.TEXTURE_2D, texture);
529 |
530 | // Tell the shader we bound the texture to texture unit 0
531 | gl.uniform1i(programInfo.uniformLocations.uSampler, 0);
532 |
533 | {
534 | const vertexCount = 36;
535 | const type = gl.UNSIGNED_SHORT;
536 | const offset = 0;
537 | gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
538 | }
539 |
540 | // Update the rotation for the next draw
541 |
542 | cubeRotation += deltaTime;
543 | }
544 |
545 | //
546 | // Initialize a shader program, so WebGL knows how to draw our data
547 | //
548 | function initShaderProgram(gl, vsSource, fsSource) {
549 | const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
550 | const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
551 |
552 | // Create the shader program
553 |
554 | const shaderProgram = gl.createProgram();
555 | gl.attachShader(shaderProgram, vertexShader);
556 | gl.attachShader(shaderProgram, fragmentShader);
557 | gl.linkProgram(shaderProgram);
558 |
559 | // If creating the shader program failed, alert
560 |
561 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
562 | alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
563 | return null;
564 | }
565 |
566 | return shaderProgram;
567 | }
568 |
569 | //
570 | // creates a shader of the given type, uploads the source and
571 | // compiles it.
572 | //
573 | function loadShader(gl, type, source) {
574 | const shader = gl.createShader(type);
575 |
576 | // Send the source to the shader object
577 |
578 | gl.shaderSource(shader, source);
579 |
580 | // Compile the shader program
581 |
582 | gl.compileShader(shader);
583 |
584 | // See if it compiled successfully
585 |
586 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
587 | alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
588 | gl.deleteShader(shader);
589 | return null;
590 | }
591 |
592 | return shader;
593 | }
594 |
595 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/sample8/webgl.css:
--------------------------------------------------------------------------------
1 | canvas {
2 | border: 2px solid black;
3 | background-color: black;
4 | }
5 | video {
6 | display: none;
7 | }
--------------------------------------------------------------------------------
/webgl-examples/tutorial/tetrahedron/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/webgl-examples/tutorial/tetrahedron/webgl-demo.js:
--------------------------------------------------------------------------------
1 | var tetrahedronRotation = 0.0;
2 |
3 | main();
4 |
5 | //
6 | // Start here
7 | //
8 | function main() {
9 | const canvas = document.querySelector('#glcanvas');
10 | const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
11 |
12 | // If we don't have a GL context, give up now
13 |
14 | if (!gl) {
15 | alert('Unable to initialize WebGL. Your browser or machine may not support it.');
16 | return;
17 | }
18 |
19 | // Vertex shader program
20 |
21 | const vsSource = `
22 | attribute vec4 aVertexPosition;
23 | attribute vec4 aVertexColor;
24 |
25 | uniform mat4 uModelViewMatrix;
26 | uniform mat4 uProjectionMatrix;
27 |
28 | varying lowp vec4 vColor;
29 |
30 | void main(void) {
31 | gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
32 | vColor = aVertexColor;
33 | }
34 | `;
35 |
36 | // Fragment shader program
37 |
38 | const fsSource = `
39 | varying lowp vec4 vColor;
40 |
41 | void main(void) {
42 | gl_FragColor = vColor;
43 | }
44 | `;
45 |
46 | // Initialize a shader program; this is where all the lighting
47 | // for the vertices and so forth is established.
48 | const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
49 |
50 | // Collect all the info needed to use the shader program.
51 | // Look up which attributes our shader program is using
52 | // for aVertexPosition, aVevrtexColor and also
53 | // look up uniform locations.
54 | const programInfo = {
55 | program: shaderProgram,
56 | attribLocations: {
57 | vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
58 | vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
59 | },
60 | uniformLocations: {
61 | projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
62 | modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
63 | },
64 | };
65 |
66 | // Here's where we call the routine that builds all the
67 | // objects we'll be drawing.
68 | const buffers = initBuffers(gl);
69 |
70 | var then = 0;
71 |
72 | // Draw the scene repeatedly
73 | function render(now) {
74 | now *= 0.001; // convert to seconds
75 | const deltaTime = now - then;
76 | then = now;
77 |
78 | drawScene(gl, programInfo, buffers, deltaTime);
79 |
80 | requestAnimationFrame(render);
81 | }
82 |
83 | requestAnimationFrame(render);
84 | }
85 |
86 | //
87 | // initBuffers
88 | //
89 | // Initialize the buffers we'll need. For this demo, we just
90 | // have one object -- a simple three-dimensional tetrahedron.
91 | //
92 | function initBuffers(gl) {
93 |
94 | // Create a buffer for the tetrahedron's vertex positions.
95 |
96 | const positionBuffer = gl.createBuffer();
97 |
98 | // Select the positionBuffer as the one to apply buffer
99 | // operations to from here out.
100 |
101 | gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
102 |
103 | // Now create an array of positions for the tetrahedron.
104 | // A equilateral triangle is needed ( well 4 of them )
105 | // Point `O` is where the height is projected
106 | // The tetrahedron is rotated around point `M`
107 | // Height from vertex `A` to the edge `BC` is `H`
108 | // The edge of the tetrahedron is 2 units long
109 | // |AH| = 1.7320508075688772935274463415059
110 | // The median and a height AH divides itself by
111 | // the other medians into 1x and 2x ( one part and two parts )
112 | // |AH|/3 = 0.57735026918962576450914878050197
113 | // Find the tetrahedron height by argument sine (