Medición de distancia de cámara AR
– UnityAssets3Free
hola , me llamo kein y aqui os traigo
esta nueva pregunta
Tengo una pregunta sobre AR (Realidad Aumentada).
Quiero saber cómo mostrar información de distancia (como centermeter…) entre la cámara AR y el objeto de destino. (usando un teléfono inteligente)
¿Puedo hacer esto en Unity? ¿Debo usar la Fundación AR? y con ARcore? ¿Cómo escribir código?
Traté de encontrar algún código relativo (abajo) pero parece que solo imprime información entre objeto y objeto, nada sobre «cámara AR»…
var other : Transform;
if (other)
var dist = Vector3.Distance(other.position, transform.position);
print ("Distance to other: " + dist);
¡Gracias otra vez!
5 respuestas 5
Aquí se explica cómo hacerlo Unity y AR Foundation 4.1. Este script de ejemplo imprime la profundidad en metros en el centro de la textura de profundidad y funciona con ARCore y ARKit:
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
public class GetDepthOfCenterPixel : MonoBehaviour {
// assign this field in inspector
[SerializeField] AROcclusionManager manager = null;
IEnumerator Start() {
while (ARSession.state < ARSessionState.SessionInitializing)
// manager.descriptor.supportsEnvironmentDepthImage will return a correct value if ARSession.state >= ARSessionState.SessionInitializing
yield return null;
if (!manager.descriptor.supportsEnvironmentDepthImage)
Debug.LogError("!manager.descriptor.supportsEnvironmentDepthImage");
yield break;
while (true)
if (manager.TryAcquireEnvironmentDepthCpuImage(out var cpuImage) && cpuImage.valid)
using (cpuImage)
Assert.IsTrue(cpuImage.planeCount == 1);
var plane = cpuImage.GetPlane(0);
var dataLength = plane.data.Length;
var pixelStride = plane.pixelStride;
var rowStride = plane.rowStride;
Assert.AreEqual(0, dataLength % rowStride, "dataLength should be divisible by rowStride without a remainder");
Assert.AreEqual(0, rowStride % pixelStride, "rowStride should be divisible by pixelStride without a remainder");
var numOfRows = dataLength / rowStride;
var centerRowIndex = numOfRows / 2;
var centerPixelIndex = rowStride / (pixelStride * 2);
var centerPixelData = plane.data.GetSubArray(centerRowIndex * rowStride + centerPixelIndex * pixelStride, pixelStride);
var depthInMeters = convertPixelDataToDistanceInMeters(centerPixelData.ToArray(), cpuImage.format);
print($"depth texture size: (cpuImage.width,cpuImage.height), pixelStride: pixelStride, rowStride: rowStride, pixel pos: (centerPixelIndex, centerRowIndex), depthInMeters of the center pixel: depthInMeters");
yield return null;
}
float convertPixelDataToDistanceInMeters(byte[] data, XRCpuImage.Format format)
switch (format)
case XRCpuImage.Format.DepthUint16:
return BitConverter.ToUInt16(data, 0) / 1000f;
case XRCpuImage.Format.DepthFloat32:
return BitConverter.ToSingle(data, 0);
default:
throw new Exception($"Format not supported: format");
}
También estoy trabajando en la imagen de profundidad AR y la idea básica es:
- obtener una imagen usando API, normalmente está en formato Depth16;
- dividir la imagen en shortbuffers, como Depth16 significa que cada píxel tiene 16 bits de largo;
- Obtener el valor de la distanciaque se almacena en los 13 bits inferiores de cada shortbuffer, puede hacer esto haciendo (shortbuffer & 0x1ff) para que pueda tener la distancia para cada píxel, normalmente en milímetros.
Al hacer esto a través de todos los píxeles, puede crear una imagen de profundidad y almacenarla como jpg u otros formatos, aquí está el código de ejemplo del uso de AR Engine para obtener la distancia:
try (Image depthImage = arFrame.acquireDepthImage())
int imwidth = depthImage.getWidth();
int imheight = depthImage.getHeight();
Image.Plane plane = depthImage.getPlanes()[0];
ShortBuffer shortDepthBuffer = plane.getBuffer().asShortBuffer();
File sdCardFile = Environment.getExternalStorageDirectory();
Log.i(TAG, "The storage path is " + sdCardFile);
File file = new File(sdCardFile, "RawdepthImage.jpg");
Bitmap disBitmap = Bitmap.createBitmap(imwidth, imheight, Bitmap.Config.RGB_565);
for (int i = 0; i < imheight; i++)
for (int j = 0; j < imwidth; j++)
int index = (i * imwidth + j) ;
shortDepthBuffer.position(index);
short depthSample = shortDepthBuffer.get();
short depthRange = (short) (depthSample & 0x1FFF);
//If you only want the distance value, here it is
byte value = (byte) depthRange;
byte value = (byte) depthRange ;
disBitmap.setPixel(j, i, Color.rgb(value, value, value));
//I rotate the image for a better view
Matrix matrix = new Matrix();
matrix.setRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(disBitmap, 0, 0, imwidth, imheight, matrix, true);
try
FileOutputStream out = new FileOutputStream(file);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
MainActivity.num++;
catch (Exception e)
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
}
Si bien las respuestas son excelentes, pueden ser demasiado complicadas y avanzadas para esta pregunta, que se trata de la distancia entre la ARCamera y otro objeto en lugar de la profundidad de los píxeles y su oclusión.
transform.position
da la posición de cualquier objeto del juego al que adjunte el script en la jerarquía. Entonces, adjunte el script al objeto ARCamera. Y obviamente, other
debe ser el objeto de destino.
Alternativamente, puede obtener referencias a los dos objetos del juego usando variables de observación o GetComponent
/raycasting debe estar actualizándose/ Ray ray = new Ray(cam.transform.position, cam.transform.forward); if (Physics.Raycast(ray, out info, 50f, layerMaskAR))//rango de detección de 50 metros bcs de 50f distance.text = string.Format(«0: 1:N2m», info .collider .nombre, info.distancia, 2);
Esta es la función que hace lo que necesita con ofc en el elemento UI txt y en la capa asignada al objeto/prefabricado. int capaMáscaraAR = 1 << 6; (aquí se ve que 6 bcs 6th es mi capa personalizada, «layerMaskAR»,) Esta es la clasificación de rayos para objetos en los que solo se ignora este objeto de capa en reposo (si no desea ignorar nada, elimine la máscara de capa de raycast e imprimirá el nombre de cualquier cosa con colisionador).
Totalmente factible por esta línea de código
Vector3.Distance(gameObject.transform.position, Camera.main.transform.position)
nota: si aun no se resuelve tu pregunta por favor dejar un comentario y pronto lo podremos de nuevo , muchas gracias
sin mas,espero que te funcione