User:Necas

From Rosetta Code

The basic formula in Javascript to Transform an object using 4x4 matrix, It includes Translation(X,Y,Z), Scale(X,Y,Z) and Rotation(X,Y,Z).

Here's a nice PDF on the subject of Transformations. [1]

Javascript Matrix 3D Engine (webworker)

<lang Javascript> self.addEventListener('message', function(e) { ///////////////////////////////////////////////////////////////// Utils functions var ifnull=(obj)=> {if (obj == null ) {obj = 0;} return obj;},// Default to zero if object get's no input

   MtCSS=(array)=> { return "matrix3d(" + array.join(',') + ")";},// Convert's to matrix array to css matrix
   radToDeg=(r)=> {return r * 180 / Math.PI;},
   degToRad=(d)=> {return d * Math.PI / 180;},
   zoom=()=> {if (sclx >= -0.000100024011 ) {sclx = -0.000100023011; scly = -0.000100023011; sclz = -0.000100023011;}},// Zoom lock optional
   rotation=()=> {if (rotationRx >= -2) {rotationRx = -2}else if (rotationRx <= -90) {rotationRx = -90}},// Rotation lock optional
   T=(x,y,z)=> {var t = [[1,0,0,0],[0,1,0,0],[0,0,1,0],[x,y,z,1]];return t;},//translationns
   S=(sx,sy,sz)=> {var scale = [[sx,0,0,0],[0,sy,0,0],[0,0,sz,0],[0,0,0,1]];return scale;},// Scale
   R=(rx,ry,rz)=> {var angX=rx,angY=ry,angZ=rz,PIh=Math.PI / 180,//rotations
   cosz=Math.cos(angZ * PIh),sinzp=Math.sin(angZ * PIh),sinzn=Math.sin(-angZ * PIh),m1 = [[cosz,sinzn,0,0],[sinzp,cosz,0,0],[0,0,1,0],[0,0,0,1]],//rZ
   cosx=Math.cos(angX * PIh),sinxp=Math.sin(angX * PIh),sinxn=Math.sin(-angX * PIh),m2 = [[1,0,0,0],[0,cosx,sinxn,0],[0,sinxp,cosx,0],[0,0,0,1]],//rX
   cosy=Math.cos(angY * PIh),sinyp=Math.sin(angY * PIh),sinyn=Math.sin(-angY * PIh),m3 = [[cosy,0,sinyp,0],[0,1,0,0],[sinyn,0,cosy,0],[0,0,0,1]],//rY
   r = mulM(m3, mulM(m2, m1));return r;},
   // Perpective
   p0=(width, height, near,far)=> {var p0 = [[2/width,0,0,0],[1,2/height,0,0],[0,0,-(far + near) / (far - near),2*far*near / (near - far)],[0,0,-1,0]];return p0;},
   p1=(near)=> {var p1 = [[near,0,0,0],[0,near,0,0],[0,0,1,0],[0,0,0,1]];return p1;},
   p2=(fovy, aspectRatio, near, far)=> {var f = 1.0 / Math.tan(fovy / 2), rangeInv = 0.1 / (near - far),l=0,r=resX,b=0,t=resY,p2 = [[f / aspectRatio,0,0,0],[0,f,0,0],[(r+l)/(r-l),(t+b)/(t-b),-(far+near) * rangeInv,2*far*near/(near-far)],[0,0,-near * far * rangeInv * 2,0]];return p2;},
   // Matrix concatenation
   mulM=(m1, m2)=> {var result = []; for (var i = 0; i < m1.length; i++) {result[i] = []; for (var j = 0; j < m2[0].length; j++) {var sum = 0; for (var k = 0; k < m1[0].length; k++) {sum += m1[i][k] * m2[k][j];} result[i][j] = sum.toPrecision(9);}}return result;},
   // Formula wrapper and axis as option
   matrixRT=(x,y,z,rx,ry,rz,sx,sy,sz)=> {var matrix = mulM(R(ifnull(rx),ifnull(ry),ifnull(rz)),T(ifnull(x),ifnull(y),ifnull(z))),matrix = mulM(S(sx, sy, sz),matrix); return matrix;},
   matrixTR=(x,y,z,rx,ry,rz,sx,sy,sz)=> {var matrix = mulM(T(ifnull(x),ifnull(y),ifnull(z)),R(ifnull(rx),ifnull(ry),ifnull(rz))),matrix = mulM(S(sx, sy, sz),matrix); return matrix;},
   // Webworker input var
   data = e.data,
   x= e.data.x, y= e.data.y, z= e.data.z,
   sclx= e.data.sclx, scly= e.data.scly, sclz= e.data.sclz,
   rotationRz= e.data.rotationRz, rotationRx= e.data.rotationRx, rotationRy= e.data.rotationRy, rotationZ= e.data.rotationZ,
   fov = e.data.fovy,near = e.data.near,far = e.data.far, resX = e.data.resX,resY = e.data.resY, 
   movaxis = e.data.movaxis, objaxis = e.data.objaxis,
   // Global env var, and conversions.
   n =near,f =far, aspect = resX / resX/2, w = (2 * n) / resX,h = (2 * n) / resX/2, fovy = degToRad(fov);
   // Function input

if (movaxis == 0) {var sTR = matrixTR(-x,z,y,rotationRx,rotationRy,rotationRz,sclx, scly, sclz);}; if (movaxis == 1) {var sTR = matrixTR(-x,z,y,rotationRx,rotationRy,rotationRz,sclx, scly, sclz;};

   // Perpective treatment

var p1 = mulM(p1(n),p2(fovy, resX / resX/2, near, far)),p01 = mulM(p0(w, h, n,f),p1),per = mulM(sTR,p01),matrixRON = MtCSS(per),

   // Webworker input var

workermatrix = ({MatrixRon: matrixRON,fovy: fov,near: near,far: far,x:x,y:y,z:z}); self.postMessage(workermatrix);}, false);</lang>