问题描述
我需要真正加速一小段代码,它根据3x3张量列表在3x3张量列表中变形约3000个球体,将它们转换为椭球体。此外,我需要透明的颜色(&Quot;Alpha;Argument<;1)。然后我想要快速而有效地绘制它们。我希望拥有与ball 3d()相同的性能,但当然不是这样的……(运行下面的代码)。下面是我的代码,其中包含一个完全可重现的示例所需的函数。你能帮我做这件事吗?在此之前,我非常感谢您。保罗
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
,它将减慢很多,因为它将对所有三角形进行排序。它还使用了等同于精灵的工具,只初始化一个球体,然后在许多不同的位置重新绘制它。精灵适用于您的示例,但如果您需要在每个椭球体上进行不同的变换,则不行。
这篇关于R高效绘制在椭球体中变形的数千个球体,在3D中具有透明度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!