web-dev-qa-db-fra.com

Comment adapter la caméra à un objet

En utilisant three.js, j'ai ce qui suit.

  • Une scène contenant plusieurs instances d'Object3D
  • Plusieurs positions prédéfinies de la caméra Vector3
  • Une largeur/hauteur dynamique du canevas si l'écran est redimensionné
  • Un utilisateur peut sélectionner un objet (d'en haut)
  • Un utilisateur peut sélectionner une position de caméra (par le haut)

Compte tenu de la visualisation d'un objet et de la position de la caméra, ils ont choisi comment calculer la position finale de la caméra pour "adapter au mieux" l'objet à l'écran?

Si les positions de la caméra sont utilisées "telles quelles" sur certains écrans, les objets saignent sur le bord de ma fenêtre tandis que d'autres apparaissent plus petits. Je pense qu'il est possible d'adapter l'objet au tronc de la caméra, mais je n'ai rien trouvé de convenable.

36
fungus1487

Je suppose que vous utilisez une caméra en perspective.

Vous pouvez définir la position de la caméra, le champ de vision ou les deux.

Le calcul suivant est exact pour un objet qui est un cube, pensez donc en termes de boîte englobante de l'objet, alignée pour faire face à la caméra.

Si la caméra est centrée et regarde le cube de face, définissez

dist = distance from the camera to the _closest face_ of the cube

et

height = height of the cube.

Si vous définissez le champ de vision de la caméra comme suit

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

alors la hauteur du cube correspondra à la hauteur visible.

À ce stade, vous pouvez sauvegarder un peu la caméra ou augmenter légèrement le champ de vision.

Si le champ de vision est fixe, utilisez l'équation ci-dessus pour résoudre la distance.


EDIT: si vous voulez que le cube width corresponde au visible largeur, laissez aspect être le rapport d'aspect du canevas (largeur du canevas divisée par la hauteur du canevas), et définir le champ de vision de la caméra comme

fov = 2 * Math.atan( ( width / aspect ) / ( 2 * dist ) ) * ( 180 / Math.PI ); // in degrees

three.js r.69

59
WestLangley

Sur la base de la réponse de WestLangleys, voici comment calculer la distance avec un champ de vision de caméra fixe:

dist = height / 2 / Math.tan(Math.PI * fov / 360);
16
shi

Pour calculer la distance à laquelle placer votre appareil photo pour adapter un objet à l'écran, vous pouvez utiliser cette formule (en Javascript):

// Convert camera fov degrees to radians
var fov = camera.fov * ( Math.PI / 180 ); 

// Calculate the camera distance
var distance = Math.abs( objectSize / Math.sin( fov / 2 ) );

objectSize est la hauteur ou la largeur de l'objet. Pour les objets cube/sphère, vous pouvez utiliser la hauteur ou la largeur. Pour un objet non cube/non sphère, où la longueur ou la largeur est supérieure, utilisez var objectSize = Math.max( width, height ) pour obtenir la plus grande valeur.

Notez que si la position de votre objet n'est pas à 0, 0, 0, Vous devez ajuster la position de votre caméra pour inclure le décalage.

Voici un CodePen montrant cela en action. Les lignes concernées:

var fov = cameraFov * ( Math.PI / 180 );
var objectSize = 0.6 + ( 0.5 * Math.sin( Date.now() * 0.001 ) );

var cameraPosition = new THREE.Vector3(
    0,
    sphereMesh.position.y + Math.abs( objectSize / Math.sin( fov / 2 ) ),
    0
);

Vous pouvez voir que si vous saisissez la poignée de la fenêtre et la redimensionnez, la sphère occupe toujours 100% de la hauteur de l'écran. De plus, l'objet évolue vers le haut et vers le bas de manière sinusoïdale (0.6 + ( 0.5 * Math.sin( Date.now() * 0.001 ) )), pour montrer que la position de la caméra prend en compte l'échelle de l'objet.

11
Andy Ray

D'après la suggestion de user151496 concernant l'utilisation du rapport d'aspect, cela semble fonctionner, même si je n'ai testé qu'avec quelques jeux de paramètres différents.

var maxDim = Math.max(w, h);
var aspectRatio = w / h;        
var distance = maxDim/ 2 /  aspectRatio / Math.tan(Math.PI * fov / 360);
1
jimf

essayez ceci pour OrbitControls

    let padding = 48;
    let w = Math.max(objectLength, objectWidth) + padding;
    let h = objectHeight + padding;

    let fovX = camera.fov * (aspectX / aspectY);
    let fovY = camera.fov;

    let distanceX = (w / 2) / Math.tan(Math.PI * fovX / 360) + (w / 2);
    let distanceY = (h / 2) / Math.tan(Math.PI * fovY / 360) + (w / 2);

    let distance = Math.max(distanceX, distanceY);
0
Matt