我正在遵循谷歌教程。我想修改一下。我现在想做的是在屏幕上添加另一个AR对象(它将是一个箭头),并且我希望它总是显示在我的屏幕上,而不是像云锚一样附着在表面上。之后,我希望它指向云锚。我现在自己尝试了,但似乎离我想要的很远。有人能给我一些解决方案或我应该尝试哪种方式吗?谢谢
package com.google.ar.core.codelab.cloudanchor;
import android.app.AlertDialog;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.google.ar.core.Anchor;
import com.google.ar.core.ArCoreApk;
import com.google.ar.core.Camera;
import com.google.ar.core.Config;
import com.google.ar.core.Frame;
import com.google.ar.core.HitResult;
import com.google.ar.core.Plane;
import com.google.ar.core.Point;
import com.google.ar.core.Point.OrientationMode;
import com.google.ar.core.PointCloud;
import com.google.ar.core.Pose;
import com.google.ar.core.Session;
import com.google.ar.core.Trackable;
import com.google.ar.core.TrackingState;
import com.google.ar.core.codelab.cloudanchor.helpers.CameraPermissionHelper;
import com.google.ar.core.codelab.cloudanchor.helpers.CloudAnchorManager;
import com.google.ar.core.codelab.cloudanchor.helpers.ResolveDialogFragment;
import com.google.ar.core.codelab.cloudanchor.helpers.SnackbarHelper;
import com.google.ar.core.codelab.cloudanchor.helpers.StorageManager;
import com.google.ar.core.codelab.cloudanchor.helpers.TapHelper;
import com.google.ar.core.codelab.cloudanchor.helpers.TrackingStateHelper;
import com.google.ar.core.codelab.cloudanchor.rendering.BackgroundRenderer;
import com.google.ar.core.codelab.cloudanchor.rendering.ObjectRenderer;
import com.google.ar.core.codelab.cloudanchor.rendering.ObjectRenderer.BlendMode;
import com.google.ar.core.codelab.cloudanchor.rendering.PlaneRenderer;
import com.google.ar.core.codelab.cloudanchor.rendering.PointCloudRenderer;
import com.google.ar.core.codelab.cloudanchor.helpers.DisplayRotationHelper;
import com.google.ar.core.exceptions.CameraNotAvailableException;
import com.google.ar.core.exceptions.UnavailableApkTooOldException;
import com.google.ar.core.exceptions.UnavailableArcoreNotInstalledException;
import com.google.ar.core.exceptions.UnavailableDeviceNotCompatibleException;
import com.google.ar.core.exceptions.UnavailableSdkTooOldException;
import com.google.ar.core.exceptions.UnavailableUserDeclinedInstallationException;
import com.google.ar.sceneform.AnchorNode;
import com.google.ar.sceneform.Node;
import com.google.ar.sceneform.lullmodel.Vec2;
import com.google.ar.sceneform.math.Quaternion;
import com.google.ar.sceneform.math.Vector3;
import com.google.ar.sceneform.rendering.ModelRenderable;
import com.google.ar.sceneform.rendering.Renderable;
import com.google.ar.sceneform.rendering.ViewRenderable;
import com.google.ar.sceneform.ux.TransformableNode;
import java.io.IOException;
import java.io.PipedOutputStream;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* Main Fragment for the Cloud Anchors Codelab.
*
* <p>This is where the AR Session and the Cloud Anchors are managed.
*/
public class CloudAnchorFragment extends Fragment implements GLSurfaceView.Renderer {
private static final String TAG = CloudAnchorFragment.class.getSimpleName();
// Rendering. The Renderers are created here, and initialized when the GL surface is created.
private GLSurfaceView surfaceView;
private boolean installRequested;
private Session session;
private final SnackbarHelper messageSnackbarHelper = new SnackbarHelper();
private final CloudAnchorManager cloudAnchorManager = new CloudAnchorManager();
private DisplayRotationHelper displayRotationHelper;
private TrackingStateHelper trackingStateHelper;
private TapHelper tapHelper;
private final StorageManager storageManager = new StorageManager();
private final BackgroundRenderer backgroundRenderer = new BackgroundRenderer();
private final ObjectRenderer virtualObject = new ObjectRenderer();
private final ObjectRenderer virtualObjectShadow = new ObjectRenderer();
private final PlaneRenderer planeRenderer = new PlaneRenderer();
private final PointCloudRenderer pointCloudRenderer = new PointCloudRenderer();
//testing for the arrow
//Draw the AR object
private final ObjectRenderer virtualObject2 = new ObjectRenderer();
//Draw the Ar object shadow
private final ObjectRenderer virtualObjectShadow2 = new ObjectRenderer();
private final PlaneRenderer planeRenderer2 = new PlaneRenderer();
private final PointCloudRenderer pointCloudRenderer2 = new PointCloudRenderer();
// Temporary matrix allocated here to reduce number of allocations for each frame.
private final float[] anchorMatrix = new float[16];
private static final String SEARCHING_PLANE_MESSAGE = "Searching for surfaces...";
private final float[] andyColor = {139.0f, 195.0f, 74.0f, 255.0f};
private Button resolveButton;
private Anchor pointer = null;
Pose firstNODE;
@Nullable
private Anchor currentAnchor = null;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
tapHelper = new TapHelper(context);
trackingStateHelper = new TrackingStateHelper(requireActivity());
}
@Override
public View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// Inflate from the Layout XML file.
View rootView = inflater.inflate(R.layout.cloud_anchor_fragment, container, false);
GLSurfaceView surfaceView = rootView.findViewById(R.id.surfaceView);
this.surfaceView = surfaceView;
displayRotationHelper = new DisplayRotationHelper(requireContext());
surfaceView.setOnTouchListener(tapHelper);
surfaceView.setPreserveEGLContextOnPause(true);
surfaceView.setEGLContextClientVersion(2);
surfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); // Alpha used for plane blending.
surfaceView.setRenderer(this);
surfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
surfaceView.setWillNotDraw(false);
Button clearButton = rootView.findViewById(R.id.clear_button);
clearButton.setOnClickListener(v -> onClearButtonPressed());
resolveButton = rootView.findViewById(R.id.resolve_button);
resolveButton.setOnClickListener(v -> onResolveButtonPressed());
return rootView;
}
@Override
public void onResume() {
super.onResume();
if (session == null) {
Exception exception = null;
String message = null;
try {
switch (ArCoreApk.getInstance().requestInstall(requireActivity(), !installRequested)) {
case INSTALL_REQUESTED:
installRequested = true;
return;
case INSTALLED:
break;
}
// ARCore requires camera permissions to operate. If we did not yet obtain runtime
// permission on Android M and above, now is a good time to ask the user for it.
if (!CameraPermissionHelper.hasCameraPermission(requireActivity())) {
CameraPermissionHelper.requestCameraPermission(requireActivity());
return;
}
// Create the session.
session = new Session(requireActivity());
Config config = new Config(session);
config.setCloudAnchorMode(Config.CloudAnchorMode.ENABLED);
session.configure(config);
} catch (UnavailableArcoreNotInstalledException
| UnavailableUserDeclinedInstallationException e) {
message = "Please install ARCore";
exception = e;
} catch (UnavailableApkTooOldException e) {
message = "Please update ARCore";
exception = e;
} catch (UnavailableSdkTooOldException e) {
message = "Please update this app";
exception = e;
} catch (UnavailableDeviceNotCompatibleException e) {
message = "This device does not support AR";
exception = e;
} catch (Exception e) {
message = "Failed to create AR session";
exception = e;
}
if (message != null) {
messageSnackbarHelper.showError(requireActivity(), message);
Log.e(TAG, "Exception creating session", exception);
return;
}
}
// Note that order matters - see the note in onPause(), the reverse applies here.
try {
session.resume();
} catch (CameraNotAvailableException e) {
messageSnackbarHelper
.showError(requireActivity(), "Camera not available. Try restarting the app.");
session = null;
return;
}
surfaceView.onResume();
displayRotationHelper.onResume();
}
@Override
public void onPause() {
super.onPause();
if (session != null) {
// Note that the order matters - GLSurfaceView is paused first so that it does not try
// to query the session. If Session is paused before GLSurfaceView, GLSurfaceView may
// still call session.update() and get a SessionPausedException.
displayRotationHelper.onPause();
surfaceView.onPause();
session.pause();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] results) {
if (!CameraPermissionHelper.hasCameraPermission(requireActivity())) {
Toast.makeText(requireActivity(), "Camera permission is needed to run this application",
Toast.LENGTH_LONG)
.show();
if (!CameraPermissionHelper.shouldShowRequestPermissionRationale(requireActivity())) {
// Permission denied with checking "Do not ask again".
CameraPermissionHelper.launchPermissionSettings(requireActivity());
}
requireActivity().finish();
}
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
// Prepare the rendering objects. This involves reading shaders, so may throw an IOException.
try {
// Create the texture and pass it to ARCore session to be filled during update().
backgroundRenderer.createOnGlThread(getContext());
planeRenderer.createOnGlThread(getContext(), "models/trigrid.png");
pointCloudRenderer.createOnGlThread(getContext());
virtualObject.createOnGlThread(getContext(), "models/andy.obj", "models/andy.png");
virtualObject.setMaterialProperties(0.0f, 2.0f, 0.5f, 6.0f);
virtualObjectShadow
.createOnGlThread(getContext(), "models/andy_shadow.obj", "models/andy_shadow.png");
virtualObjectShadow.setBlendMode(BlendMode.Shadow);
virtualObjectShadow.setMaterialProperties(1.0f, 0.0f, 0.0f, 1.0f);
//Tutorial
//The arrow I want to test
//planeRenderer2.createOnGlThread(getContext(), "models/trigrid.png");
virtualObject2.createOnGlThread(getContext(), "models/arrow.obj", "models/color.png");
virtualObject2.setMaterialProperties(0.0f, 2.0f, 0.5f, 6.0f);
virtualObjectShadow2
.createOnGlThread(getContext(), "models/andy_shadow.obj", "models/andy_shadow.png");
virtualObjectShadow2.setBlendMode(BlendMode.Shadow);
virtualObjectShadow2.setMaterialProperties(1.0f, 0.0f, 0.0f, 1.0f);
//modify part
} catch (IOException e) {
Log.e(TAG, "Failed to read an asset file", e);
}
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
displayRotationHelper.onSurfaceChanged(width, height);
GLES20.glViewport(0, 0, width, height);
}
@Override
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 (session == null) {
return;
}
// Notify ARCore session that the view size changed so that the perspective matrix and
// the video background can be properly adjusted.
displayRotationHelper.updateSessionIfNeeded(session);
try {
session.setCameraTextureName(backgroundRenderer.getTextureId());
// 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 = session.update();
cloudAnchorManager.onUpdate();
Camera camera = frame.getCamera();
// Handle one tap per frame.
handleTap(frame, camera);
// If frame is ready, render camera preview image to the GL surface.
backgroundRenderer.draw(frame);
// Keep the screen unlocked while tracking, but allow it to lock when tracking stops.
trackingStateHelper.updateKeepScreenOnFlag(camera.getTrackingState());
// If not tracking, don't draw 3D objects, show tracking failure reason instead.
if (camera.getTrackingState() == TrackingState.PAUSED) {
messageSnackbarHelper.showMessage(
getActivity(), TrackingStateHelper.getTrackingFailureReasonString(camera));
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.
// The first three components are color scaling factors.
// The last one is the average pixel intensity in gamma space.
final float[] colorCorrectionRgba = new float[4];
frame.getLightEstimate().getColorCorrection(colorCorrectionRgba, 0);
// Visualize tracked points.
// Use try-with-resources to automatically release the point cloud.
try (PointCloud pointCloud = frame.acquirePointCloud()) {
pointCloudRenderer.update(pointCloud);
pointCloudRenderer.draw(viewmtx, projmtx);
}
// No tracking error at this point. If we didn't detect any plane, show searchingPlane message.
if (!hasTrackingPlane()) {
messageSnackbarHelper.showMessage(getActivity(), SEARCHING_PLANE_MESSAGE);
}
// Visualize planes.
planeRenderer.drawPlanes(
session.getAllTrackables(Plane.class), camera.getDisplayOrientedPose(), projmtx);
//Trying Draw
//Drawing
if (currentAnchor != null && currentAnchor.getTrackingState() == TrackingState.TRACKING) {
currentAnchor.getPose().toMatrix(anchorMatrix, 0);
// Update and draw the model and its shadow.
virtualObject.updateModelMatrix(anchorMatrix, 1f);
virtualObjectShadow.updateModelMatrix(anchorMatrix, 1f);
virtualObject.draw(viewmtx, projmtx, colorCorrectionRgba, andyColor);
virtualObjectShadow.draw(viewmtx, projmtx, colorCorrectionRgba, andyColor);
pointer.getPose().toMatrix(anchorMatrix, 0);
virtualObject2.updateModelMatrix(anchorMatrix, 1f);
virtualObjectShadow2.updateModelMatrix(anchorMatrix, 1f);
virtualObject2.draw(viewmtx, projmtx, colorCorrectionRgba, andyColor);
}
//Trying draw arrow
} catch (Throwable t) {
// Avoid crashing the application due to unhandled exceptions.
Log.e(TAG, "Exception on the OpenGL thread", t);
}
}
// Handle only one tap per frame, as taps are usually low frequency compared to frame rate.
private void handleTap(Frame frame, Camera camera) {
if (currentAnchor != null) {
return; // Do nothing if there was already an anchor.
}
MotionEvent tap = tapHelper.poll();
MotionEvent tap2 = tapHelper.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())
&& (PlaneRenderer.calculateDistanceToPlane(hit.getHitPose(), camera.getPose()) > 0))
|| (trackable instanceof Point
&& ((Point) trackable).getOrientationMode()
== OrientationMode.ESTIMATED_SURFACE_NORMAL)) {
// Hits are sorted by depth. Consider only closest hit on a plane or oriented point.
// 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.
currentAnchor = hit.createAnchor();
pointer = hit.createAnchor();
getActivity().runOnUiThread(() -> resolveButton.setEnabled(false));
messageSnackbarHelper.showMessage(getActivity(), "Now hosting anchor...");
cloudAnchorManager.hostCloudAnchor(session, currentAnchor, /* ttl= */ 300, this::onHostedAnchorAvailable);
break;
}
}
}
}
/**
* Checks if we detected at least one plane.
*/
private boolean hasTrackingPlane() {
for (Plane plane : session.getAllTrackables(Plane.class)) {
if (plane.getTrackingState() == TrackingState.TRACKING) {
return true;
}
}
return false;
}
private synchronized void onClearButtonPressed() {
// Clear the anchor from the scene.
cloudAnchorManager.clearListeners();
resolveButton.setEnabled(true);
currentAnchor = null;
}
private synchronized void onHostedAnchorAvailable(Anchor anchor) {
Anchor.CloudAnchorState cloudState = anchor.getCloudAnchorState();
if (cloudState == Anchor.CloudAnchorState.SUCCESS) {
int shortCode = storageManager.nextShortCode(getActivity());
storageManager.storeUsingShortCode(getActivity(), shortCode, anchor.getCloudAnchorId());
messageSnackbarHelper.showMessage(
getActivity(), "Cloud Anchor Hosted. Short code: " + shortCode);
currentAnchor = anchor;
} else {
messageSnackbarHelper.showMessage(getActivity(), "Error while hosting: " + cloudState.toString());
}
/*if (cloudState == Anchor.CloudAnchorState.SUCCESS) {
messageSnackbarHelper.showMessage(
getActivity(), "Cloud Anchor Hosted. ID: " + anchor.getCloudAnchorId());
currentAnchor = anchor;
} else {
messageSnackbarHelper.showMessage(getActivity(), "Error while hosting: " + cloudState.toString());
}*/
}
private synchronized void onResolveButtonPressed() {
ResolveDialogFragment dialog = ResolveDialogFragment.createWithOkListener(
this::onShortCodeEntered);
dialog.show(getActivity().getSupportFragmentManager(), "Resolve");
}
private synchronized void onShortCodeEntered(int shortCode) {
String cloudAnchorId = storageManager.getCloudAnchorId(getActivity(), shortCode);
if (cloudAnchorId == null || cloudAnchorId.isEmpty()) {
messageSnackbarHelper.showMessage(
getActivity(),
"A Cloud Anchor ID for the short code " + shortCode + " was not found.");
return;
}
resolveButton.setEnabled(false);
cloudAnchorManager.resolveCloudAnchor(
session,
cloudAnchorId,
anchor -> onResolvedAnchorAvailable(anchor, shortCode));
}
//Create Anchor
private synchronized void onResolvedAnchorAvailable(Anchor anchor, int shortCode) {
Anchor.CloudAnchorState cloudState = anchor.getCloudAnchorState();
if (cloudState == Anchor.CloudAnchorState.SUCCESS) {
messageSnackbarHelper.showMessage(getActivity(), "Cloud Anchor Resolved. Short code: " + shortCode);
currentAnchor = anchor;
} else {
messageSnackbarHelper.showMessage(
getActivity(),
"Error while resolving anchor with short code " + shortCode + ". Error: "
+ cloudState.toString());
resolveButton.setEnabled(true);
}
}
}
我的应用程序正在运行(我希望绿色箭头指向andy,但似乎它们彼此相连。)
按照本教程进行对象交互,如旋转、缩放和移动。
https://blog.yudiz.com/object-interaction-in-arcore-for-android/
本文向大家介绍three.js实现围绕某物体旋转,包括了three.js实现围绕某物体旋转的使用技巧和注意事项,需要的朋友参考一下 话不多说,请看代码: 可以拖动右上角观察变化 以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持呐喊教程!
我试着让两个立方体以不同的方式旋转。 为了设置旋转,我这样做。 在多维数据集类内部,我没有使用GL11.glLoadId相()来重置旋转,而是做了这样的事情。 这将重置每个轴的旋转。 数组“rot”保存x、y和z旋转,并通过多维数据集类中的这3种方法进行更新。 单独地,每个GL11.glRotatef(etc, etc, etc)和GL11.glRotatef(etc*-1.0f, etc, et
使用此代码执行asynctask之前,在progressdialog中显示旋转动画 ProgressDialog pDialog=ProgressDialog.show(getActivity(),null,null,true,false);pDialog.SetContentView(r.Layout.Loading); 这是xml
本文向大家介绍Javascript 多物体运动的实现,包括了Javascript 多物体运动的实现的使用技巧和注意事项,需要的朋友参考一下 我们先来看下之前的运动的代码,是否支持多物体运动,会出现怎么样的问题。 以下是Javascript 代码: 此时当鼠标移入到第一个div 时,他是正常运行的。但是如果现在又移动到第二个或者第三个div时候就会出现bug。 image 这个是什么原因呢? 看图可
本文向大家介绍Unity实现移动物体到鼠标点击位置,包括了Unity实现移动物体到鼠标点击位置的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Unity实现移动物体到鼠标点击位置的具体代码,供大家参考,具体内容如下 目的: 移动物体到鼠标点击处屏幕所对应的空间位置,并使物体正对着点击的对象,不能倾斜。 首先,需要获取点击屏幕所对应的空间位置,这可以通过先获取屏幕坐标,然后转成空间坐标
本文向大家介绍Unity3D实现人物移动示例,包括了Unity3D实现人物移动示例的使用技巧和注意事项,需要的朋友参考一下 一个是通过W、A、S、D来移动人物(示例一),另个是按屏幕上的按钮来移动人物(示例二)。很简单,只改了几行代码。 下面是“Assets”文件夹里面的资源。 示例一: 示例二 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。