Skip to content

Commit 8c7d63d

Browse files
committed
draw elements instanced
1 parent 6d58df3 commit 8c7d63d

File tree

4 files changed

+312
-1
lines changed

4 files changed

+312
-1
lines changed

lots-o-images/index.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ <h1>Lots-O-Images benchmarks</h1>
2929
<div><a href="lots-o-images-draw-elements.html">
3030
<img src="lots-o-images-draw-elements.png" /></a><br/>
3131
<a href="lots-o-images-draw-elements.html">Lots O Images - DrawElements {alpha:false, antialias:false}</a><br>
32-
<p>This sample uses the standard drawElements function call, ones for each image quad.</p>
32+
<p>This sample uses the standard drawElements function call, once for each image quad.</p>
3333
</div>
3434
<hr/>
3535

@@ -40,5 +40,12 @@ <h1>Lots-O-Images benchmarks</h1>
4040
</div>
4141
<hr/>
4242

43+
<div><a href="lots-o-images-draw-elements-instanced.html">
44+
<img src="lots-o-images-draw-elements.png" /></a><br/>
45+
<a href="lots-o-images-draw-elements-instanced.html">Lots O Images - DrawElementsInstanced {alpha:false, antialias:false}</a><br>
46+
<p>This sample uses the drawElementsElements from ANGLE_instanced_arrays.</p>
47+
</div>
48+
<hr/>
49+
4350
</body>
4451
</html>

lots-o-images/launcher.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ function initialize() {
112112
alpha: settings.alpha,
113113
antialias: settings.antialias,
114114
preserveDrawingBuffer: settings.preserveDrawingBuffer,
115+
powerPreference: 'high-performance',
115116
};
116117
const gl = canvas.getContext('webgl', ctxOptions);
117118
if (!gl) {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<!--
2+
* Copyright 2011, Google Inc.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are
7+
* met:
8+
*
9+
* * Redistributions of source code must retain the above copyright
10+
* notice, this list of conditions and the following disclaimer.
11+
* * Redistributions in binary form must reproduce the above
12+
* copyright notice, this list of conditions and the following disclaimer
13+
* in the documentation and/or other materials provided with the
14+
* distribution.
15+
* * Neither the name of Google Inc. nor the names of its
16+
* contributors may be used to endorse or promote products derived from
17+
* this software without specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
-->
31+
<!doctype html>
32+
<html>
33+
<head>
34+
<meta charset="utf-8">
35+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
36+
<title>Lots-O-Images - DrawElementsInstanced</title>
37+
<link href="../jquery-ui-1.8.2.custom/css/ui-lightness/jquery-ui-1.8.2.custom.css" rel="stylesheet" />
38+
<link rel="stylesheet" href="../google-io/2011/style.css" />
39+
<style>
40+
#fpsContainer {
41+
width: 200px;
42+
}
43+
.fps {
44+
white-space: pre;
45+
}
46+
.fps input[type=checkbox] + label {
47+
color: #888;
48+
}
49+
.fps input[type=checkbox]:checked + label {
50+
color: #FFF;
51+
}
52+
</style>
53+
</head>
54+
<body>
55+
<div id="info"><span><span id="title"></span></span></div>
56+
<div id="fpsContainer">
57+
<div>target fps: <span id="targetFPS"></span></div>
58+
<div id="targetFPSSlider"></div>
59+
<div class="fps"> fps: <span id="fps"></div>
60+
<div class="fps">avg-fps: <span id="afps"></div>
61+
<div class="fps"> count: <span id="cnt"></span></div>
62+
<hr>
63+
</div>
64+
<div id="viewContainer">
65+
<canvas id="canvas" width="512" height="512" style="width: 100%; height: 100%;"></canvas>
66+
</div>
67+
</body>
68+
<script src="../jquery-ui-1.8.2.custom/js/jquery-1.4.2.min.js"></script>
69+
<script src="../jquery-ui-1.8.2.custom/js/jquery-ui-1.8.2.custom.min.js"></script>
70+
<script src="../js/perf-harness.js"></script>
71+
<script src="../js/twgl-full.4.x.min.js"></script>
72+
<script src="lots-o-images-draw-elements-instanced.js"></script>
73+
<script src="launcher.js"></script>
74+
</html>
75+
76+
77+
78+
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
function createApp(gl, settings) {
2+
// globals
3+
let g_maxImages = 0;
4+
let g_numImages = 0;
5+
const g_imageSize = 32;
6+
const ext = gl.getExtension('ANGLE_instanced_arrays');
7+
if (!ext) {
8+
return alert('need ANGLE_instanced_arrays');
9+
}
10+
11+
const vs = `
12+
uniform vec2 dimensions;
13+
attribute vec2 position;
14+
attribute vec2 texCoord;
15+
attribute vec2 worldPosition;
16+
attribute vec4 colorMult;
17+
varying vec2 v_texCoord;
18+
varying vec4 v_colorMult;
19+
void main() {
20+
v_texCoord = texCoord;
21+
v_colorMult = colorMult;
22+
gl_Position = vec4(
23+
(((position + worldPosition) / dimensions) * 2.0 - 1.0) * vec2(1, -1), 0, 1);
24+
}
25+
`;
26+
const fs = `
27+
precision mediump float;
28+
varying vec2 v_texCoord;
29+
varying vec4 v_colorMult;
30+
31+
uniform sampler2D diffuseSampler;
32+
33+
void main() {
34+
gl_FragColor = texture2D(diffuseSampler, v_texCoord) * v_colorMult;
35+
}
36+
`;
37+
38+
39+
function r(min, max) {
40+
if (max === undefined) {
41+
max = min;
42+
min = 0;
43+
}
44+
return Math.random() * (max - min) + min;
45+
}
46+
47+
const numVertsPerPlane = 4;
48+
const numPlanesPerBuffer = 65536 / numVertsPerPlane;
49+
const positions = [0, 0, 32, 0, 0, 32, 32, 32];
50+
const texcoords = [0, 0, 1, 0, 0, 1, 1, 1];
51+
const colors = [];
52+
const indices = [0, 1, 2, 2, 1, 3];
53+
for (let i = 0; i < numPlanesPerBuffer; ++i) {
54+
const color = [r(1), r(1), r(1), r(0.5, 1)];
55+
colors.push(...color);
56+
}
57+
58+
function createBuffer(gl, data, Type, target) {
59+
target = target || gl.ARRAY_BUFFER;
60+
Type = Type || Float32Array;
61+
const buf = gl.createBuffer();
62+
gl.bindBuffer(target, buf);
63+
gl.bufferData(target, new Type(data), gl.STATIC_DRAW);
64+
return buf;
65+
}
66+
67+
const positionBuffer = createBuffer(gl, positions);
68+
const texcoordBuffer = createBuffer(gl, texcoords);
69+
const indexBuffer = createBuffer(gl, indices, Uint16Array, gl.ELEMENT_ARRAY_BUFFER);
70+
71+
function createInstanceSet(gl) {
72+
const instances = [];
73+
for (let i = 0; i < numPlanesPerBuffer; ++i) {
74+
instances.push({
75+
x: r(gl.canvas.width),
76+
y: r(gl.canvas.height),
77+
xVel: Math.sign(r(-1000, 1000)) * 60,
78+
yVel: Math.sign(r(-1000, 1000)) * 60,
79+
firstVertex: i * 2,
80+
});
81+
}
82+
return {
83+
instances,
84+
colorBuffer: createBuffer(gl, colors),
85+
worldPositionBuffer: createBuffer(gl, new Array(numPlanesPerBuffer * 2).fill(0)),
86+
worldPosition: new Float32Array(numPlanesPerBuffer * 2),
87+
};
88+
}
89+
90+
const instanceSets = [];
91+
92+
function addInstanceSet(gl) {
93+
const instanceSet = createInstanceSet(gl);
94+
instanceSets.push(instanceSet);
95+
g_maxImages += instanceSet.instances.length;
96+
}
97+
98+
const textures = twgl.createTexture(gl, {
99+
src: '../google-io/2011/assets/google.png',
100+
});
101+
102+
const program = twgl.createProgram(gl, [vs, fs]);
103+
const positionLoc = gl.getAttribLocation(program, 'position');
104+
const texcoordLoc = gl.getAttribLocation(program, 'texCoord');
105+
const worldPositionLoc = gl.getAttribLocation(program, 'worldPosition');
106+
const colorLoc = gl.getAttribLocation(program, 'colorMult');
107+
const dimensionsLoc = gl.getUniformLocation(program, 'dimensions');
108+
109+
function fillRange(dst, offset, count, x, y) {
110+
for (let i = 0; i < count; ++i) {
111+
dst[offset++] = x;
112+
dst[offset++] = y;
113+
}
114+
}
115+
116+
function update(elapsedTime, _numImages) {
117+
g_numImages = _numImages;
118+
119+
twgl.resizeCanvasToDisplaySize(gl.canvas);
120+
121+
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
122+
123+
while (g_maxImages < g_numImages) {
124+
addInstanceSet(gl);
125+
}
126+
127+
// --Update Instance Positions---------------------------------------
128+
if (settings.update) {
129+
const width = gl.canvas.clientWidth - g_imageSize;
130+
const height = gl.canvas.clientHeight - g_imageSize;
131+
const advance = elapsedTime;
132+
const numSets = Math.ceil(g_numImages / numPlanesPerBuffer);
133+
for (let setNdx = 0; setNdx < numSets; ++setNdx) {
134+
const {instances, worldPosition, worldPositionBuffer} = instanceSets[setNdx];
135+
const numImages = Math.min(numPlanesPerBuffer, g_numImages - setNdx * numPlanesPerBuffer)
136+
for (let ii = 0; ii < numImages; ++ii) {
137+
const instance = instances[ii];
138+
instance.x += advance * instance.xVel;
139+
instance.y += advance * instance.yVel;
140+
if (instance.x < 0) {
141+
instance.x = 0;
142+
instance.xVel = Math.abs(instance.xVel);
143+
} else if (instance.x > width) {
144+
instance.x = width;
145+
instance.xVel = -Math.abs(instance.xVel);
146+
}
147+
if (instance.y < 0) {
148+
instance.y = 0;
149+
instance.yVel = Math.abs(instance.yVel);
150+
} else if (instance.y > height) {
151+
instance.y = height;
152+
instance.yVel = -Math.abs(instance.yVel);
153+
}
154+
const offset = instance.firstVertex * 2;
155+
worldPosition[offset ] = instance.x;
156+
worldPosition[offset + 1] = instance.y;
157+
}
158+
gl.bindBuffer(gl.ARRAY_BUFFER, worldPositionBuffer);
159+
gl.bufferData(gl.ARRAY_BUFFER, worldPosition, gl.DYNAMIC_DRAW);
160+
}
161+
}
162+
}
163+
164+
function render() {
165+
renderBegin();
166+
renderScene();
167+
renderEnd();
168+
}
169+
170+
function renderBegin() {
171+
gl.colorMask(true, true, true, true);
172+
gl.clearColor(1, 1, 1, 1);
173+
gl.clear(gl.COLOR_BUFFER_BIT);
174+
gl.disable(gl.BLEND);
175+
176+
if (settings.blend) {
177+
gl.enable(gl.BLEND);
178+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
179+
}
180+
}
181+
182+
function renderScene() {
183+
gl.useProgram(program);
184+
185+
gl.uniform2f(dimensionsLoc, gl.canvas.width, gl.canvas.height);
186+
187+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
188+
gl.enableVertexAttribArray(positionLoc);
189+
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
190+
191+
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
192+
gl.enableVertexAttribArray(texcoordLoc);
193+
gl.vertexAttribPointer(texcoordLoc, 2, gl.FLOAT, false, 0, 0);
194+
195+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
196+
197+
const numSets = Math.ceil(g_numImages / numPlanesPerBuffer);
198+
for (let setNdx = 0; setNdx < numSets; ++setNdx) {
199+
const {colorBuffer, worldPositionBuffer} = instanceSets[setNdx];
200+
const numImages = Math.min(numPlanesPerBuffer, g_numImages - setNdx * numPlanesPerBuffer);
201+
202+
gl.bindBuffer(gl.ARRAY_BUFFER, worldPositionBuffer);
203+
gl.enableVertexAttribArray(worldPositionLoc);
204+
gl.vertexAttribPointer(worldPositionLoc, 2, gl.FLOAT, false, 0, 0);
205+
ext.vertexAttribDivisorANGLE(worldPositionLoc, 1);
206+
207+
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
208+
gl.enableVertexAttribArray(colorLoc);
209+
gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);
210+
ext.vertexAttribDivisorANGLE(colorLoc, 1);
211+
212+
ext.drawElementsInstancedANGLE(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, numImages);
213+
}
214+
}
215+
216+
function renderEnd() {
217+
// nothing to do.
218+
}
219+
220+
return {
221+
update: update,
222+
render: render,
223+
};
224+
}
225+

0 commit comments

Comments
 (0)