I want to update my data associated with anchors that are updated each frame. How do I get the frame from ArSceneView for every frame?
The ArSceneView updates the ARCore Frame object before drawing the scene. You can access the frame by calling getArFrame() from a method registered with setOnUpdateListener().
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.sceneView = (ArSceneView) findViewById(R.id.scene_view);
sceneView.getScene().setOnUpdateListener((this::onSceneUpdate));
}
private void onSceneUpdate(FrameTime updatedTime) {
Frame frame = sceneView.getArFrame();
Collection<Anchor> updatedAnchors = frame.getUpdatedAnchors();
for (Anchor anchor : updatedAnchors) {
// Handle updated anchors...
}
}
Related
By using the code below, the textView is always face the camera. However, the textview object is keeping shaky all the time. Is that possible to add anchor with the code below to keep the textview object steady and static while rotating the phone?
I have tried to render a textview object in the scene and always facing to camera.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.sceneform_arfragment);
arFragment.getPlaneDiscoveryController().hide();
arFragment.getPlaneDiscoveryController().setInstructionView(null);
arFragment.getArSceneView().getPlaneRenderer().setEnabled(false);
node = new Node();
node.setParent(arFragment.getArSceneView().getScene());
node.setLocalPosition(new Vector3(0f, 0f, -1f));
ViewRenderable.builder()
.setView(this, R.layout.card)
.build()
.thenAccept(renderable -> {
node.setRenderable(renderable);
TextView textView = (TextView) renderable.getView();
textView.setText("Hello Sceneform");
});
arFragment.getArSceneView().getScene().addOnUpdateListener(this::onSceneUpdate);}
private void onSceneUpdate(FrameTime frameTime) {
arFragment.onUpdate(frameTime);
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);
}
My expected result is the textview object facing to camera without shaky .
I am developing an AR app that allow you to move a ball by swiping the screen. I am able to detect the swipe but I am unsure how I can move the ball. so I want the ball to move from one position to another based on how long the screen is swipe. so when you swipe the ball is moved like been thrown.
Can any one help me out with this. thanks
To move a renderable, you can delete it at the old position and place it at the new one. Here is an example - this is button driven rather than swipe driven, but the movement can be used similarly. The code below works on the currently selected anchorNode - i.e. the user can select different nodes to move.
//Add a listener for the left button
FloatingActionButton leftButtom = findViewById(R.id.left_button);
leftButtom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Move the anchor left
Log.d(TAG,"Moving anchor left");
if (currentSelectedAnchorNode != null) {
//Get the current Pose and transform it then set a new anchor at the new pose
Session session = arFragment.getArSceneView().getSession();
Anchor currentAnchor = currentSelectedAnchorNode.getAnchor();
Pose oldPose = currentAnchor.getPose();
Pose newPose = oldPose.compose(Pose.makeTranslation(-0.05f,0,0));
currentSelectedAnchorNode = moveRenderable(currentSelectedAnchorNode, newPose);
}
}
});
private AnchorNode moveRenderable(AnchorNode markAnchorNodeToMove, Pose newPoseToMoveTo) {
//Move a renderable to a new pose
if (markAnchorNodeToMove != null) {
arFragment.getArSceneView().getScene().removeChild(markAnchorNodeToMove);
anchorNodeList.remove(markAnchorNodeToMove);
} else {
Log.d(TAG,"moveRenderable - markAnchorNode was null");
return null;
}
Frame frame = arFragment.getArSceneView().getArFrame();
Session session = arFragment.getArSceneView().getSession();
Anchor markAnchor = session.createAnchor(newPoseToMoveTo.extractTranslation());
AnchorNode newMarkAnchorNode = new AnchorNode(markAnchor);
newMarkAnchorNode.setRenderable(andyRenderable);
newMarkAnchorNode.setParent(arFragment.getArSceneView().getScene());
anchorNodeList.add(newMarkAnchorNode);
return newMarkAnchorNode;
}
I am trying to create a app that uses skiasharp on an overlay for the camera on iPhone (native). My camera stream appears nicely but no overlay. the initial viewcontroller that creates the stream looks like:
public async override void ViewDidLoad()
{
base.ViewDidLoad();
await AuthorizeCameraUse();
imagePicker = new UIImagePickerController();
// set our source to the camera
imagePicker.SourceType = UIImagePickerControllerSourceType.Camera;
// set
imagePicker.MediaTypes = new string[] { "public.image" };
imagePicker.CameraOverlayView = new CameraOverlayView();
imagePicker.ModalPresentationStyle = UIModalPresentationStyle.CurrentContext;
. . .
my CameraOverlayView looks like:
public class CameraOverlayView :SKCanvasView
{
public CameraOverlayView() : base()
{
Initialize();
}
public CameraOverlayView(CGRect frame) : base(frame) {
Initialize();
}
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.Red,
StrokeWidth = 25
};
protected void Initialize()
{
this.PaintSurface += CameraOverlayView_PaintSurface;
//using (var surface = SKSurface.Create( 640, 480, SKColorType.Rgba8888, SKAlphaType.Premul))
//{
// SKCanvas myCanvas = surface.Canvas;
// myCanvas.DrawCircle(300, 300, 100, paint);
// // Your drawing code goes here.
//}
}
private void CameraOverlayView_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
var surface = e.Surface;
// then we get the canvas that we can draw on
var canvas = surface.Canvas;
// clear the canvas / view
canvas.Clear(SKColors.White);
// DRAWING SHAPES
// create the paint for the filled circle
var circleFill = new SKPaint
{
IsAntialias = true,
Style = SKPaintStyle.Fill,
Color = SKColors.Blue
};
// draw the circle fill
canvas.DrawCircle(100, 100, 40, circleFill);
}
}
my Paint event is never fired , if I run this code in simple example it does.
thanks to Russ Fustino help it turns out I was not using the CameraOverlayView (CGRect frame) : base (frame) constructor and because of that the DrawInSurface overload is not called.
Nothing to draw into. when I did this the paint event fired.
I'm referring to WatchFace sample for Android Wear. The example DigitialWatchFaceWearableConfigActivity uses a color picker to change the Watch Face background. I want to use an image background on the circledimageview. What happens is the image remains the same size in both center and non-centered positions and only the black circle changes size. What do I need to implement in onCenterPosition and onNonCenterPosition in order to shrink and grow the background image?
#Override
public void onCenterPosition(boolean animate) {
if (animate) {
mShrinkAnimator.cancel();
if (!mExpandAnimator.isRunning()) {
mExpandCircleAnimator.setFloatValues(mColor.getCircleRadius(), mExpandCircleRadius);
mExpandLabelAnimator.setFloatValues(mLabel.getAlpha(), EXPAND_LABEL_ALPHA);
mExpandAnimator.start();
}
} else {
mExpandAnimator.cancel();
mColor.setCircleRadius(mExpandCircleRadius);
mLabel.setAlpha(EXPAND_LABEL_ALPHA);
}
}
#Override
public void onNonCenterPosition(boolean animate) {
if (animate) {
mExpandAnimator.cancel();
if (!mShrinkAnimator.isRunning()) {
mShrinkCircleAnimator.setFloatValues(mColor.getCircleRadius(), mShrinkCircleRadius);
mShrinkLabelAnimator.setFloatValues(mLabel.getAlpha(), SHRINK_LABEL_ALPHA);
mShrinkAnimator.start();
}
} else {
mShrinkAnimator.cancel();
mColor.setCircleRadius(mShrinkCircleRadius);
mLabel.setAlpha(SHRINK_LABEL_ALPHA);
}
}
You can use following simple code of ScaleX and ScaleY to manipulate background of onCenterPosition and onNonCenterPosition,
#Override
public void onCenterPosition(boolean b) {
image.setAlpha(1f);
image.setBackgroundResource(R.drawable.blue_oval); // This one is needed if you want to change background on center position
image.setScaleX(1.0f);
image.setScaleY(1.0f);
text.setScaleY(1.0f);
text.setAlpha(1f);
}
#Override
public void onNonCenterPosition(boolean b) {
image.setAlpha(0.5f);
image.setBackgroundResource(R.drawable.gray_oval); // This one is needed if you want to change background on non center position
image.setScaleX(0.8f);
image.setScaleY(0.8f);
text.setScaleY(0.8f);
text.setAlpha(0.5f);
}
I want to resize a UIView (e.g. TextField, UIGridView, ...) after the keyboard appears. Getting the appropriate events isn't the issue. I really stock by calculating the delta to shrink my view depending on the height of the keyboard.
If I have my iPad in front of me in portrait mode all calculations happens as expected. But If my device is in landscape mode or upside down, I'm really struggling getting the right dimensions! Some view frames/bounds aren't converted (in landscape mode is the height still higher then its width). Other views are translated depending if I've started my app already in landscape mode. The next challenge is working with consistent size measures. Sometimes the dimensions are like the real pixels (for a new iPad 2048) sometimes the scale factor isn't considered (for a new iPad 1024).
Any other idea how to the the correct frame size? Or are there any helpers which recognise the current orientation and provides me with the effective sizes?
My current code to achieve my expected behaviour is like this:
MyViewController
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
// My code...
AppDelegate.CurrentDelegate.KeyboardAppeared += KeyboardAppeared;
AppDelegate.CurrentDelegate.KeyboardDisappeared += KeyboardDisappeared;
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
AppDelegate.CurrentDelegate.KeyboardAppeared -= KeyboardAppeared;
AppDelegate.CurrentDelegate.KeyboardDisappeared -= KeyboardDisappeared;
}
private void KeyboardAppeared(object sender, KeyboardEventArgs e)
{
if (_keyboardButton != null)
_keyboardButton.Enabled = true;
var frame = LayoutHelper.RectangleForKeyboardAppearance(_textField, View.Window, e.Height);
LayoutHelper.ResizeViewForKeyboard(_textField, frame);
}
private void KeyboardDisappeared(object sender, EventArgs e)
{
if (_keyboardButton != null)
_keyboardButton.Enabled = false;
var frame = View.Bounds;
LayoutHelper.ResizeViewForKeyboard(_textField, frame);
}
MyHelperClass
public static RectangleF RectangleForKeyboardAppearance(UIView view, float windowHeight, float keyboardHeight)
{
var topOfKeyboard = windowHeight - keyboardHeight; // Obere linke Ecke der Tastatur auf den Bildschirm bezogen
var viewHeightWindow1 = view.ConvertPointFromView(new PointF(0, topOfKeyboard), null);
var frame = new RectangleF(view.Frame.X, view.Frame.Y, view.Frame.Width, (viewHeightWindow1.Y + view.Bounds.Y));
return frame;
}
public static void ResizeViewForKeyboard(UIView view, RectangleF frame)
{
UIView.BeginAnimations("viewMovementForKeyboard");
UIView.SetAnimationBeginsFromCurrentState(true);
UIView.SetAnimationDuration(0.3f);
view.Frame = frame;
UIView.CommitAnimations();
}