Skip to content

Commit a37d281

Browse files
authored
Merge pull request #2473 from Spongman/drawBuffersScaled
webgl: cache un-scaled primitive geometries this changeset reduces geometry creation when drawing many 3d primitives of different sizes, thus improving render performance. spheres/ellipsoids, cylinders & boxes are all scale-invariant, toruses only differ by the ratio between their two radii.
2 parents a5ec514 + 34fbbeb commit a37d281

File tree

5 files changed

+249
-233
lines changed

5 files changed

+249
-233
lines changed

src/webgl/p5.Matrix.js

Lines changed: 87 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,17 @@
1212
var p5 = require('../core/core');
1313
var polarGeometry = require('../math/polargeometry');
1414
var constants = require('../core/constants');
15-
var GLMAT_ARRAY_TYPE =
16-
typeof Float32Array !== 'undefined' ? Float32Array : Array;
15+
16+
var GLMAT_ARRAY_TYPE = Array;
17+
var isMatrixArray = function(x) {
18+
return x instanceof Array;
19+
};
20+
if (typeof Float32Array !== 'undefined') {
21+
GLMAT_ARRAY_TYPE = Float32Array;
22+
isMatrixArray = function(x) {
23+
return x instanceof Array || x instanceof Float32Array;
24+
};
25+
}
1726

1827
/**
1928
* A class to describe a 4x4 matrix
@@ -69,7 +78,7 @@ p5.Matrix.prototype.set = function(inMatrix) {
6978
if (inMatrix instanceof p5.Matrix) {
7079
this.mat4 = inMatrix.mat4;
7180
return this;
72-
} else if (inMatrix instanceof GLMAT_ARRAY_TYPE) {
81+
} else if (isMatrixArray(inMatrix)) {
7382
this.mat4 = inMatrix;
7483
return this;
7584
} else if (arguments.length === 16) {
@@ -171,7 +180,7 @@ p5.Matrix.prototype.transpose = function(a) {
171180
this.mat4[13] = a13;
172181
this.mat4[14] = a23;
173182
this.mat4[15] = a.mat4[15];
174-
} else if (a instanceof GLMAT_ARRAY_TYPE) {
183+
} else if (isMatrixArray(a)) {
175184
a01 = a[1];
176185
a02 = a[2];
177186
a03 = a[3];
@@ -226,7 +235,7 @@ p5.Matrix.prototype.invert = function(a) {
226235
a31 = a.mat4[13];
227236
a32 = a.mat4[14];
228237
a33 = a.mat4[15];
229-
} else if (a instanceof GLMAT_ARRAY_TYPE) {
238+
} else if (isMatrixArray(a)) {
230239
a00 = a[0];
231240
a01 = a[1];
232241
a02 = a[2];
@@ -366,7 +375,16 @@ p5.Matrix.prototype.inverseTranspose = function(matrix) {
366375
this.mat3[8] = matrix.mat4[10];
367376
}
368377

369-
this.invert3x3().transpose3x3(this.mat3);
378+
var inverse = this.invert3x3();
379+
// check inverse succeded
380+
if (inverse) {
381+
inverse.transpose3x3(this.mat3);
382+
} else {
383+
// in case of singularity, just zero the matrix
384+
for (var i = 0; i < 9; i++) {
385+
this.mat3[i] = 0;
386+
}
387+
}
370388
return this;
371389
};
372390

@@ -401,53 +419,54 @@ p5.Matrix.prototype.determinant = function() {
401419
* @chainable
402420
*/
403421
p5.Matrix.prototype.mult = function(multMatrix) {
404-
var _dest = new GLMAT_ARRAY_TYPE(16);
405-
var _src = new GLMAT_ARRAY_TYPE(16);
422+
var _src;
406423

407-
if (multMatrix instanceof p5.Matrix) {
424+
if (multMatrix === this || multMatrix === this.mat4) {
425+
_src = this.copy().mat4; // only need to allocate in this rare case
426+
} else if (multMatrix instanceof p5.Matrix) {
408427
_src = multMatrix.mat4;
409-
} else if (multMatrix instanceof GLMAT_ARRAY_TYPE) {
428+
} else if (isMatrixArray(multMatrix)) {
410429
_src = multMatrix;
430+
} else {
431+
return; // nothing to do.
411432
}
412433

413434
// each row is used for the multiplier
414435
var b0 = this.mat4[0],
415436
b1 = this.mat4[1],
416437
b2 = this.mat4[2],
417438
b3 = this.mat4[3];
418-
_dest[0] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12];
419-
_dest[1] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13];
420-
_dest[2] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14];
421-
_dest[3] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15];
439+
this.mat4[0] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12];
440+
this.mat4[1] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13];
441+
this.mat4[2] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14];
442+
this.mat4[3] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15];
422443

423444
b0 = this.mat4[4];
424445
b1 = this.mat4[5];
425446
b2 = this.mat4[6];
426447
b3 = this.mat4[7];
427-
_dest[4] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12];
428-
_dest[5] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13];
429-
_dest[6] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14];
430-
_dest[7] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15];
448+
this.mat4[4] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12];
449+
this.mat4[5] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13];
450+
this.mat4[6] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14];
451+
this.mat4[7] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15];
431452

432453
b0 = this.mat4[8];
433454
b1 = this.mat4[9];
434455
b2 = this.mat4[10];
435456
b3 = this.mat4[11];
436-
_dest[8] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12];
437-
_dest[9] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13];
438-
_dest[10] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14];
439-
_dest[11] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15];
457+
this.mat4[8] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12];
458+
this.mat4[9] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13];
459+
this.mat4[10] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14];
460+
this.mat4[11] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15];
440461

441462
b0 = this.mat4[12];
442463
b1 = this.mat4[13];
443464
b2 = this.mat4[14];
444465
b3 = this.mat4[15];
445-
_dest[12] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12];
446-
_dest[13] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13];
447-
_dest[14] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14];
448-
_dest[15] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15];
449-
450-
this.mat4 = _dest;
466+
this.mat4[12] = b0 * _src[0] + b1 * _src[4] + b2 * _src[8] + b3 * _src[12];
467+
this.mat4[13] = b0 * _src[1] + b1 * _src[5] + b2 * _src[9] + b3 * _src[13];
468+
this.mat4[14] = b0 * _src[2] + b1 * _src[6] + b2 * _src[10] + b3 * _src[14];
469+
this.mat4[15] = b0 * _src[3] + b1 * _src[7] + b2 * _src[11] + b3 * _src[15];
451470

452471
return this;
453472
};
@@ -458,42 +477,32 @@ p5.Matrix.prototype.mult = function(multMatrix) {
458477
* @param {p5.Vector|Float32Array|Number[]} s vector to scale by
459478
* @chainable
460479
*/
461-
p5.Matrix.prototype.scale = function() {
462-
var x, y, z;
463-
var args = new Array(arguments.length);
464-
for (var i = 0; i < args.length; ++i) {
465-
args[i] = arguments[i];
480+
p5.Matrix.prototype.scale = function(x, y, z) {
481+
if (x instanceof p5.Vector) {
482+
// x is a vector, extract the components from it.
483+
y = x.y;
484+
z = x.z;
485+
x = x.x; // must be last
486+
} else if (x instanceof Array) {
487+
// x is an array, extract the components from it.
488+
y = x[1];
489+
z = x[2];
490+
x = x[0]; // must be last
466491
}
467-
//if our 1st arg is a type p5.Vector
468-
if (args[0] instanceof p5.Vector) {
469-
x = args[0].x;
470-
y = args[0].y;
471-
z = args[0].z;
472-
} else if (args[0] instanceof Array) {
473-
//otherwise if it's an array
474-
x = args[0][0];
475-
y = args[0][1];
476-
z = args[0][2];
477-
}
478-
var _dest = new GLMAT_ARRAY_TYPE(16);
479-
_dest[0] = this.mat4[0] * x;
480-
_dest[1] = this.mat4[1] * x;
481-
_dest[2] = this.mat4[2] * x;
482-
_dest[3] = this.mat4[3] * x;
483-
_dest[4] = this.mat4[4] * y;
484-
_dest[5] = this.mat4[5] * y;
485-
_dest[6] = this.mat4[6] * y;
486-
_dest[7] = this.mat4[7] * y;
487-
_dest[8] = this.mat4[8] * z;
488-
_dest[9] = this.mat4[9] * z;
489-
_dest[10] = this.mat4[10] * z;
490-
_dest[11] = this.mat4[11] * z;
491-
_dest[12] = this.mat4[12];
492-
_dest[13] = this.mat4[13];
493-
_dest[14] = this.mat4[14];
494-
_dest[15] = this.mat4[15];
495-
496-
this.mat4 = _dest;
492+
493+
this.mat4[0] *= x;
494+
this.mat4[1] *= x;
495+
this.mat4[2] *= x;
496+
this.mat4[3] *= x;
497+
this.mat4[4] *= y;
498+
this.mat4[5] *= y;
499+
this.mat4[6] *= y;
500+
this.mat4[7] *= y;
501+
this.mat4[8] *= z;
502+
this.mat4[9] *= z;
503+
this.mat4[10] *= z;
504+
this.mat4[11] *= z;
505+
497506
return this;
498507
};
499508

@@ -505,22 +514,24 @@ p5.Matrix.prototype.scale = function() {
505514
* @chainable
506515
* inspired by Toji's gl-matrix lib, mat4 rotation
507516
*/
508-
p5.Matrix.prototype.rotate = function(a, axis) {
509-
var x, y, z, _a, len;
517+
p5.Matrix.prototype.rotate = function(a, x, y, z) {
518+
var _a, len;
510519

511520
if (this.p5 && this.p5._angleMode === constants.DEGREES) {
512521
_a = polarGeometry.degreesToRadians(a);
513522
} else {
514523
_a = a;
515524
}
516-
if (axis instanceof p5.Vector) {
517-
x = axis.x;
518-
y = axis.y;
519-
z = axis.z;
520-
} else if (axis instanceof Array) {
521-
x = axis[0];
522-
y = axis[1];
523-
z = axis[2];
525+
if (x instanceof p5.Vector) {
526+
// x is a vector, extract the components from it.
527+
y = x.y;
528+
z = x.z;
529+
x = x.x; //must be last
530+
} else if (x instanceof Array) {
531+
// x is an array, extract the components from it.
532+
y = x[1];
533+
z = x[2];
534+
x = x[0]; //must be last
524535
}
525536

526537
len = Math.sqrt(x * x + y * y + z * z);
@@ -591,13 +602,13 @@ p5.Matrix.prototype.translate = function(v) {
591602
};
592603

593604
p5.Matrix.prototype.rotateX = function(a) {
594-
this.rotate(a, [1, 0, 0]);
605+
this.rotate(a, 1, 0, 0);
595606
};
596607
p5.Matrix.prototype.rotateY = function(a) {
597-
this.rotate(a, [0, 1, 0]);
608+
this.rotate(a, 0, 1, 0);
598609
};
599610
p5.Matrix.prototype.rotateZ = function(a) {
600-
this.rotate(a, [0, 0, 1]);
611+
this.rotate(a, 0, 0, 1);
601612
};
602613

603614
/**

src/webgl/p5.RendererGL.Retained.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,36 @@ p5.RendererGL.prototype.drawBuffers = function(gId) {
290290
return this;
291291
};
292292

293+
/**
294+
* Calls drawBuffers() with a scaled model/view matrix.
295+
*
296+
* This is used by various 3d primitive methods (in primitives.js, eg. plane,
297+
* box, torus, etc...) to allow caching of un-scaled geometries. Those
298+
* geometries are generally created with unit-length dimensions, cached as
299+
* such, and then scaled appropriately in this method prior to rendering.
300+
*
301+
* @private
302+
* @method drawBuffersScaled
303+
* @param {String} gId ID in our geom hash
304+
* @param {Number} scaleX the amount to scale in the X direction
305+
* @param {Number} scaleY the amount to scale in the Y direction
306+
* @param {Number} scaleZ the amount to scale in the Z direction
307+
*/
308+
p5.RendererGL.prototype.drawBuffersScaled = function(
309+
gId,
310+
scaleX,
311+
scaleY,
312+
scaleZ
313+
) {
314+
var uMVMatrix = this.uMVMatrix.copy();
315+
try {
316+
this.uMVMatrix.scale(scaleX, scaleY, scaleZ);
317+
this.drawBuffers(gId);
318+
} finally {
319+
this.uMVMatrix = uMVMatrix;
320+
}
321+
};
322+
293323
p5.RendererGL.prototype._drawArrays = function(drawMode, gId) {
294324
this.GL.drawArrays(drawMode, 0, this.gHash[gId].lineVertexCount);
295325
return this;

src/webgl/p5.RendererGL.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -707,30 +707,30 @@ p5.RendererGL.prototype.translate = function(x, y, z) {
707707
* @chainable
708708
*/
709709
p5.RendererGL.prototype.scale = function(x, y, z) {
710-
this.uMVMatrix.scale([x, y, z]);
710+
this.uMVMatrix.scale(x, y, z);
711711
return this;
712712
};
713713

714714
p5.RendererGL.prototype.rotate = function(rad, axis) {
715-
if (!axis) {
716-
axis = [0, 0, 1];
715+
if (typeof axis === 'undefined') {
716+
return this.rotateZ(rad);
717717
}
718-
this.uMVMatrix.rotate(rad, axis);
718+
p5.Matrix.prototype.rotate.apply(this.uMVMatrix, arguments);
719719
return this;
720720
};
721721

722722
p5.RendererGL.prototype.rotateX = function(rad) {
723-
this.rotate(rad, [1, 0, 0]);
723+
this.rotate(rad, 1, 0, 0);
724724
return this;
725725
};
726726

727727
p5.RendererGL.prototype.rotateY = function(rad) {
728-
this.rotate(rad, [0, 1, 0]);
728+
this.rotate(rad, 0, 1, 0);
729729
return this;
730730
};
731731

732732
p5.RendererGL.prototype.rotateZ = function(rad) {
733-
this.rotate(rad, [0, 0, 1]);
733+
this.rotate(rad, 0, 0, 1);
734734
return this;
735735
};
736736

0 commit comments

Comments
 (0)