Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
3d ThreeJS:在调整浏览器窗口大小后计算透视摄影机的FOV_3d_Three.js_Perspectivecamera - Fatal编程技术网

3d ThreeJS:在调整浏览器窗口大小后计算透视摄影机的FOV

3d ThreeJS:在调整浏览器窗口大小后计算透视摄影机的FOV,3d,three.js,perspectivecamera,3d,Three.js,Perspectivecamera,更改浏览器窗口大小后,我需要获得正确的Three.JS camera FOV。我查看了以下问题,但似乎找不到问题的答案: 我的相机设置如下(“此”指我设置的游戏相机对象): 当用户调整浏览器窗口的大小时,将调用以下更新代码。我包括了我在这里找到的代码:()用于尝试计算新的FOV('aFOV') 但它似乎不起作用。调整窗口大小后(例如,将其拖宽500像素),我可以看到渲染3D场景的更大宽度。渲染视图似乎没有扭曲(即没有或多或少的“鱼眼”外观)。但是camera.fov值没有改变(在控制台日

更改浏览器窗口大小后,我需要获得正确的Three.JS camera FOV。我查看了以下问题,但似乎找不到问题的答案:

我的相机设置如下(“此”指我设置的游戏相机对象):

当用户调整浏览器窗口的大小时,将调用以下更新代码。我包括了我在这里找到的代码:()用于尝试计算新的FOV('aFOV')

但它似乎不起作用。调整窗口大小后(例如,将其拖宽500像素),我可以看到渲染3D场景的更大宽度。渲染视图似乎没有扭曲(即没有或多或少的“鱼眼”外观)。但是camera.fov值没有改变(在控制台日志中,我之前得到'45'作为fov,之后得到'45'作为fov),我计算的fov一点也不正确——值为'6.33189…'

因此,在我看来,FOV用于设置projectionMatrix,但当调用updateProjectionMatrix()时,不会进行反向计算来更新FOV。我正在使用THREE.JS r87(修订版87)

以下是我在()链接中找到的用于计算FOV的原始代码:

var height = 500;
var distance = 1000;
var fov = 2 * Math.atan((height) / (2 * distance)) * (180 / Math.PI);
itsLeftCamera = new THREE.PerspectiveCamera(fov , 400 / 500, 1.0, 1000);
该链接上的评论似乎表明该公式是正确的

问题:

  • camera.UpdateProjectMatrix()没有更改.fov属性,对吗
  • 我的理解是当屏幕变宽时FOV会改变,对吗?还是我对FOV的含义感到困惑
  • 我做错了什么?如何正确计算摄像机视场
提前谢谢

---编辑----

在问了这个问题之后,我决定试着看看我是否能解决这个问题

我从这里找到的@rabbi76的优秀图表开始:我修改了图片以显示计算FOV公式的推导,如果知道远平面尺寸和相机距离的话

我现在明白了公式的推导。我看到,如果给定一个起始垂直视场,那么我可以计算出远平面的宽度和高度,如下所示:

  this.cameraDist = CAMERA_DIST;
  this.aspectRatio = window.innerWidth / window.innerHeight;
  this.farPlaneHeight = Math.tan(this.vertFOV/2) * this.cameraDist;
  this.farPlaneWidth = this.Height * this.aspectRatio;
但我还是被卡住了。我不理解渲染窗口大小(即浏览器窗口)与远平面大小之间的相关性。如果我的相机是巨大的(例如1000000),我的远平面也将是巨大的

我假设渲染窗口位于近平面和远平面之间。所以我需要的是到渲染平面的距离

在更改window.innerHeight或window.innerWidth后,我仍然无法确定如何确定新的摄影机FOV

--编辑2--

@拉比在评论中提出了正确的答案。我想了解它,所以在考虑这一点时绘制了一些图表:

该图显示的是,随着视口平面大小的变化(h1-->h2),可以计算有效视野(FOV)中的结果变化

如果视口不是正方形,那么如果垂直视场已知且纵横比已知,也可以使用此公式计算水平视场

为了得到最终答案,我使用以下代码:

//Below is code used when initializing the perspective camera
this.viewportWidth = window.innerWidth;
this.viewportHeight = window.innerHeight;
this.aspectRatio = window.innerWidth / window.innerHeight;
this.vertFOV = params.FOV || CAMERA_FOV
this.horizFOV = this.calculateHorizFOV();
this.camera = new THREE.PerspectiveCamera(this.vertFOV, this.aspectRatio, 1, this.cameraDist);
...
calculateHorizFOV() {
  let radVertFOV = this.vertFOV * Pi/180;
  let radHhorizFOV = 2 * Math.atan( Math.tan(radVertFOV/2) * this.aspectRatio);
  let horizFOV = radHorizFOV * 180/Pi;
  return horizFOV;
} 
然后,当用户调整屏幕大小时,我使用此代码

function onWindowResize() {
  let oldHeight = gameCamera.viewportHeight;
  let oldWidth = gameCamera.viewportWidth;
  let newHeight = window.innerHeight;
  let newWidth = window.innerWidth;
  gameCamera.viewportHeight = newHeight;
  gameCamera.viewportWidth = newWidth;
  gameCamera.aspectRatio = newWidth / newHeight;
  let oldRadFOV = gameCamera.vertFOV * Pi/180;
  let newRadVertFOV = 2*Math.atan( Math.tan(oldRadFOV/2) * newHeight/oldHeight);
  gameCamera.vertFOV = newRadVertFOV * 180/Pi;
  gameCamera.calculateHorizFOV();  
  gameCamera.camera.aspect = gameCamera.aspectRatio;
  gameCamera.camera.updateProjectionMatrix();
  renderer.setSize( window.innerWidth, window.innerHeight );
} //onWindowResize()

如果您想知道,如果某个点位于视图体积中且未剪裁,则必须将该点投影到视口中。
用于此:

camera   = THREE.PerspectiveCamera
pt_world = Three.Vector3

pt_ndc = new THREE.Vector3()
pt_ndc.copy(pt_world).project(camera)
如果结果是在规格化设备空间中,则结果为a,且点位于视图体积(在视口上)。标准化设备空间的范围为(-1,-1,-1)到(1,1,1),并形成一个完美的立方体体积。 (见附件)

注意,投影矩阵描述了从场景的三维点到视口的二维点的映射。投影矩阵从视图空间转换到剪辑空间,剪辑空间中的坐标通过与剪辑坐标的w分量相除转换为(-1,-1,-1)至(1,1,1)范围内的归一化设备坐标(NDC)


摄像机。视野是垂直视野,而不是水平视野。我也想到了,应该有一个水平视场和一个垂直视场。在上面的讨论中,我只是改变了屏幕的宽度,这样就可以改变水平视场。但我复制的公式只考虑了高度。。。我知道@WestLangley也指出了这一点。但它仍然不能回答我的问题。@Rabbid76,谢谢你看这个。我的动机是能够判断渲染对象在视口中是否可见。如果没有,那么我会将相机从场景中移开。我将通过计算矢量到物体和相机视线之间的角度来实现这一点。若和物体的角度超过1/2视场,那个么它就看不见了。所以我想要的就是FOV。我不想改变观点。我只需要在用户调整浏览器窗口大小时做出响应。这似乎没有改变观点,但确实改变了观点FOV@Rabbid76我需要一点时间来消化你建议的配方。谢谢,这可能会有所帮助:我将此标记为已接受的答案,因为@rabbi76在上面的评论中给了我正确的答案,我希望他能得到信任。此帖子没有对我的问题的直接答案,因此请参见原始问题中的编辑#2以了解解释。此答案与我最终尝试做的一样(查看对象是否在视口中)。
function onWindowResize() {
  let oldHeight = gameCamera.viewportHeight;
  let oldWidth = gameCamera.viewportWidth;
  let newHeight = window.innerHeight;
  let newWidth = window.innerWidth;
  gameCamera.viewportHeight = newHeight;
  gameCamera.viewportWidth = newWidth;
  gameCamera.aspectRatio = newWidth / newHeight;
  let oldRadFOV = gameCamera.vertFOV * Pi/180;
  let newRadVertFOV = 2*Math.atan( Math.tan(oldRadFOV/2) * newHeight/oldHeight);
  gameCamera.vertFOV = newRadVertFOV * 180/Pi;
  gameCamera.calculateHorizFOV();  
  gameCamera.camera.aspect = gameCamera.aspectRatio;
  gameCamera.camera.updateProjectionMatrix();
  renderer.setSize( window.innerWidth, window.innerHeight );
} //onWindowResize()
camera   = THREE.PerspectiveCamera
pt_world = Three.Vector3

pt_ndc = new THREE.Vector3()
pt_ndc.copy(pt_world).project(camera)