Sceneform ARCore Android studio - android-studio-3.0

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;
}

Related

Draw line instead of rendering Anchor in arcore

I am new to AR, I am working on an APP using ARCore using this one AR-REMOTE-SUPPORT
When I am drawing it from my screen it is creating default android anchor, I want line instead of default android anchor.
How can I achieve this.
here is the function which is placing Anchors on the screen
public void onDrawFrame(GL10 gl) {
// Clear screen to notify driver it should not load any pixels from previous frame.
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
if (mSession == null) {
return;
}
// Notify ARCore session that the view size changed so that the perspective matrix and
// the video background can be properly adjusted.
mDisplayRotationHelper.updateSessionIfNeeded(mSession);
try {
// Obtain the current frame from ARSession. When the configuration is set to
// UpdateMode.BLOCKING (it is by default), this will throttle the rendering to the
// camera framerate.
Frame frame = mSession.update();
Camera camera = frame.getCamera();
// Handle taps. Handling only one tap per frame, as taps are usually low frequency
// compared to frame rate.
MotionEvent tap = queuedSingleTaps.poll();
if (tap != null && camera.getTrackingState() == TrackingState.TRACKING) {
for (HitResult hit : frame.hitTest(tap)) {
// Check if any plane was hit, and if it was hit inside the plane polygon
Trackable trackable = hit.getTrackable();
// Creates an anchor if a plane or an oriented point was hit.
if ((trackable instanceof Plane && ((Plane) trackable).isPoseInPolygon(hit.getHitPose()))
|| (trackable instanceof Point
&& ((Point) trackable).getOrientationMode()
== Point.OrientationMode.ESTIMATED_SURFACE_NORMAL)) {
// Hits are sorted by depth. Consider only closest hit on a plane or oriented point.
// Cap the number of objects created. This avoids overloading both the
// rendering system and ARCore.
if (anchors.size() >= 250) {
anchors.get(0).detach();
anchors.remove(0);
}
// Adding an Anchor tells ARCore that it should track this position in
// space. This anchor is created on the Plane to place the 3D model
// in the correct position relative both to the world and to the plane.
anchors.add(hit.createAnchor());
break;
}
}
}
// Draw background.
mBackgroundRenderer.draw(frame);
// If not tracking, don't draw 3d objects.
if (camera.getTrackingState() == TrackingState.PAUSED) {
return;
}
// Get projection matrix.
float[] projmtx = new float[16];
camera.getProjectionMatrix(projmtx, 0, 0.1f, 100.0f);
// Get camera matrix and draw.
float[] viewmtx = new float[16];
camera.getViewMatrix(viewmtx, 0);
// Compute lighting from average intensity of the image.
final float lightIntensity = frame.getLightEstimate().getPixelIntensity();
if (isShowPointCloud()) {
// Visualize tracked points.
PointCloud pointCloud = frame.acquirePointCloud();
mPointCloud.update(pointCloud);
mPointCloud.draw(viewmtx, projmtx);
// Application is responsible for releasing the point cloud resources after
// using it.
pointCloud.release();
}
// Check if we detected at least one plane. If so, hide the loading message.
if (mMessageSnackbar != null) {
for (Plane plane : mSession.getAllTrackables(Plane.class)) {
if (plane.getType() == Plane.Type.HORIZONTAL_UPWARD_FACING
&& plane.getTrackingState() == TrackingState.TRACKING) {
hideLoadingMessage();
break;
}
}
}
if (isShowPlane()) {
// Visualize planes.
mPlaneRenderer.drawPlanes(
mSession.getAllTrackables(Plane.class), camera.getDisplayOrientedPose(), projmtx);
}
// Visualize anchors created by touch.
float scaleFactor = 1.0f;
for (Anchor anchor : anchors) {
if (anchor.getTrackingState() != TrackingState.TRACKING) {
continue;
}
// Get the current pose of an Anchor in world space. The Anchor pose is updated
// during calls to session.update() as ARCore refines its estimate of the world.
anchor.getPose().toMatrix(mAnchorMatrix, 0);
// Update and draw the model and its shadow.
mVirtualObject.updateModelMatrix(mAnchorMatrix, mScaleFactor);
//mVirtualObjectShadow.updateModelMatrix(mAnchorMatrix, scaleFactor);
mVirtualObject.draw(viewmtx, projmtx, lightIntensity);
mVirtualObjectShadow.draw(viewmtx, projmtx, lightIntensity);
}
sendARViewMessage();
} catch (Throwable t) {
// Avoid crashing the application due to unhandled exceptions.
Log.e(TAG, "Exception on the OpenGL thread", t);
}
}
Any help would be appreciated
TIA
One simple way to draw a line in ARCore is to create it between two anchor points.
The line itself is generally a 3D object also.
Here is a tested working example, based on the nice approach in this answer: https://stackoverflow.com/a/52816504/334402
private void drawLine(AnchorNode node1, AnchorNode node2) {
//Draw a line between two AnchorNodes (adapted from https://stackoverflow.com/a/52816504/334402)
Log.d(TAG,"drawLine");
Vector3 point1, point2;
point1 = node1.getWorldPosition();
point2 = node2.getWorldPosition();
//First, find the vector extending between the two points and define a look rotation
//in terms of this Vector.
final Vector3 difference = Vector3.subtract(point1, point2);
final Vector3 directionFromTopToBottom = difference.normalized();
final Quaternion rotationFromAToB =
Quaternion.lookRotation(directionFromTopToBottom, Vector3.up());
MaterialFactory.makeOpaqueWithColor(getApplicationContext(), new Color(0, 255, 244))
.thenAccept(
material -> {
/* Then, create a rectangular prism, using ShapeFactory.makeCube() and use the difference vector
to extend to the necessary length. */
Log.d(TAG,"drawLine insie .thenAccept");
ModelRenderable model = ShapeFactory.makeCube(
new Vector3(.01f, .01f, difference.length()),
Vector3.zero(), material);
/* Last, set the world rotation of the node to the rotation calculated earlier and set the world position to
the midpoint between the given points . */
Anchor lineAnchor = node2.getAnchor();
nodeForLine = new Node();
nodeForLine.setParent(node1);
nodeForLine.setRenderable(model);
nodeForLine.setWorldPosition(Vector3.add(point1, point2).scaled(.5f));
nodeForLine.setWorldRotation(rotationFromAToB);
}
);
}
You can see the full source here: https://github.com/mickod/LineView

How to place an object at specific location in ARcore?

I am trying to place an object at specific location without tapping, Is there any direct method to place an object at real world location.
Certainly you could do this.
Search flat surface.
2.override onUpdate method.
loop through trackables and than your model has been projected without tapping.
i just give you an idea, how onUpdate method is look like, this is pseudo code
frame = arFragment.getArSceneView().getArFrame();
if (frame != null) {
//get the trackables
Iterator<Plane> var3 = frame.getUpdatedTrackables(Plane.class).iterator();
while (var3.hasNext()) {
Plane plane = var3.next();
//If a plane has been detected & is being tracked by ARCore
if (plane.getTrackingState() == TrackingState.TRACKING) {
//Hide the plane discovery helper animation
arFragment.getPlaneDiscoveryController().hide();
//Get all added anchors to the frame
Iterator<Anchor> iterableAnchor = frame.getUpdatedAnchors().iterator();
//place the first object only if no previous anchors were added
if (!iterableAnchor.hasNext()) {
//Perform a hit test at the center of the screen to place an object without tapping
List<HitResult> hitTest = frame.hitTest(getScreenVector3().x, getScreenVector3().y);
//iterate through all hits
Iterator<HitResult> hitTestIterator = hitTest.iterator();
while (hitTestIterator.hasNext()) {
HitResult hitResult = hitTestIterator.next();
//Create an anchor at the plane hit
Anchor modelAnchor = plane.createAnchor(hitResult.getHitPose());
//Attach a node to this anchor with the scene as the parent
anchorNode = new AnchorNode(modelAnchor);
anchorNode.setParent(arFragment.getArSceneView().getScene());
**create a new TranformableNode that will carry our model**
}
}
}
}
}
}
You can add the node directly to the scene:
node.localPosition = Vector3(x, y, z)
arSceneView.scene.addChild(node)

ARCore Unity: How do I Start and Stop Plane Detection on Command?

I am creating an app with ARCore, but I don't want ARCore to look for planes as soon as the app starts. Instead, I want the plane detection to begin when I hit a button in my app. It would also be great if I could stop the plane detection on command as well.
Does anyone know how I could do start and stop the ARCore plane detection on command?
I am building the app in Unity.
Thanks so much in advance!
on ARPlaneVisualizer.cs, there is this code
void OnEnable()
{
m_PlaneLayer = LayerMask.NameToLayer ("ARGameObject");
ARInterface.planeAdded += PlaneAddedHandler;
ARInterface.planeUpdated += PlaneUpdatedHandler;
ARInterface.planeRemoved += PlaneRemovedHandler;
HidePlane(true);
}
void OnDisable()
{
ARInterface.planeAdded -= PlaneAddedHandler;
ARInterface.planeUpdated -= PlaneUpdatedHandler;
ARInterface.planeRemoved -= PlaneRemovedHandler;
HidePlane(false);
}
you can use the OnEnable() code as start tracking and OnDisable() code to stop tracking.
Initially create bool to restrict surface detection code and inatially make bool to true.
bool isSurfaceDetected = true;
if (isSurfaceDetected) {
Session.GetTrackables<TrackedPlane> (_newPlanes, TrackableQueryFilter.New);
// Iterate over planes found in this frame and instantiate corresponding GameObjects to visualize them.
foreach (var curPlane in _newPlanes) {
// Instantiate a plane visualization prefab and set it to track the new plane. The transform is set to
// the origin with an identity rotation since the mesh for our prefab is updated in Unity World
// coordinates.
var planeObject = Instantiate (plane, Vector3.zero, Quaternion.identity,
transform);
planeObject.GetComponent<DetectedPlaneVisualizer> ().Initialize (curPlane);
// Debug.Log ("test....");
// Apply a random color and grid rotation.
// planeObject.GetComponent<Renderer>().material.SetColor("_GridColor", new Color(Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f)));
// planeObject.GetComponent<Renderer>().material.SetFloat("_UvRotation", Random.Range(0.0f, 360.0f));
//
}
Create a stop button in canvas and attatch below method
public void StopTrack()
{
// Make isSurfaceDetected to false to disable plane detection code
isSurfaceDetected = false;
// Tag DetectedPlaneVisualizer prefab to Plane(or anything else)
GameObject[] anyName = GameObject.FindGameObjectsWithTag ("Plane");
// In DetectedPlaneVisualizer we have multiple polygons so we need to loop and diable DetectedPlaneVisualizer script attatched to that prefab.
for (int i = 0; i < anyName.Length; i++)
{
anyName[i].GetComponent<DetectedPlaneVisualizer> ().enabled = false;
}
}
Make sure that stop button method is in ARController

Dealing with game cursor, not windows cursor

Earlier, I had an issue with my Windows cursor being uncoordinated with the game and asked here how I could solve this. A member suggested me to hide the Windows cursor and create a custom game cursor, so I did this. However, a new problem occurred.
My game cursor is usually offset to the right of the Windows mouse, so when I want to move the game cursor to the left side of the window and click my left mouse button, it causes a disturbance to the game, such as bringing an application in the background to the top.
Here is a picture of what I mean: http://i.imgur.com/nChwToh.png
As you can see, the game cursor is offset to the right of the Windows cursor, and if I use game cursor to click on something on the left side of the window, the application in the background (Google Chrome in this case), will be brought up to the front, causing disturbance to the game.
Is there anything I can do to use my game cursor without any disturbances?
I have just tried to move everything out of their classes, all into the main Game class.
This fixed the problem, but does not give me an answer to WHY this happens.
The code is exactly the same, it's just organized to separate classes.
So, does anyone know why this is?
Why is using object-oriented programming instead of putting everything in the game class going mess up my mouse coordination and stuff?
Normally, you would have a texture for you in-game cursor where, for instance, the pixel at [16,16] is where you are "aiming" (the center of a crosshair, for instance). What you owuld to to draw this centered on the mouse is to use Mouse.GetState() to get the position, and then offset the drawing of your mouse-texture by the negative of the "center" of the "aim"-point.
so let's say we make a custom Mouse-Class:
public class GameMouse
{
public Vector2 Position = Vector2.Zero;
private Texture2D Texture { get; set; }
private Vector2 CenterPoint = Vector2.Zero;
public MouseState State { get; set; }
public MouseState PreviousState { get; set; }
//Returns true if left button is pressed (true as long as you hold button)
public Boolean LeftDown
{
get { return State.LeftButton == ButtonState.Pressed; }
}
//Returns true if left button has been pressed since last update (only once per click)
public Boolean LeftPressed
{
get { return (State.LeftButton == ButtonState.Pressed) &&
(PreviousState.LeftButton == ButtonState.Released); }
}
//Initialize texture and states.
public GameMouse(Texture2D texture, Vector2 centerPoint)
{
Texture = texture;
CenterPoint = centerPoint;
State = Mouse.GetState();
//Calling Update will set previousstate and update Position.
Update();
}
public void Update()
{
PreviousState = State;
State = Mouse.GetState();
Position.X = State.X;
Position.Y = State.Y;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Begin();
spriteBatch.Draw(Texture, Position - CenterPoint, Color.White);
spriteBatch.End();
}
}

Actionscript 3, rotate object on drag

I have an object I need to rotate by clicking and dragging. Following some AS2 code I got the object to rotate a bit every time the mouse is clicked, but can't get it to work with drag.
needle.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag_2);
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop_2);
function fl_ClickToDrag_2(event:MouseEvent):void
{
var angle = Math.atan2(mouseY-needle.y,mouseX-needle.x);
// apply rotation to handle by converting angle into degrees
needle.rotation = angle*180/Math.PI;
// rotate the grip opposite the handle so it won't rotate along with it
//this.grip._rotation = -this._rotation;
}
function fl_ReleaseToDrop_2(event:MouseEvent):void
{
needle.stopDrag();
}
Well the problem I see is that the MOUSE_DOWN event only fires once per click, so you only run the code in the handler once.
There could be a better way than this but this is how I'd consider doing it:
EDITED FOR DETAIL:
public class Test extends MovieClip {
private var n:Needle;
public function Test() {
// constructor code
n = new Needle();
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseDownF,false,0,true);
stage.addEventListener(MouseEvent.MOUSE_UP,mouseUpF,false,0,true);
n.x = stage.stageWidth/2; //center needle on stage
n.y = stage.stageHeight/2;
addChild(n); //add needle to stage
}
public function mouseDownF(e:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_MOVE,rotate,false,0,true);
}
public function rotate(e:MouseEvent):void {
var angle:Number = Math.atan2(mouseY - n.y,mouseX - n.x); //get angle in radians (pythagoras)
angle = angle * 180/Math.PI -90; //convert to degrees , the 90 is to have it point to the mouse
n.rotation = angle; //rotate
}
public function mouseUpF(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_MOVE,rotate);
}
}
So when the user clicks down (mouseDown) it activates an event listener that fires the rotate handler every time the mouse moves. When the user lets go of the click the event listener is destroyed. The false,0,true); when adding the event listener is to make it a weakly referenced listener so that it gets collected by the garbage collector and doesn't just sit in memory taking up space forever.

Resources