如何使用 `rgl` 和 `animation` 使用加速度计数据旋转手对象
How to rotate hand object with accelerometer data using `rgl` and `animation`
假设我有一个线框、3D 对象,例如 https://free3d.com/3d-model/freerealsichand-85561.html
假设我想将所述物体的手腕固定为加速度计手表的读数(例如,通过航位推算获取位置)。
如何在 rgl
中绘制这样的 3-D 图像?
如何根据加速度计数据的变化旋转/平移所述图像?
奖金:我如何玩这个 activity 的 animation
。 (例如,图书馆 animation
)
加速度计是 3-DOF:x-acc、y-acc、z-acc,没有任何其他数据。
link 包括几种格式的手,但 rgl
目前无法阅读它们。它最接近 .OBJ 格式,但无法读取该文件中记录的法线或纹理,因此失败。您可能想尝试更新 readOBJ
以支持更多 OBJ 格式;或者,您可以像这样删除该信息:
hand <- readLines("hand.OBJ")
poly <- grepl("^f ", hand)
hand[poly] <- gsub("/[^ ]+", "", hand[poly])
handmesh <- readOBJ(textConnection(hand))
这将给出一些警告,因为它忽略了该文件的其他部分,但它会生成一个 rgl
可以处理的对象。你可以这样画:
shade3d(handmesh, col = "pink")
要平移和旋转形状,请使用 userMatrix
上的 translate3d
和 rotate3d
函数,例如
par3d(userMatrix = rotate3d(par3d("userMatrix"), 0.1, 1,0,0))
将手绕 x 轴旋转 0.1 弧度。 (如果您想要永久更改,也可以旋转 handmesh
本身。)
您需要花一些时间弄清楚手腕的坐标是什么,并将您的 3-DOF 数据转换为正确的坐标系。
您不需要 animation
动画;请参阅 ?rgl::play3d
中的示例。例如,要绕 x 轴旋转手,您可以使用
open3d()
shade3d(handmesh, col = "pink")
play3d(spin3d(axis = c(1, 0, 0)))
根据@user2554330提供的答案,我深挖了细节。
rgl::readOBJ有点不完善,我把这件事通知了R-forge:rgl:https://r-forge.r-project.org/tracker/index.php?func=detail&aid=6543&group_id=234&atid=949
# rgl::readOBJ
beginT = Sys.time();
hand <- readLines("hand.OBJ")
poly <- grepl("^f ", hand)
hand[poly] <- gsub("/[^ ]+", "", hand[poly])
handmesh <- readOBJ(textConnection(hand))
endT = Sys.time(); print(endT-beginT);
# Time difference of 1.555696964263916 secs
我的 hack 有四个功能:
#' Convert String Matrix to Numeric Matrix
#'
#' @param m string matrix
#'
#' @return numeric matrix
#' @export
numericMatrix = function(m)
{
m = as.matrix(m);
mdim = dim(m);
nm <- mapply(m, FUN=as.numeric);
matrix(data=nm, nrow=mdim[1], ncol=mdim[2])
}
#' Convert String List of "f" to numeric multi-dimensional array
#'
#' @param fobj
#'
#' @return fn, multidimension array of rows, cols, and values
#' @export
#'
numericF = function(fobj)
{
rdim = dim(fobj)[1]; # rows
cdim = dim(fobj)[2]; # cols
ddim = 3;
fn = array(NA,dim=c(rdim,cdim,ddim));
for(rn in 1:rdim)
{
for(cn in 1:cdim)
{
rcdat = fobj[rn,cn];
fdat = as.numeric(unlist(strsplit(rcdat,"/",fixed=T))); # basic numeric case
fn[rn,cn,] = fdat;
}
}
#fn[1:10,1:4,1:3]
fn;
}
#' Internally equivalent to rgl 'readOBJ'
#'
#' @param rawobj Raw object read in using parseFileOBJ
#'
#' rgl::readOBJ
#' hand <- readLines("hand.OBJ")
#' poly <- grepl("^f ", hand)
#' hand[poly] <- gsub("/[^ ]+", "", hand[poly])
#' handmesh <- readOBJ(textConnection(hand))
#'
#' mymesh = buildBasicMeshFromOBJ(parseFileOBJ("hand.OBJ"));
#'
#' These appear to be equivalent in the basic form
#'
#' @return list object equivalent to readOBJ output
#' @export
#'
buildBasicMeshFromOBJ <- function(rawobj)
{
mesh = list();
vb = as.matrix(rawobj$v);
vb = cbind(vb,1);
mesh$vb = t(vb);
mesh$it = matrix(0,nrow=3,ncol=0);
mesh$primitivetype = "triangle";
mesh$ib = t(as.matrix(rawobj$fn[,,1]));
attr(mesh,"class") = c("mesh3d","shape3d");
mesh;
}
#' Parse file of type OBJ
#'
#' Specification for OBJ format can be found here:
#' http://www.martinreddy.net/gfx/3d/OBJ.spec
#'
#' Requires gdata::trim
#'
#' @param filename
#'
#' @return list 'rawobj' with all details from the file
#' @export
#'
#' @examples
#' rawobj = parseFileOBJ("hand.obj");
parseFileOBJ <- function(filename)
{
linestxt <- readLines(filename) # read all lines
linestxt = gsub("\s+"," ",gdata::trim(linestxt)); # replace multiple spaces with single space
linesobj = strsplit(linestxt," ",fixed=T); # split on spaces
rawobj = list();
rawobj$lines = c();
rawobj$comments = c();
for(i in 1:length(linesobj))
{
hir = gdata::trim(linesobj[[i]]);
key = hir[1];
rdat = hir[-1];
rlen = length(rdat);
rstr = paste(rdat,collapse=" ");
if (key=="#") {
rawobj$lines = c(rawobj$lines,"comments");
rawobj$comments = c(rawobj$comments,rstr);
} else { rawobj$lines = c(rawobj$lines,key);
if(is.null(rawobj[[key]])) { rawobj[[key]] = rdat; } else
{ rawobj[[key]] = rbind(rawobj[[key]],rdat);}
}
}
if(!is.null(rawobj[["v"]])) { rawobj[["v"]] = numericMatrix(rawobj[["v"]]); }
if(!is.null(rawobj[["vn"]])) { rawobj[["vn"]] = numericMatrix(rawobj[["vn"]]); }
if(!is.null(rawobj[["vt"]])) { rawobj[["vt"]] = numericMatrix(rawobj[["vt"]]); }
# "f" could be numeric (f 1 2 3 4) or (f -4 -3 -2 -1) or references to v,vn,vt (f 1/1/1 2/2/2 3/3/3 4/4/4) or (f v/vt/vn v/vt/vn v/vt/vn v/vt/vn) or (f 1//1 2//2 3//3 4//4)
# rdat = c("1102/9904/4404","2981/9909/4404","3943/9910/4404","2854/9905/4404");
# rdat = c('1//1','2//2','3//3',4//4');
if(!is.null(rawobj[["f"]])) { rawobj[["fn"]] = numericF(rawobj[["f"]]); }
rawobj;
}
基本用法:
# Takes longer, but processes "all" info in the file
beginT = Sys.time();
rawobj = parseFileOBJ("hand.OBJ");
endT = Sys.time(); print(endT-beginT); beginT = endT;
# Time difference of 6.9523830413818359 secs
mymesh = buildBasicMeshFromOBJ(rawobj);
endT = Sys.time(); print(endT-beginT);
# Time difference of 0.0030009746551513672 secs
rawobject 具有 所有 根据此规范在 OBJ 文件中找到的信息:http://www.martinreddy.net/gfx/3d/OBJ.spec
假设我有一个线框、3D 对象,例如 https://free3d.com/3d-model/freerealsichand-85561.html
假设我想将所述物体的手腕固定为加速度计手表的读数(例如,通过航位推算获取位置)。
如何在 rgl
中绘制这样的 3-D 图像?
如何根据加速度计数据的变化旋转/平移所述图像?
奖金:我如何玩这个 activity 的 animation
。 (例如,图书馆 animation
)
加速度计是 3-DOF:x-acc、y-acc、z-acc,没有任何其他数据。
link 包括几种格式的手,但 rgl
目前无法阅读它们。它最接近 .OBJ 格式,但无法读取该文件中记录的法线或纹理,因此失败。您可能想尝试更新 readOBJ
以支持更多 OBJ 格式;或者,您可以像这样删除该信息:
hand <- readLines("hand.OBJ")
poly <- grepl("^f ", hand)
hand[poly] <- gsub("/[^ ]+", "", hand[poly])
handmesh <- readOBJ(textConnection(hand))
这将给出一些警告,因为它忽略了该文件的其他部分,但它会生成一个 rgl
可以处理的对象。你可以这样画:
shade3d(handmesh, col = "pink")
要平移和旋转形状,请使用 userMatrix
上的 translate3d
和 rotate3d
函数,例如
par3d(userMatrix = rotate3d(par3d("userMatrix"), 0.1, 1,0,0))
将手绕 x 轴旋转 0.1 弧度。 (如果您想要永久更改,也可以旋转 handmesh
本身。)
您需要花一些时间弄清楚手腕的坐标是什么,并将您的 3-DOF 数据转换为正确的坐标系。
您不需要 animation
动画;请参阅 ?rgl::play3d
中的示例。例如,要绕 x 轴旋转手,您可以使用
open3d()
shade3d(handmesh, col = "pink")
play3d(spin3d(axis = c(1, 0, 0)))
根据@user2554330提供的答案,我深挖了细节。
rgl::readOBJ有点不完善,我把这件事通知了R-forge:rgl:https://r-forge.r-project.org/tracker/index.php?func=detail&aid=6543&group_id=234&atid=949
# rgl::readOBJ
beginT = Sys.time();
hand <- readLines("hand.OBJ")
poly <- grepl("^f ", hand)
hand[poly] <- gsub("/[^ ]+", "", hand[poly])
handmesh <- readOBJ(textConnection(hand))
endT = Sys.time(); print(endT-beginT);
# Time difference of 1.555696964263916 secs
我的 hack 有四个功能:
#' Convert String Matrix to Numeric Matrix
#'
#' @param m string matrix
#'
#' @return numeric matrix
#' @export
numericMatrix = function(m)
{
m = as.matrix(m);
mdim = dim(m);
nm <- mapply(m, FUN=as.numeric);
matrix(data=nm, nrow=mdim[1], ncol=mdim[2])
}
#' Convert String List of "f" to numeric multi-dimensional array
#'
#' @param fobj
#'
#' @return fn, multidimension array of rows, cols, and values
#' @export
#'
numericF = function(fobj)
{
rdim = dim(fobj)[1]; # rows
cdim = dim(fobj)[2]; # cols
ddim = 3;
fn = array(NA,dim=c(rdim,cdim,ddim));
for(rn in 1:rdim)
{
for(cn in 1:cdim)
{
rcdat = fobj[rn,cn];
fdat = as.numeric(unlist(strsplit(rcdat,"/",fixed=T))); # basic numeric case
fn[rn,cn,] = fdat;
}
}
#fn[1:10,1:4,1:3]
fn;
}
#' Internally equivalent to rgl 'readOBJ'
#'
#' @param rawobj Raw object read in using parseFileOBJ
#'
#' rgl::readOBJ
#' hand <- readLines("hand.OBJ")
#' poly <- grepl("^f ", hand)
#' hand[poly] <- gsub("/[^ ]+", "", hand[poly])
#' handmesh <- readOBJ(textConnection(hand))
#'
#' mymesh = buildBasicMeshFromOBJ(parseFileOBJ("hand.OBJ"));
#'
#' These appear to be equivalent in the basic form
#'
#' @return list object equivalent to readOBJ output
#' @export
#'
buildBasicMeshFromOBJ <- function(rawobj)
{
mesh = list();
vb = as.matrix(rawobj$v);
vb = cbind(vb,1);
mesh$vb = t(vb);
mesh$it = matrix(0,nrow=3,ncol=0);
mesh$primitivetype = "triangle";
mesh$ib = t(as.matrix(rawobj$fn[,,1]));
attr(mesh,"class") = c("mesh3d","shape3d");
mesh;
}
#' Parse file of type OBJ
#'
#' Specification for OBJ format can be found here:
#' http://www.martinreddy.net/gfx/3d/OBJ.spec
#'
#' Requires gdata::trim
#'
#' @param filename
#'
#' @return list 'rawobj' with all details from the file
#' @export
#'
#' @examples
#' rawobj = parseFileOBJ("hand.obj");
parseFileOBJ <- function(filename)
{
linestxt <- readLines(filename) # read all lines
linestxt = gsub("\s+"," ",gdata::trim(linestxt)); # replace multiple spaces with single space
linesobj = strsplit(linestxt," ",fixed=T); # split on spaces
rawobj = list();
rawobj$lines = c();
rawobj$comments = c();
for(i in 1:length(linesobj))
{
hir = gdata::trim(linesobj[[i]]);
key = hir[1];
rdat = hir[-1];
rlen = length(rdat);
rstr = paste(rdat,collapse=" ");
if (key=="#") {
rawobj$lines = c(rawobj$lines,"comments");
rawobj$comments = c(rawobj$comments,rstr);
} else { rawobj$lines = c(rawobj$lines,key);
if(is.null(rawobj[[key]])) { rawobj[[key]] = rdat; } else
{ rawobj[[key]] = rbind(rawobj[[key]],rdat);}
}
}
if(!is.null(rawobj[["v"]])) { rawobj[["v"]] = numericMatrix(rawobj[["v"]]); }
if(!is.null(rawobj[["vn"]])) { rawobj[["vn"]] = numericMatrix(rawobj[["vn"]]); }
if(!is.null(rawobj[["vt"]])) { rawobj[["vt"]] = numericMatrix(rawobj[["vt"]]); }
# "f" could be numeric (f 1 2 3 4) or (f -4 -3 -2 -1) or references to v,vn,vt (f 1/1/1 2/2/2 3/3/3 4/4/4) or (f v/vt/vn v/vt/vn v/vt/vn v/vt/vn) or (f 1//1 2//2 3//3 4//4)
# rdat = c("1102/9904/4404","2981/9909/4404","3943/9910/4404","2854/9905/4404");
# rdat = c('1//1','2//2','3//3',4//4');
if(!is.null(rawobj[["f"]])) { rawobj[["fn"]] = numericF(rawobj[["f"]]); }
rawobj;
}
基本用法:
# Takes longer, but processes "all" info in the file
beginT = Sys.time();
rawobj = parseFileOBJ("hand.OBJ");
endT = Sys.time(); print(endT-beginT); beginT = endT;
# Time difference of 6.9523830413818359 secs
mymesh = buildBasicMeshFromOBJ(rawobj);
endT = Sys.time(); print(endT-beginT);
# Time difference of 0.0030009746551513672 secs
rawobject 具有 所有 根据此规范在 OBJ 文件中找到的信息:http://www.martinreddy.net/gfx/3d/OBJ.spec