阻止自动更新modelMatrix并修改rgl

时间:2017-06-29 14:26:51

标签: r rgl

我正在尝试使用par3d()在rgl中设置自定义userMatrix,但由于只读modelMatrix的重新计算,所产生的视图会产生不必要的副作用。 (https://www.rdocumentation.org/packages/rgl/versions/0.97.0/topics/par3d,章节:渲染) 此外,近距离和远距离剔除平面(我似乎无法修改)在靠近/远离视点时过早地切割物体。

我的目标是以交互方式导航(使用Z轴向上)一个带有回归平面和曲面的点云,比在场景中居中的旋转和缩放更自由(我已经看到使用rgl.setMouseCallbacks的平移示例) )。

重新绘制场景以移动它实际上不是一个选项,但是对一些场景对象应用自定义转换可能是另一种方法,但更像是一种解决方法。

提前感谢您的反馈!

2 个答案:

答案 0 :(得分:0)

你的问题太模糊了。什么是“不必要的副作用”?但我会尝试:

在最简单的情况下,模型矩阵M设置为U V,其中V由系统设置(如?par3d中所述),U完全在您的控制之下。因此,如果您想要完全控制M,首先将U设置为标识并读取M以获得V,然后为了获得新的M',将U设置为M'V ^ -1。

剪切平面是投影矩阵的一个特征。那里你没有很多控制权。

答案 1 :(得分:0)

因此,此示例代码在rgl中生成FPV或第三人称视图,包括hack(微调-550常量)以使视图更接近枢轴点(如果有人的话,这不应该是必要的完全控制所有矩阵)。 近距离裁剪/剔除仍在那里,但可以接受。

library("rgl")
library("Morpho")

rglInit <- function()
{
  rgl.open()
  rgl.viewpoint(fov=110, type="userviewpoint")

  defaultUserMatrix <<- par3d()$userMatrix
}

lookAt3d <-function(eye, center, up)
{
  cat("*** lookat\n")
  cat("eye\n")
  print(eye)
  cat("center\n")
  print(center)
  cat("up\n")
  print(up)

  fwd = center - eye
  fwd = fwd / sqrt(sum(fwd^2))
  upn = up / sqrt(sum(up^2))

  side = crossProduct(fwd, up)
  upnt = crossProduct(side, fwd)

  M = rbind(c(side, 0), c(upnt, 0), c(-fwd, 0), c(0,0,0,1))
  M = M %*% t(translationMatrix(-550 * fwd[1] - eye[1],
                                -550 * fwd[2] - eye[2],
                                -550 * fwd[3] - eye[3])) # -550 hack seems to put the view closer to the pivot point
  cat("result\n")
  print(M)
  return (M)
}

yawPitchDirection3d <- function(yawAngle, pitchAngle)
{
  c(
    cos(pitchAngle) * cos(yawAngle),
    cos(pitchAngle) * sin(yawAngle),
    sin(pitchAngle))
}

lookAtYawPitch3d <- function(eye, yawAngle, pitchAngle)
{
  fwd = yawPitchDirection3d(yawAngle, pitchAngle)
  lookAt3d(eye, eye + fwd, c(0,0,1))
}

addTestScene <- function()
{
  data(volcano)

  z <- 2 * volcano # Exaggerate the relief

  x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N)
  y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W)

  zlim <- range(z)
  zlen <- zlim[2] - zlim[1] + 1

  colorlut <- terrain.colors(zlen) # height color lookup table

  col <- colorlut[ z-zlim[1]+1 ] # assign colors to heights for each point

  rgl.surface(x, y, z, coords = c(1,3,2), color=col, back="lines")

  axis3d('x', pos=c( NA, 0, 0 ), col = "red")
  axis3d('y', pos=c( 0, NA, 0 ), col = "green")
  axis3d('z', pos=c( 0, 0, NA ), col = "blue")
}

view = list()

resetView <- function()
{
  view$yaw <<- 0.6
  view$pitch <<- -1
  view$eye <<- c(-360, -250,115)

  setView()
}

setView <- function(yawDiff = 0.0, pitchDiff = 0.0, fwdDiff = 0.0, sideDiff = 0.0,
                    newView = NULL, delta = T)
{
  view$yaw <<- view$yaw + yawDiff
  view$pitch <<- view$pitch + pitchDiff

  if (view$pitch > 0.99 * pi / 2)
  {
    view$pitch <<- 0.99 * pi / 2
  }
  if (view$pitch < -0.99 * pi / 2)
  {
    view$pitch <<- -0.99 * pi / 2
  }

  cat("*** Setview\n")
  cat("Yaw\n")
  print(view$yaw)
  cat("Pitch\n")
  print(view$pitch)
  cat("Eye\n")
  print(view$eye)

  fwd = yawPitchDirection3d(view$yaw, view$pitch)
  up = c(0,0,1)
  upn = up / sqrt(sum(up^2))

  side = crossProduct(fwd, up)

  view$eye <<- view$eye + sideDiff * side + fwdDiff * fwd

  userView = lookAtYawPitch3d(eye = view$eye,
                              yawAngle = view$yaw,
                              pitchAngle = view$pitch)

  par3d(userMatrix = userView)
}

setMouseCallbacks <- function()
{
  clickPrev <- list()

  rgl.setMouseCallbacks(1,
                        begin = function(x, y)
                        {
                          clickPrev$x1 <<- x
                          clickPrev$y1 <<- y
                        }, 
                        update = function(x, y)
                        {
                          setView(yawDiff = -0.05 * (x - clickPrev$x1) / pi,
                                  pitchDiff = -0.05 * (y - clickPrev$y1) / pi)

                          clickPrev$x1 <<- x
                          clickPrev$y1 <<- y

                          cat("*** Drag MB1\n")
                          cat("userMatrix\n")
                          print(par3d()$userMatrix)
                          cat("modelMatrix\n")
                          print(par3d()$modelMatrix)
                          cat("projMatrix\n")
                          print(par3d()$projMatrix)
                        }
  )

  rgl.setMouseCallbacks(2,
                        begin = function(x, y)
                        {
                          clickPrev$x2 <<- x
                          clickPrev$y2 <<- y
                        }, 
                        update = function(x, y)
                        {
                          setView(fwdDiff = -0.5 * (y - clickPrev$y2),
                                  sideDiff = -0.5 * (x - clickPrev$x2))

                          clickPrev$x2 <<- x
                          clickPrev$y2 <<- y

                          cat("*** Drag MB2\n")
                          cat("userMatrix\n")
                          print(par3d()$userMatrix)
                          cat("modelMatrix\n")
                          print(par3d()$modelMatrix)
                          cat("projMatrix\n")
                          print(par3d()$projMatrix)
                        }
  )
}

rglInit()
resetView()
addTestScene()
setMouseCallbacks()