How to Calculate Angle of Rotation to Make Width Fit Desired Size in Perspective Mode

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>

Get the width and height of rotated object after transform

This is the best working formula I have come up with:

var h = $(obj).height() * Math.abs(Math.cos(deg)) + $(obj).width() * Math.abs(Math.sin(deg));
var w = $(obj).width() * Math.abs(Math.cos(deg)) + $(obj).height() * Math.abs(Math.sin(deg));

The Projection Of The CALayer Rotation

If I am understanding you correctly, what you are trying to do is determine the relative position of two different points after a series of transforms. Working out the equations for doing this can be tricky, I find it helpful to write everything out in terms of the matrices first and then get the equations by multiplying out the matrices myself.

Lets say your anchor is at the origin, using column major matrices (like open GL, and CA Layer do). Position1 will represent the left edge of your rectangle, Position2 the right.

Position1 = {1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1};

Position2 ={1,0,0,w,
0,1,0,0,
0,0,1,0,
0,0,0,1};

Position 2 now needs to be rotated by your angle around the y axis so we declare

Rotation = {cos,0,sin,0,
0,1, 0,0,
-sin,0,cos,0,
0,0, 0,1};

The rotation needs to be applied to Position2 and both of them need to be multiplied by a projection matrix. Position1 needs no rotation because it lies on the axis of rotation. It is important to realize that just setting m34 to a small negative number is not doing anything magic, what you are really doing is multiplying by the projection matrix

YourProjection = {1,0,0        ,0,
0,1,0 ,0,
0,0,1 ,0,
0,0,-1.0/1800,1};

Multiplying by a different format of projection matrix works just as well, use whatever you are most familiar with. You could use a matrix like Open GL or the kind you are using because they are really equivalent.

Position2 = MultiplyMatrices(Rotation,Position2);
Position2 = MultiplyMatrices(YourProjection,Position2);
Position1 = MultiplyMatrices(YourProjection,Position1);

Position1 and Position2 now hold the exact positions that they will be given when your CALayer performs its transform on them. Since these are in homogeneous coordinates you have to make sure to divide your x,y,z components (m41,42,43) by w (m44) to convert back to cartesian. Then all you need to do to get the width is

float width = Position1.m41-Position2.m41;

If you haven't already, you should probably make yourself functions that do matrix multiplication so that you can do calculations like this quickly and easily. Also you can't get confused because of algebra mistakes this way :). If you really want to do it algebraically just multiply this out and it should give you what you are looking for. Also in case my matrix notation was confusing, here is a conversion from column major to CALayer variables.

{m11,m12,m13,m14,
m21,m22,m23,m24,
m31,m32,m33,m34,
m41,m42,m43,m44};

where a simple translation matrix would be

{1,0,0,0,
0,1,0,0,
0,0,1,0,
x,y,z,1};

Why changing the position changes the effect of 3D transform?

although both of them has the same perspective view why changing their position changed the effect of 3D transform ?

They have the same perspective, yes but the trick is in the perspective-origin which is set to be the center of the parent element (not the elements). Your Red element is already in center so it will only comes close to your while the yellow element isn't in the center so its movement will be different.

To better illustrate here is another example using a rotate transformation.

.container {
border:2px solid red;
perspective:300px;
perspective-origin:50% 50%;
padding:20px;
display:flex;
justify-content:space-around;
}

.container > div {
width:50px;
height:50px;
background:blue;
transform:rotateY(20deg);
}
<div class="container">
<div></div>
<div></div>
<div></div>
</div>

<div class="container" style="perspective-origin:10% 50%">
<div></div>
<div></div>
<div></div>
</div>

<div class="container" style="perspective-origin:70% 50%">
<div></div>
<div></div>
<div></div>
</div>

Why perspective isn't giving the same result when some styles are updated?

Each have almost the same values, one perspective looks fine,

No they don't have the same values. One is using position:absolute and the the other one position:relative and this make a big difference. If you inspect the god element you will notice that its height is 0 when using the position:absolute (the first case) which is creating the issue.

Here is a simplified code to better show your issue:

.box {
display: inline-block;
vertical-align:top;
width: 100px;
perspective: 200px;
position: relative;
margin: 20px;
background:blue;
}

.box>div {
position: relative;
padding: 10px;
background: red;
color: #fff;
transition: 1s all linear;
transform-origin: top left;
}

body:hover .box > div {
transform: rotateY(-40deg);
}
<div class="box">
<div>Some text here</div>
</div>
<div class="box">
<div style="position:absolute;">Some text here</div>
</div>

How to determine the angle of rotation for a rotating/animating cylinder? Three.js

I have created a new fiddle: http://jsfiddle.net/5vxvLdub/3/

Relevant portion:

    function fuzzyEqual( n1, n2 ) {
var epsilon = .01;
return ( n1 - epsilon < n2 ) && ( n1 + epsilon > n2 );
}

var desiredNum = 3,
faces = 8,
theta = Math.PI * 2 * ( faces - desiredNum - 5.5 ) / faces,
destY = Math.cos( theta ),
destZ = Math.sin( theta );

// request new frame
requestAnimationFrame(function(){
// ugly method :p
if ( fuzzyEqual( o.y, destY ) && fuzzyEqual( o.z, destZ ) ){
return;
}
animate(time);
});


Related Topics



Leave a reply



Submit