abernier
abernier

Reputation: 28208

Apply perspective matrix order

I'm actually working on a script domvertices which computes the 4 vertices 3d-coordinates of a any DOM element: http://bl.ocks.org/abernier/97a5fb8c1bebacd1958e

var el = document.getElementById('foo');
var vertices = domvertices(el);
console.log(vertices);

outputs:

{
  a: {x: , y: , z: },
  b: {x: , y: , z: },
  c: {x: , y: , z: },
  d: {x: , y: , z: }
}

In order to acheive that, I walk the dom up and for each element store the matrix applied to it (cf. ¹).

Finally, I apply the matrices back to the targetted element in the reverse order.

--

Actually it works great!

My only problem is about perspective... For now, I don't take perspective nor perspective-origin into account when computing element's matrix¹.

As a result, deformation from perspective isn't taken into account(as a workaround when drawing vertices, I append them into the element subjected to perspective so they are correctly positionned).

I'd like to take perspective and perspective-origin when computing element's matrix.

I can easily make a perpective matrix, my problem is when to apply perspective and perspectiveOrigin matrix to ¹ ?

What about nested multiple perspective?

¹: Element's matrix is composed as followed (read right to left):

transformOrigin^-1 * transform * transformOrigin * relativePosition * Identity

Any help appreciated.

Upvotes: 2

Views: 405

Answers (2)

jbenker
jbenker

Reputation: 236

You can find a TypeScript library on github which supports perspective transformations and some common transformation methods like globalToLocal, localToGlobal and localToLocal: jsidea core library. You can find the matrix-extraction in the jsidea.geom.Transform.extractMatrix function. It looks like that:

//subtract transform-origin
matrix.appendPosition(-originX, -originY, -originZ);
//append transform-matrix
matrix.appendCSS(style.transform);
//add transform-origin
matrix.appendPosition(originX, originY, originZ);
//add local position 
//Difficult to calc the local position, 
//because the offsetParent, offsetLeft and offsetTop are not reliable.
matrix.appendPosition(position.x, position.y, 0);
//subtract the perspective-origin
matrix.appendPosition(-perspectiveOriginX, -perspectiveOriginY, 0);
//apply the perspective (aka focalLength)
matrix.appendPerspective(perspective);
//add perspective-origin
matrix.appendPosition(perspectiveOriginX, perspectiveOriginY, 0);

Under some conditions the library uses multiple matrices for one element. If the element is in a nested-perspective context and the parent is not preserving 3d (transform-style: flat). You can take a look at the at this code.

Upvotes: 1

Brendan Annable
Brendan Annable

Reputation: 2747

Your perspective matrix needs to be equivalent to being the left-most matrix in the sequence of applied matrices.

e.g. as taken from nearly all WebGL fragment shaders

gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

The projection matrix is on the left.

Upvotes: 2

Related Questions