Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 4 commits
  • 2 files changed
  • 0 commit comments
  • 1 contributor
Commits on Apr 18, 2012
@vilya 2D particles with no colour attribute
Particles are textured and were ignoring the colour attribute, so this change removes it.

Coords for particles are now given in 2D and there's a uniform shader variable to specify their depth. This will let us draw things in separate 2D layers.
e3df0d0
@vilya Animation! 034cb91
@vilya Ortho camera. 67d6d67
Commits on Apr 19, 2012
@vilya Add text rendering.
Draws HTML text into a hidden 2D canvas, then loads the result into a WebGL texture for drawing on the screen.
d273390
Showing with 197 additions and 46 deletions.
  1. +39 −10 index.html
  2. +158 −36 js/main.js
View
49 index.html
@@ -16,19 +16,16 @@
<!-- Vertex shader. -->
<script type="x-shader/x-vertex" id="shader-vs">
- attribute vec3 vertexPos;
- attribute vec3 vertexColor;
+ attribute vec2 vertexPos;
uniform mat4 worldToViewportMatrix;
-
- varying vec4 vColor;
+ uniform float zDepth;
void main()
{
- vec4 worldPos = vec4(vertexPos, 1);
+ vec4 worldPos = vec4(vertexPos, zDepth, 1);
gl_Position = worldToViewportMatrix * worldPos;
gl_PointSize = 10.0;
- vColor = vec4(vertexColor, 1);
}
</script>
@@ -38,16 +35,48 @@
uniform sampler2D texture;
- varying vec4 vColor;
-
void main()
{
vec4 texColor = texture2D(texture, gl_PointCoord);
gl_FragColor = texColor;
}
</script>
+
+ <!-- Text vertex shader. -->
+ <script type="x-shader/x-vertex" id="text-vs">
+ attribute vec2 vertexPos;
+ attribute vec2 vertexUV;
+
+ uniform mat4 worldToViewportMatrix;
+ uniform float zDepth;
+
+ varying vec2 vTexCoords;
+
+ void main()
+ {
+ vec4 worldPos = vec4(vertexPos, zDepth, 1);
+ gl_Position = worldToViewportMatrix * worldPos;
+ vTexCoords = vertexUV;
+ }
+ </script>
+
+ <!-- Text fragment shader. -->
+ <script type="x-shader/x-fragment" id="text-fs">
+ precision mediump float;
+
+ uniform sampler2D texture;
+
+ varying vec2 vTexCoords;
+
+ void main()
+ {
+ vec4 texColor = texture2D(texture, vTexCoords);
+ gl_FragColor = texColor;
+ }
+ </script>
</head>
- <body onload="wtf.main('wtf-canvas');">
- <canvas id="wtf-canvas" width="800" height="800"></canvas>
+ <body onload="wtf.main();">
+ <canvas id="wtf-draw-canvas" width="800" height="800"></canvas>
+ <canvas id="wtf-text-canvas" width="512" height="128" style="display: none;"></canvas>
</body>
</html>
View
194 js/main.js
@@ -1,16 +1,26 @@
var wtf = function () { // start of the wtf namespace
//
+// Constants
+//
+
+var kParticleZ = 0.1;
+var kOverlayZ = 0.2;
+
+
+//
// Global variables
//
-// Wrapper for all WebGL functions and constants. Call initWebGL(canvas) to
-// initialise it before using.
+// Wrapper for all WebGL functions and constants.
var gl;
+// The 2D canvas context we use for background rendering of text.
+var tl;
+
// The current shader program.
var gShaderProgram
-var gGridShader;
+var gTextShader;
// Input handling variables.
var gInput = {
@@ -82,9 +92,8 @@ function texture(textureURL)
tex.isLoaded = false;
tex.image = new Image();
tex.image.onload = function () {
- gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
-
gl.bindTexture(gl.TEXTURE_2D, tex);
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tex.image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
@@ -98,24 +107,93 @@ function texture(textureURL)
}
-function init(canvas)
+function text(x, y, message)
+{
+ // Figure out the size we need the canvas to be.
+ //var textSize = ctx.measureText(message);
+
+ tl.clearRect(0, 0, tl.canvas.width, tl.canvas.height);
+ tl.fillText(message, x, y);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, gl.textTexture);
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tl.canvas);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ 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);
+
+ var world = gl.world;
+
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+ gl.useProgram(gTextShader);
+ gTextShader.enableAttribs();
+ gl.uniformMatrix4fv(gTextShader.uniforms.worldToViewportMatrix, false, gl.projectionMatrix);
+
+ gl.uniform1f(gTextShader.uniforms.zDepth, kOverlayZ);
+ gl.uniform1i(gTextShader.uniforms.texture, 0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.textPos);
+ gl.vertexAttribPointer(gTextShader.attribs['vertexPos'], 2, gl.FLOAT, false, 8, 0);
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.textUV);
+ gl.vertexAttribPointer(gTextShader.attribs['vertexUV'], 2, gl.FLOAT, false, 8, 0);
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+
+ gl.disable(gl.BLEND);
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+ gl.bindTexture(gl.TEXTURE_2D, null);
+
+ gTextShader.disableAttribs();
+}
+
+
+function init(drawCanvas, textCanvas)
{
- gl = WebGLUtils.setupWebGL(canvas);
+ gl = WebGLUtils.setupWebGL(drawCanvas);
if (!gl)
return;
+ gl.viewportWidth = drawCanvas.width;
+ gl.viewportHeight = drawCanvas.height;
+
+ tl = textCanvas.getContext('2d');
- gl.viewportWidth = canvas.width;
- gl.viewportHeight = canvas.height;
+ tl.fillStyle = "#CC0000"; // This determines the text colour, it can take a hex value or rgba value (e.g. rgba(255,0,0,0.5))
+ tl.textAlign = "left"; // This determines the alignment of text, e.g. left, center, right
+ tl.textBaseline = "top"; // This determines the baseline of the text, e.g. top, middle, bottom
+ tl.font = "48px monospace"; // This determines the size of the text and the font family used
// Set up the default camera projection matrix.
gl.projectionMatrix = mat4.identity();
- mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, gl.projectionMatrix);
+ //mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, gl.projectionMatrix);
+ mat4.ortho(0.0, 1.0, 0.0, 1.0, 10.0, -10.0, gl.projectionMatrix);
// Set up the camera positioning matrix.
gl.cameraMatrix = mat4.identity();
mat4.translate(gl.cameraMatrix, [0, 0, 5]);
gl.targetDistance = 5;
+ // Set up a texture for generating text into.
+ gl.textTexture = gl.createTexture();
+ gl.textPos = gl.createBuffer();
+ gl.textUV = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.textPos);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0.1, 0.1,
+ 0.5, 0.1,
+ 0.1, 0.3,
+ 0.5, 0.3
+ ]), gl.STATIC_DRAW);
+ gl.bindBuffer(gl.ARRAY_BUFFER, gl.textUV);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0
+ ]), gl.STATIC_DRAW);
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+
// Set up some OpenGL state.
gl.clearColor(0.1, 0.1, 0.1, 1.0);
gl.cullFace(gl.BACK);
@@ -124,32 +202,40 @@ function init(canvas)
// Set up the shaders
gShaderProgram = program("shader-vs", "shader-fs",
- [ "worldToViewportMatrix", "texture" ], // uniforms
- [ "vertexPos", "vertexColor" ] ); // attributes
+ [ "worldToViewportMatrix", "zDepth", "texture" ], // uniforms
+ [ "vertexPos" ] ); // attributes
+ gTextShader = program("text-vs", "text-fs",
+ [ "worldToViewportMatrix", "zDepth", "texture" ], // uniforms
+ [ "vertexPos", "vertexUV" ] ); // attributes
// Set up the world.
var world = {
'vertexCount': 1024,
'vertexPos': gl.createBuffer(),
- 'vertexColor': gl.createBuffer(),
- 'texture': texture("img/crate.gif")
+ 'texture': texture("img/crate.gif"),
+ 'points': null,
+ 'velocities': null,
+ 'lastUpdate': 0
};
var points = [];
- var colors = [];
+ var velocities = [];
Math.seedrandom('JSPointSprites');
for (var i = 0; i < world.vertexCount; i++) {
- for (var j = 0; j < 3; j++) {
- points.push(Math.random() * 10.0 - 5.0);
- colors.push(Math.random());
- }
+ points.push(Math.random(), Math.random()); // Coords are between 0 and 1.
+
+ // Make sure every particle is moving at a minimum speed.
+ var angle = radians(Math.random() * 360);
+ var speed = Math.random() * 0.3 + 0.1;
+ var vx = Math.cos(angle) * speed;
+ var vy = Math.sin(angle) * speed;
+ velocities.push(vx, vy);
}
+ world.points = new Float32Array(points);
+ world.velocities = new Float32Array(velocities);
+ world.lastUpdate = Date.now();
gl.bindBuffer(gl.ARRAY_BUFFER, world.vertexPos);
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.STATIC_DRAW);
-
- gl.bindBuffer(gl.ARRAY_BUFFER, world.vertexColor);
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
-
+ gl.bufferData(gl.ARRAY_BUFFER, world.points, gl.DYNAMIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.world = world;
@@ -183,14 +269,11 @@ function draw()
gl.useProgram(gShaderProgram);
gShaderProgram.enableAttribs();
gl.uniformMatrix4fv(gShaderProgram.uniforms.worldToViewportMatrix, false, transform);
- gl.uniform1i(gShaderProgram.uniforms.texture, 0);
+ gl.uniform1f(gShaderProgram.uniforms.zDepth, kParticleZ);
+ gl.uniform1i(gShaderProgram.uniforms.texture, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, world.vertexPos);
- gl.vertexAttribPointer(gShaderProgram.attribs['vertexPos'], 3, gl.FLOAT, false, 12, 0);
-
- gl.bindBuffer(gl.ARRAY_BUFFER, world.vertexColor);
- gl.vertexAttribPointer(gShaderProgram.attribs['vertexColor'], 3, gl.FLOAT, false, 12, 0);
-
+ gl.vertexAttribPointer(gShaderProgram.attribs['vertexPos'], 2, gl.FLOAT, false, 8, 0);
gl.drawArrays(gl.POINTS, 0, world.vertexCount);
gl.disable(gl.BLEND);
@@ -198,6 +281,38 @@ function draw()
gl.bindTexture(gl.TEXTURE_2D, null);
gShaderProgram.disableAttribs();
+
+ // Draw the overlay text.
+ var frameTime = new Number(Date.now() - world.lastUpdate);
+ text(1, 1, "Frame time: " + frameTime.toFixed(0) + " ms");
+}
+
+
+function update()
+{
+ var world = gl.world;
+ var end = world.vertexCount * 2;
+ var now = Date.now();
+
+ var dt = (now - world.lastUpdate) / 1000.0; // in seconds
+
+ for (var i = 0; i < end; i++) {
+ world.points[i] += world.velocities[i] * dt;
+ if (world.points[i] < 0) {
+ world.points[i] = -world.points[i];
+ world.velocities[i] = -world.velocities[i];
+ }
+ else if (world.points[i] > 1) {
+ world.points[i] = 2.0 - world.points[i];
+ world.velocities[i] = -world.velocities[i];
+ }
+ }
+
+ world.lastUpdate = now;
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, world.vertexPos);
+ gl.bufferSubData(gl.ARRAY_BUFFER, 0, world.points);
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
}
@@ -217,8 +332,8 @@ function keyUp(event)
function handleKeys()
{
- var speed = 0.2;
- var angle = radians(1);
+ var speed = 0.10;
+ var angle = radians(3);
if (gInput.keysDown['A'])
mat4.translate(gl.cameraMatrix, [-speed, 0, 0]); // move right
@@ -311,14 +426,20 @@ function radians(angleInDegrees)
// Main
//
-function main(canvasId)
+function main(drawCanvasId, textCanvasId)
{
- var canvas = document.getElementById(canvasId);
- init(canvas);
+ if (!drawCanvasId)
+ drawCanvasId = "wtf-draw-canvas";
+ if (!textCanvasId)
+ textCanvasId = "wtf-text-canvas";
+
+ var drawCanvas = document.getElementById(drawCanvasId);
+ var textCanvas = document.getElementById(textCanvasId);
+ init(drawCanvas, textCanvas);
document.onkeydown = keyDown;
document.onkeyup = keyUp;
- canvas.onmousedown = mouseDown;
+ drawCanvas.onmousedown = mouseDown;
document.onmouseup = mouseUp;
document.onmousemove = mouseMove;
@@ -326,6 +447,7 @@ function main(canvasId)
window.requestAnimFrame(tick);
handleKeys();
draw();
+ update();
}
tick();
}

No commit comments for this range

Something went wrong with that request. Please try again.