Calculate Absolute Dimensions of a Div Rotated in Perspective with CSS3

Calculate absolute dimensions of a div rotated in perspective with css3

I get a headache with matrices, so I'm doing this with proportions.

If you see the div from above (hence seeing the rotation in the two dimensions it takes place in), you're seeing it as a segment on the xz plane, with coordinates (-250, 0) (250, 0), or in general (-w/2, 0) (w/2, 0)
After a rotation on the y axis, the coordinates will become, similarly to what you stated

(-Math.cos(angle) * w/2, -Math.sin(angle) * w/2)
( Math.cos(angle) * w/2, Math.sin(angle) * w/2)

, being the rotation counterclockwise, with the origin at the center of the div, and of angle radians.

Using the perspective means that these coordinates are not displayed just by discarding the z, but they are first projected according to their distance from the observer.

Now, the projection plane is the one where the unrotated things lay, with z = 0. I deduce this from the fact that when unrotated divs are projected, they remain the same size.
If you take a point with distance p (the perspective value) from the z plane, so with xz coordinates (0, -p), and draw a line from this point to the vertices of the rotated segment, up to when it crosses the projection plan, the points you get are the new segment coordinates which yield the div final size.

With a proportion between the triangles (0, -p) (0, 0) (x, 0) and (0, -p) (0, sin*w/2) (cos*w/2, sin*w/2), you get that

p : x = (p + sin*w/2) : cos*w/2
x = (p * cos*w/2) / (p + sin*w/2)

which in general means that when you project the point (x, y, z) onto the plan you get

x * p / (p + z)
y * p / (p + z)
0

So your final div coordinates (on xz, relative to div's center) will be

(-Math.cos(angle) * w/2 * p / (p + -Math.sin(angle) * w/2), 0)
( Math.cos(angle) * w/2 * p / (p + Math.sin(angle) * w/2), 0)

From which you can calculate its width but also its position - which is non trivial, since its nearest-to-the-viewer half will appear bigger than the other half.

Look at the following test for more details (it fails when you're too close to the objects, I'm not sure why, probably some variable overflows)

var WIDTH = 500;var P = 300;jQuery(function(){function test(width, angle, p) {    $('body').        append($('<div id="info" />')).        append($('<div id="container" />').            css({                margin: '50px 0px',                border: '1px solid black',                width: width+'px',                '-webkit-perspective': p            }).            append($('<div id="real" />').addClass('the_div').css({ 'width': width+'px' }))).        append($('<div id="fake" />').addClass('the_div'));
setInterval(function() { angle += 1;
$('#real').css({ '-webkit-transform': 'rotateY('+angle+'deg)' }).html(width);
// initial coordinates var A = 0; var B = width; // translate the center (assuming -perspective-origin at 50%) A -= width/2; B -= width/2; // new coordinates A = calc(A, angle*Math.PI/180, p); B = calc(B, angle*Math.PI/180, p); // translate back A += width/2; B += width/2; if(B < A) { var tmp = A; A = B; B = tmp; } // swap var realwidth = B-A; $('#fake').html(width+'<br/>'+A+', '+B).css({ 'width': realwidth+'px', 'margin-left': A+'px' });
// shows debug information var debug = function(values) { return values.map(function(i){ return i+': '+eval(i); }).join('<br />'); } $('#info').html($('<div />').html(debug(['width', 'p', 'angle', 'A', 'B', 'realwidth'])));
}, 40);}
function calc(oldx, angle, p) { var x = Math.cos(angle) * oldx; var z = Math.sin(angle) * oldx;
return x * p / (p+z);}
test(WIDTH, 0, P);});
* {  margin: 0px;  padding: 0px;}body {  padding: 40px 100px;}.the_div {  height: 100px;  border: 2px solid black;  background-color: rgba(255, 192, 0, 0.5);}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

CSS3 rotate3d pr rotateX get actual height of element

I benefited from efe's comment and calculated real view height of rotated element.

There is technical explanation about solution on djjeck's answer.

You can view this question's answer with an example: http://jsfiddle.net/TqJJL/3/

Calculate real height with this code:

// initial coordinates
var A = 0;
var B = width; // default size of element
// new coordinates
A = calc(A, angle*Math.PI/180, p);
B = calc(B, angle*Math.PI/180, p);
// translate back
A += width/2;
B += width/2;
if(B < A) { var tmp = A; A = B; B = tmp; } // swap

var realHeight = B-A;

function calc(oldx, angle, p) {
var x = Math.cos(angle) * oldx;
var z = Math.sin(angle) * oldx;

return x * p / (p+z);
}

How to calculate angle of rotation to make width fit desired size in perspective mode?

I would consider a different way to find the formula without matrix calculation1 to obtain the following:

R = (p * cos(angle) * D)/(p - (sin(angle) * D))

Where p is the perspective and angle is the angle rotation and D is the element width and R is the new width we are searching for.

If we have an angle of -45deg and a perspective equal to 100px and an initial width 200px then the new width will be: 58.58px

.box {  width: 200px;  height: 200px;  border: 1px solid;  background:    linear-gradient(red,red) right/58.58px 100% no-repeat;  position:relative;}
img { transform-origin:right;}
<div class="box">  <img src="https://picsum.photos/id/1/200/200" style="transform:perspective(100px) rotateY(-45deg)"></div>

What is the formula for proportions of elements using perspective and translateZ?

Yes!

There's actually quite a simple formula for finding the offset - the 3d Projection article on Wikipedia has a diagram and the formula.

The formula is bx = ax * bz / az where:

  • ax is the original distance from the transform origin point
  • az is the perspective + the negative translateZ
  • bz is the perspective

and this will give you:

  • bx - the new distance from the transform origin point

So, you need to know:

  • bz : the perspective (eg: 1000px)
  • ax : the offset from the transform origin point, eg: if the origin point is 50% then this needs to be the element's top relative to the center of the parent element (parent.height/2 + element.top) -- let's say -500px
  • z : the element's translateZ (eg: -600px)
  • az is then bz + z * -1, in this case: 1000 + (-600 * -1) = 1600

so the formula is: -500 * 1000 / 1600 = -312.5

The element is offset vertically -312.5px from the origin, whereas originally it was offset -500px, the difference between the two number is what you'll need to add to the old top value to get the equivalent new value.

This formula also works for the Y axis.

I put together a quick example here: http://jsfiddle.net/trolleymusic/xYRgx/

Determine the visual size of an object at a given distance from origin (using perspective)

The angular width of a square 50 units wide, when seen from a distance of x units, is 2 atan(25/x) (in radians).

How to calculate absolute position of transformed div

Ok, you should add a tag : 'geometry'.
First thing, remember to sine and cosine, then take a calculator :
rotation around the x assis is 45 degrees

The cos of 45 it's around 0,7, then//value of cos for 45 degrees
0.7*150=106 //the height of the rectangle afther transformation
(150-106)/2 //the space remaining in the parent up and down the element divided by 2

the result is 22 and this is positive top or the negative bottom you need.

Same for the second block: (250-(0.7*250))/2 = 37.5

Remember to recalculate the value of the angle if you change it. More rounded the numbers are, more you will be accurate. Remember that calulation can be heavy for many tag.

Reverse 3d rotation in CSS3 - perspective-origin, transform-origin?

You have to set -webkit-transform-style: preserve-3d in the parent; if it is in the grand parent doesn't affect the children.

(Probably it should "cascade", but it just doesn't).

Once you do it, you will find that the children are invisible, because they are behind the parent, but that's another story. Make the parent semitransparent and you will see them.



Related Topics



Leave a reply



Submit