Slow 3D rotation with antialiasing in Mathematica 7
3D surface rotation in Mathematica 7 with anti-aliasing turned off is very fast and smooth. However, turning on anti-aliasing, even at a moderate level, drastically reduces the rendered frame rate, making rotation very choppy. This happens to a much greater degree in Mathematica than it does in other 3D applications.
Why is anti-aliasing disproportionately slower in Mathematica?
A way to greatly enhance the feel of 3D graphics would be to turn off AA during rotation, but turn it on as soon as rotation is stopped. Can this be done in Mathematica 7?
An example was requested. I will use a variation of Mike's code. Please try the following with Edit > Preferences > Appearance > Graphics
first set to No antialiasing
and then Highest quality
. Also try the settings in between. For me, any setting besides No antialiasing
is not smooth. I can visually distinguish three different levels of AA, so it is not a matter of my GPU forcing all or none, yet all of them are slow.
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
]
UPDATE and OBSERVATION
While playing around with Alexey and Mike's code, something strange and good happened. I suddenly have smooth antialiased rotation! I don't know what precipitated the change, and I have not closed Mathematica for fear that it will go away, but this proves what I suspected, that it CAN be fast.
More strange, I have the slow and fast behavior happening in parallel in the same notebook. One graphic is rotating smoothly, and another produced with the same code is choppy. I theorize that some cell option was modified by running Alexey and Mike's code, and it is having a very desirable effect. I am going to do my best to figure out what it is.
The helpful options were RotationAction -> "Clip", SphericalRegion -> True
that appeared in Alexey's code incidentally. These, or their effect (ViewAngle
), "stick" with a graphic in the same way that rotation does, therefore I was able to type new code without these options over the old, and run it, and still get the smooth rotation (which explains what I saw above). See answers below for some elaboration.
While a viable workaround has been discovered, I am still interested in an explanation for the choppy rotation with AA on. I do not believe that the "fitting" of the graphic is an e开发者_高级运维xplanation, but merely a correlation, as the fitting still needs to take place with AA off, and yet the rotation is smooth.
After Mr. Wizard pointed out that changing the ViewAngle improved performance, I had a hunch as to what was causing it.
Normally, when you rotate graphics in Mathematica, you'll notice the box that contains the graphics resizes itself as the image is rotated around. Why? Most of the settings are set to the default of Automatic
, so they try to fiddle around to make the graphics fit nicely within the screen. Specifically, Plot3D
(and many other 3D Plot
functions) have a named parameter called RotationAction
. According to the Mathematica documentation:
3D graphics by default resize and move to fit when they are interactively rotated
This parameter defaults to RotationAction->"Fit"
, which tries to always make sure the entire 3D graphics fits on screen. Instead, you can force the graphics to clip using RotationAction->"Clip"
. This causes the bounding box to remain the same. Instead of resizing, it merely chops off whatever goes off screen. Performance is improved dramatically as Mathematica doesn't have to continuously reshape the image to make everything fit on screen.
Example code:
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"]
Some further notes
Upon further analysis, RotationAction->"Clip"
has some issues with rotation initially. On the very first rotation of the graphics, it rotates extremely fast. I don't know why this is so, only Wolfram Research could possibly answer that. After the initial rotation though, it rotates at the normal speed as any other graphics though.
The smoothest way of accomplishing nice rotation for me was given by:
Plot3D[..., RotationAction -> "Clip", ViewAngle -> 0.4]
This is as close to the default clipping volume as possible, without any strange issues with fast rotations or cut off graphics.
Perhaps someone else can think of something clever with Mouseover
. This works by displaying a different expression when the mouse is over the displayed object or not; try this to see:
Mouseover[
Style[
Graphics[Circle[]],
Antialiasing \[Rule] True
],
Style[
Graphics[Circle[]],
Antialiasing \[Rule] False
]
]
Unfortunately I have no idea how one would switch antialiasing on and off, nor do I know how to make something like Plot[f,range,Option->Mouseover[1,2]]
.
The problem seems to be that Mouseover
doesn't evaluate to different things when the cursor is/is not over it, but rather it displays different things--or so it looks.
Maybe someone who understands dynamic constructs better can work out how to use the infrastructure that lets Mouseover
do its thing to solve your problem.
Building off of Alexey's answer, I changed the code slightly so it doesn't modify the front end settings:
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]
It accomplishes the same, but it avoids modifying $FrontEnd.
Here is a function which automatically tacks on the necessary logic for providing dynamically changing antialiasing:
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]]
Usage is what you what expect:
DynamicAA[Plot3D[{x^2 + y^2, -x^2 -y^2}, {x, -2, +2}, {y, -2, +2}, ImageSize->700]]
Based on acl's idea:
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]
You can see what happens with the option with:
Dynamic["HardwareAntialiasingQuality" /.
Last@Last@Options[$FrontEnd, RenderingOptions],
UpdateInterval -> .1]
How it works: it switches off antialiasing for the currend FrontEnd session when you rotate the plot and switches it on when you release the mouse. The only problem is that when the mouse is released and antialiasing is switched on, the FrontEnd does not render the graphics again to make it antialiased. The solution is to click the plot without rotating it - and it becomes antialiased!
I appear to have discovered—for my configuration—a magic option that allows for smooth 3D rotation with full antialiasing on. This works for every 3D plot type I have tried therefore unless this also magically stops working I have my solution. I am very interested to know if this has the same effect on other systems.
The option is ViewAngle
. Any numeric value appears to work; Automatic
does not.
Evaluating the code below the first graphic rotates poorly and the second graphic rotates smoothly.
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]
I have a problem with Mike's RotationAction -> "Clip"
method, in that I get unexpected and sometimes extreme cropping when rotate the graphic. However, adding SphericalRegion -> True
restores the behavior that I get with ViewAngle
, and the angle is chosen automatically:
Plot3D[{x^2 + y^2, -(x^2 + y^2)}, {x, -2, +2}, {y, -2, +2},
ImageSize -> 700, SphericalRegion -> True, RotationAction -> "Clip"]
精彩评论