I know that "how to optimize this code?" kind of question is generally not welcomed in stack overflow. But I think this is only the way i could phrase my question. I wrote a code that projects a 4 dimensional points onto a 3 dimensional space. I then draw the 3d points using the p5.js library.
Here is my code: https://jsfiddle.net/dfq8ykLw/
Now my question here is, how am I supposed to make this run faster, and optimize the code? Since I am supposed to draw few thousand points (sometimes more) per frame, and calculate the rotation for each of those points, my code tend to run incredibly slowly (mac devices can run this a little faster for some reason).
I tried drawing points instead of vertices, which ended up running even slower.
Are there any suggestion of how to improve the performance? Or an advice of what kind of library to use for drawing 3 dimensional shapes?
Just to explain, my program stores the points as nested array, just like [[Point object, Point object, ...], ...]
.
Each array in the data works as a face, with each Point
object being the vertices.
I first rotate each of these points by applying 6 rotations (for axis xy, xz, xw, yz, yw and zw), then draw them by projecting them onto the 3d space.
Any help is appreciated, as I am terribly stuck!
in source code
Begin shape drawing. However in WEBGL mode, application performance will likely drop as a result of too many calls to beginShape() / endShape(). As a high performance alternative, ... _main.default.RendererGL.prototype.beginShape
So we may want to avoid too many beginShape
calls.
Idem call it on cube instead of face
beginShape()
data.forEach((hyperobject, i) => {
// face
for (var p in hyperobject){
hyperobject[p].rotate(angles[0], angles[1], angles[2], angles[3], angles[4], angles[5])
hyperobject[p].draw()
}
if (i % 6 === 0) {
endShape(CLOSE);
beginShape()
}
})
endShape()
However there are some ugly drawn line, because default mode is TRIANGLE_FAN
_main.default.RendererGL.prototype.beginShape = function(mode) { this.immediateMode.shapeMode = mode !== undefined ? mode : constants.TRIANGLE_FAN;
So we may specify TRIANGLES
instead:
function draw(){
//noLoop()
background(0);
// translate(250, 250);
for (var a in angles){
angles[a] += angleSpeeds[a];
}
beginShape(TRIANGLES)
data.forEach((hyperobject, i) => {
// face
const [a, b, c, d] = hyperobject.map(a => {
a.rotate(angles[0], angles[1], angles[2], angles[3], angles[4], angles[5])
return a
})
//first triangle
a.draw()
b.draw()
c.draw()
a.draw()
b.draw()
d.draw()
if (i % 6 === 0) {
endShape()
beginShape(TRIANGLES)
}
})
endShape()
}
Note that you could factorize the rotation
const [axy, axz, axw, ayz, ayw, azw] = angles
const f = x => [Math.cos(x), Math.sin(x)]
const [Ca, Sa] = f(axy)
const [Cb, Sb] = f(axz)
const [Cc, Sc] = f(axw)
const [Cd, Sd] = f(ayz)
const [Ce, Se] = f(ayw)
const [Cf, Sf] = f(azw)
const R = [
[Ca*Cb*Cc, -Cb*Cc*Sa, -Cc*Sb, -Sc],
[Ca*(-Cb*Sc*Se-Ce*Sb*Sd)+Cd*Ce*Sa, -Sa*(-Cb*Sc*Se-Ce*Sb*Sd)+Ca*Cd*Ce, -Cb*Ce*Sd+Sb*Sc*Se, -Cc*Se],
[Ca*(Sb*(Sd*Se*Sf+Cd*Cf)-Cb*Ce*Sc*Sf)+Sa*(-Cd*Se*Sf+Cf*Sd), -Sa*(Sb*(Sd*Se*Sf+Cd*Cf)-Cb*Ce*Sc*Sf)+Ca*(-Cd*Se*Sf+Cf*Sd), Cb*(Sd*Se*Sf+Cd*Cf)+Ce*Sb*Sc*Sf, -Cc*Ce*Sf],
[Ca*(Sb*(-Cf*Sd*Se+Cd*Sf)+Cb*Ce*Cf*Sc)+Sa*(Cd*Cf*Se+Sd*Sf),-Sa*(Sb*(-Cf*Sd*Se+Cd*Sf)+Cb*Ce*Cf*Sc)+Ca*(Cd*Cf*Se+Sd*Sf), Cb*(-Cf*Sd*Se+Cd*Sf)-Ce*Cf*Sb*Sc, Cc*Ce*Cf]
]
Point.prototype.rotate = function (R) {
const X = [this.origx, this.origy, this.origz, this.origw]
const [x,y,z,w] = prod(R, X)
Object.assign(this, { x, y, z, w })
}
but this is not the bottleneck, (like 1ms to 50ms for drawing), so keeping your matrix decomposition may be preferable.
I can't put the code snippet here since webgl not secure https://jsfiddle.net/gk4Lvptm/