mshaffer
mshaffer

Reputation: 993

Using R: how to animate multiple 3D objects in single rgl canvas?

I have data where a participant had positional data on each hand:

left: right:

positional data has

pos.x
pos.y
pos.z

at some time t

The initial question was about importing OBJ to work with RGL: https://stackoverflow.com/posts/46626767/revisions

I have figured that part out. I have written functions to improve rgl mesh framework for open-source OBJ files.

I placed the required functions online: https://gist.github.com/MonteShaffer/d142210cddf346c86aeab1ea2d1d7e9d

The positional data should be captured on a wrist watch, so I want to be able to show two or more 3D data objects and animate each independently based on positional/time data.

That is, treat the hand like a rigid object with the wrist-watch region moving appropriately.

I placed the hand.OBJ file online: https://gist.github.com/MonteShaffer/6c0057b1431364caf120220db77dde4b

I am aware of basic graphing, updating, spinning:

library(rgl)

mymesh = buildBasicMeshFromOBJ(parseFileOBJ("hand.OBJ"));

open3d()
shade3d(mymesh, col = "pink")
par3d(userMatrix = rotate3d(par3d("userMatrix"), 0.1, 1,0,0))
play3d(spin3d(axis = c(1, 0, 0)))

My goal is to plot multiple objects on the same rgl canvas.

e.g.,

righthand = mymesh
lefthand = mymesh

head = buildBasicMeshFromOBJ(parseFileOBJ("head.obj"));

and have each element move independently as an animation over time based on positional/time data for each element. For now the head stays still, but each hand moves based on the rigid idea with the position representing the wrist.

It would be a bonus that the mouse drag could still occur (to change 3D views around the hands and head) while the animation is going on.

Upvotes: 1

Views: 637

Answers (1)

user2554330
user2554330

Reputation: 44897

You can move objects within the scene by using a function like rotate3d. Despite its name, it allows for quite general kinds of movement: see the help page.

So instead of using par3d to move things, move the objects themselves.

rgl doesn't provide a way to modify objects that are already in the scene (though the WebGL display of rgl objects does...), so the basic idea is the following:

  • Plot the object, and save the ids (e.g. ids <- shade3d(mymesh))
  • Then, in a loop:
    • Turn off updates (using par3d(skipRedraw=TRUE))
    • Delete the object (e.g. rgl.pop(id=ids))
    • Move and replot the object
    • Turn on updates.

The play3d function provides a framework to automate this, but you don't need to use it. For example, this plots two icosahedra and randomly rotates them independently:

orig1 <- icosahedron3d()
id1 <- shade3d(orig1, col = "green")
orig2 <- translate3d(orig1, 4, 0, 0)
id2 <- shade3d(orig2, col = "blue")

repeat {
  orig1 <- rotate3d(orig1, 0.01, rnorm(1, 1), rnorm(1), rnorm(1))
  orig2 <- rotate3d(orig2, 0.05, rnorm(1, -1), rnorm(1), rnorm(1))
  par3d(skipRedraw = TRUE)
  rgl.pop(id = c(id1, id2))
  id1 <- shade3d(orig1, col = "green")
  id2 <- shade3d(orig2, col = "blue")
  par3d(skipRedraw = FALSE)
}

Another way to do this is to set up two separate subscenes. Then each can be controlled by its own par3d() setting. For example,

icos <- icosahedron3d()
ids <- mfrow3d(1,2)
shade3d(icos, col = "red")
next3d()
shade3d(icos, col = "green")

Now each of the icosahedra can be manipulated independently with the mouse. If you want to do it with par3d, use something like par3d(..., subscene = ids[1]) to affect the left pane, par3d(..., subscene = ids[2]) for the right pane.

Upvotes: 1

Related Questions