mirror of
https://github.com/greggman/twgl.js.git
synced 2025-12-08 19:26:07 +00:00
619 lines
26 KiB
HTML
619 lines
26 KiB
HTML
<!DOCTYPE html>
|
|
<!-- this file is auto-generated from README.md. Do not edited directly -->
|
|
<!--
|
|
@license twgl.js 7.0.0 Copyright (c) 2015, Gregg Tavares All Rights Reserved.
|
|
Available via the MIT license.
|
|
see: http://github.com/greggman/twgl.js for details
|
|
-->
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="Content-Language" content="en">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
|
<meta property="og:title" content="TWGL.js, a tiny WebGL helper library" />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:image" content="http://twgljs.org/resources/images/twgljs.png" />
|
|
<meta property="og:description" content="TWGL.js, a tiny WebGL helper library" />
|
|
<meta property="og:url" content="http://twgljs.org" />
|
|
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:site" content="@greggman">
|
|
<meta name="twitter:creator" content="@greggman">
|
|
<meta name="twitter:domain" content="twgljs.org">
|
|
<meta name="twitter:title" content="TWGL.js">
|
|
<meta name="twitter:url" content="http://twgljs.org">
|
|
<meta name="twitter:description" content="TWGL.js, a tiny WebGL helper library">
|
|
<meta name="twitter:image:src" content="http://twgljs.org/resources/images/twgljs.png">
|
|
|
|
|
|
<title>TWGL.js, a tiny WebGL helper library</title>
|
|
|
|
<link rel="stylesheet" href="/resources/css/base.css" type="text/css" />
|
|
<link href="/resources/images/twgljs-icon.png" rel="shortcut icon" type="image/png">
|
|
</head>
|
|
<body>
|
|
<iframe src="examples/background.html"></iframe>
|
|
<div id="frame">
|
|
<div class="nav">
|
|
<ul>
|
|
<li><a href="/docs/">Docs</a></li>
|
|
<li><a href="#examples">Examples</a></li>
|
|
<li><a href="#download">Download</a></li>
|
|
</ul>
|
|
</div>
|
|
<div id="content">
|
|
<h1>TWGL: A Tiny WebGL helper Library<div id="pronounce" style="font-size: xx-small;">[rhymes with wiggle]</div></h1>
|
|
<p><a href="https://github.com/greggman/twgl.js/actions/workflows/test.yml"><img src="https://github.com/greggman/twgl.js/actions/workflows/test.yml/badge.svg" alt="Build Status"></a></p>
|
|
<p>This library's sole purpose is to make using the WebGL API less verbose.</p>
|
|
<h2>TL;DR</h2>
|
|
<p>If you want to get stuff done use <a href="http://threejs.org">three.js</a>. If you want
|
|
to do stuff low-level with WebGL consider using <a href="http://github.com/greggman/twgl.js/">TWGL</a>.</p>
|
|
<h2>The tiniest example</h2>
|
|
<p>Not including the shaders (which is a simple quad shader) here's the entire code</p>
|
|
<pre><code class="language-html"><canvas id="c"></canvas>
|
|
<script src="../dist/7.x/twgl-full.min.js"></script>
|
|
<script>
|
|
const gl = document.getElementById("c").getContext("webgl");
|
|
const programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
|
|
|
|
const arrays = {
|
|
position: [-1, -1, 0, 1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0],
|
|
};
|
|
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
|
|
|
|
function render(time) {
|
|
twgl.resizeCanvasToDisplaySize(gl.canvas);
|
|
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
|
|
const uniforms = {
|
|
time: time * 0.001,
|
|
resolution: [gl.canvas.width, gl.canvas.height],
|
|
};
|
|
|
|
gl.useProgram(programInfo.program);
|
|
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
|
|
twgl.setUniforms(programInfo, uniforms);
|
|
twgl.drawBufferInfo(gl, bufferInfo);
|
|
|
|
requestAnimationFrame(render);
|
|
}
|
|
requestAnimationFrame(render);
|
|
</script>
|
|
</code></pre>
|
|
<p><a href="/examples/tiny.html">And here it is live</a>.</p>
|
|
<h2>Why? What? How?</h2>
|
|
<p>WebGL is a very verbose API. Setting up shaders, buffers, attributes and uniforms
|
|
takes a lot of code. A simple lit cube in WebGL might easily take over 60 calls into WebGL.</p>
|
|
<p>At its core there's really only a few main functions</p>
|
|
<ul>
|
|
<li><code>twgl.createProgramInfo</code> compiles a shader and creates setters for attribs and uniforms</li>
|
|
<li><code>twgl.createBufferInfoFromArrays</code> creates buffers and attribute settings</li>
|
|
<li><code>twgl.setBuffersAndAttributes</code> binds buffers and sets attributes</li>
|
|
<li><code>twgl.setUniforms</code> sets the uniforms</li>
|
|
<li><code>twgl.createTextures</code> creates textures of various sorts</li>
|
|
<li><code>twgl.createFramebufferInfo</code> creates a framebuffer and attachments.</li>
|
|
</ul>
|
|
<p>There's a few extra helpers and lower-level functions if you need them but those 6 functions are the core of TWGL.</p>
|
|
<p>Compare the TWGL vs WebGL code for a point lit cube.</p>
|
|
<h3>Compiling a Shader and looking up locations</h3>
|
|
<p>TWGL</p>
|
|
<pre><code class="language-javascript">const programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
|
|
</code></pre>
|
|
<p>WebGL</p>
|
|
<pre><code class="language-javascript">// Note: I'm conceding that you'll likely already have the 30 lines of
|
|
// code for compiling GLSL
|
|
const program = twgl.createProgramFromScripts(gl, ["vs", "fs"]);
|
|
|
|
const u_lightWorldPosLoc = gl.getUniformLocation(program, "u_lightWorldPos");
|
|
const u_lightColorLoc = gl.getUniformLocation(program, "u_lightColor");
|
|
const u_ambientLoc = gl.getUniformLocation(program, "u_ambient");
|
|
const u_specularLoc = gl.getUniformLocation(program, "u_specular");
|
|
const u_shininessLoc = gl.getUniformLocation(program, "u_shininess");
|
|
const u_specularFactorLoc = gl.getUniformLocation(program, "u_specularFactor");
|
|
const u_diffuseLoc = gl.getUniformLocation(program, "u_diffuse");
|
|
const u_worldLoc = gl.getUniformLocation(program, "u_world");
|
|
const u_worldInverseTransposeLoc = gl.getUniformLocation(program, "u_worldInverseTranspose");
|
|
const u_worldViewProjectionLoc = gl.getUniformLocation(program, "u_worldViewProjection");
|
|
const u_viewInverseLoc = gl.getUniformLocation(program, "u_viewInverse");
|
|
|
|
const positionLoc = gl.getAttribLocation(program, "a_position");
|
|
const normalLoc = gl.getAttribLocation(program, "a_normal");
|
|
const texcoordLoc = gl.getAttribLocation(program, "a_texcoord");
|
|
</code></pre>
|
|
<h3>Creating Buffers for a Cube</h3>
|
|
<p>TWGL</p>
|
|
<pre><code class="language-javascript">const arrays = {
|
|
position: [1,1,-1,1,1,1,1,-1,1,1,-1,-1,-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,1,1,1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,-1,1,-1,1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,-1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,-1,-1],
|
|
normal: [1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1],
|
|
texcoord: [1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1],
|
|
indices: [0,1,2,0,2,3,4,5,6,4,6,7,8,9,10,8,10,11,12,13,14,12,14,15,16,17,18,16,18,19,20,21,22,20,22,23],
|
|
};
|
|
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
|
|
</code></pre>
|
|
<p>WebGL</p>
|
|
<pre><code class="language-javascript">const positions = [1,1,-1,1,1,1,1,-1,1,1,-1,-1,-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,1,1,1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,-1,1,-1,1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,-1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,-1,-1];
|
|
const normals = [1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1];
|
|
const texcoords = [1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1];
|
|
const indices = [0,1,2,0,2,3,4,5,6,4,6,7,8,9,10,8,10,11,12,13,14,12,14,15,16,17,18,16,18,19,20,21,22,20,22,23];
|
|
|
|
const positionBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
|
|
const normalBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
|
|
const texcoordBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texcoords), gl.STATIC_DRAW);
|
|
const indicesBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
|
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
|
|
</code></pre>
|
|
<h3>Setting Attributes and Indices for a Cube</h3>
|
|
<p>TWGL</p>
|
|
<pre><code class="language-javascript">twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
|
|
</code></pre>
|
|
<p>WebGL</p>
|
|
<pre><code class="language-javascript">gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0);
|
|
gl.enableVertexAttribArray(positionLoc);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
|
|
gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 0, 0);
|
|
gl.enableVertexAttribArray(normalLoc);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
|
|
gl.vertexAttribPointer(texcoordLoc, 2, gl.FLOAT, false, 0, 0);
|
|
gl.enableVertexAttribArray(texcoordLoc);
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
|
|
</code></pre>
|
|
<h3>Setting Uniforms for a Lit Cube</h3>
|
|
<p>TWGL</p>
|
|
<pre><code class="language-javascript">// At Init time
|
|
const uniforms = {
|
|
u_lightWorldPos: [1, 8, -10],
|
|
u_lightColor: [1, 0.8, 0.8, 1],
|
|
u_ambient: [0, 0, 0, 1],
|
|
u_specular: [1, 1, 1, 1],
|
|
u_shininess: 50,
|
|
u_specularFactor: 1,
|
|
u_diffuse: tex,
|
|
};
|
|
|
|
// At render time
|
|
uniforms.u_viewInverse = camera;
|
|
uniforms.u_world = world;
|
|
uniforms.u_worldInverseTranspose = m4.transpose(m4.inverse(world));
|
|
uniforms.u_worldViewProjection = m4.multiply(viewProjection, world);
|
|
|
|
twgl.setUniforms(programInfo, uniforms);
|
|
</code></pre>
|
|
<p>WebGL</p>
|
|
<pre><code class="language-javascript">// At Init time
|
|
const u_lightWorldPos = [1, 8, -10];
|
|
const u_lightColor = [1, 0.8, 0.8, 1];
|
|
const u_ambient = [0, 0, 0, 1];
|
|
const u_specular = [1, 1, 1, 1];
|
|
const u_shininess = 50;
|
|
const u_specularFactor = 1;
|
|
const u_diffuse = 0;
|
|
|
|
// At render time
|
|
gl.uniform3fv(u_lightWorldPosLoc, u_lightWorldPos);
|
|
gl.uniform4fv(u_lightColorLoc, u_lightColor);
|
|
gl.uniform4fv(u_ambientLoc, u_ambient);
|
|
gl.uniform4fv(u_specularLoc, u_specular);
|
|
gl.uniform1f(u_shininessLoc, u_shininess);
|
|
gl.uniform1f(u_specularFactorLoc, u_specularFactor);
|
|
gl.uniform1i(u_diffuseLoc, u_diffuse);
|
|
gl.uniformMatrix4fv(u_viewInverseLoc, false, camera);
|
|
gl.uniformMatrix4fv(u_worldLoc, false, world);
|
|
gl.uniformMatrix4fv(u_worldInverseTransposeLoc, false, m4.transpose(m4.inverse(world)));
|
|
gl.uniformMatrix4fv(u_worldViewProjectionLoc, false, m4.multiply(viewProjection, world));
|
|
</code></pre>
|
|
<h3>Loading / Setting up textures</h3>
|
|
<p>TWGL</p>
|
|
<pre><code class="language-javascript">const textures = twgl.createTextures(gl, {
|
|
// a power of 2 image
|
|
hftIcon: { src: "images/hft-icon-16.png", mag: gl.NEAREST },
|
|
// a non-power of 2 image
|
|
clover: { src: "images/clover.jpg" },
|
|
// From a canvas
|
|
fromCanvas: { src: ctx.canvas },
|
|
// A cubemap from 6 images
|
|
yokohama: {
|
|
target: gl.TEXTURE_CUBE_MAP,
|
|
src: [
|
|
'images/yokohama/posx.jpg',
|
|
'images/yokohama/negx.jpg',
|
|
'images/yokohama/posy.jpg',
|
|
'images/yokohama/negy.jpg',
|
|
'images/yokohama/posz.jpg',
|
|
'images/yokohama/negz.jpg',
|
|
],
|
|
},
|
|
// A cubemap from 1 image (can be 1x6, 2x3, 3x2, 6x1)
|
|
goldengate: {
|
|
target: gl.TEXTURE_CUBE_MAP,
|
|
src: 'images/goldengate.jpg',
|
|
},
|
|
// A 2x2 pixel texture from a JavaScript array
|
|
checker: {
|
|
mag: gl.NEAREST,
|
|
min: gl.LINEAR,
|
|
src: [
|
|
255,255,255,255,
|
|
192,192,192,255,
|
|
192,192,192,255,
|
|
255,255,255,255,
|
|
],
|
|
},
|
|
// a 1x8 pixel texture from a typed array.
|
|
stripe: {
|
|
mag: gl.NEAREST,
|
|
min: gl.LINEAR,
|
|
format: gl.LUMINANCE,
|
|
src: new Uint8Array([
|
|
255,
|
|
128,
|
|
255,
|
|
128,
|
|
255,
|
|
128,
|
|
255,
|
|
128,
|
|
]),
|
|
width: 1,
|
|
},
|
|
});
|
|
</code></pre>
|
|
<p>WebGL</p>
|
|
<pre><code class="language-javascript">// Let's assume I already loaded all the images
|
|
|
|
// a power of 2 image
|
|
const hftIconTex = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, hftIconImg);
|
|
gl.generateMipmaps(gl.TEXTURE_2D);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
// a non-power of 2 image
|
|
const cloverTex = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, hftIconImg);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
// From a canvas
|
|
const cloverTex = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, ctx.canvas);
|
|
gl.generateMipmaps(gl.TEXTURE_2D);
|
|
// A cubemap from 6 images
|
|
const yokohamaTex = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
|
|
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, posXImg);
|
|
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, negXImg);
|
|
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, posYImg);
|
|
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, negYImg);
|
|
gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, posZImg);
|
|
gl.texImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, negZImg);
|
|
gl.generateMipmaps(gl.TEXTURE_CUBE_MAP);
|
|
// A cubemap from 1 image (can be 1x6, 2x3, 3x2, 6x1)
|
|
const goldengateTex = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex);
|
|
const size = goldengate.width / 3; // assume it's a 3x2 texture
|
|
const slices = [0, 0, 1, 0, 2, 0, 0, 1, 1, 1, 2, 1];
|
|
const tempCtx = document.createElement("canvas").getContext("2d");
|
|
tempCtx.canvas.width = size;
|
|
tempCtx.canvas.height = size;
|
|
for (let ii = 0; ii < 6; ++ii) {
|
|
const xOffset = slices[ii * 2 + 0] * size;
|
|
const yOffset = slices[ii * 2 + 1] * size;
|
|
tempCtx.drawImage(element, xOffset, yOffset, size, size, 0, 0, size, size);
|
|
gl.texImage2D(faces[ii], 0, format, format, type, tempCtx.canvas);
|
|
}
|
|
gl.generateMipmaps(gl.TEXTURE_CUBE_MAP);
|
|
// A 2x2 pixel texture from a JavaScript array
|
|
const checkerTex = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([
|
|
255,255,255,255,
|
|
192,192,192,255,
|
|
192,192,192,255,
|
|
255,255,255,255,
|
|
]));
|
|
gl.generateMipmaps(gl.TEXTURE_2D);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
// a 1x8 pixel texture from a typed array.
|
|
const stripeTex = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, 1, 8, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, new Uint8Array([
|
|
255,
|
|
128,
|
|
255,
|
|
128,
|
|
255,
|
|
128,
|
|
255,
|
|
128,
|
|
]));
|
|
gl.generateMipmaps(gl.TEXTURE_2D);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
</code></pre>
|
|
<h3>Creating Framebuffers and attachments</h3>
|
|
<p>TWGL</p>
|
|
<pre><code class="language-javascript">const attachments = [
|
|
{ format: RGBA, type: UNSIGNED_BYTE, min: LINEAR, wrap: CLAMP_TO_EDGE },
|
|
{ format: DEPTH_STENCIL, },
|
|
];
|
|
const fbi = twgl.createFramebufferInfo(gl, attachments);
|
|
</code></pre>
|
|
<p>WebGL</p>
|
|
<pre><code class="language-javascript">const fb = gl.createFramebuffer(gl.FRAMEBUFFER);
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
|
|
const tex = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.drawingBufferWidth, gl.drawingBufferHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
|
|
const rb = gl.createRenderbuffer();
|
|
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
|
|
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, rb);
|
|
</code></pre>
|
|
<h3>Setting uniform and uniformblock structures and arrays</h3>
|
|
<p>Given an array of GLSL structures like this</p>
|
|
<pre><code class="language-glsl">struct Light {
|
|
float intensity;
|
|
float shininess;
|
|
vec4 color;
|
|
}
|
|
uniform Light lights[2];
|
|
</code></pre>
|
|
<p>TWGL</p>
|
|
<pre><code class="language-javascript">const progInfo = twgl.createProgramInfo(gl, [vs, fs]);
|
|
...
|
|
twgl.setUniforms(progInfo, {
|
|
lights: [
|
|
{ intensity: 5.0, shininess: 100, color: [1, 0, 0, 1] },
|
|
{ intensity: 2.0, shininess: 50, color: [0, 0, 1, 1] },
|
|
],
|
|
});
|
|
</code></pre>
|
|
<p>WebGL</p>
|
|
<pre><code class="language-javascript">// assuming we already compiled and linked the program
|
|
const light0IntensityLoc = gl.getUniformLocation('lights[0].intensity');
|
|
const light0ShininessLoc = gl.getUniformLocation('lights[0].shininess');
|
|
const light0ColorLoc = gl.getUniformLocation('lights[0].color');
|
|
const light1IntensityLoc = gl.getUniformLocation('lights[1].intensity');
|
|
const light1ShininessLoc = gl.getUniformLocation('lights[1].shininess');
|
|
const light1ColorLoc = gl.getUniformLocation('lights[1].color');
|
|
...
|
|
gl.uniform1f(light0IntensityLoc, 5.0);
|
|
gl.uniform1f(light0ShininessLoc, 100);
|
|
gl.uniform4fv(light0ColorLoc, [1, 0, 0, 1]);
|
|
gl.uniform1f(light1IntensityLoc, 2.0);
|
|
gl.uniform1f(light1ShininessLoc, 50);
|
|
gl.uniform4fv(light1ColorLoc, [0, 0, 1, 1]);
|
|
</code></pre>
|
|
<p>If you just want to set the 2nd light in TWGL you can do this</p>
|
|
<pre><code class="language-javascript">const progInfo = twgl.createProgramInfo(gl, [vs, fs]);
|
|
...
|
|
twgl.setUniforms(progInfo, {
|
|
'lights[1]': { intensity: 5.0, shininess: 100, color: [1, 0, 0, 1] },
|
|
});
|
|
</code></pre>
|
|
<h3>Compare</h3>
|
|
<p><a href="/examples/twgl-cube.html">TWGL example</a> vs <a href="/examples/webgl-cube.html">WebGL example</a></p>
|
|
<h2>Examples</h2>
|
|
<ul>
|
|
<li><a href="/examples/tiny.html">tiny</a></li>
|
|
<li><a href="/examples/twgl-cube.html">twgl cube</a></li>
|
|
<li><a href="/examples/textures.html">textures</a></li>
|
|
<li><a href="/examples/primitives.html">primitives</a></li>
|
|
<li><a href="/examples/2d-lines.html">2d-lines</a></li>
|
|
<li><a href="/examples/dynamic-buffers.html">dynamic-buffers</a></li>
|
|
<li><a href="/examples/zoom-around.html">zoom-around</a></li>
|
|
<li><a href="/examples/text.html">text</a></li>
|
|
<li><a href="/examples/kaleidoscope.html">kaleidoscope</a></li>
|
|
<li><a href="/examples/tunnel.html">tunnel</a></li>
|
|
<li><a href="/examples/gpgpu-particles.html">GPGPU particles</a></li>
|
|
<li><a href="/examples/itemlist.html">item list</a></li>
|
|
<li><a href="/examples/no-box-skybox.html">no box skybox</a></li>
|
|
<li><a href="/examples/crossorigin.html">cross origin</a></li>
|
|
<li><a href="/examples/vertex-array-objects.html">vertex array objects</a></li>
|
|
<li><a href="/examples/instancing.html">instancing</a></li>
|
|
</ul>
|
|
<h3>WebGL 2 Examples</h3>
|
|
<ul>
|
|
<li><a href="/examples/uniform-buffer-objects.html">uniform buffer objects</a></li>
|
|
<li><a href="/examples/3d-textures-tone-mapping.html">3d textures tone mapping</a></li>
|
|
<li><a href="/examples/samplers.html">samplers</a></li>
|
|
<li><a href="/examples/webgl2-textures.html">webgl2 textures</a></li>
|
|
<li><a href="/examples/3d-texture-volume.html">3d texture volume</a></li>
|
|
<li><a href="/examples/3d-texture-volume-no-buffers.html">3d texture volume no buffers</a></li>
|
|
<li><a href="/examples/2d-array-texture.html">2d array texture</a></li>
|
|
<li><a href="/examples/transform-feedback.html">transform feedback</a></li>
|
|
<li><a href="/examples/transform-feedback-particles.html">transform feedback particles</a></li>
|
|
<li><a href="/examples/transform-feedback-particles-va.html">transform feedback particles vertex arrays</a></li>
|
|
</ul>
|
|
<h3>OffscreenCanvas Example</h3>
|
|
<ul>
|
|
<li><a href="/examples/offscreencanvas.html">OffscreenCanvas</a></li>
|
|
</ul>
|
|
<h2>ES6 module support</h2>
|
|
<ul>
|
|
<li><a href="/examples/modules.html">modules</a></li>
|
|
</ul>
|
|
<h2>AMD support</h2>
|
|
<ul>
|
|
<li><a href="/examples/amd-compiled.html">amd</a></li>
|
|
</ul>
|
|
<h2>CommonJS / Browserify support</h2>
|
|
<ul>
|
|
<li><a href="/examples/browserify.html">browserify</a></li>
|
|
</ul>
|
|
<h2>Other Features</h2>
|
|
<ul>
|
|
<li><p>Includes some optional 3d math functions (full version)</p>
|
|
<p>You are welcome to use any math library as long as it stores matrices as flat Float32Array
|
|
or JavaScript arrays.</p>
|
|
</li>
|
|
<li><p>Includes some optional primitive generators (full version)</p>
|
|
<p>planes, cubes, spheres, ... Just to help get started</p>
|
|
</li>
|
|
</ul>
|
|
<h2>Usage</h2>
|
|
<p>See the examples. Otherwise there's a few different versions</p>
|
|
<ul>
|
|
<li><code>twgl-full.module.js</code> the es6 module version</li>
|
|
<li><code>twgl-full.min.js</code> the minified full version</li>
|
|
<li><code>twgl-full.js</code> the concatenated full version</li>
|
|
<li><code>twgl.min.js</code> the minimum version (no 3d math, no primitives)</li>
|
|
<li><code>twgl.js</code> the concatenated minimum version (no 3d math, no primitives)</li>
|
|
</ul>
|
|
<h2>Download</h2>
|
|
<ul>
|
|
<li><p>from github</p>
|
|
<p><a href="http://github.com/greggman/twgl.js">http://github.com/greggman/twgl.js</a></p>
|
|
</li>
|
|
<li><p>from bower</p>
|
|
<pre><code class="language-bash">bower install twgl.js
|
|
</code></pre>
|
|
</li>
|
|
<li><p>from npm</p>
|
|
<pre><code class="language-bash">npm install twgl.js
|
|
</code></pre>
|
|
<p>or</p>
|
|
<pre><code class="language-bash">npm install twgl-base.js
|
|
</code></pre>
|
|
</li>
|
|
<li><p>from git</p>
|
|
<pre><code class="language-bash">git clone https://github.com/greggman/twgl.js.git
|
|
</code></pre>
|
|
</li>
|
|
</ul>
|
|
<h2>Rationale and other chit-chat</h2>
|
|
<p>TWGL's is an attempt to make WebGL simpler by providing a few tiny helper functions
|
|
that make it much less verbose and remove the tedium. TWGL is <strong>NOT</strong> trying to help
|
|
with the complexity of managing shaders and writing GLSL. Nor is it a 3D library like
|
|
<a href="http://threejs.org">three.js</a>. It's just trying to make WebGL less verbose.</p>
|
|
<p>TWGL can be considered a spiritual successor to <a href="http://github.com/greggman/tdl">TDL</a>. Where
|
|
as TDL created several <em>classes</em> that wrapped WebGL, TWGL tries not to wrap anything. In fact
|
|
you can manually create nearly all TWGL data structures.</p>
|
|
<p>For example the function <code>setAttributes</code> takes an object of attributes.
|
|
In WebGL you might write code like this</p>
|
|
<pre><code class="language-javascript">gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0);
|
|
gl.enableVertexAttribArray(positionLoc);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
|
|
gl.vertexAttribPointer(normalLoc, 3, gl.FLOAT, false, 0, 0);
|
|
gl.enableVertexAttribArray(normalLoc);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
|
|
gl.vertexAttribPointer(texcoordLoc, 2, gl.FLOAT, false, 0, 0);
|
|
gl.enableVertexAttribArray(texcoordLoc);
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
|
|
gl.vertexAttribPointer(colorLoc, 4, gl.UNSIGNED_BYTE, true, 0, 0);
|
|
gl.enableVertexAttribArray(colorLoc);
|
|
</code></pre>
|
|
<p><code>setAttributes</code> is just the simplest code to do that for you.</p>
|
|
<pre><code class="language-javascript">// make attributes for TWGL manually
|
|
const attribs = {
|
|
a_position: { buffer: positionBuffer, size: 3, },
|
|
a_normal: { buffer: normalBuffer, size: 3, },
|
|
a_texcoord: { buffer: texcoordBuffer, size: 2, },
|
|
a_color: { buffer: colorBuffer, size: 4, type: gl.UNSIGNED_BYTE, normalize: true, },
|
|
};
|
|
twgl.setAttributes(attribSetters, attribs);
|
|
</code></pre>
|
|
<p>The point of the example above is TWGL is a <strong>thin</strong> wrapper. All it's doing is trying
|
|
to make common WebGL operations easier and less verbose. Feel free to mix it with raw WebGL.</p>
|
|
<h2>API Docs</h2>
|
|
<p><a href="/docs/">API Docs are here</a>.</p>
|
|
<h2>Want to learn WebGL?</h2>
|
|
<p>Try <a href="http://webglfundamentals.org">webglfundamentals.org</a></p>
|
|
|
|
</div>
|
|
</div>
|
|
<style>
|
|
#forkongithub a {
|
|
background: #000;
|
|
color: #fff;
|
|
text-decoration: none;
|
|
font-family: arial,sans-serif;
|
|
text-align: center;
|
|
font-weight: bold;
|
|
padding: 5px 40px;
|
|
font-size: 12px;
|
|
line-height: 24px;
|
|
position: relative;
|
|
transition: 0.5s;
|
|
display: block;
|
|
}
|
|
#forkongithub a:hover {
|
|
background: #c11;
|
|
color: #fff;
|
|
}
|
|
#forkongithub a::before,#forkongithub a::after {
|
|
content: "";
|
|
width: 100%;
|
|
display: block;
|
|
position: absolute;
|
|
top: 1px;
|
|
left: 0;
|
|
height: 1px;
|
|
background: #fff;
|
|
}
|
|
#forkongithub a::after {
|
|
bottom: 1px;
|
|
top: auto;
|
|
}
|
|
|
|
@media screen and (min-width: 400px){
|
|
#forkongithub{
|
|
position: fixed;
|
|
display: block;
|
|
top: 0;
|
|
right: 0;
|
|
width: 200px;
|
|
overflow: hidden;
|
|
height: 200px;
|
|
z-index: 9999;
|
|
}
|
|
#forkongithub a{
|
|
width: 200px;
|
|
position: absolute;
|
|
top: 40px;
|
|
right: -40px;
|
|
transform: rotate(45deg);
|
|
-webkit-transform: rotate(45deg);
|
|
-ms-transform: rotate(45deg);
|
|
-moz-transform: rotate(45deg);
|
|
-o-transform: rotate(45deg);
|
|
box-shadow: 4px 4px 10px rgba(0,0,0,0.8);
|
|
}
|
|
}
|
|
|
|
</style>
|
|
<div id="forkongithub"><a href="https://github.com/greggman/twgl.js">Fork me on GitHub</a></div>
|
|
</body>
|
|
<script src="/3rdparty/prettify.js"></script>
|
|
<script src="/resources/js/index.js"></script>
|
|
<script>
|
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
|
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
|
|
|
ga('create', 'UA-61260681-1', 'auto');
|
|
ga('send', 'pageview');
|
|
|
|
</script>
|
|
</html>
|
|
|
|
|