rgl:如何避免透明 3D 椭球体中的莫尔效应?
rgl: How to avoid moire effect in transparent 3D ellipsoids?
在我的 heplots
包中,我绘制了假设和误差 3D 椭球来表示多元线性检验。
我发现当 H 椭球实际上只是 2D 时,我会得到令人不快的莫尔效应,如下所示。
请注意,Error ellipsoid 没有此缺陷。
在此 MWE 中对 heplot3d
的调用指定没有线框,但使用表面的透明阴影。
library(rgl)
library(heplots)
data(penguins, package="palmerpenguins")
peng <- penguins
peng.mod0 <-lm(cbind(bill_length, bill_depth, flipper_length, body_mass) ~ species, data=peng)
heplot3d(peng.mod0, shade=TRUE, shade.alpha=0.2, wire=FALSE, size="effect")
有什么办法可以修改这个函数中的代码来避免这个问题吗?是什么原因造成的?这与表面的法线有什么关系吗?
这里的问题是椭圆体的前表面和后表面是在同一平面上绘制的。 rgl
绘制透明物体的方式依赖于将物体从后向前排序,但它只能近似地做到这一点:例如两个相交三角形的不同部分需要不同的排序。
在您的示例中,rgl
尝试对扁平椭圆体的正面和背面进行排序,但数值错误意味着它有点随机化绘图顺序,而且看起来真的很难看。
避免这种情况的最简单方法是在绘制椭圆体的调用中使用 back = "cull"
。这样后面就完全不画了,好看多了。
两个椭球相交的地方还是会出现问题;修复它更难。您需要将红色椭圆体分成蓝色椭圆体每一侧的部分,然后分别绘制。可能还需要将红色内部的蓝色部分与外部的部分分开绘制。这些事情现在可以使用 clipMesh3d
功能,但很难做到正确。
编辑添加:
这里更好的解决办法是在绘制透明椭圆体时设置depth_mask = FALSE
。 (这是另一个material 属性,它默认为TRUE
。)解释如下:
“深度遮罩”决定绘制对象是否会阻止后面绘制的对象可见。不透明的对象应该总是用 depth_mask = TRUE
绘制,因为它们应该总是隐藏它们后面的东西。
更难决定对透明对象使用哪种设置。因为它们是在绘制之前排序的,所以深度掩码应该无关紧要,但因为排序只是近似的,所以有时它会有所帮助。在您的情况下,您正在绘制两个完全相同深度的形状,直至舍入误差。对于 depth_mask = TRUE
,有时不会绘制第二个,因为舍入误差使它看起来更远。如果你设置 depth_mask = FALSE
,两者都会被绘制,并且椭圆看起来更好。并非所有形状都如此,但在这种情况下它有效。
我所做的一些计算建议在 alpha > 0.5
时使用 depth_mask = TRUE
,对于较小的 alpha
值使用 depth_mask = FALSE
。
在我的 heplots
包中,我绘制了假设和误差 3D 椭球来表示多元线性检验。
我发现当 H 椭球实际上只是 2D 时,我会得到令人不快的莫尔效应,如下所示。
请注意,Error ellipsoid 没有此缺陷。
在此 MWE 中对 heplot3d
的调用指定没有线框,但使用表面的透明阴影。
library(rgl)
library(heplots)
data(penguins, package="palmerpenguins")
peng <- penguins
peng.mod0 <-lm(cbind(bill_length, bill_depth, flipper_length, body_mass) ~ species, data=peng)
heplot3d(peng.mod0, shade=TRUE, shade.alpha=0.2, wire=FALSE, size="effect")
有什么办法可以修改这个函数中的代码来避免这个问题吗?是什么原因造成的?这与表面的法线有什么关系吗?
这里的问题是椭圆体的前表面和后表面是在同一平面上绘制的。 rgl
绘制透明物体的方式依赖于将物体从后向前排序,但它只能近似地做到这一点:例如两个相交三角形的不同部分需要不同的排序。
在您的示例中,rgl
尝试对扁平椭圆体的正面和背面进行排序,但数值错误意味着它有点随机化绘图顺序,而且看起来真的很难看。
避免这种情况的最简单方法是在绘制椭圆体的调用中使用 back = "cull"
。这样后面就完全不画了,好看多了。
两个椭球相交的地方还是会出现问题;修复它更难。您需要将红色椭圆体分成蓝色椭圆体每一侧的部分,然后分别绘制。可能还需要将红色内部的蓝色部分与外部的部分分开绘制。这些事情现在可以使用 clipMesh3d
功能,但很难做到正确。
编辑添加:
这里更好的解决办法是在绘制透明椭圆体时设置depth_mask = FALSE
。 (这是另一个material 属性,它默认为TRUE
。)解释如下:
“深度遮罩”决定绘制对象是否会阻止后面绘制的对象可见。不透明的对象应该总是用
depth_mask = TRUE
绘制,因为它们应该总是隐藏它们后面的东西。更难决定对透明对象使用哪种设置。因为它们是在绘制之前排序的,所以深度掩码应该无关紧要,但因为排序只是近似的,所以有时它会有所帮助。在您的情况下,您正在绘制两个完全相同深度的形状,直至舍入误差。对于
depth_mask = TRUE
,有时不会绘制第二个,因为舍入误差使它看起来更远。如果你设置depth_mask = FALSE
,两者都会被绘制,并且椭圆看起来更好。并非所有形状都如此,但在这种情况下它有效。我所做的一些计算建议在
alpha > 0.5
时使用depth_mask = TRUE
,对于较小的alpha
值使用depth_mask = FALSE
。