透明的 R 三维平面不应该隐藏 plot3d 的点/球形。

4
我想在一个三维绘图中放置点/球和一个平面。我希望该平面具有约为0.5的alpha透明度(它既不应完全透明也不应完全不透明)。这样我就可以通过平面看到点/球和坐标轴。
我尝试了:
library(rgl)

#Generating points:
m=20
a1=runif(m,-1,1)
a2=runif(m,-1,1)
b=a1+2*a2+rnorm(m,mean=0,sd=0.3)

# Plotting the points:
plot3d(a1,a2,b, type='s', xlim = c(-1, 1), ylim = c(-1, 1), zlim = c(-3.1, 3.1),xlab = 'a_i,1', ylab = 'a_i,2', zlab = 'b_i',alpha=0.9)
# Plotting the transparent plane:
planes3d(1, 2, -1, 0, col = 'red', alpha = 0.1, add=T)
# plot the points again (because I thought, maybe the the execution order could be relevant)
plot3d(a1,a2,b, add=T, type='s', xlim = c(-1, 1), ylim = c(-1, 1), zlim = c(-3.1, 3.1),xlab = 'a_i,1', ylab = 'a_i,2', zlab = 'b_i',alpha=0.9)

我得到的结果是,我可以通过平面看到坐标轴,但是我不能看到隐藏在平面后面的点/球 :(
一些球的部分无法通过平面看到: enter image description here 我希望也能通过平面看到所有的点/球(就像坐标轴那样),我想看到所有20个点/球,包括被平面覆盖/隐藏/遮挡的球。

你的代码不完整。plot3d在rgl中而不是scatterplot3d中。你对planes3d的调用使用了变量x,但是没有定义x。 - G5W
@ulfelder 谢谢,但我认为alpha是planes3D使用的一个图形参数,因为它对于坐标轴很有效,并且在这篇帖子中,它对于多个平面也很有效(可以看到每个平面通过所有其他平面)。 - Jakob
@Jakob 感谢你更新你的代码。目前为止,它对我来说运行得很好。我得到了一个透明的平面,并通过平面看到了点。如果你还没有这样做,我建议重新启动 R 并按照上面的代码精确地运行它。它对我有效。 - G5W
@G5W 谢谢,当我尝试这个时,我意识到我忘记了一行 m=20,所以我添加了这一行。但是在重新启动 R 后,我仍然无法通过平面看到球体。我只能看到球体的部分没有被平面覆盖 :( - Jakob
1
我和Jakob看到了同样的问题。看起来像是个bug:这个平面正在向z缓冲区写入,但由于它部分透明,它不应该这么做。 - user2554330
1
如果您的WebGL正在使用硬件加速,并且硬件加速的GL库可以处理多层透明度(我想其中一些可以),那么它将正确地呈现它。但我的肯定不行。 - Mike Wise
2个回答

3
您正在使用“数据导向例程”,这些例程可以快速渲染,但会扭曲轴线,因为数据点通常在几何上不相关。可能是为了速度而进行剪切和渲染,并忽略了alpha缓冲区,以便能够快速绘制大量点。
如果您使用不同的渲染技术,则可以获得此效果,但当然速度会慢得多。并且它尊重坐标之间的纵横比。
library(rgl)

sphere3d <- function(cen, r=1,n = 65, ...){
  f <- function(s,t){ 
    cbind(   r * cos(t)*cos(s) + cen[1],
             r *        sin(s) + cen[2],
             r * sin(t)*cos(s) + cen[3])
  }
  persp3d(f, slim = c(-pi/2,pi/2), tlim = c(0, 2*pi), n = n, add = T,axes=T,...)
}

m=20
xx=runif(m,-1,1)
yy=runif(m,-1,1)
zz=xx+2*yy+rnorm(m,mean=0,sd=0.3)

# Plotting the points:
for (i in 1:m){
  cen <- c(xx[i],yy[i],zz[i])
  sphere3d(cen,col="black",r=0.15,n=17)
}

# add corner points to make the bounding box span the space
sphere3d(c(-1,-1,-3),col="black",r=0.15,n=17)
sphere3d(c( 1, 1, 3),col="black",r=0.15,n=17)

# Plotting the transparent plane:
planes3d(1, 2, -1, 0, col = 'red', alpha = 0.5)

# no axes by default
axes3d( edges="bbox",box=T )

产生这种效果-但请注意,它也不完美,并且在您设置球体的透明度时也会出现类似的问题。通常情况下,只有使用与光线追踪相关的东西才能完全正确地完成多层透明度,但这样做非常缓慢。

enter image description here

这是另一种正面视图,alpha设置为0.8。

enter image description here


非常感谢!!!球体的alpha值对我来说并不是很重要。您的代码对我的应用程序来说足够快,并且使用您的代码获得的图片看起来很棒 :) - Jakob
好的,请在您获得足够的积分后接受并点赞此答案 :) - Mike Wise
我已经给你点赞了,但是只有在我的声望>=15之后,StackOverflow才会计算它。如果有人有改进你的解决方案的想法,我也会感激不尽。 - Jakob
也许另一个人会修复这个 bug :) - Mike Wise
2
他这样做了。从 R-forge 尝试使用 rgl 0.98.4(或在 Github 上等待其最终赶上,或在几周后从 CRAN 获取)。 - user2554330

3

我认为这是一个bug,但有一个解决方法。当你绘制平面时,明确表示你不想使用深度遮罩,即使用

planes3d(1, 2, -1, 0, col = 'red', alpha = 0.1, depth_mask = FALSE)

需要补充说明:

实际上,有两个bug。上面那行修复了一个bug。而另一个bug是,由于飞机没有像球体那样被xlim, ylim, zlim的值所限制,所以它在球体之前被绘制。(如果两者都是透明的,则无法避免此问题,但如果球体是实心的,则应该先绘制它们。)你可以使用另一种解决方法来强制将其绘制在第二个位置。在调用plot3d()后,请运行以下命令:

subs <- subsceneInfo()
useSubscene3d(subs$children)
planes3d(1, 2, -1, 0, col = 'red', alpha = 0.1, depth_mask = FALSE)
useSubscene3d(subs$id)

如果限制不重要,可以将其省略,事情就会顺利进行,无需其他的解决方案。

1
除了让所有的球看起来都在前面,不确定这会有多大帮助。 - Mike Wise
如果球的alpha值为1,则它们将遮挡它们前面的平面,但平面将绘制在球后面的部分上,因此应该没问题。Jakob将alpha设置为0.9,这使事情变得更加困难。然后rgl尝试从后向前绘制,但它并不总是正确的(因为一些多边形相交,所以无法确定哪一个在前面)。 - user2554330
抱歉,Mike是对的——这个错误与我想象的不同。 - user2554330
@user2554330 谢谢,但是就像你自己纠正的那样,即使我没有为球设置 alpha 值,例如:`# 绘制点: plot3d(a1,a2,b, type='s', xlim = c(-1, 1), ylim = c(-1, 1), zlim = c(-3.1, 3.1),xlab = 'a_i,1', ylab = 'a_i,2', zlab = 'b_i')

绘制透明平面:

planes3d(1, 2, -1, 0, col = 'red', alpha = 0.9, add=T,depth_mask = FALSE)` 结果所有的球看起来都在前面。
- Jakob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接