r - R有效地绘制了数千个在椭圆体中变形的具有透明度的3D球体
问题描述
我需要真正加速一小段代码,根据将它们转换为椭圆体的 3x3 张量列表,在 3d rgl 空间中变形大约 3000 个球体。此外,我需要透明颜色(“alpha”参数<1)。然后我想快速有效地绘制它们。我希望具有与 spheres3d() 相同的性能,但当然不是这样......(运行下面的代码)。下面是我的代码,其中包含一个完全可重现的示例所需的功能。你能帮我做这件事吗?提前谢谢了。保罗
library(Morpho)
library(Rvcg)
library(rgl)
rep.row<-function(x,n){ #### rep rows of a matrix
matrix(rep(x,each=n),nrow=n)
}
traslamesh<-function(mesh,c){ #### just translate a mesh in the 3d space according a position vector
newvb<-t(mesh$vb[-4,])+rep.row(c,nrow(t(mesh$vb[-4,])))
newmesh<-list(vb=t(cbind(newvb,1)),it=mesh$it)
class(newmesh)<-"mesh3d"
newmesh
}
defosph<-function(sphere,mat,after=T){#### this deforms a sphere in an ellipspoid according to a 3x3 tensor
if(after==T){newvb<-t(sphere$vb[-4,])%*%t(mat)}else{newvb<-t(mat%*%sphere$vb[-4,])}
newmesh<-list(vb=t(cbind(newvb,1)),it=sphere$it)
class(newmesh)<-"mesh3d"
newmesh
}
creasph<-function(radius=1,centroid=c(0,0,0),subdivision=1){ #### just a wrap of vcgSphere
temp_sphere<-vcgSphere(subdivision = subdivision)
temp_sphere$vb[1,]<-temp_sphere$vb[1,]+centroid[1]
temp_sphere$vb[2,]<-temp_sphere$vb[2,]+centroid[2]
temp_sphere$vb[3,]<-temp_sphere$vb[3,]+centroid[3]
final_sphere<-scalemesh(temp_sphere, radius, center = "none")
return(final_sphere)
}
positions<-matrix(rnorm(9000,2,20),ncol=3) ###### positions where we want to plot
spheres3d(positions,alpha=0.5) #### very fast to plot and reasonably fast to naviagate in the 3d rgl window
tensor1<-matrix(rnorm(9),ncol=3) #### a random tensor; let's use the same one for deforming all the 3000 spheres. In the real application each sphere will have its own tensor.
open3d()
for(i in 1:dim(positions)[1]){ #### embarrassingly slow ......
sphi<-creasph(radius=1,subdivision=2)
shade3d(traslamesh(scalemesh(defosph(sphi,tensor1,after=F),1,center="none"),positions[i,]),col=2,alpha=0.5)
print(i)
}
我想根据 n 张量使椭球体变形并有效地绘制它们
解决方案
您正在做的两件事会使这段代码变慢。首先,您要绘制 3000 个对象,并在每个对象之后更新显示。这很容易解决:par3d(skipRedraw=TRUE)
在开始和par3d(skipRedraw=FALSE)
结束时调用,绘图会快得多。
你正在做的第二件事更难修复。您正在将椭球构造为网格,这使得每个椭球都是 320 个三角形的集合。因为你有 3000 个,所以你有将近一百万个三角形要绘制。 rgl
可以处理这个问题,但真正缓慢的是你声明它们都是透明的。要绘制这些,它需要按照从最远到最近的顺序对所有百万个三角形进行排序以绘制它们。每次它从在一个椭圆体中绘制一个三角形切换到在另一个椭圆体中绘制一个三角形时,它都需要经历相当昂贵的上下文更改。
如果您设置alpha = 1
,您将获得更快的显示,因为不需要排序。
您可以做的另一件事是将所有 3000 个椭圆体合并到一个巨大的网格中。它仍然需要对三角形进行排序,但不需要所有这些上下文更改。
下面的代码说明了这些建议。我假设您保留原始代码来设置功能。
# Skip redrawing and set alpha = 1
open3d()
par3d(skipRedraw=TRUE)
for(i in 1:dim(positions)[1]){ #### reasonably fast
sphi<-creasph(radius=1,subdivision=2)
shade3d(traslamesh(scalemesh(defosph(sphi,tensor1,after=F),1,center="none"),positions[i,]),col=2,alpha=1)
print(i)
}
par3d(skipRedraw=FALSE)
# Keep alpha = 0.5, but plot just one big mesh
open3d()
for(i in 1:dim(positions)[1]){ #### pretty slow, but faster than the original
sphi<-creasph(radius=1,subdivision=2)
sphi <- traslamesh(scalemesh(defosph(sphi,tensor1,after=F),1,center="none"),positions[i,])
if (i == 1) result <- sphi else result <- merge(result, sphi)
print(i)
}
shade3d(result, col=2, alpha = 0.5)
第二种方法仍然很慢:它会在所有这些合并中进行大量分配。您可以通过使用网格内部构件来大大加快构建部件的速度。它的更新速度也很慢,因为alpha = 0.5
.
内置球体显示速度如此之快的原因是它并没有试图做得这么好。它对球体中心进行排序,而不是对构成每个球体的所有三角形进行排序。如果你设置fastTransparency = FALSE
,它会慢很多,因为它会对所有的三角形进行排序。它还使用“精灵”的等价物,只初始化一个球体并在许多不同的位置重新绘制它。Sprites 适用于您的示例,但如果您需要在每个椭圆体上进行不同的转换,则不会。
推荐阅读
- python - 我有一个矩阵,其中每个元素都是一个标签和一个值。我如何表示它以便标签给出颜色和强度值?
- unity3d - 如何在检查器中为 OnClick 重新排序侦听器?
- git - 如何在工作树中“git reset”?
- javascript - 如何在不创建新的类实例的情况下从另一个类调用我的非静态函数?- 反应本机路由器通量
- vstest - VSTest:命令测试程序集的执行
- c++ - Windows (COM) API 在没有特定库的情况下表现不同
- unity3d - Unity2D 不一致的 AddForce
- ios - PDFAnnotation 有监听器吗?
- php - 如何在单个数组中添加值(用于解析)
- java - JDK11 - 如何在解组期间忽略命名空间