Búsqueda de sitios web

javascript - Ajustando la cámara para una forma visible en Three.js


Tengo una CubeGeometry a la que la cámara está mirando, y quiero que la cámara haga zoom para que el cubo sea completamente visible, pero no más grande.

Mi intento inicial fue convertir los vértices del cubo al sistema de coordenadas de la cámara,

function toScreenXY(position, camera) {
  var pos = position.clone();
  var projScreenMat = new THREE.Matrix4();
  projScreenMat.multiply(camera.projectionMatrix, camera.matrixWorldInverse);
  projScreenMat.multiplyVector3( pos );

  return pos;
}
function ScaleInView() {
  camera.fov = 0.0;
  for (var i=0; i<8; i++) {
    proj2d = toScreenXY(cube.geometry.vertices[i],camera);
    angle = 57.296 * Math.max(Math.atan(proj2d.x/proj2d.z), Math.atan(proj2d.y/proj2d.z));
    camera.fov = Math.max(camera.fov,angle);
  }
  camera.updateProjectionMatrix();
}

Pensé que esto funcionaría, pero a veces es demasiado pequeño y otras veces demasiado grande (dependiendo de la posición de la cámara).

También necesito hacer esto para la cámara ortográfica.

Editar: Sé cómo hacer esto cuando el cubo está frente a la cámara, estoy buscando una forma de hacerlo cuando la cámara se mueve a alguna posición arbitraria (r, theta, phi) (coordenadas polares esféricas; r en realidad es constante para mis propósitos).

Respuesta #1

Cámara en perspectiva. Si la cámara está centrada y mirando el cubo de frente, define

dist=distancia desde la cámara hasta la cara frontal (¡importante!) del cubo

y

height=altura del cubo.

Si configuras el campo de visión de la cámara de la siguiente manera

fov = 2 * Math.atan( height / ( 2 * dist ) ) * ( 180 / Math.PI );

entonces la altura del cubo coincidirá con la altura visible.

Cámara Ortográfica. Si la cámara está centrada y mirando el cubo de frente, definir

aspect=la relación de aspecto de tu ventana (es decir, ancho/alto)

y

height=altura del cubo.

Luego construye tu cámara de esta manera:

camera = new THREE.OrthographicCamera( -aspect * height/2, aspect * height/2, height/2, -height/2, near, far );

La altura del cubo coincidirá con la altura visible.

En cualquier caso, si la cámara no está centrada, o está viendo el cubo desde un ángulo, entonces el problema es más complicado.

Además, si la ventana es más estrecha que alta, entonces el ancho es el factor limitante, y el problema es más complicado.

Respuesta #2

Multiplicar por camera.matrixWorldInverse da un vector en las coordenadas de la cámara, pero lo importante es que no aplica perspectiva.

function toCameraCoords(position) {
  return camera.matrixWorldInverse.multiplyVector3(position.clone());
}

Luego podemos encontrar el ángulo más pequeño que incluirá todas las esquinas de la caja en la escena. arctan(D.x/D.z) da el ángulo BCD donde B es lo que la cámara está viendo, C es la posición de la cámara, y D la posición de un objeto que deseas que sea visible en las coordenadas de la cámara.

En mi caso, lo siguiente asegura que la caja delimitadora del cubo sea completamente visible.

function ScaleInView() {
  var tmp_fov = 0.0;

  for (var i=0; i<8; i++) {
    proj2d = toCameraCoords(boundbox.geometry.vertices[i]);

    angle = 114.59 * Math.max( // 2 * (Pi / 180)
      Math.abs(Math.atan(proj2d.x/proj2d.z) / camera.aspect),
      Math.abs(Math.atan(proj2d.y/proj2d.z))
    );
    tmp_fov = Math.max(tmp_fov, angle);
 }

 camera.fov = tmp_fov + 5; // An extra 5 degrees keeps all lines visible
 camera.updateProjectionMatrix();
}