使用相机将 3D 透视投影到 2D 屏幕上的基本渲染(无需 opengl)

2024-03-30

假设我有一个如下的数据结构:

Camera {
   double x, y, z

   /** ideally the camera angle is positioned to aim at the 0,0,0 point */
   double angleX, angleY, angleZ;
}

SomePointIn3DSpace {
   double x, y, z
}

ScreenData {
   /** Convert from some point 3d space to 2d space, end up with x, y */
   int x_screenPositionOfPt, y_screenPositionOfPt

   double zFar = 100;

   int width=640, height=480
}

...

如果没有屏幕剪辑或其他任何东西,给定空间中的某个 3d 点,我将如何计算某个点的屏幕 x,y 位置。我想将该 3d 点投影到 2d 屏幕上。

Camera.x = 0
Camera.y = 10;
Camera.z = -10;


/** ideally, I want the camera to point at the ground at 3d space 0,0,0 */
Camera.angleX = ???;
Camera.angleY = ????
Camera.angleZ = ????;

SomePointIn3DSpace.x = 5;
SomePointIn3DSpace.y = 5;
SomePointIn3DSpace.z = 5;

ScreenData.x 和 y 是空间中 3d 点的屏幕 x 位置。我如何计算这些值?

我可能会使用这里找到的方程,但我不明白屏幕宽度/高度如何发挥作用。另外,我不明白维基条目中观看者的位置与相机的位置是什么。

http://en.wikipedia.org/wiki/3D_projection http://en.wikipedia.org/wiki/3D_projection


“完成方式”是使用同质变换和坐标。你在空间中取一个点并且:

  • 使用模型矩阵相对于相机定位它。
  • 使用投影矩阵以正交方式或透视方式对其进行投影。
  • 应用视口变换将其放置在屏幕上。

这变得相当模糊,但我会尝试涵盖重要的部分,并将其中一些留给您。我假设您了解矩阵数学的基础知识:)。

齐次向量、点、变换

在 3D 中,同质点是 [x, y, z, 1] 形式的列矩阵。最后一个分量是“w”,一个缩放因子,对于向量来说是 0:这会导致你无法平移向量,这在数学上是正确的。我们不会去那里,我们正在讨论要点。

齐次变换是 4x4 矩阵,使用它们是因为它们允许将转换表示为矩阵乘法,而不是加法,这对于您的显卡来说既方便又快捷。也很方便,因为我们可以通过将它们相乘来表示连续的变换。我们通过执行变换*点来将变换应用于点。

主要有 3 种齐次变换:

  • 翻译, http://www.riemers.net/eng/ExtraReading/homogenous_matrices.php
  • 回转, http://knol.google.com/k/matrices-for-3d-applications-translation-rotation# and
  • Scaling. http://www.riemers.net/eng/ExtraReading/homogenous_matrices.php

还有其他一些值得探索的转变,特别是“观看”转变。然而,我只想给出一个简短的列表和一些链接。对点进行的移动、缩放和旋转的连续应用统称为模型变换矩阵,并将它们相对于相机放置在场景中。重要的是要认识到我们正在做的事情类似于在相机周围移动物体,而不是相反。

正交和透视

要将世界坐标转换为屏幕坐标,您首先需要使用投影矩阵,它通常有两种形式:

  • 正交,常用于 2D 和 CAD。
  • 透视,适合游戏和 3D 环境。

正交投影矩阵构造如下:

其中参数包括:

  • Top:可见空间上边缘的 Y 坐标。
  • Bottom:可见空间下边缘的 Y 坐标。
  • Left:可见空间左边缘的X坐标。
  • Right:可见空间右边缘的X坐标。

我认为这很简单。您所建立的是一个将出现在屏幕上的空间区域,您可以对其进行剪辑。这里很简单,因为可见空间的区域是一个矩形。透视剪裁更为复杂,因为出现在屏幕或观看体积上的区域是一个frustrum http://en.wikipedia.org/wiki/Frustum.

如果您在维基百科上的透视投影方面遇到困难,这里是构建合适矩阵的代码,由 geeks3D 提供 http://www.geeks3d.com/20090729/howto-perspective-projection-matrix-in-opengl/

void BuildPerspProjMat(float *m, float fov, float aspect,
float znear, float zfar)
{
  float xymax = znear * tan(fov * PI_OVER_360);
  float ymin = -xymax;
  float xmin = -xymax;

  float width = xymax - xmin;
  float height = xymax - ymin;

  float depth = zfar - znear;
  float q = -(zfar + znear) / depth;
  float qn = -2 * (zfar * znear) / depth;

  float w = 2 * znear / width;
  w = w / aspect;
  float h = 2 * znear / height;

  m[0]  = w;
  m[1]  = 0;
  m[2]  = 0;
  m[3]  = 0;

  m[4]  = 0;
  m[5]  = h;
  m[6]  = 0;
  m[7]  = 0;

  m[8]  = 0;
  m[9]  = 0;
  m[10] = q;
  m[11] = -1;

  m[12] = 0;
  m[13] = 0;
  m[14] = qn;
  m[15] = 0;
}

变量是:

  • fov:视野,pi/4 弧度是一个很好的值。
  • aspect:高度与宽度的比率。
  • 近、远:用于剪辑,我会忽略这些。

生成的矩阵是列主矩阵,在上面的代码中索引如下:

0   4   8  12
1   5   9  13
2   6  10  14
3   7  11  15

视口变换、屏幕坐标

这两种变换都需要另一个矩阵矩阵将事物放入屏幕坐标中,称为视口变换。这就是这里描述的,我不会介绍它(非常简单) http://www.songho.ca/opengl/gl_transform.html.

因此,对于点 p,我们会:

  • 执行模型变换矩阵*p,得到pm。
  • 执行投影矩阵 * pm,结果为 pp。
  • 根据观看量剪裁 pp。
  • 执行视口变换矩阵 * pp,结果为 ps:屏幕上的点。

Summary

我希望这涵盖了大部分内容。上面有漏洞,有些地方含糊不清,有问题可以在下面留言。这个主题通常值得在教科书中用整整一章来写,我已尽我最大的努力来提炼这个过程,希望对您有利!

我链接到了上面的内容,但我强烈建议您阅读此内容并下载二进制文件。它是一个很好的工具,可以帮助您进一步了解这些转换以及它如何在屏幕上获得分数:

http://www.songho.ca/opengl/gl_transform.html http://www.songho.ca/opengl/gl_transform.html

就实际工作而言,您需要实现用于齐次变换的 4x4 矩阵类以及可以与其相乘以应用变换的齐次点类(请记住,[x, y, z, 1])。您需要按照上面和链接中的描述生成转换。一旦你理解了这个过程,一切就不再那么困难了。祝你好运:)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用相机将 3D 透视投影到 2D 屏幕上的基本渲染(无需 opengl) 的相关文章

  • 将二维整数作为 Readonly/const 存储在单独的类中,同时保持非公开

    这是我在使用这个地方作为我的 去处 以获取关于什么有效 无效 为什么等的一般意见之后的第一个问题 那么让我们试试这个 由于我的经验有限 我一直在尝试寻找更好的方法来创建固定数据字段 我可以在整个程序中引用这些字段 例如我反复显示的最终用户可
  • 根据值更改 DataGrid 单元格颜色

    我有一个 WPF 数据网格 我想要根据值使用不同的单元格颜色 我的 xaml 上有以下代码 Style TargetType DataGridCell 但不是只选择一个单元格而是选择所有行 我缺少什么 如果您尝试设置DataGrid Cel
  • 如何设置环境名称(IHostingEnvironment.EnvironmentName)?

    默认 ASP NET Core Web 项目包含以下行Startup cs if string Equals env EnvironmentName Development StringComparison OrdinalIgnoreCas
  • 命名空间中不存在类型或命名空间名称 - 但命名空间确实存在

    我已经工作了很长时间没有任何问题的项目突然开始抛出错误 例如 The type or namespace name xxx does not exist in the namespace yyy are you missing an ass
  • 数据绑定问题,请解释

    public partial class Form1 Form MyClass myClass new MyClass one two public Form1 InitializeComponent textBox1 DataBindin
  • C# 如何在没有 GacUtil 的情况下在 GAC 中注册程序集?

    我需要使用批处理文件在 GAC 中注册程序集 有没有办法找到安装位置GacUtil exe或者有没有办法在没有 GacUtil 的情况下注册程序集 Your bestbet is to use a powershell script tha
  • 无法从 ViewPager 中的 Fragment 编辑 ActionBar 标题

    我有一个Activity它通过一个托管多个片段ViewPager 在活动的onCreate方法我使用以下代码来更改ActionBar title Toolbar toolbar findViewById R id toolbar setSu
  • const int 列表而不是 enum

    我开始研究大型 C 代码库 并发现使用带有多个 const ints 字段的静态类 这个类的行为与枚举完全一样 我想将类转换为实际的枚举 但权力被拒绝 我想转换它的主要原因是这样我可以将枚举作为数据类型而不是 int 这对可读性有很大帮助
  • 如何将 Activator.CreateInstance 与字符串一起使用?

    在我的反射代码中 我的通用代码部分遇到了问题 特别是当我使用字符串时 var oVal object Test var oType oVal GetType var sz Activator CreateInstance oType oVa
  • 为什么 Cassandra 客户端在生产中没有 epoll 时会失败? [复制]

    这个问题在这里已经有答案了 当我在本地运行服务时 我收到一条警告 指出 epoll 不可用 因此它使用 NIO 很公平 当我将其部署到 Kubernetes 中时 我得到了以下信息 这导致服务无法运行 2017 03 29T19 09 22
  • cygwin $'\r':命令未找到错误

    我稍微修改了一个项目 在调试下它运行得很好 当我尝试在不调试的情况下构建它时 它显示错误 无法修复它 make Making all in third party make 1 Entering directory cygdrive c U
  • CGAL:如何有效计算多面体的面面积?

    我有一个多面体 其面是三角形 我知道在 CGAL 中 Triangle 3 类提供了 squared area 方法 通过它我们可以计算三角形的面积 有什么方法可以将其应用到多面体方面吗 或者关于如何计算每个面的面积有什么想法吗 这是一个例
  • 计算距离早上 8 点还有多少小时

    我知道如何计算两个日期之间的差异 但如何计算给定日期与下一个上午 8 点之间的时间 var now DateTime Now var tomorrow8am now AddDays 1 Date AddHours 8 double tota
  • 从多页 tiff 中提取帧 - C#

    有一个多页 tiff 我想从此 Tiff 文件中提取第 n 页 帧 n 并保存它 如果我的多页 tiff 有 3 帧 在我提取一页 帧后 我想留下 1 张图像有 2 页 帧 并且 1 张图像只有 1 页 帧 下面是一些代码 用于将多帧 ti
  • Android 以编程方式停止 toast 通知?

    有没有办法以编程方式停止 Toast 消息 假设我有一个按钮 单击它可以滚动 toast 消息 并且在 onclick 事件中我想停止队列中的所有消息并只显示新消息 我该怎么做 我的代码的简化版本如下 代码 public class Hel
  • 飞碟 - html 实体未呈现

    我正在使用 Flying saucer lib 生成 pdf 但我对一些 html 实体有问题 我已经在寻找解决方案 我在这个论坛和其他地方找到了很多提示 但仍然存在问题 我尝试过这种方法 http sdtidbits blogspot c
  • 用什么? MVC、MVP 或 MVVM 还是……?

    我将启动一个 Java 项目来开发桌面应用程序 使用什么作为表示层模式 MVC MVP MVVM 或 如果可能的话 举一些可行的小例子 Actually the ultimate post you re looking for is thi
  • 需要同步仅增量计数器吗?

    我使用整数作为计数器 该整数只会增加 并且肯定有多个线程会同时增加它 当没有其他线程尝试访问其值时 在程序执行结束时读取该计数器的值 我假设我不必为这种仅增量计数器使用锁或任何类型的同步 这是正确的吗 如果这有什么区别的话 我用 Java
  • Hibernate 命名查询使用 Like 和 % % 运算符?

    在我的 Hibernate JPA 示例代码中 public List
  • 如何获取 res.drawable 文件夹的路径来复制文件?

    我正在编写我的应用程序AndroidStudio 我的里面有gif文件drawable gifs文件夹 我希望将该文件复制到MediaStore Images Media单击按钮后的文件夹 目前 即使使用发布的一些答案 我也无法获取我的 g

随机推荐

  • 对主干集合进行排序

    所需的功能 我正在使用 Backbone Collection 来查看可排序列表中的数据 我已经得到了单击某些 dom 元素会在我的 Collection 上设置属性的部分 以确定我想要排序的字段以及应该进行哪个方向的排序 然后应该在集合上
  • 从构建秘密设置 docker env var

    使用新的Docker时有没有办法设置环境变量构建增强功能 https docs docker com develop develop images build enhancements 试过 RUN mount type secret id
  • 无法使用 flutter 在 iOS 14 上运行 ios 应用程序 [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我刚刚安装了 iOS 14 beta 并将 Xcode 更新到最新版本 12 beta 3 我收到类似的错误 Unabl
  • 从字符串中的链接获取网站标题

    字符串 这是徽章 https stackoverflow com badges https stackoverflow com badges布拉布拉布拉 如果字符串包含一个链接 见上文 我想解析该链接的网站标题 它应该返回 徽章 堆栈内存溢
  • 在xamarin中使用共享首选项[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我尝试在应用程序关闭并重新打开后保存字符串值 我查看了所有 SharedPreferences 但我不明白是否需要打开新
  • 强制转换是可重写的操作吗?如果是这样,怎么办?

    是否可以在 C 中覆盖 C 风格 强制转换 假设我有代码 double x 42 int k int x 我可以让第二行中的强制转换执行我编写的一些代码吗 就像是 I don t know C I have no idea if this
  • 如何覆盖 Primefaces 默认 CSS?

    我正在尝试覆盖素面主题我的css看起来像这样文件1 xhtml ui menubar font family Verdana Arial Helvetica sans serif font size 11px important backg
  • 如果一个成员是 IDisposable,我们是否应该实现 IDisposable?

    我想是这样 但看一下 ASP NET 中的一个内置类 public sealed class HttpPostedFile public Stream InputStream get Stream implements IDisposabl
  • 如何防止 ASP.NET 和 Kentico 处理静态文件

    我有一个 Kentico CMS 网站 正在处理静态资源 例如 png 文件 我希望 ASP NET 不处理这些文件 我该怎么做呢 我正在使用 Kentico CMS Web 表单 运行 IIS 7 5 和 ASP NET 3 5 应用程序
  • Android XML 解析器跳过标签

    我正在制作一个可以阅读 RSS 源的阅读器 起初我想使用一个库 但意识到他们无法加载一些数据 所以我决定制作自己的阅读器 但这是问题所在 我的解析器并不总是返回图像 具体取决于此 RSS 等站点图片位于内容 数据中 http www znb
  • Typescript 键盘事件:“Event”类型的参数不可分配给“KeyboardEvent”类型的参数

    即使代码完美运行 我也会出现以下错误 TS2345 Argument of type Event is not assignable to parameter of type KeyboardEvent Property altKey is
  • 无法在cmake中使用find_package找到Lua标头

    我正在尝试使用 CMake 为我使用 Lua 的项目构建生成 make 文件 当我运行 make 时出现此错误 path to my project luaudio luaudio c 1 17 fatal error lua h No s
  • nifi 中的 JSON 数组到多个 JSON 对象

    我想在 Nifi 中实现以下请求响应场景 我的目标是在更多不同的处理器中使用每个值作为数组 对象键 1 对象键 2 因此 如果我可以将其转换为多个 JSON 那么使用拆分 JSON 我可以稍后使用多个值 请为此提出各种解决方案 输入 JSO
  • SQL 存储过程 LIKE

    这是一个简单的问题 我似乎想不出解决方案 我在我的存储过程中定义了这个 communityDesc varchar 255 NULL communityDesc 是 aaa bbb ccc 在我的实际查询中我尝试使用IN WHERE ARE
  • 返回一个空数组

    我试图想出返回空数组的最佳方法 而不是null 有什么区别吗foo and bar private static File foo return Collections emptyList toArray new File 0 privat
  • C++ 中‘operator’的不明确重载

    我在这里阅读了几篇关于此类错误的文章 但我无法解决这个问题 很快我定义了运算符 int 和函数 f 无法编译 我测试了几件事 但无法解决问题 谢谢 ex1 cpp In function int main int char ex1 cpp
  • 在react js中调用axios get请求时出现网络错误

    我在 macOS 中使用 React js 当我尝试调用时axios get 我收到网络错误 我读过许多像我一样使用 React Native 的其他案例 答案是添加设置以允许他们使用http在 Mac 中而不是https 但是该设置不能在
  • 编写新的脚本“语言”时从哪里开始?

    我需要编写一个在 PHP 下运行的基本脚本 模板引擎 理想情况下 我能够将我自己的标记语言与 X HTML 模板混合 并通过服务器端解析器运行文档 以动态地用数据库提供的 X HTML 替换我自己的标记 不幸的是 就我对 PHP 和脚本的了
  • Python- strptime ValueError 未转换的数据仍然存在::00

    我有一个 csv 文件 其中有一列的日期看起来像 2 15 2016 1 44 00 PM 我遇到了以下代码的错误 任何人都可以提供有关错误的输入吗 CODE import csv import datetime as dt import
  • 使用相机将 3D 透视投影到 2D 屏幕上的基本渲染(无需 opengl)

    假设我有一个如下的数据结构 Camera double x y z ideally the camera angle is positioned to aim at the 0 0 0 point double angleX angleY