ScalaFX:如何在透视中旋转耦合 2 个数字

ScalaFX: How to couple 2 figures rotationally in perspective

一个基本的旋转问题 - 如何将 2 个数字(一个 box/cube 和一个球体放在立方体的任何地方,但在中心),以便这 2 个旋转耦合(这就是为什么我不希望球体位于立方体的中心)透视。

换句话说,当我用鼠标旋转立方体并且"bring"球体更靠近前方(比如旋转180度)时,视角会相应改变并且球体在视觉上变大(相对于后面的位置)?

问了几位 ScalaFX 专家 - 他们都说这是一个很好的问题,并建议 post 在这里。

干杯:

扎尔

>

我不完全确定您要做什么,但是您可以通过对包含所有这些对象的 Group 应用 Rotate 变换来旋转多个对象。如果您只想旋转部分对象,而不是所有对象,则必须构建场景,以便旋转的对象具有共同的父对象 Group - none 的 [=116] =] 属于它的对象。将 Rotate 变换应用于该父对象 Group 也会旋转其所有子对象。旋转将围绕该父级 Group.

的原点

更新:忘了说怎么解决透视问题了。场景中的 3D 对象不直接受透视影响,因为透视是场景渲染方式的 属性。此渲染由 Camera 个对象执行。使用 perspective 渲染场景(与使用 orthogonalparallel 相对,因为它被称为在 JavaFX/ScalaFX) 中,将 PerspectiveCamera 添加到场景并使用该相机查看场景。有关这方面的更多信息,请参阅以下内容:Getting Started with JavaFX 3D Graphics: Camera

更新 2:我已经创建了一个 gist on GitHub 以及用于执行此操作的完整程序。

更新 3:使框透明并在框内移动球体。现在 left/primary 鼠标按钮在拖动时旋转框 + 球体; right/secondary 鼠标按钮从盒子中移动相机推车 towards/away,相应地改变视角。

更新 4:因此,如果我对您的理解是正确的,您想要变换 3D 场景中的形状,使它们看起来好像已应用了透视。我说得对吗?

如果是这样,这不是 "built-in" 能力的原因如下。如果您已经知道所有这些,请原谅我,顺便说一句 - 我只是想提供一个全面的答案。 :-)

  • Scene graphs (as typically used by retained mode 3D系统,如JavaFX)捕获的几何图形、位置、旋转、颜色等分层树结构中的 3D 场景。这个想法是建模者只需要担心场景的内容——确保尺寸、对齐等是正确的——而不需要担心场景是如何渲染的。
  • Perspective 可以在场景是 rendered 时应用,因为它会从特定的视角出现;即当场景被转换为二维投影时,例如 GUI window。 (确定场景在透视中的样子的过程是渲染算法的一部分 - 但不需要对场景进行修改、变形等。)如果未启用透视,则通常渲染场景 正交,没有任何消失点,明显缩放等。这里的关键点是场景本身不受其观看方式的影响。
  • 通过这种安排,同一场景可以有多个视图。他们不仅每个人都可以有不同的观点,而且有些可以是正交的,有些可以使用透视——但每个人都可以正确地渲染场景而没有任何令人困惑的伪影。如果它按照您认为的方式工作,那么您一次只能看到场景的一个视图,因为在渲染过程中场景需要变形才能从那个唯一的角度看。编辑场景时,您需要移除这些变形以防止 mind-blowing 给建模者造成混淆。

简而言之,将场景本身变形以显示它在透视中的样子是一个非常不寻常的要求。这就是为什么在我所知道的任何 3D 系统中都没有 built-in 执行此操作的能力。

假设您希望继续 - 使用 JavaFX - 请记住以下几点:

  1. 我不相信常规的 3D 图元(即 BoxSphereCylinder)可以变形来表示它们的透视图。您将必须使用 TriangleMeshMeshView 对象构建形状(前者捕获形状的几何形状,后者允许将其视为 3D 形状)。
  2. 要应用透视,您必须重新定位 TriangleMesh 实例中的顶点,以适当地变形场景。如果您需要能够改变视点,或旋转盒子和球体,那么这些变化需要是动态的,以便计算出的顶点坐标对变化的视点 and/or 旋转做出反应。由于 fish-eye 在高级别透视膨胀下的效果,您可能需要比预期更多的顶点。
  3. 鉴于您的要求,您仍然需要一个摄像头来查看场景。显然,您 不能 使用 PerspectiveCamera 渲染场景,否则它会将场景视为未调整并应用第二级透视,破坏您精心计算的变形。然后,您将需要使用 ParallelCamera 来生成您的 sce 的正交视图e.
  4. 不幸的是,JavaFX 对使用 ParallelCamera 3D 场景的支持还很不成熟。 (ParallelCamera 主要用于渲染 2D 场景,例如对话框、按钮、菜单、滑块等)您可能会发现在实践中很难使用。 (您可以使用 PerspectiveCamera 通过利用非常狭窄的视野并将相机从场景中移开一段距离来近似正交投影。您还需要调整裁剪平面以避免图像消失。)
  5. 最后,在某些时候,您需要能够将相机定位在与用于透视变形的视点相同的位置。当相机与该视点同步时,您的场景 - 尽管是正交渲染的 - 将显示为预期场景的正确透视投影。每当相机和视点分开时,场景就会显得不自然和扭曲,这是你的意图。

总而言之,我想说的是您打算做的事情绝非微不足道,而且实现方式超出了 Whosebug 答案的范围。祝你好运!

我希望在旋转变换期间有一个控制透视的参数,但找不到。示例问题定义明确——你有一个 BOX/CUBE 和一个更小的球体;现在,当您旋转 BOX 时,球体会随之旋转,但是 "in perspective",这意味着如果您将球体放在前面,它看起来(绘制)会随着 "perspective".

相应地变大

扎尔

>

麦克:

抱歉耽搁了,我正在为一个完全不同的应用领域的客户完成一些事情,pulled-away 来自我的 "teaching perspective" 玩具 ...

刚收到新答案的通知并快速浏览了一下 - 我马上注意到的一件事是球体在透明盒子外面而不是在透明盒子里面(还没有看代码)。

我实际上期望的是 "built-in" 视角 "argument"(在旋转变换中,或场景定义中,或 stand-alone 函数中 - 以一种方式是另一种方式),例如,它允许根据底部 2 个(最初)平行的相对边缘之间的角度呈现不同的透视图。我当然明白,实际上它取决于视点位置,你不是"allowed"强行改变这个角度,但这里的目标只是一个"cause-and-effect"3D场景中的玩具。

控制相机不允许这样做,因为它会非常平滑地施加透视(就像在现实生活中一样)而不是让 child 直接控制边缘并立即看到她的动作改变视角,而不是玩弄观点。

正如在最初的问题中提到的那样,我希望有一个如下图所示的功能(而且我希望它在合理的 3D 产品中是 BUILT-IN,因为它非常基本,而不是强迫我或你手动编写一些本应来自 get-go 的代码 - 透视图只是一个基本的基础,希望在下一个版本中以某种形式的渲染涵盖):

def doPersepctive(myBox: MyBoxContainer, angle: Int, viewPoint: Point): Int = {
// 以 "angle" 定义的方式呈现透视外观 //(最初)myBoxContainer 的平行边,来自 viewPoint Point (3D)。 // 旋转 MyBoxContainer 边界内的所有内容。这 //当然,角度越大,后面的球体就越小。 // Returns mouseEvent 后的 rotatedAngle 稍后启用 auto-replay,所以 // 孩子可以检查她的行为并查看这些行为的效果。 }

再次感谢您的参赛,我一定会看一下代码,然后回复-但是您看到的是上面的一般图片。抱歉再次延迟:

Z

>

麦克:

这更像是初衷-虽然我在第一次尝试中也发现了优点,实际上。

我使球体(在第一个版本中)透明(通过 diffuseColor = Color.web("#ffff0080") ),所以现在她可以玩两个版本了,而且两者都非常相似child 的视角(意味着其中一个 object 是透明的,而且这些版本中的 object 是不同的)。

现在 - 我试图使 BOX 透明(球体在外面)但我失败了 - 这有什么原因吗?换句话说,试图让 object 传递 "behind" 可见?一个透明 object 从另一个透明 object 后面经过,这么说?

在第二个版本中我也看不到 "behind the object",这意味着我看不到从球体后面经过的盒子的边缘。不仅如此——即使它不在球体后面(但只在盒子的正面后面),我也看不到后缘!

从某种意义上说,我的问题是 "CAN both objects be made transparent" - 我猜这是最接近我想问的问题。可能有不同的“透明度 %”,但仍然透明…

再次发送:

扎尔

>

是的,迈克 - 你的回答是完全相关的,我确实接受了当前 ScalaFX 实现的 thoughtfully-explained 缺点。如果我需要 "click" 某个地方正式标记它,请告诉我 - 我是这个小组的新手,真的不知道手续。

再次发送:

扎尔

> 顺便说一句,如果可以将 Sphere 添加为 Box 的 child,那么你...... <

那是不可能的,但是我可以在 运行 TIME 而不是在编译时添加球体吗?换句话说,是否有一个 "addObject" 在孩子玩盒子 1 分钟后添加球体,在 运行 程序后 1 分钟,球体出现。在这里看不到这样的东西:

http://www.scalafx.org/api/8.0/index.html#package

可能是我遗漏了什么?

扎尔

>