consigo un dolor de cabeza con las matrices, por lo que estoy haciendo esto con proporciones.
Si ve el div desde arriba (de ahí ver la rotación en las dos dimensiones que tiene lugar en), que se está viendo como un segmento en el plano xz, con coordenadas (-250, 0) (250, 0)
, o en general (-w/2, 0) (w/2, 0)
Después de una la rotación en el eje y, las coordenadas se convertirá, de manera similar a lo que usted declaró
(-Math.cos(angle) * w/2, -Math.sin(angle) * w/2)
(Math.cos(angle) * w/2, Math.sin(angle) * w/2)
, siendo el giro a la izquierda, con el origen en el centro de la div, y de angle
radianes.
Usar la perspectiva significa que estas coordenadas no se muestran simplemente descartando la z, sino que primero se proyectan según su distancia del observador.
Ahora, el plano de proyección es aquel en el que se encuentran las cosas no giradas, con z = 0. Esto lo deduzco del hecho de que cuando se proyectan divisiones no giradas, siguen siendo del mismo tamaño. Si toma un punto con la distancia p
(el valor de la perspectiva) desde el plano z, entonces con las coordenadas xz (0, -p) y dibuja una línea desde este punto hasta los vértices del segmento girado, hasta cuando cruza el plan de proyección, los puntos que obtienes son las coordenadas del nuevo segmento que producen el tamaño final div.
Con una proporción entre los triángulos (0, -p) (0, 0) (x, 0)
y (0, -p) (0, sin*w/2) (cos*w/2, sin*w/2)
, se obtiene que
p : x = (p + sin*w/2) : cos*w/2
x = (p * cos*w/2)/(p + sin*w/2)
que en general significa que cuando se proyecta el punto (x, y, z)
en el plan se obtiene
x * p/(p + z)
y * p/(p + z)
0
Así que su último Las coordenadas div (en xz, relativas al centro de div) serán
(-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)
Desde el que puede calcular su ancho pero también su posición, que no es trivial, ya que su mitad más cercana al visor aparecerá más grande que la otra mitad.
vistazo a la siguiente prueba para más detalles (se produce un error cuando se está demasiado cerca de los objetos, no estoy seguro de por qué, probablemente algunos desbordamientos de variables)
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
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);
});
</script>
<style type="text/css">
* { margin: 0px; padding: 0px; }
body { padding: 40px 100px; }
.the_div { height: 100px; border: 2px solid black; background-color: rgba(255, 192, 0, 0.5); }
</style>
</head>
<body></body>
</html>
Tenga en cuenta que si estás no dando un valor de perspectiva, el resultado será igual a tener un valor infinito para él.
Esta es una buena pregunta: nunca he sido muy claro sobre exactamente cómo funciona el valor de la perspectiva. –
Agregué la definición oficial para la función de perspectiva del W3C. Todavía no estoy seguro de cómo calcular eso. – Elias
A pesar de haber hecho un grado de matemáticas y saber un poco sobre cómo las matrices se relacionan con el álgebra lineal, todavía no estoy seguro de cómo usar esto con gráficos en 3D. Puede tomar la opción de basura si conoce algunos de los requisitos, y mida el ancho con diferentes perspectivas, colóquelo en una hoja de cálculo y luego ajústele manualmente una curva. Probablemente sea más rápido de todos modos que el cálculo completo, y tendría suficiente precisión (para los píxeles debe redondear al más cercano de todos modos, entonces un error de <0.5 no hace la diferencia) –