【问题标题】:Slow 3D rotation with antialiasing in Mathematica 7在 Mathematica 7 中使用抗锯齿进行慢速 3D 旋转
【发布时间】:2011-08-21 08:21:32
【问题描述】:
Mathematica 7 中的

3D 表面旋转在关闭抗锯齿的情况下非常快速且平滑。然而,开启抗锯齿,即使在中等水平,也会大大降低渲染帧速率,使旋转非常不稳定。这在 Mathematica 中比在其他 3D 应用程序中发生的程度要大得多。

  1. 为什么在 Mathematica 中抗锯齿异常缓慢?

  2. 一种大大增强 3D 图形感觉的方法是在旋转过程中关闭 AA,但在旋转停止后立即打开它。这可以在 Mathematica 7 中完成吗?


请求了一个示例。我将使用 Mike 代码的变体。请尝试以下操作,首先将Edit > Preferences > Appearance > Graphics 设置为No antialiasing,然后再设置Highest quality。还可以尝试两者之间的设置。对我来说,除了No antialiasing 之外的任何设置都不流畅。我可以在视觉上区分三个不同级别的 AA,所以这不是我的 GPU 强制全部或不强制的问题,但它们都很慢。

Animate[Plot3D[{x^2 + y^2, -x^2 - y^2}, {x, -2, 2}, {y, -2, 2},
  ImageSize -> 700,
  ViewPoint -> 
   Dynamic[{Sin[theta] Cos[phi], Sin[theta] Sin[phi], Cos[theta]}]],
 {theta, 0, Pi}, {phi, 0, 2 Pi},
 RefreshRate -> 120
]

更新和观察

在玩弄 Alexey 和 Mike 的代码时,发生了一些奇怪而美好的事情。我突然有了平滑的抗锯齿旋转!我不知道是什么促成了这种变化,并且我没有关闭 Mathematica 担心它会消失,但这证明了我的怀疑,它可以很快。

更奇怪的是,我在同一个笔记本中并行发生了缓慢和快速的行为。一个图形旋转平稳,另一个使用相同代码生成的图形不稳定。我推测某些单元格选项是通过运行 Alexey 和 Mike 的代码来修改的,并且它具有非常理想的效果。我会尽力弄清楚它是什么。


有用的选项是偶然出现在 Alexey 的代码中的 RotationAction -> "Clip", SphericalRegion -> True。这些或它们的效果 (ViewAngle) 以与旋转相同的方式“粘”在图形上,因此我能够在没有这些选项的情况下输入新代码而不是旧代码,然后运行它,仍然可以获得平滑的旋转(这解释了我在上面看到的)。有关详细说明,请参阅下面的答案。

虽然已经发现了可行的解决方法,但我仍然对在 AA 开启的情况下不连贯旋转的解释感兴趣。我不认为图形的“拟合”是一种解释,而仅仅是一种相关性,因为拟合仍然需要在 AA 关闭的情况下进行,但旋转是平滑的。

【问题讨论】:

  • 我也注意到了这一点。我知道你可以在其中完成一些模糊相似的事情的唯一地方是在Manipulate 内,通过使用PerformanceGoal->Speed。
  • 你使用的是什么操作系统?
  • @Mr.Wizard 你能举个例子吗?
  • @Mr.巫师:也许是一种heisenbug?虽然在这种情况下,这似乎是一个非常理想的 heisenbug。
  • 笔记本保存和 mma 重新启动后,速度差异仍然存在。应该可以确定差异。

标签: 3d wolfram-mathematica antialiasing


【解决方案1】:

在向导先生指出更改 ViewAngle 可以提高性能后,我预感到是什么原因造成的。

通常,当您在 Mathematica 中旋转图形时,您会注意到包含图形的框会随着图像的旋转而自行调整大小。为什么?大多数设置都设置为默认的Automatic,所以他们试图摆弄以使图形很好地适应屏幕。具体来说,Plot3D(和许多其他 3D 的Plot 函数)有一个名为RotationAction 的命名参数。根据Mathematica documentation:

默认情况下,3D 图形在交互旋转时会调整大小并移动以适应它们

此参数默认为RotationAction->"Fit",它试图始终确保整个 3D 图形适合屏幕。相反,您可以使用RotationAction->"Clip" 强制剪切图形。这会导致边界框保持不变。它不是调整大小,而是切断屏幕外的任何内容。由于 Mathematica 不必不断地重塑图像以使所有内容都适合屏幕,因此性能得到了显着的改进。

示例代码:

Plot3D[{x^2 + y^2, -(x^2 + y^2)}, {x, -2, +2}, {y, -2, +2}, 
 ImageSize -> 700, RotationAction -> "Fit"]

Plot3D[{x^2 + y^2, -(x^2 + y^2)}, {x, -2, +2}, {y, -2, +2}, 
 ImageSize -> 700, RotationAction -> "Clip"]

一些进一步的说明

经过进一步分析,RotationAction->"Clip" 最初在轮换方面存在一些问题。在图形的第一次旋转时,它旋转得非常快。我不知道为什么会这样,只有 Wolfram Research 可能会回答这个问题。不过,在初始旋转之后,它会像任何其他图形一样以正常速度旋转。

对我来说完成漂亮旋转的最流畅的方法是:

 Plot3D[..., RotationAction -> "Clip", ViewAngle -> 0.4]

这尽可能接近默认剪切量,不会出现快速旋转或截断图形的任何奇怪问题。

【讨论】:

  • 今天早上(这里是凌晨 4 点 17 分!)我在这上面花了太多时间。
  • Wolfram 应该认真考虑记录这个选项会对性能产生巨大影响的事实
  • 既然你不睡觉我也谈谈。 ;-) 首先,我想知道为什么这只会在开启 AA 时导致严重减速。其次,我在上面的示例中出现了奇怪的行为。一旦我开始旋转它,使用"Clip" 的那个会立即放大并且太远了。我想知道这是否是一个错误,或者我是否有冲突的配置。
  • 奇怪,在这里我看不出情节旋转的流畅度有任何区别(这是在 OS X 10.7.1 上,在带有可怜的集成显卡的 macbook 上;不是怪物机器或任何东西)
  • @acl:奇怪。在我的笔记本电脑(2.16 GHz Core 2 Duo 和糟糕的 8600M GS)上,剪辑版对我来说实际上运行得更快。我也将 AA 设置为可能的最高设置。你有它在中间设置?我认为它可能不一定受 GPU 限制,因为每当我在笔记本电脑上旋转图形时,都会看到 CPU 使用率飙升。
【解决方案2】:

也许其他人可以用Mouseover 想出一些聪明的东西。当鼠标悬停在显示的对象上时,这通过显示不同的表达式来起作用;试试这个看看:

Mouseover[
 Style[
  Graphics[Circle[]],
  Antialiasing \[Rule] True
  ],
 Style[
  Graphics[Circle[]],
  Antialiasing \[Rule] False
  ]
 ]

不幸的是,我不知道如何打开和关闭抗锯齿,也不知道如何制作像 Plot[f,range,Option->Mouseover[1,2]] 这样的东西。

问题似乎是 Mouseover 不会评估光标在/不在它上面时不同的东西,而是它显示不同的东西 - - 或者看起来是这样。

也许更了解动态构造的人可以弄清楚如何使用让Mouseover 解决您的问题的基础架构。

【讨论】:

  • 这是一个有趣的想法,但我无法让它与 3D 一起使用。 $FrontEnd 选项是 RenderingOptions -> {"HardwareAntialiasingQuality"}
  • @Mr.Wizard 更准确​​地说,RenderingOptions -> {"HardwareAntialiasingQuality" -> 0.} 用于关闭抗锯齿功能,RenderingOptions -> {"HardwareAntialiasingQuality" -> 1.} 用于最高质量。
  • @Alexey,是的。我想我应该把它包括在内。
  • @acl:我非常喜欢这个答案。我将看看我能做些什么来将Dynamic 投入其中以获得更有用的解决方案。
【解决方案3】:

根据 Alexey 的回答,我稍微更改了代码,因此它不会修改前端设置:

aa = True;
EventHandler[
 Style[
  Plot3D[{x^2 + y^2, -(x^2 + y^2)}, {x, -2, +2}, {y, -2, +2}, 
   ImageSize -> 700, RotationAction -> "Clip", 
   SphericalRegion -> True],
   Antialiasing -> Dynamic[aa, TrackedSymbols :> {aa}]],
 {"MouseUp" :> (aa = True), "MouseDown" :> (aa = False)}, 
 PassEventsDown -> True]

它实现了相同的功能,但它避免了修改 $FrontEnd。

这是一个自动添加必要逻辑以提供动态变化的抗锯齿的功能:

Clear[DynamicAA]; (* Perhaps I should also add the HoldFirst attribute too, not sure *)
DynamicAA[graphics_] := Module[{aa},
  aa = True;
  EventHandler[
   Style[graphics, 
    Antialiasing -> Dynamic[aa, TrackedSymbols :> {aa}]], {"MouseUp" :> (aa = True), 
    "MouseDown" :> (aa = False)}, PassEventsDown -> True]]

使用是你所期望的:

DynamicAA[Plot3D[{x^2 + y^2, -x^2 -y^2}, {x, -2, +2}, {y, -2, +2}, ImageSize->700]]

【讨论】:

  • 不幸的是,这似乎没有帮助。也就是在AA开启的情况下,旋转还是很慢;这似乎在很大程度上与表面的复杂性无关。使用较大的图形尺寸更容易感受到这些效果。
  • 我不确定为什么需要在上面的 ViewPoint 之后添加“动态”。 Manipulate 会在每次 theta 或 phi 自动更改时更新 plot3D?
  • Dynamic 已添加,因此它不会在您每次调整其中一个滑块时渲染绘图。实际上,我从文档中部分窃取了这个想法,该文档用于几乎完全相同的事情。
  • @Mike 我没有看到您的代码有抗锯齿功能。无论全局 $FrontEnd 设置如何,该图都不会消除锯齿。
  • @Alexey:我已经修复了代码。我在笔记本电脑上检查了它。我不小心使用了Rule 而不是DelayedRule。现在应该可以正常工作了。
【解决方案4】:

基于acl的想法:

EventHandler[
 Plot3D[{x^2 + y^2, -x^2 - y^2}, {x, -2, 2}, {y, -2, 2}, 
  ImageSize -> 700, RotationAction -> "Clip", 
  SphericalRegion -> 
   True], {"MouseUp" :> (SetOptions[$FrontEndSession, 
     RenderingOptions -> {"HardwareAntialiasingQuality" -> 1.}]), 
  "MouseClicked" :> (SetOptions[$FrontEndSession, 
     RenderingOptions -> {"HardwareAntialiasingQuality" -> 1.}]), 
  "MouseDown" :> (SetOptions[$FrontEndSession, 
     RenderingOptions -> {"HardwareAntialiasingQuality" -> 0.}])}, 
 PassEventsDown -> True]

您可以通过以下方式查看该选项会发生什么:

Dynamic["HardwareAntialiasingQuality" /. 
  Last@Last@Options[$FrontEnd, RenderingOptions], 
 UpdateInterval -> .1]

它是如何工作的:它会在您旋转绘图时关闭当前 FrontEnd 会话的抗锯齿,并在您释放鼠标时将其打开。唯一的问题是当释放鼠标并打开抗锯齿功能时,前端不会再次渲染图形以使其抗锯齿。解决方案是单击绘图而不旋转它 - 它会变得抗锯齿!

【讨论】:

  • 我已经编辑了我的答案,以便对您的代码进行稍微修改的版本。我用Dynamic 替换了您对$FrontEnd 的修改,外部变量给出了抗锯齿的状态。有趣的是,当我意识到你发布了这个答案时,我正在查看 EventHandler 的文档。
  • @Mr.Wizard 有趣的是,有没有办法强制前端以编程方式重新渲染图形而不点击它?
  • @Mike,Alexey,查看我更新的问题。发生了一些有趣的事情。
  • Alexey,不管你是否知道,RotationAction -> "Clip" 和 SphericalRegion -> True 的组合本身就是解决方案。
【解决方案5】:

对于我的配置,我似乎发现了一个神奇的选项,它允许在完全抗锯齿的情况下进行平滑的 3D 旋转。这适用于我尝试过的每种 3D 绘图类型,因此除非这也神奇地停止工作,否则我有我的解决方案。我很想知道这是否对其他系统有同样的影响。

选项是ViewAngle。任何数值似乎都有效; Automatic 没有。

评估下面的代码第一个图形旋转不佳,第二个图形旋转平滑。

Plot3D[Sin[x + y^2], {x, -3, 3}, {y, -2, 2}, ImageSize -> 900]

Plot3D[Sin[x + y^2], {x, -3, 3}, {y, -2, 2}, ImageSize -> 900, ViewAngle -> 0.43]

我对 Mike 的 RotationAction -> "Clip" 方法有疑问,因为我在旋转图形时会出现意外且有时会出现极端裁剪。但是,添加SphericalRegion -> True 会恢复我使用ViewAngle 获得的行为,并且会自动选择角度:

Plot3D[{x^2 + y^2, -(x^2 + y^2)}, {x, -2, +2}, {y, -2, +2}, 
 ImageSize -> 700, SphericalRegion -> True, RotationAction -> "Clip"]

【讨论】:

  • 如果我不得不猜测,我敢打赌这是因为默认行为会自动更改边界并调整大小。我将做一些测试,看看这是不是真的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-21
  • 2020-09-05
相关资源
最近更新 更多