如何使用`rgl`和`animation`旋转加速度计数据的手对象

时间:2017-10-08 01:39:54

标签: r animation accelerometer rgl

假设我有一个线框,3D对象,例如https://free3d.com/3d-model/freerealsichand-85561.html

假设我想将所述物体的手腕固定为加速度计腕表的读数(例如,通过航位推算得到位置)。

如何在rgl

中绘制这样的三维图像

如何根据加速度计数据的变化旋转/翻译所述图像?

奖励:如何播放此活动的animation。 (例如,图书馆animation

加速度计是3-DOF:x-acc,y-acc,z-acc,没有任何其他数据。

2 个答案:

答案 0 :(得分:1)

该链接包含多种格式的手,但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")

要翻译和旋转形状,请使用translate3d上的rotate3duserMatrix功能,例如

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)))

答案 1 :(得分: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

我的黑客有四个功能:

#' 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