How to render an object that always moves along the motion - arcore

I am rendering an object using node.setWorldPosition(0,0,-2f).
But I hope it always shows up in front of my camera view 2 meters away
I tried to display the node that is always facing my camera, but when I move the device forward, I can't move the node. Im not using anchor to fixed my object.
private void nodeAlwaysFaceCamera() {
Vector3 cameraPosition = arFragment.getArSceneView().getScene().getCamera().getWorldPosition();
Vector3 cardPosition = node.getWorldPosition();
Vector3 direction = Vector3.subtract(cameraPosition, cardPosition);
Quaternion lookRotation = Quaternion.lookRotation(direction, Vector3.up());
node.setWorldRotation(lookRotation);
}
Render the object 2 meters in front of the camera
node = new Node();
node.setParent(arFragment.getArSceneView().getScene());
node.setWorldPosition(new Vector3(0f, 0f, -2f));
node.setRenderable(viewRenderable);
My expected result is that the object will stick to the camera while moving.

Instead of getting the world position, you should use the Pose of the Camera. So instead of this
Vector3 cameraPosition = arFragment.getArSceneView().getScene().getCamera().getWorldPosition();
You can use:
Pose cameraPose = arFragment.getArSceneView().getScene().getCamera().getPose();
Or alternatively you can create a new Pose without the rotation of the camera.
Pose cameraPose = arFragment.getArSceneView().getScene().getCamera().getPose().extractTranslation();
Then you can use that pose to compose the pose for the object that you want to have in front of the camera. In example this will place the object in front of the camera at the same height at a distance of 2m (using the second cameraPose):
// Compose the Pose of the Object relative to the cameraPose
Pose objectPose = cameraPose.compose(Pose.makeTranslation(0,0,-2f));
// Create an Anchor for the object
Anchor objectAnchor = arFragment.getArSceneView().getSession().createAnchor(objectPose);
AnchorNode objectAnchorNode = AnchorNode(objectAnchor);
// Here is your code
node = new Node();
node.setParent(anchorNode);
node.setRenderable(viewRenderable);
....

Related

SceneKit + ARKit: Billboarding without rolling with camera

I'm trying to draw a billboarded quad using SceneKit and ARKit. I have basic billboarding working, however when I roll the camera the billboard also rotates in place. This video shows this in action as I roll the camera to the left (the smily face is the billboard):
Instead I'd like the billboard to still face the camera but keep oriented vertically in the scene, no matter what the camera is doing
Here's how I compute billboarding:
// inside frame update function
struct Vertex {
var position: SIMD3<Float>
var texCoord: SIMD2<Float>
}
let halfSize = Float(0.25)
let cameraNode = sceneView.scene.rootNode.childNodes.first!
let modelTransform = self.scnNode.simdWorldTransform
let viewTransform = cameraNode.simdWorldTransform.inverse
let modelViewTransform = viewTransform * modelTransform
let right = SIMD3<Float>(modelViewTransform[0][0], modelViewTransform[1][0], modelViewTransform[2][0]);
let up = SIMD3<Float>(modelViewTransform[0][1], modelViewTransform[1][1], modelViewTransform[2][1]);
// drawBuffer is a MTL buffer of vertex data
let data = drawBuffer.contents().bindMemory(to: ParticleVertex.self, capacity: 4)
data[0].position = (right + up) * halfSize
data[0].texCoord = SIMD2<Float>(0, 0)
data[1].position = -(right - up) * halfSize
data[1].texCoord = SIMD2<Float>(1, 0)
data[2].position = (right - up) * halfSize
data[2].texCoord = SIMD2<Float>(0, 1)
data[3].position = -(right + up) * halfSize
data[3].texCoord = SIMD2<Float>(1, 1)
Again this gets the billboard facing the camera correctly, however when I roll the camera, the billboard rotates along with it.
What I'd like instead is for the billboard to point towards the camera but keep its orientation in the world. Any suggestions on how to fix this?
Note that my code example is simplified so I can't use SCNBillboardConstraint or anything like that; I need to be able to compute the billboarding myself
Here's the solution I came up with: create a new node that matches the camera's position and rotation, but without any roll:
let tempNode = SCNNode()
tempNode.simdWorldPosition = cameraNode.simdWorldPosition
// This changes the node's pitch and yaw, but not roll
tempNode.simdLook(at: cameraNode.simdConvertPosition(SIMD3<Float>(0, 0, 1), to: nil))
let view = tempNode.simdWorldTransform.inverse
let modelViewTransform = view * node.simdWorldTransform
This keeps the billboard pointing upwards in world space, even as the camera rolls.
I had actually tried doing this earlier by setting tempNode.eulerAngles.z = 0, however that seems to effect the rest of the transform matrix in unexpected ways
There's probably a way to do this without creating a temporary node too but this works well enough for me

How do I rotate a SCNNode around a point?

I have a SCNNode - sceneNode - which is a child of rootNode and contains all of my child nodes. Upon the user tapping a button, I want to rotate the scene around a certain point on the y-axis. For example, the camera's point of view is known, and I want to rotate everything by 90º around the camera. The camera is no longer at 0, 0, 0.
I've tried playing around with the SCNMatrix4MakeTranslation function, and then changing the y value on the euler angles, but I've not been able to get it to work expectedly.
Your question is rather ambiguous, if you were to rotate the entire scene 90degrees “around the camera” the scene would end up next to the camera and you wouldn’t see it.
To rotate a SCNNode around a point other than its own pivot, as the question in the title, create a translation matrix that moves it to that point, multiply with a rotation matrix to the SCNNode, and then multiply with the inverse of the translation matrix.
However, what you probably want to do instead is do basically the same process with the camera node instead of the sceneNode. That will make the camera move around the sceneNode, giving the appearance the scene is rotating in place.
For example:
//get the current camera's transform and store it in cammat
GLKMatrix4 cammat = SCNMatrix4ToGLKMatrix4(self.myView.pointOfView.transform);
//create a rotation matrix of 90 degrees over axis Y
GLKQuaternion quaty = GLKQuaternionMakeWithAngleAndAxis(M_PI/2, 0, 1, 0);
GLKMatrix4 rotMat = GLKMatrix4MakeWithQuaternion(quaty);
//set the camera transform to rotMat * cammat, which basically rotates the camera first, and then moves it back to the same offset it was.
self.myView.pointOfView.transform = SCNMatrix4FromGLKMatrix4(GLKMatrix4Multiply(rotMat, cammat));

How can I place an anchor in ARKit relative to the ground with WorldAlignment rather than relative to the camera?

I'm following along the SpriteKit example with ARKit and want to change the behavior such that instead of placing the sprite just in front of the camera - I want the sprite to always be at a fixed distance above the floor (plane?), e.g. eye-level. I also want to use the WorldAlignment gravityAndHeading so that I can always place it in the same part of the room.
Here's the sample code
if let currentFrame = sceneView.session.currentFrame {
// Create a transform with a translation of 1.5 meters in front of the camera
var translation = matrix_identity_float4x4
translation.columns.3.z = -1.5
let transform = simd_mul(currentFrame.camera.transform, translation)
// Add a new anchor to the session
let anchor = ARAnchor(transform: transform)
sceneView.session.add(anchor: anchor)
}
Do I need to get the camera's height position when I pass in the translation to currentFrame.camera.transform, or is there something that will give me the absolute or relative position vs 0?
Also, I'm assuming that I should turn on plane detection and add my anchor on plane detected? configuration.planeDetection = .horizontal

Calcul new coords of camera after a 90 degres rotation in a isometric 2D projection

I made a 2D isometric renderer. It works fine but now I want to show my scene from 4 differents point of view (NO NW SE SW) but, on a 90° rotation, my camera cannot keep the center of my scene on screen.
What's working :
I calcul new projection of scene to match the new viewport (x y z in my world).
I reorganise part of my scene(chunk) to draw them in a correct order
I reorganise 'tiles' of 'chunks' to draw them in a correct order
I can keep the correct center with a 180 degres rotation.
What's do not working :
I cannot find a correct translation to apply to my camera after a 90 degres rotation.
What I know :
To keep the same center on a 180° rotation with my camera I have to do this :
camera.Position -= new Vector2(2 * camera.Position.X + camera.Width, 2 * camera.Position.Y + camera.Height);
Illustration
If the center of your map is origo (0,0,0), this gets easy:
First you store your default camera position in a Vector3 CameraOffset, then you calculate position using a rotation-matrix. 90* in redians is half a Pi, so we will use PiOverTwo. We will also use an enum to decide what direction to be pointing, so you can say
Camera.Orientation = Orientation.East;
and the camera should fix itself :)
public enum Orientation
{
North, East, South, West
}
in camera:
public Vector3 Position { get; protected set; }
Vector3 _CameraOffset = new Vector3(0, 20, 20);
public Vector3 CameraOffset
{
get
{
return _Orientation;
}
set
{
_Orientation = value;
UpdateOrientation();
}
}
Orientation _Orientation = Orientation.North;
public Orientation Orientation
{
get
{
return _Orientation;
}
set
{
_Orientation = value;
UpdateOrientation();
}
}
private void UpdateOrientation()
{
Position = Vector3.Transform(CameraOffset, Matrix.CreateRotationY(MathHelper.PiOverTwo * (int)Orientation));
}
If you want a gliding movement between positions, I think I can help too ;)
If your camera does not focus on Vector3.Zero and should not rotate around it, you just need to change:
Position = Vector3.Transform(CameraOffset, Matrix.CreateRotationY(MathHelper.PiOverTwo * (int)Orientation));
to:
Position = Vector3.Transform(CameraOffset, Matrix.CreateRotationY(MathHelper.PiOverTwo * (int)Orientation) * Matrix.CreateTranslation(FocusPoint));
Here, FocusPoint is the point in 3D that you rotate around (your worlds center). And now you also know how to let your camera move around, if you call UpdateOrientation() in your Camera.Update() ;)
EDIT; So sorry, totally missed the point that you use 2D. I'll be back later to see if I can help :P

Moving a 3d camera on XNA

Im doing some practices on XNA, and i created a class that represents a Camera.
My objective is that when the user press some keys make a translation of the camera (not the target) 90 degrees in the X axys (to see an object that i placed in the scene from different angles). By the moment i move the camera in X, Y, and Z without problems.
Actually to set up my camera i use the following lines of code:
public void SetUpCamera()
{
#region ## SET DEFAULTS ##
this.FieldOfViewAngle = 45.0f;
this.AspectRatio =1f;
this.NearPlane = 1.0f;
this.FarPlane = 10000.0f;
#endregion
this.ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(this.FieldOfViewAngle), 16 / 9, this.NearPlane, this.FarPlane);
this.ViewMatrix = Matrix.CreateLookAt(new Vector3(this.PositionX, this.PositionY, this.PositionZ), new Vector3(this.TargetX, this.TargetY, this.TargetZ), Vector3.Up);
}
I have this method to move the camera:
public void UpdateView()
{
this.ViewMatrix = Matrix.CreateLookAt(new Vector3(this.PositionX, this.PositionY, this.PositionZ), new Vector3(this.TargetX, this.TargetY, this.TargetZ), Vector3.Up);
}
Then in the game (update event handler i have the following code)
if (keyboardstate.IsKeyDown(Keys.NumPad9))
{
this.GameCamera.PositionZ -= 1.0f;
}
if (keyboardstate.IsKeyDown(Keys.NumPad3))
{
this.GameCamera.PositionZ += 1.0f;
}
this.GameCamera.UpdateView();
I would like to know how to make this camera translation of 90 degrees to surround one object that i placed in the screen.
To explain my self better about the camera movement here is a video on youtube that uses the exact movement that im trying to describe (see from 14 second)
http://www.youtube.com/watch?v=19mbKZ0I5u4
Assuming the camera in the video is orbiting the car, here is how you would accomplish that in XNA.
For the sake of readability, we'll just use vectors instead of their individual components. So 'target' means it's a Vector3 that includes TargetX, TargetY, & TargetZ. Same with the camera’s position. You can break X, Y, Z values out into fields and make Vector3s out of them to plug into this code if you want to later, but really it would be best for you to work at vector level instead of component level.
//To orbit the car (target)
cameraPosition = Vector3.Transform(cameraPosition – target, Matrix.CreateRotationY(0.01f)) + target;
this.ViewMatrix = Matrix.CreateLookAt(cameraPosition, target, Vector3.Up);
Since all matrix rotations act about an axis that intersects the world origin, to use a rotation matrix to rotate the camera around the car, the object of rotation has to be shifted such that the target (and thus the rotation axis) is located at the world origin. CameraPosition - target accomplishes that. Now cameraPosition can be rotated a little bit. Once cameraPosition is rotated a little bit, it needs to be sent back to the scene at hand, that's what the '+ target' at the end of the line is for.
The 0.01f can be adjusted to whatever rotation rate suits you.

Resources