web-dev-qa-db-ja.com

カメラをオブジェクトに合わせる方法

Three.jsを使用すると、次のものがあります。

  • 複数のObject3Dインスタンスを含むシーン
  • 事前定義された複数のカメラVector3位置
  • 画面のサイズが変更された場合のキャンバスの動的な幅/高さ
  • ユーザーはオブジェクトを選択できます(上から)
  • ユーザーはカメラの位置を選択できます(上から)

表示されているオブジェクトとカメラの位置を考えると、最終的なカメラの位置を計算して、画面上のオブジェクトに「最適に適合する」方法を選択しましたか?

一部の画面でカメラの位置が「そのまま」使用されると、オブジェクトはビューポートの端を越えて出血しますが、他のオブジェクトは小さく表示されます。オブジェクトをカメラの錐台に収めることは可能だと思いますが、適切なものを見つけることができませんでした。

36
fungus1487

私はあなたが透視カメラを使用していると仮定しています。

カメラの位置、視野、またはその両方を設定できます。

次の計算は、立方体であるオブジェクトに対して正確であるため、カメラに面するように配置されたオブジェクトの境界ボックスの観点から考えてください。

カメラが中央にあり、キューブを正面から見る場合、

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

そして

height = height of the cube.

カメラの視野を次のように設定した場合

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

キューブの高さは表示される高さと一致します。

この時点で、カメラを少しバックアップするか、視野を少し増やすことができます。

視野が固定されている場合、上記の方程式を使用して距離を解きます。


編集:キューブwidthを目に見えるwidthに一致させたい場合、aspectをキャンバスの縦横比(キャンバスの幅をキャンバスの高さで割った値)とし、カメラの視野を次のように設定します

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

three.js r.69

59
WestLangley

WestLangleysの答えに基づいて、固定カメラの視野で距離を計算する方法があります:

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

カメラをオブジェクトが画面に収まるように配置する距離を計算するには、次の式を(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はオブジェクトの高さまたは幅です。立方体/球体オブジェクトの場合、高さまたは幅のいずれかを使用できます。長さまたは幅が大きい非キューブ/非球体オブジェクトの場合は、var objectSize = Math.max( width, height )を使用して大きな値を取得します。

オブジェクトの位置が_0, 0, 0_にない場合は、カメラの位置を調整してオフセットを含める必要があることに注意してください。

これはCodePenです これが実際に動作していることを示しています。関連する行:

_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
);
_

ウィンドウハンドルをつかんでサイズを変更すると、球体はまだ画面の高さの100%を占めることがわかります。さらに、オブジェクトは、カメラの位置がオブジェクトのスケールを考慮して表示するために、正弦波の方法(0.6 + ( 0.5 * Math.sin( Date.now() * 0.001 ) ))で拡大縮小します。

11
Andy Ray

アスペクト比の使用に関するuser151496の提案から、これは機能しているように見えますが、いくつかの異なるパラメータセットでテストしただけです。

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

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