Last active
August 24, 2020 09:45
-
-
Save dptole/4579eadc840885874674b6ec11cb1b5c to your computer and use it in GitHub Desktop.
WebGL standalone example: 3D cube (js) https://jsfiddle.net/4bdwavo0/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- https://jsfiddle.net/4bdwavo0/ --> | |
<!doctype html> | |
<html> | |
<head> | |
<!-- https://webglfundamentals.org/ --> | |
<style> | |
input[type="range"] { | |
width: 100%; | |
} | |
</style> | |
<!-- VERTEX --> | |
<script id="vertex" type="text/x-webgl-vertex-shader"> | |
attribute vec4 a_position; | |
uniform mat4 u_transform; | |
attribute vec4 a_color; | |
varying vec4 v_color; | |
void main() { | |
gl_Position = u_transform * a_position; | |
v_color = gl_Position; | |
v_color = a_color; | |
} | |
</script> | |
<!-- SHADER --> | |
<script id="shader" type="text/x-webgl-fragment-shader"> | |
precision mediump float; | |
varying vec4 v_color; | |
void main() { | |
gl_FragColor = v_color; | |
} | |
</script> | |
<!-- TABLE CONTENT --> | |
<script id="table_content" type="text/html"> | |
<tbody> | |
<tr> | |
<td colspan="2" style="padding: 0; margin: 0"> | |
<table style="width: 100%"> | |
<tbody> | |
<tr> | |
<td style="width: 33%; border: 2px solid brown; vertical-align: top"> | |
<div>TRANSLATE X: <span id="translate_x_range_value"></span></div> | |
<div> | |
<input type="range" id="translate_x_range" min="-500" max="300" value="150"> | |
</div> | |
<div>TRANSLATE Y: <span id="translate_y_range_value"></span></div> | |
<div> | |
<input type="range" id="translate_y_range" min="-500" max="300" value="150"> | |
</div> | |
<div>TRANSLATE Z: <span id="translate_z_range_value"></span></div> | |
<div> | |
<input type="range" id="translate_z_range" min="-500" max="300" value="0"> | |
</div> | |
</td> | |
<td style="width: 33%; border: 2px solid cyan; vertical-align: top"> | |
<div>ROTATE X: <span id="rotate_x_range_value"></span>°</div> | |
<div> | |
<input type="range" id="rotate_x_range" min="-360" max="360" value="30"> | |
</div> | |
<div>ROTATE Y: <span id="rotate_y_range_value"></span>°</div> | |
<div> | |
<input type="range" id="rotate_y_range" min="-360" max="360" value="30"> | |
</div> | |
<div>ROTATE Z: <span id="rotate_z_range_value"></span>°</div> | |
<div> | |
<input type="range" id="rotate_z_range" min="-360" max="360" value="0"> | |
</div> | |
<div>PIVOT X: <span id="rotate_pivot_x_range_value"></span></div> | |
<div> | |
<input type="range" id="rotate_pivot_x_range" min="-100" max="100" value="0"> | |
</div> | |
<div>PIVOT Y: <span id="rotate_pivot_y_range_value"></span></div> | |
<div> | |
<input type="range" id="rotate_pivot_y_range" min="-100" max="100" value="0"> | |
</div> | |
<div>PIVOT Z: <span id="rotate_pivot_z_range_value"></span></div> | |
<div> | |
<input type="range" id="rotate_pivot_z_range" min="-100" max="100" value="0"> | |
</div> | |
</td> | |
<td style="width: 33%; border: 2px solid pink; vertical-align: top"> | |
<div>SCALE X: <span id="scale_x_range_value"></span></div> | |
<div> | |
<input type="range" id="scale_x_range" min="-3" max="3" step="0.1" value="0.5"> | |
</div> | |
<div>SCALE Y: <span id="scale_y_range_value"></span></div> | |
<div> | |
<input type="range" id="scale_y_range" min="-3" max="3" step="0.1" value="0.5"> | |
</div> | |
<div>SCALE Z: <span id="scale_z_range_value"></span></div> | |
<div> | |
<input type="range" id="scale_z_range" min="-3" max="3" step="0.1" value="0.5"> | |
</div> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</td> | |
<td rowspan="4" style="vertical-align: top; border: 2px solid green"> | |
<div id="info1block"> | |
<div>Coords:</div> | |
<pre id="info1"></pre> | |
</div> | |
<div id="info2block"> | |
<div>Transformation matrix:</div> | |
<div>(VERTEX: u_transform)</div> | |
<pre id="info2"></pre> | |
</div> | |
</td> | |
</tr> | |
<tr> | |
<td colspan="2" style="text-align: center; border: 2px solid green" id="c"></td> | |
</tr> | |
<tr> | |
<td style="text-align: center; border: 2px solid blue">VERTEX</td> | |
<td style="text-align: center; border: 2px solid red">SHADER</td> | |
</tr> | |
<tr> | |
<td style="vertical-align: top; border: 2px solid blue" id="v"></td> | |
<td style="vertical-align: top; border: 2px solid red" id="s"></td> | |
</tr> | |
</tbody> | |
</script> | |
<script> | |
var mat4 = { | |
translation: function(tx, ty, tz) { | |
return [ | |
1, 0, 0, 0, | |
0, 1, 0, 0, | |
0, 0, 1, 0, | |
tx, ty, tz, 1, | |
] | |
}, | |
xRotation: function(deg) { | |
var _1_rad = Math.PI / 180 | |
var c = Math.cos(deg * _1_rad) | |
var s = Math.sin(deg * _1_rad) | |
return [ | |
1, 0, 0, 0, | |
0, c, s, 0, | |
0, -s, c, 0, | |
0, 0, 0, 1, | |
] | |
}, | |
yRotation: function(deg) { | |
var _1_rad = Math.PI / 180 | |
var c = Math.cos(deg * _1_rad) | |
var s = Math.sin(deg * _1_rad) | |
return [ | |
c, 0, -s, 0, | |
0, 1, 0, 0, | |
s, 0, c, 0, | |
0, 0, 0, 1, | |
] | |
}, | |
zRotation: function(deg) { | |
var _1_rad = Math.PI / 180 | |
var c = Math.cos(deg * _1_rad) | |
var s = Math.sin(deg * _1_rad) | |
return [ | |
c, s, 0, 0, | |
-s, c, 0, 0, | |
0, 0, 1, 0, | |
0, 0, 0, 1, | |
] | |
}, | |
scaling: function(sx, sy, sz) { | |
return [ | |
sx, 0, 0, 0, | |
0, sy, 0, 0, | |
0, 0, sz, 0, | |
0, 0, 0, 1, | |
] | |
}, | |
projection: function(w, h, d) { | |
return [ | |
2 / w, 0, 0, 0, | |
0, -2 / h, 0, 0, | |
0, 0, 2 / d, 0, | |
-1, 1, 0, 1, | |
] | |
}, | |
orthographic: function(left, right, bottom, top, near, far) { | |
return [ | |
2 / (right - left), 0, 0, 0, | |
0, 2 / (top - bottom), 0, 0, | |
0, 0, 2 / (near - far), 0, | |
(left + right) / (left - right), (bottom + top) / (bottom - top), (near + far) / (near - far), 1, | |
]; | |
}, | |
multiply: function(a, b) { | |
var b00 = b[0 * 4 + 0] | |
var b01 = b[0 * 4 + 1] | |
var b02 = b[0 * 4 + 2] | |
var b03 = b[0 * 4 + 3] | |
var b10 = b[1 * 4 + 0] | |
var b11 = b[1 * 4 + 1] | |
var b12 = b[1 * 4 + 2] | |
var b13 = b[1 * 4 + 3] | |
var b20 = b[2 * 4 + 0] | |
var b21 = b[2 * 4 + 1] | |
var b22 = b[2 * 4 + 2] | |
var b23 = b[2 * 4 + 3] | |
var b30 = b[3 * 4 + 0] | |
var b31 = b[3 * 4 + 1] | |
var b32 = b[3 * 4 + 2] | |
var b33 = b[3 * 4 + 3] | |
var a00 = a[0 * 4 + 0] | |
var a01 = a[0 * 4 + 1] | |
var a02 = a[0 * 4 + 2] | |
var a03 = a[0 * 4 + 3] | |
var a10 = a[1 * 4 + 0] | |
var a11 = a[1 * 4 + 1] | |
var a12 = a[1 * 4 + 2] | |
var a13 = a[1 * 4 + 3] | |
var a20 = a[2 * 4 + 0] | |
var a21 = a[2 * 4 + 1] | |
var a22 = a[2 * 4 + 2] | |
var a23 = a[2 * 4 + 3] | |
var a30 = a[3 * 4 + 0] | |
var a31 = a[3 * 4 + 1] | |
var a32 = a[3 * 4 + 2] | |
var a33 = a[3 * 4 + 3] | |
return [ | |
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30, | |
b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31, | |
b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32, | |
b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33, | |
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30, | |
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31, | |
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32, | |
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33, | |
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30, | |
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31, | |
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32, | |
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33, | |
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30, | |
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31, | |
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32, | |
b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33, | |
] | |
}, | |
multiplyArray: function(mats) { | |
return mats.slice(1).reduce(function(r, m) { | |
return mat4.multiply(r, m) | |
}, mats[0]) | |
}, | |
inspect: function(m4) { | |
var mm = m4.map(function(a) { | |
return a.toFixed(2).padStart(6, ' ') | |
}) | |
return [ | |
mm[ 0] + ' ' + mm[ 1] + ' ' + mm[ 2] + ' ' + mm[ 3], | |
mm[ 4] + ' ' + mm[ 5] + ' ' + mm[ 6] + ' ' + mm[ 7], | |
mm[ 8] + ' ' + mm[ 9] + ' ' + mm[10] + ' ' + mm[11], | |
mm[12] + ' ' + mm[13] + ' ' + mm[14] + ' ' + mm[15], | |
].join('\n') | |
} | |
} | |
function createShader(gl, type, source) { | |
var shader = gl.createShader(type) | |
gl.shaderSource(shader, source) | |
gl.compileShader(shader) | |
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS) | |
if(success) { | |
return { | |
success: true, | |
data: shader | |
} | |
} | |
var source_lines = source.split(/\n/) | |
var source_code = source_lines.map(function(line, i) { | |
return (i + 1).toString().padStart(source_lines.length.toString().length, '0') + ' ' + line | |
}) | |
var output = gl.getShaderInfoLog(shader).replace('\0', '') | |
gl.deleteShader(shader) | |
var shader_type = gl.VERTEX_SHADER === type ? 'VERTEX SHADER' : 'FRAGMENT SHADER' | |
var header_error = `Error creating shader (${shader_type})` | |
var line = '-'.repeat(50) | |
return { | |
success: false, | |
data: [header_error].concat(line, output, line, source_code).join('\n') | |
} | |
} | |
function createProgram(gl, vertex_shader, fragment_shader) { | |
var program = gl.createProgram() | |
gl.attachShader(program, fragment_shader) | |
gl.attachShader(program, vertex_shader) | |
gl.linkProgram(program) | |
var success = gl.getProgramParameter(program, gl.LINK_STATUS) | |
if(success) { | |
program.fragment_shader = fragment_shader | |
program.vertex_shader = vertex_shader | |
gl.program = program | |
return { | |
success: true, | |
data: program | |
} | |
} | |
var output = gl.getProgramInfoLog(program).replace('\0', '') | |
gl.deleteProgram(program) | |
return { | |
success: false, | |
data: ['Error compiling program'].concat(output).join('\n') | |
} | |
} | |
function setupEvents(draw) { | |
function rangeSelector(range_selector, output_selector) { | |
var evs = ['wheel', 'change', 'mousemove'] | |
function wrap(f) { | |
return function(e) { | |
if(e.type === 'wheel' && e.isTrusted) { | |
e.preventDefault() | |
var direction = e.deltaY > 0 ? -1 : 1 | |
var step = parseFloat(this.step) || 1 | |
this.value = parseFloat(this.value) + direction * step | |
} | |
f.apply(this, arguments) | |
requestAnimationFrame(draw) | |
} | |
} | |
function f(e) { | |
var s = document.querySelector(output_selector) | |
if(s && e && e.target) s.textContent = e.target.value | |
} | |
var el = document.querySelector(range_selector) | |
if(el) { | |
for(var i = 0; i < evs.length; i++) | |
el.addEventListener(evs[i], wrap(f), {passive: evs[i] !== 'wheel'}) | |
evs.length && el.dispatchEvent(new Event(evs[0])) | |
} | |
} | |
rangeSelector('#translate_x_range', '#translate_x_range_value') | |
rangeSelector('#translate_y_range', '#translate_y_range_value') | |
rangeSelector('#translate_z_range', '#translate_z_range_value') | |
rangeSelector('#rotate_x_range', '#rotate_x_range_value') | |
rangeSelector('#rotate_y_range', '#rotate_y_range_value') | |
rangeSelector('#rotate_z_range', '#rotate_z_range_value') | |
rangeSelector('#rotate_pivot_x_range', '#rotate_pivot_x_range_value') | |
rangeSelector('#rotate_pivot_y_range', '#rotate_pivot_y_range_value') | |
rangeSelector('#rotate_pivot_z_range', '#rotate_pivot_z_range_value') | |
rangeSelector('#scale_x_range', '#scale_x_range_value') | |
rangeSelector('#scale_y_range', '#scale_y_range_value') | |
rangeSelector('#scale_z_range', '#scale_z_range_value') | |
} | |
function main() { | |
return new Promise(function(resolve, reject) { | |
function draw() { | |
// Add colors | |
gl.enableVertexAttribArray(a_color_ref) | |
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer) | |
// Tell the attribute how to get data out of color_buffer (ARRAY_BUFFER) | |
var size = 3 // 3 components per iteration | |
var type = gl.UNSIGNED_BYTE // the data is 8bit unsigned values | |
var normalize = true // normalize the data (convert from 0-255 to 0-1) | |
var stride = 0 // 0 = move forward size * sizeof(type) each iteration to get the next position | |
var offset = 0 // start at the beginning of the buffer | |
gl.vertexAttribPointer( | |
a_color_ref, size, type, normalize, stride, offset | |
) | |
// Add coords | |
gl.enableVertexAttribArray(a_position_ref) | |
gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer) | |
// Tell the attribute how to get data out of position_buffer (ARRAY_BUFFER) | |
var size = 3 // 3 components per iteration | |
var type = gl.FLOAT // the data is 32bit floats | |
var normalize = false // don't normalize the data | |
var stride = 0 // 0 = move forward size * sizeof(type) each iteration to get the next position | |
var offset = 0 // start at the beginning of the buffer | |
gl.vertexAttribPointer( | |
a_position_ref, size, type, normalize, stride, offset | |
) | |
// Add uniforms | |
var left = 0 | |
var right = gl.canvas.clientWidth | |
var bottom = gl.canvas.clientHeight | |
var top = 0 | |
var near = -400 | |
var far = 400 | |
var ortmat4 = mat4.orthographic(left, right, bottom, top, near, far) | |
var tramat4 = mat4.translation( | |
parseFloat(document.querySelector('#translate_x_range').value), | |
parseFloat(document.querySelector('#translate_y_range').value), | |
parseFloat(document.querySelector('#translate_z_range').value) | |
) | |
var xrotmat4 = mat4.xRotation( | |
parseFloat(document.querySelector('#rotate_x_range').value) | |
) | |
var yrotmat4 = mat4.yRotation( | |
parseFloat(document.querySelector('#rotate_y_range').value) | |
) | |
var zrotmat4 = mat4.zRotation( | |
parseFloat(document.querySelector('#rotate_z_range').value) | |
) | |
var pivmat4 = mat4.translation( | |
parseFloat(document.querySelector('#rotate_pivot_x_range').value), | |
parseFloat(document.querySelector('#rotate_pivot_y_range').value), | |
parseFloat(document.querySelector('#rotate_pivot_z_range').value) | |
) | |
var scamat4 = mat4.scaling( | |
parseFloat(document.querySelector('#scale_x_range').value), | |
parseFloat(document.querySelector('#scale_y_range').value), | |
parseFloat(document.querySelector('#scale_z_range').value) | |
) | |
var m4 = mat4.multiplyArray([ | |
ortmat4, | |
tramat4, | |
xrotmat4, | |
yrotmat4, | |
zrotmat4, | |
pivmat4, | |
scamat4, | |
]) | |
var square_coords = [ | |
'X = ' + (tramat4[12] + x).toFixed(2), | |
'Y = ' + (tramat4[13] + y).toFixed(2), | |
'Z = ' + (tramat4[14] + z).toFixed(2), | |
'Width = ' + (scamat4[0] * width).toFixed(2), | |
'Height = ' + (scamat4[5] * height).toFixed(2), | |
'Depth = ' + (scamat4[10] * depth).toFixed(2), | |
] | |
document.querySelector('#info1').textContent = square_coords.join('\n') | |
document.querySelector('#info2').textContent = [ | |
'Orthographic', | |
mat4.inspect(ortmat4), | |
'Translation', | |
mat4.inspect(tramat4), | |
'Rotation X', | |
mat4.inspect(xrotmat4), | |
'Rotation Y', | |
mat4.inspect(yrotmat4), | |
'Rotation Z', | |
mat4.inspect(zrotmat4), | |
'Rotation pivot', | |
mat4.inspect(pivmat4), | |
'Scaling', | |
mat4.inspect(scamat4), | |
'uniform u_transform', | |
mat4.inspect(m4) | |
].join('\n') | |
gl.uniformMatrix4fv(u_transform_ref, false, m4) | |
gl.drawArrays(gl.TRIANGLES, 0, 36) | |
} | |
var shader = document.querySelector('#shader').textContent | |
var vertex = document.querySelector('#vertex').textContent | |
var can = document.createElement('canvas') | |
can.width = 300 | |
can.height = 300 | |
can.style.backgroundColor = 'white' | |
can.style.border = '1px solid red' | |
can.style.width = can.width + 'px' | |
can.style.height = can.height + 'px' | |
var gl = can.getContext('webgl') | |
if(!gl) { | |
stderr.textContent = 'No WebGL context' | |
return reject() | |
} | |
var vertex_shader_result = createShader(gl, gl.VERTEX_SHADER, vertex) | |
if(!vertex_shader_result.success) { | |
stderr.textContent = vertex_shader_result.data | |
return reject() | |
} | |
var vertex_shader = vertex_shader_result.data | |
var fragment_shader_result = createShader(gl, gl.FRAGMENT_SHADER, shader) | |
if(!fragment_shader_result.success) { | |
stderr.textContent = fragment_shader_result.data | |
return reject() | |
} | |
var fragment_shader = fragment_shader_result.data | |
var program_result = createProgram(gl, vertex_shader, fragment_shader) | |
if(!program_result.success) { | |
stderr.textContent = program_result.data | |
return reject() | |
} | |
var program = program_result.data | |
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height) | |
gl.clearColor(0, 0, 0, 0) | |
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) | |
gl.enable(gl.CULL_FACE) | |
gl.enable(gl.DEPTH_TEST) | |
gl.useProgram(program) | |
// ################################################################# | |
// References | |
// Attributes | |
var a_position_ref = gl.getAttribLocation(program, 'a_position') | |
var a_color_ref = gl.getAttribLocation(program, 'a_color') | |
// Uniforms | |
var u_transform_ref = gl.getUniformLocation(program, 'u_transform') | |
// ################################################################# | |
// Color buffer | |
var color_buffer = gl.createBuffer() | |
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer) | |
var back_color = [ | |
255, 0, 0, | |
255, 0, 0, | |
255, 0, 0, | |
] | |
var front_color = [ | |
0, 255, 0, | |
0, 255, 0, | |
0, 255, 0, | |
] | |
var left_color = [ | |
0, 0, 255, | |
0, 0, 255, | |
0, 0, 255, | |
] | |
var right_color = [ | |
255, 0, 255, | |
255, 0, 255, | |
255, 0, 255, | |
] | |
var top_color = [ | |
255, 255, 0, | |
255, 255, 0, | |
255, 255, 0, | |
] | |
var bottom_color = [ | |
0, 255, 255, | |
0, 255, 255, | |
0, 255, 255, | |
] | |
var colors = [].concat( | |
back_color, | |
back_color, | |
front_color, | |
front_color, | |
left_color, | |
left_color, | |
right_color, | |
right_color, | |
top_color, | |
top_color, | |
bottom_color, | |
bottom_color, | |
) | |
gl.bufferData( | |
gl.ARRAY_BUFFER, | |
new Uint8Array(colors), | |
gl.STATIC_DRAW | |
) | |
// ################################################################# | |
// Position buffer | |
var position_buffer = gl.createBuffer() | |
gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer) | |
var x = 0 | |
var y = 0 | |
var z = 0 | |
var width = 100 | |
var height = 100 | |
var depth = 100 | |
var back_tri_1 = [ | |
100, 100, 100, | |
-100, 100, 100, | |
100, -100, 100, | |
] | |
var back_tri_2 = [ | |
100, -100, 100, | |
-100, 100, 100, | |
-100, -100, 100, | |
] | |
var front_tri_1 = [ | |
100, 100, -100, | |
100, -100, -100, | |
-100, 100, -100, | |
] | |
var front_tri_2 = [ | |
-100, 100, -100, | |
100, -100, -100, | |
-100, -100, -100, | |
] | |
var left_tri_1 = [ | |
-100, 100, 100, | |
-100, 100, -100, | |
-100, -100, 100, | |
] | |
var left_tri_2 = [ | |
-100, -100, 100, | |
-100, 100, -100, | |
-100, -100, -100, | |
] | |
var right_tri_1 = [ | |
100, 100, 100, | |
100, -100, 100, | |
100, 100, -100, | |
] | |
var right_tri_2 = [ | |
100, 100, -100, | |
100, -100, 100, | |
100, -100, -100, | |
] | |
var top_tri_1 = [ | |
100, 100, 100, | |
100, 100, -100, | |
-100, 100, 100, | |
] | |
var top_tri_2 = [ | |
-100, 100, 100, | |
100, 100, -100, | |
-100, 100, -100, | |
] | |
var bottom_tri_1 = [ | |
100, -100, 100, | |
-100, -100, 100, | |
100, -100, -100, | |
] | |
var bottom_tri_2 = [ | |
100, -100, -100, | |
-100, -100, 100, | |
-100, -100, -100, | |
] | |
var coords = [].concat( | |
back_tri_1, | |
back_tri_2, | |
front_tri_1, | |
front_tri_2, | |
left_tri_1, | |
left_tri_2, | |
right_tri_1, | |
right_tri_2, | |
top_tri_1, | |
top_tri_2, | |
bottom_tri_1, | |
bottom_tri_2, | |
) | |
gl.bufferData( | |
gl.ARRAY_BUFFER, | |
new Float32Array(coords), | |
gl.STATIC_DRAW | |
) | |
// ################################################################# | |
var t = document.createElement('table') | |
t.innerHTML = document.querySelector('#table_content').innerHTML | |
t.style.width = '100%' | |
document.body.appendChild(t) | |
t.querySelector('#c').appendChild(can) | |
var v = document.createElement('pre') | |
v.style.whiteSpace = 'pre-wrap' | |
document.querySelector('#v').appendChild(v) | |
v.textContent = vertex | |
var s = document.createElement('pre') | |
s.style.whiteSpace = 'pre-wrap' | |
document.querySelector('#s').appendChild(s) | |
s.textContent = shader | |
setupEvents(draw) | |
draw() | |
resolve(window.gl = gl) | |
}) | |
} | |
window.addEventListener('DOMContentLoaded', main, {passive: true}) | |
</script> | |
</head> | |
<body> | |
<pre style="white-space: pre-wrap" id="stderr"></pre> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment