r - 使用 misc3d 绘制平滑的隐式曲面
问题描述
该misc3d
软件包提供了行进立方体算法的出色实现,允许绘制隐式曲面。
例如,让我们绘制一个 Dupin cyclide:
a = 0.94; mu = 0.56; c = 0.34 # cyclide parameters
f <- function(x, y, z, a, c, mu){ # implicit equation f(x,y,z)=0
b <- sqrt(a^2-c^2)
(x^2+y^2+z^2-mu^2+b^2)^2 - 4*(a*x-c*mu)^2 - 4*b^2*y^2
}
# define the "voxel"
nx <- 50; ny <- 50; nz <- 25
x <- seq(-c-mu-a, abs(mu-c)+a, length=nx)
y <- seq(-mu-a, mu+a, length=ny)
z <- seq(-mu-c, mu+c, length=nz)
g <- expand.grid(x=x, y=y, z=z)
voxel <- array(with(g, f(x,y,z,a,c,mu)), c(nx,ny,nz))
# plot the surface
library(misc3d)
surf <- computeContour3d(voxel, level=0, x=x, y=y, z=z)
drawScene.rgl(makeTriangles(surf))
不错,就是表面不光滑。文档drawScene.rgl
说:“对象特定的渲染功能,例如平滑和材质,是通过设置对象来控制的。” 我不知道那是什么意思。如何获得光滑的表面?
我有一个解决方案,但不是一个简单的解决方案:这个解决方案包括mesh3d
从 的输出构建一个对象computeContour3d
,并将表面法线包含在这个mesh3d
.
由 定义的隐式曲面的曲面法线f(x,y,z)=0
简单地由 的梯度给出f
。对于这个例子,不难推导出梯度。
gradient <- function(xyz,a,c,mu){
x <- xyz[1]; y <- xyz[2]; z <- xyz[3]
b <- sqrt(a^2-c^2)
c(
2*(2*x)*(x^2+y^2+z^2-mu^2+b^2) - 8*a*(a*x-c*mu),
2*(2*y)*(x^2+y^2+z^2-mu^2+b^2) - 8*b^2*y,
2*(2*z)*(x^2+y^2+z^2-mu^2+b^2)
)
}
然后按如下方式计算法线:
normals <- apply(surf, 1, function(xyz){
gradient(xyz,a,c,mu)
})
现在我们准备制作mesh3d
对象:
mesh <- list(vb = rbind(t(surf),1),
it = matrix(1:nrow(surf), nrow=3),
primitivetype = "triangle",
normals = rbind(-normals,1))
class(mesh) <- c("mesh3d", "shape3d")
最后用rgl
:
library(rgl)
shade3d(mesh, color="red")
不错,现在表面光滑了。
但是有没有更直接的方法来获得光滑的表面,而无需构建mesh3d
对象?它们在文档中的含义是什么:“对象特定的渲染功能,例如平滑和材质,是通过在对象中设置来控制的。” ?
解决方案
我不知道文档的建议是什么。但是,您可以通过网格对象比您更容易地做到这一点(尽管结果不是那么好),使用该addNormals()
函数自动计算法线而不是通过公式。
以下是步骤:
像你一样计算表面。
创建没有法线的网格。这基本上就是你所做的,但是使用tmesh3d()
:
mesh <- tmesh3d(t(surf), matrix(1:nrow(surf), nrow=3), homogeneous = FALSE)
计算哪些顶点与其他顶点重复:
verts <- apply(mesh$vb, 2, function(column) paste(column, collapse = " "))
firstcopy <- match(verts, verts)
重写索引以使用第一个副本。这是必要的,因为这些misc3d
函数给出了一组不连贯的三角形;我们需要弄清楚哪些是连接的。
it <- as.numeric(mesh$it)
it <- firstcopy[it]
dim(it) <- dim(mesh$it)
mesh$it <- it
此时,网格中有很多未使用的顶点;如果内存有问题,您可能需要添加一个步骤来删除它们。我要跳过那个。
添加法线
mesh <- addNormals(mesh)
这是之前和之后的镜头。左边没有法线,右边有法线。
它不像您使用计算法线的解决方案那样平滑,但找到它们并不总是那么容易。
推荐阅读
- wordpress - 在 Wordpress 中注册之前检查外部数据库
- javascript - 如何访问另一个模型的数据库以在 Django 的当前模型字段中执行一些计算?
- r - 是否有一个 R 函数来查找列表中元素的下一个位置
- javascript - React Axios Post 已经附加 Bearer Token 仍然得到 401 Unauthorized
- wagtail - FieldPanel 未能反映在 content_panels 上
- sorting - Sortperm 用于 Julia lang 中的矩阵排序
- excel - Expression.Error:我们无法将值 null 转换为文本类型。详细信息:值=类型=类型
- google-analytics - 通过访问论坛页面对 Google Analytics(分析)数据进行细分
- php - 如何使用 PHP MySQL Ajax JQuery 上传图像或任何文件并通过患者姓名更改其文件名?
- node.js - Windows 上带有 Docker 的 NodeJs - Nodemon 没有更新