如何计算给定坐标处相机可见矩形的大小? [复制]

2024-04-29

我制作了一个小型的 Three.js 应用程序,它将一堆圆圈从画布的底部移动到顶部:

let renderer, scene, light, circles, camera;

initialize();
animate();

function initialize() {
  renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  scene = new THREE.Scene();

  light = new THREE.AmbientLight();
  scene.add(light);

  circles = new THREE.Group();
  scene.add(circles);

  camera = new THREE.PerspectiveCamera(45, renderer.domElement.clientWidth / renderer.domElement.clientHeight, 1);
  camera.position.z = circles.position.z + 500;
}


function animate() {
  // Update each circle.
  Array.from(circles.children).forEach(circle => {
    if (circle.position.y < visibleBox(circle.position.z).max.y) {
      circle.position.y += 4;
    } else {
      circles.remove(circle);
    }
  });

  // Create a new circle.
  let circle = new THREE.Mesh();
  circle.geometry = new THREE.CircleGeometry(30, 30);
  circle.material = new THREE.MeshToonMaterial({ color: randomColor(), transparent: true, opacity: 0.5 });
  circle.position.z = _.random(camera.position.z - camera.far, camera.position.z - (camera.far / 10));
  circle.position.x = _.random(visibleBox(circle.position.z).min.x, visibleBox(circle.position.z).max.x);
  circle.position.y = visibleBox(circle.position.z).min.y;
  circles.add(circle);

  // Render the scene.
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

function visibleBox(z) {
 return new THREE.Box2(
   new THREE.Vector2(-1000, -1000),
   new THREE.Vector2(1000, 1000)
 );
}

function randomColor() {
  return `#${ _.sampleSize("abcdef0123456789", 6).join("")}`;
}
body {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.js">
</script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js">
</script>

我使用该功能visibleBox(z)确定在哪里创建和销毁每个圆圈。我已经对该函数的返回值进行了硬编码,但我希望它能够计算相机在给定深度处可见的矩形的大小,z.

换句话说,我希望每个圆都准确地创建在相机平截头体的底部(上图中红色矩形的底部边缘),并在它到达平截头体的顶部(相机的顶部边缘)时准确地销毁。红色矩形)。

那么,我如何计算这个矩形呢?


像这样更改函数:

function visibleBox(z) {
    var t = Math.tan( THREE.Math.degToRad( camera.fov ) / 2 )
    var h = t * 2 * z;
    var w = h * camera.aspect;
    return new THREE.Box2(new THREE.Vector2(-w, h), new THREE.Vector2(w, -h));
}

并像这样设置圆位置:

circle.position.z = _.random(-camera.near, -camera.far);
var visBox = visibleBox(circle.position.z)
circle.position.x = _.random(visBox.min.x, visBox.max.x);
circle.position.y = visBox.min.y;

代码演示:

let renderer, scene, light, circles, camera;

initialize();
animate();

function initialize() {
  renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  scene = new THREE.Scene();

  light = new THREE.AmbientLight();
  scene.add(light);

  circles = new THREE.Group();
  scene.add(circles);

  camera = new THREE.PerspectiveCamera(45, renderer.domElement.clientWidth / renderer.domElement.clientHeight, 1);
  camera.position.z = circles.position.z + 500;
}


function animate() {
  // Update each circle.
  Array.from(circles.children).forEach(circle => {
    if (circle.position.y < visibleBox(circle.position.z).max.y) {
      circle.position.y += 4;
    } else {
      circles.remove(circle);
    }
  });

  // Create a new circle.
  let circle = new THREE.Mesh();
  circle.geometry = new THREE.CircleGeometry(30, 30);
  circle.material = new THREE.MeshToonMaterial({ color: randomColor(), transparent: true, opacity: 0.5 });
  circle.position.z = _.random(-(camera.near+(camera.far-camera.near)/5), -camera.far);
  var visBox = visibleBox(circle.position.z)
  circle.position.x = _.random(visBox.min.x, visBox.max.x);
  circle.position.y = visBox.min.y;
  circles.add(circle);

  // Render the scene.
  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}

function visibleBox(z) {
    var t = Math.tan( THREE.Math.degToRad( camera.fov ) / 2 )
    var h = t * 2 * z;
    var w = h * camera.aspect;
    return new THREE.Box2(new THREE.Vector2(-w, h), new THREE.Vector2(w, -h));
}

function randomColor() {
  return `#${ _.sampleSize("abcdef0123456789", 6).join("")}`;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.js">
</script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js">
</script>

解释

投影矩阵描述了从场景的 3D 点到视口的 2D 点的映射。它从眼睛空间变换到剪辑空间,并且剪辑空间中的坐标除以w剪辑坐标的组成部分。 NDC 的范围为 (-1,-1,-1) 到 (1,1,1)。


在透视投影中,深度值和到相机的 z 距离之间的关系不是线性的。
透视投影矩阵如下所示:

r = right, l = left, b = bottom, t = top, n = near, f = far

2*n/(r-l)      0              0               0
0              2*n/(t-b)      0               0
(r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1    
0              0              -2*f*n/(f-n)    0

由此得出视图空间中的 z 坐标与标准化设备坐标 z 分量和深度之间的关系:

z_ndc = ( -z_eye * (f+n)/(f-n) - 2*f*n/(f-n) ) / -z_eye
depth = (z_ndc + 1.0) / 2.0

反向操作如下所示:

n = near, f = far

z_ndc = 2.0 * depth - 1.0;
z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));

如果透视投影矩阵已知,则可以按如下方式完成:

A = prj_mat[2][2]
B = prj_mat[3][2]
z_eye = B / (A + z_ndc)

See 如何在现代 OpenGL 中使用片段着色器中的 gl_FragCoord.z 线性渲染深度? https://stackoverflow.com/questions/7777913/how-to-render-depth-linearly-in-modern-opengl-with-gl-fragcoord-z-in-fragment-sh/45710371#45710371


视图空间中的投影面积与视图空间的 Z 坐标之间是线性关系。这取决于视角和纵横比。

标准化设备大小可以转换为视图空间中的大小,如下所示:

aspect = w / h
tanFov = tan( fov_y * 0.5 );

size_x = ndx_size_x * (tanFov * aspect) * z_eye;
size_y = ndx_size_y * tanFov * z_eye;

如果透视投影矩阵已知并且投影是对称的(视线位于视口的中心并且视野没有移位),则可以按如下方式完成:

size_x = ndx_size_x * / (prj_mat[0][0] * z_eye);
size_y = ndx_size_y * / (prj_mat[1][1] * z_eye);

See 视野 + 纵横比 + 投影矩阵的视图矩阵(HMD OST 校准) https://stackoverflow.com/questions/46182845/field-of-view-aspect-ratio-view-matrix-from-projection-matrix-hmd-ost-calib/46195462#46195462


请注意,标准化设备坐标中的每个位置都可以通过逆投影矩阵转换为视图空间坐标:

mat4 inversePrjMat = inverse( prjMat );
vec4 viewPosH      = inversePrjMat * vec3( ndc_x, ndc_y, 2.0 * depth - 1.0, 1.0 );
vec3 viewPos       = viewPos.xyz / viewPos.w;

See 如何在给定视图空间深度值和 ndc xy 的情况下恢复视图空间位置 https://stackoverflow.com/questions/11277501/how-to-recover-view-space-position-given-view-space-depth-value-and-ndc-xy/46118945#46118945


这意味着具有特定深度的未投影矩形可以如下计算:

vec4 viewLowerLeftH  = inversePrjMat * vec3( -1.0, -1.0, 2.0 * depth - 1.0, 1.0 );
vec4 viewUpperRightH = inversePrjMat * vec3(  1.0,  1.0, 2.0 * depth - 1.0, 1.0 );
vec3 viewLowerLeft   = viewLowerLeftH.xyz / viewLowerLeftH.w;
vec3 viewUpperRight  = viewUpperRightH.xyz / viewUpperRightH.w;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何计算给定坐标处相机可见矩形的大小? [复制] 的相关文章

  • 将构造函数传递给 Array.map?

    我怎样才能做这样的事情 var a 1 2 3 4 a map Date constructor 此代码在 Google V8 上引发错误 SyntaxError Unexpected number 我也尝试过 a map Date con
  • 使用 .add() 选择多个 jQuery 对象

    是否 add http api jquery com add 方法允许一次选择多个对象而不是一次添加一个 one add two add three add four on click function 以下变量的设置方式相同 因为每个变量
  • 如何使用 jQuery 在按下按钮后保持按钮处于活动状态

    我见过一些非常相似的问题 但一直无法找到我正在寻找的答案 我已经确定了解决方法 但想知道执行该任务的正确方法 我想要的是单击按钮并使活动状态保持不变 下一次单击将切换状态 这是所需的 我真正需要知道的是如何解决 uiButton activ
  • 所有事件的 HTML5 EventSource 监听器?

    我使用 EventSource 在 JavaScript 客户端应用程序中推送通知 我可以像这样附加事件监听器 source addEventListener my custom event type function e console
  • 如何从 Javascript/Typescript 中的数组对象计算运行总计并使用 HTML 在每个实例上显示输出?

    我正在开发一个 MEAN 堆栈项目 并且有一个如下所示的数组 savings any 300 450 350 500 我还有一个名为 saving bf 的变量 它是从数据库中检索的结转储蓄 其值如下 savings bf 15000 我想
  • 是否可以进行条件解构或有后备?

    我有一个具有许多深层嵌套属性的对象 我希望能够访问 MY KEY 上的属性 如下 但如果该属性不存在 则获取 MY OTHER KEY 我怎样才能做到这一点 const X Y MY KEY Values segments segment
  • 从 html5

    我正在寻找一种方法来根据用户代理字符串将控件属性添加到视频标签 我不希望在 iPad 和 Android 之外的任何浏览器或设备上出现控件属性 所以我认为用户代理是最好的识别方法 因为 ipad 和 android 一词出现在各自的 UA
  • 如何避免 TypeScript 中出现虚假的“未使用参数”警告

    我遇到过很多次这种情况 最后决定弄清楚正确的方法是什么 如果我有一个声明方法的抽象父类 然后一些具体子类在其实现中实现真正的逻辑 并且显然使用方法参数 但某些子类不需要在该方法中执行任何操作 因此不要使用方法参数 那些不必执行任何操作的方法
  • Next.js:如何将 source-map-explorer 与 Next.js 一起使用

    我想分析我的 Next js 构建源地图浏览器 https www npmjs com package source map explorer 有人可以帮我编写脚本吗 对于 React CRA 我使用以下脚本 build analyze n
  • 如何在 Angular 2 应用程序中使 DateAdapter 单例?

    我正在开发一个带有延迟加载模块的 Angular 7 应用程序 我也使用有角度的材料组件 我想在日期选择器组件中本地化并支持多个区域设置 当应用程序语言发生变化时 我想在整个应用程序中全局更改它 可以通过 DateAdapter setLo
  • 在 JQuery ui 自动完成中显示图像

    我有一个带有 JQuery ui 自动完成功能的脚本 可以完美运行 有一个显示用户名字和姓氏的搜索过程 但在我的数据库中 还有用户的图片 我想将其显示在带有名字和姓氏的建议中 数据库中pic包含图片url 剧本 function searc
  • Angularjs - 将 True/False 显示为 Yes/No

    有没有一种简单的方法可以将真 假值显示为是 否 我正在从数据库检索包含以下内容的 JSON 对象 对象 WithCertification true 这是 HTML 有认证 elem WithCertification 正在显示这个 认证真
  • Onblur 事件在另一个 div 的 onclick 之前触发

    如上所述 我有一个按钮 单击该按钮将打开子菜单 对于子菜单中的每个选项 都有三个元素 我认为实际上还有更多元素 但为了简单起见 将其保留为 3 我将焦点放在子菜单的主 div 白色 框架 上 Onblur 这个 div 然后我隐藏子菜单 这
  • iPhone 点击时使 div 变暗

    当您的 div 附加了点击处理程序时 当点击该 div 时 iPhone 会使该 div 变暗 作为点击指示器 示例 在移动 Safari 上查看http jsbin com awejo3 4 http jsbin com awejo3 4
  • JsGrid 将嵌套对象加载到表中

    我正在 Django 中开发一个 Web 项目并使用 jsGrid 我遇到了问题并且找不到解决方案 我有一个嵌套的 JSON 数据 它是通过组合多个数据库表记录创建的 这是我的 JSON count 3 results personnel
  • 角度 4 单击按钮功能未触发

    我正在尝试检查文本输入是否为空或不在角度 4 中 我没有为此使用表单 这只是一个输入字段 当我在下面的按钮中执行 addLocaton 函数时 需要进行检查 我的输入字段
  • 如何在 Firefox 插件中追加到文件?

    var tabs require sdk tabs var iofile require sdk io file var widgets require sdk widget var selection require sdk select
  • 错误:模块“html”不提供视图引擎(Express)

    我正在尝试设置一个简单的路由应用程序 但在渲染页面时不断遇到错误 Error Module html does not provide a view engine 奇怪的是我已经在 app js 文件中指定了视图引擎 但仍然收到错误 app
  • Javascript/jQuery 外部高度()

    Does idOfLememt outerHeight 对所有浏览器产生相同的结果 IE7 有什么不同吗 只要去http api jquery com outerHeight http api jquery com outerHeight
  • Angular 2:使用正则表达式进行数字验证

    我正在尝试验证 IE 11 中的数字字段

随机推荐

  • Python:为什么 IDLE 这么慢?

    IDLE http en wikipedia org wiki IDLE Python 是我最喜欢的 Python 编辑器 它提供了非常漂亮且直观的 Python shell 对于单元测试和调试非常有用 并且还提供了一个简洁的调试器 然而
  • 使用 DRF 中序列化器字段的子集反序列化 POST 请求

    我遇到了一个相当简单的问题 但找到了一些解决方案 并且不停地想知道预期的 DRF 方法是什么 我有一个 简化的 模型和序列化器 如下所示 class CartProduct models Model cart models ForeignK
  • 如何控制knitr kable科学记数法?

    我有一个像这样的数据框 gt summary variable value 1 var1 5 810390e 06 2 var2 5 018182e 06 3 var3 5 414286e 06 4 var4 3 000779e 02 5
  • 如何以可移植的方式验证 ANSI C 的标准输入缓冲区中是否有某些信息?

    我正在尝试用 ANSI C 开发一个可移植函数来验证标准输入缓冲区是否为空 这个想法是用它来验证用户是否按下了某个键 在 Windows 中 使用 kbhit 来自 conio h 很容易做到这一点 但它依赖于操作系统 不过 我想开发自己的
  • Xcode 6 本地化无法读取字符串文件

    Xcode 无法生成 xliff 本地化文件并出现错误本地化无法读取字符串文件 请检查系统日志以获取更多详细信息 有谁知道我在哪里可以找到这些日志 它是 Xcode 6 3 2 GM 但我也尝试过 6 3 1 版本 同 6 3 1 错误发生
  • 能否为一种 XAML 样式定义多个 TargetType?

    在 HTML CSS 中 您可以定义可应用于多种类型元素的样式 例如 highlight color red 可以应用于 P 和 DIV 例如 p class highlight this will be highlighted p div
  • 为什么C的数据段被分成两部分?

    所有全局初始化值都存储在 data段 即已初始化的数据段和未初始化的值存储在bss编译器将这些未初始化的值自动初始化为零bss Then why data段被分隔为 data and bss 是否有优势 或者有什么好处 C 编程语言 它是用
  • Xcode 在 Swift 2.2 和 Swift 3.0 之间切换

    自从我下载了新的 Xcode 并转换 更新了我的语法以来 Xcode 一直在上述 Swift 版本之间随机切换 我在终端中运行了 swift version 它确认 目前 我正在运行 Swift 2 2 我看到这个问题 Swift 编译器混
  • Semaphore.wait(timeout: .now()) 的目的是什么?

    看了一些苹果代码示例 我发现了这一点 func metadataOutput output AVCaptureMetadataOutput didOutput metadataObjects AVMetadataObject from co
  • “sdist”.tar.gz 发行版和 python Egg 有什么区别?

    我有一点困惑 似乎有两种不同类型的 Python 包 源代码发行版 setup py sdist 和 Egg 发行版 setup py bdist egg 两者似乎只是具有相同数据 Python 源文件 的档案 一个区别是pip最推荐的包管
  • 可扩展列表视图未扩展

    您好 需要像这样准备屏幕 这是我的可扩展列表视图的代码 适配器类 新适配器 java public class NewAdapter extends BaseExpandableListAdapter public ArrayList
  • libicuuc.so.55:无法打开共享对象文件

    当我使用 swift build 进行编译时 我的 Ubuntu 机器上出现以下错误 swift build home xxxxxxxxx Downloads swift DEVELOPMENT SNAPSHOT 2016 02 25 a
  • 是否可以使用 ES6/Babel 进行多个类导入?

    我正在开发一个反应项目 我的第一个项目 最近我重组了我的文件夹结构以使其更有意义 为了让我的生活更轻松 在我的组件文件夹中 我有一个index js文件如下所示 export from App export from Home export
  • 如何使用 compose 将 docker 卷安装到我的 docker 项目中?

    我有一个 Maven 项目 我正在 Docker 内运行 Maven 构建 但问题是 每次运行它时 它都会下载所有 Maven 依赖项 并且不会缓存任何 Maven 下载 我找到了一些解决方法 将本地 m2 文件夹挂载到 Docker 容器
  • 如何在输入数字时在数字输入字段中添加破折号?

    我正在尝试使用 javascript 将破折号插入到 html 数字字段中4th输入时输入数字 我在模糊中执行此操作 而不是在按键 按键上等中执行此操作 但是当我尝试将功能更改为on key press on key up事件它没有给出预期
  • 将耗时的进程从我的 ASP.NET 应用程序中移走

    我的 Asp net 应用程序生成动态 pdf 有时这需要一段时间 并且是一个相当繁重的过程 实际上我不希望我的用户等待pdf 只需在生成后将其发送到那里的邮件即可 所以我尝试了网络服务 我将一个 id 从数据库获取数据 和一些字符串传递给
  • AngularJS:使用控制器和 ng-repeat 重新加载 div 上的数据

    我是 Angular JS 的新手 正在学习它 我有一个 div 并在启动时使用控制器从 json 加载数据 代码如下 但我想在执行特定操作后 json 对象发生更改时再次重新加载它 索引 html DOCTYPE html PUBLIC
  • Angular:core.module 风格发生了什么?

    Tl dr 看来是core module风格不再是官方的一部分角度风格指南 https angular io guide styleguide 但它一定是最近才被删除的 导入单例服务的新最佳实践是什么 为什么删除了该样式 我刚刚读过this
  • 使 JavaScript 画布矩形可点击

    我正在创建一个简单的计算器 Here http startupsandfinance com online calculator html这是 我几乎完成了基本设计 但我对如何使按钮可点击感到困惑 一个技巧可能是为每个按钮创建一个 div
  • 如何计算给定坐标处相机可见矩形的大小? [复制]

    这个问题在这里已经有答案了 我制作了一个小型的 Three js 应用程序 它将一堆圆圈从画布的底部移动到顶部 let renderer scene light circles camera initialize animate funct