java - 某个 z 深度处的 xy 位置

标签 java math opengl 3d processing

在处理(java 方言)中有 screenX、screenY(和 screenZ 但我们现在跳过它)的方法。

假设我在 xyz = 50, 100, 500 处有一个对象。然后使用 screenX 和 screenY,您现在可以将它们显示在 Canvas 上的位置。
float x = screenX(50, 100, 500);float y = screenY(50, 100, 500);
这是引用:
http://processing.org/reference/screenX_.html

我感兴趣的是一种逆方法。
例如,我想要一个球体在 x=175 和 y=100 的 Canvas 上出现。球体的 z 值应该为 700。那么实际的 x 和 y 位置在 z=700 处会是什么,以使其在 Canvas 上的 175,100 处出现?

所以方法是 float unscreenX(float x, float y, float z)它会返回 x 值。

我的数学/编程技能不是那么高级(让我们称之为糟糕)(我更像是一名设计师)所以我正在寻找一些帮助。我都准备好在处理板上询问,但通常这里有更多人对矩阵等有更深入的了解。

处理中的正常 screenX 方法可以在这里找到:
https://github.com/processing/processing/blob/master/core/src/processing/opengl/PGraphicsOpenGL.java

public float screenX(float x, float y, float z) {
    return screenXImpl(x, y, z);
  }

protected float screenXImpl(float x, float y, float z) {
    float ax =
      modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03;
    float ay =
      modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13;
    float az =
      modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23;
    float aw =
      modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33;
    return screenXImpl(ax, ay, az, aw);
  }


  protected float screenXImpl(float x, float y, float z, float w) {
    float ox =
      projection.m00*x + projection.m01*y + projection.m02*z + projection.m03*w;
    float ow =
      projection.m30*x + projection.m31*y + projection.m32*z + projection.m33*w;

    if (nonZero(ow)) {
      ox /= ow;
    }
    float sx = width * (1 + ox) / 2.0f;
    return sx;
  }

Corse 也有 y 和 z(我不理解 z,但让我们忽略它)。
我认为这可能会为如何反转它提供一些见解。

模型 View 和投影是一个 3d 矩阵,代码在这里:
https://github.com/processing/processing/blob/master/core/src/processing/core/PMatrix3D.java
但我想这是非常基本和常见的。

我还在处理板上发了一个帖子,因为你永远不知道。它解释了我想要的有点不同。
http://forum.processing.org/topic/unscreenx-and-unscreeny

对于描述这篇文章的标签,我没有去具体原因我可以想象一个从未使用过 java 但确实使用过 c++ 并且有矩阵经验的程序员仍然能够提供一个很好的答案。

希望有人可以提供帮助。

最佳答案

我强烈建议您学习一些用于 3d 图形的线性代数或矩阵数学。它既有趣又简单,但比 SO 答案要长一些。不过我会试试 :) 免责声明:我不知道您正在使用的 API!

看起来您正在为一个位置(通常称为顶点)返回 3 个坐标。但是您还提到了一个投影矩阵,该函数有 4 个坐标。通常,着色器或 API 将采用 4 个坐标作为顶点。 x,y,z,w。为了让它们出现在屏幕上,它会执行以下操作:

xscreen = x/w
yscreen = y/w
zbuffer = z/w

这很有用,因为您可以选择 w。如果你只是在做 2d 绘图,你可以把 w=1。但是如果你在做 3d 并且想要一些透视效果,你想要除以与相机的距离。这就是投影矩阵的用途。它主要获取您点的 z,其中 z 表示到相机的距离并将其放入 w。它也可能会稍微缩放一些东西,比如视野。

回顾您发布的代码,这正是最后一个 ScreenXImpl 函数所做的。
它应用了一个投影矩阵,它主要只是将 z 移动到 w,然后除以 w。最后它做了一个额外的缩放和从 (-1,1) 到 (0,widhtinpixels) 的偏移,但我们可以忽略它。

现在,我为什么要漫谈这些东西?您要做的就是获取给定 xscreen、yscreen、zbuffer 的 x、y、z 坐标,对吗?好吧,诀窍就是倒退。为了做到这一点,您需要牢牢把握前进的方向:)

倒退有两个问题:1)您真的了解或关心 zbuffer 值吗? 2)你知道投影矩阵做了什么吗?
对于 1) 假设我们不在乎。有很多可能的值,所以我们可能只选择一个。对于 2) 您必须查看它的作用。一些投影矩阵可能只需要 (x,y,z,w) 和输出 (x,y,z,1)。那将是2d。或者 (x,y+z,z,1) 这将是等距的。但从角度来看,它通常是 (x,y,1,z)。加上一些缩放等。

我刚刚注意到你的第二个 screenXImpl 已经将 x,y,z,w 传递到下一阶段。这有时很有用,但对于所有实际情况,w 将为 1。

在这一点上,我意识到我在解释事情方面很糟糕。 :) 你真的应该拿起那本线性代数书,我从这本书中学到的:http://www.amazon.com/Elementary-Linear-Algebra-Howard-Anton但它带来了一个很好的讲座,所以我不知道它本身有多大用处。

无论如何!让我们更实用。回到你的代码:screenXImpl 的最后一个函数。我们现在知道输入 w=1 和 ow=~z 和 ox=~x;这里的波浪线意味着乘以一些比例加上一些偏移。我们必须开始的屏幕 x 是 ~ox/ow。 (+1/2,*width .. 这就是波浪线的用途)。现在我们又回到了 1)...如果你想要一个特别的盎司 - 现在就选一个。否则,我们可以选择任何一个。对于渲染,在相机前选择任何易于使用的东西可能是有意义的。像 1。
protected float screenXImpl(float x, float y, float z, float w==1) {
float ox = 1*x + 0*y + 0*z + 0*w; // == x
float ow = 0*x + 0*y + 1*z + 0*w; // == z == 1

ox /= ow; // == ox

float sx = width * (1 + ox) / 2.0f;
return sx;
}

跆拳道? sx = 宽度 * (1+ox)/2 ?为什么我不直接说?好吧,我输入的所有零可能都不是零。但它最终会同样简单。那些可能不是那些。我试图展示你必须做出的重要假设才能回去。现在应该就像从 sx 回到 ox 一样简单。

那是最难的部分!但是您仍然必须从最后一个函数转到第二个函数。我想第二个到第一个很容易。 :) 该函数正在进行线性矩阵变换。这对我们有好处。它接受四个隐式值 (x,y,z) 和 (w=1) 的输入,并输出四个其他值 (ax,ay,az,aw)。我们可以弄清楚如何手动返回那里!我在学校里必须这样做……四个未知数,四个方程。你知道 ax,ay,az,aw... 求解 x,y,z 并且你免费得到 w=1!很有可能,很好的锻炼,但也很乏味。好消息是,这些方程的书写方式称为矩阵。 (x,y,z,1) * MODELMATRIX = (ax,ay,az,aw)。真的很方便,因为我们可以找到MODELMATRIX^-1。这叫逆天!就像 1/2 是 2 的倒数乘法实数或 -1 是 1 的倒数加法。你真的应该读一读这很有趣而且不难,顺便说一句:)。
无论如何,使用任何标准库来获取模型矩阵的逆。可能类似于modelView.Inverse()。然后用它做同样的功能,你就倒退了。简单!

现在,为什么我们不早先对 PROJECTION 矩阵做同样的事情呢?很高兴你问了!那个需要 4 个输入 (x,y,z,w) 并且只输出三个输出 (screenx,screeny,zbufferz)。所以如果不做一些假设,我们就无法解决它!一种直观的方式来看待这个问题,如果你有一个 3d 点,你在 2d 屏幕上投影,就会有很多可能的解决方案。所以我们必须选择一些东西。而且我们不能使用方便的矩阵逆函数。

让我知道这是否有帮助。我有一种感觉,它不是,但我写得很开心! google for unproject in processing 也给出了这个:http://forum.processing.org/topic/read-3d-positions-gluunproject

关于java - 某个 z 深度处的 xy 位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16972908/

相关文章:

java - 哪个方法调用 run()?

algorithm - 将引脚最佳地放置在轴上作为算术级数

java - Eclipse 中的 JOGL OpenGL 抛出 NoSuchMethodError

c++ - 多重指数实现

python - 在 Python 中求解数学函数

opengl - 检索着色器存储缓冲区的属性

opengl - 在 OpenGL 中,一个着色器程序是否可以在一次绘制调用中同时渲染到 FBO 和默认帧缓冲区?

java - 如何以右对齐方式打印数字?

java - org.apache.hadoop.io.Text无法转换为org.apache.hadoop.io.NullWritable

java - 将类的方法调用到接口(interface)中