Skip to content

Commit

Permalink
Added handling of anchor events in AKSceneTracker6DOF
Browse files Browse the repository at this point in the history
Summary:
Now, using the anchor event function to decide whether a mesh anchor has changed or not.
Before, we used the number of triangles of a mesh to make this decision.

Reviewed By: enpe

Differential Revision:
D65504172

Privacy Context Container: L1191897

fbshipit-source-id: fac76e642ce51257632086a75499480a8ac4581d
  • Loading branch information
janherling authored and facebook-github-bot committed Nov 6, 2024
1 parent a7707da commit 5936a1d
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 82 deletions.
41 changes: 39 additions & 2 deletions impl/ocean/devices/arkit/AKSceneTracker6DOF.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "ocean/devices/arkit/ARKit.h"
#include "ocean/devices/arkit/AKDevice.h"

#include "ocean/base/StringApple.h"

#include "ocean/devices/SceneTracker6DOF.h"
#include "ocean/devices/VisualTracker.h"

Expand Down Expand Up @@ -41,6 +43,24 @@ class OCEAN_DEVICES_ARKIT_EXPORT AKSceneTracker6DOF :
*/
using IdentifierMap = std::unordered_map<std::string, Index32>;

/**
* Helper class implementing a hash function for ARMeshAnchor.
*/
struct ARMeshAnchorHash
{
/**
* Hash function returning a hash value for an ARMeshAnchor object
* @param anchor The anchor for which the hash will be returned
* @return The resulting hash value
*/
inline size_t operator()(const ARMeshAnchor* anchor) const;
};

/**
* Definition of an unordered set holding ARMeshAnchor objects.
*/
using ARMeshAnchorSet = std::unordered_set<ARMeshAnchor*, ARMeshAnchorHash>;

public:

/**
Expand Down Expand Up @@ -92,6 +112,18 @@ class OCEAN_DEVICES_ARKIT_EXPORT AKSceneTracker6DOF :
*/
void onNewSample(const HomogenousMatrix4& world_T_camera, SharedSceneElements&& sceneElements, const Timestamp& timestamp, Metadata&& metadata);

/**
* Event function for added anchors.
* @see AKDevice::onAddedAnchors().
*/
void onAddedAnchors(const ARAnchors& anchors) override;

/**
* Event function for updated anchors.
* @see AKDevice::onUpdateAnchors().
*/
void onUpdateAnchors(const ARAnchors& anchors) override;

/**
* Returns the name of this tracker.
* @return The trackers's name
Expand Down Expand Up @@ -151,10 +183,15 @@ class OCEAN_DEVICES_ARKIT_EXPORT AKSceneTracker6DOF :
/// The counter for unique mesh ids.
unsigned int meshIdCounter_ = 0u;

/// The number of triangles each mesh currently has.
std::vector<size_t> numberTriangles_;
/// The set holding all updated ARMeshAnchor objects.
ARMeshAnchorSet updatedMeshAnchors_;
};

inline size_t AKSceneTracker6DOF::ARMeshAnchorHash::operator()(const ARMeshAnchor* anchor) const
{
return std::hash<std::string>()(StringApple::toUTF8(anchor.identifier.UUIDString));
}

inline std::string AKSceneTracker6DOF::deviceNameAKSceneTracker6DOF()
{
return std::string("ARKit 6DOF Scene Tracker");
Expand Down
157 changes: 77 additions & 80 deletions impl/ocean/devices/arkit/AKSceneTracker6DOF.mm
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,6 @@

// first, we check whether any mesh as changed, unfortuately ARKit does not provide some kind of mesh version, so that we use the number of triangles to decided whether the mesh has been updated

bool meshHasChanged = false;

for (ARAnchor* anchor in arFrame.anchors)
{
if (![anchor isKindOfClass:[ARMeshAnchor class]])
Expand All @@ -210,106 +208,73 @@

ARMeshAnchor* meshAnchor = (ARMeshAnchor*)(anchor);

if (updatedMeshAnchors_.find(meshAnchor) == updatedMeshAnchors_.cend())
{
continue;
}

const std::string meshIdentifier = StringApple::toUTF8(meshAnchor.identifier.UUIDString);

const IdentifierMap::const_iterator iMesh = identifierMap_.find(meshIdentifier);
IdentifierMap::iterator iMesh = identifierMap_.find(meshIdentifier);
if (iMesh == identifierMap_.cend())
{
meshHasChanged = true;
break;
iMesh = identifierMap_.insert(std::make_pair(meshIdentifier, ++meshIdCounter_)).first;
}
else
{
ARMeshGeometry* meshGeometry = meshAnchor.geometry;
const Index32 meshId = iMesh->second;

ocean_assert(iMesh->second < numberTriangles_.size());
if (meshGeometry.faces.count != numberTriangles_[iMesh->second])
{
meshHasChanged = true;
break;
}
}
}
const simd_float4x4 simdTransform = meshAnchor.transform;
HomogenousMatrixF4 world_T_mesh;

if (meshHasChanged)
{
for (ARAnchor* anchor in arFrame.anchors)
{
if (![anchor isKindOfClass:[ARMeshAnchor class]])
{
continue;
}
memcpy(world_T_mesh.data() + 0, &simdTransform.columns[0], sizeof(float) * 4);
memcpy(world_T_mesh.data() + 4, &simdTransform.columns[1], sizeof(float) * 4);
memcpy(world_T_mesh.data() + 8, &simdTransform.columns[2], sizeof(float) * 4);
memcpy(world_T_mesh.data() + 12, &simdTransform.columns[3], sizeof(float) * 4);

ARMeshAnchor* meshAnchor = (ARMeshAnchor*)(anchor);
ARMeshGeometry* meshGeometry = meshAnchor.geometry;

const std::string meshIdentifier = StringApple::toUTF8(meshAnchor.identifier.UUIDString);
Vectors3 vertices;
Vectors3 perVertexNormals;
Indices32 triangleIndices;

IdentifierMap::iterator iMesh = identifierMap_.find(meshIdentifier);
if (iMesh == identifierMap_.cend())
if (extractVectors3(meshGeometry.vertices, vertices) && extractVectors3(meshGeometry.normals, perVertexNormals) && extractIndices(meshGeometry.faces, triangleIndices))
{
#ifdef OCEAN_DEBUG
ocean_assert(vertices.size() == perVertexNormals.size());
for (const Index32& index : triangleIndices)
{
iMesh = identifierMap_.insert(std::make_pair(meshIdentifier, ++meshIdCounter_)).first;

numberTriangles_.resize(meshIdCounter_ + 1, 0);
ocean_assert(index < vertices.size());
}
const Index32 meshId = iMesh->second;

const simd_float4x4 simdTransform = meshAnchor.transform;
HomogenousMatrixF4 world_T_mesh;

memcpy(world_T_mesh.data() + 0, &simdTransform.columns[0], sizeof(float) * 4);
memcpy(world_T_mesh.data() + 4, &simdTransform.columns[1], sizeof(float) * 4);
memcpy(world_T_mesh.data() + 8, &simdTransform.columns[2], sizeof(float) * 4);
memcpy(world_T_mesh.data() + 12, &simdTransform.columns[3], sizeof(float) * 4);
#endif

ARMeshGeometry* meshGeometry = meshAnchor.geometry;
ocean_assert(triangleIndices.size() % 3 == 0);
if (triangleIndices.empty() || triangleIndices.size() % 3 != 0)
{
continue;
}

Vectors3 vertices;
Vectors3 perVertexNormals;
Indices32 triangleIndices;
// ARKit sometimes provides invalid per-vertex normals, we remove these triangles

if (extractVectors3(meshGeometry.vertices, vertices) && extractVectors3(meshGeometry.normals, perVertexNormals) && extractIndices(meshGeometry.faces, triangleIndices))
for (size_t n = 0; n < triangleIndices.size(); /*noop*/)
{
#ifdef OCEAN_DEBUG
ocean_assert(vertices.size() == perVertexNormals.size());
for (const Index32& index : triangleIndices)
if (Numeric::isNan(perVertexNormals[triangleIndices[n + 0]].x())
|| Numeric::isNan(perVertexNormals[triangleIndices[n + 1]].x())
|| Numeric::isNan(perVertexNormals[triangleIndices[n + 2]].x()))
{
ocean_assert(index < vertices.size());
}
#endif
triangleIndices[n + 0] = triangleIndices[triangleIndices.size() - 3];
triangleIndices[n + 1] = triangleIndices[triangleIndices.size() - 2];
triangleIndices[n + 2] = triangleIndices[triangleIndices.size() - 1];

ocean_assert(triangleIndices.size() % 3 == 0);
if (triangleIndices.empty() || triangleIndices.size() % 3 != 0)
{
continue;
triangleIndices.resize(triangleIndices.size() - 3);
}

// ARKit sometimes provides invalid per-vertex normals, we remove these triangles

for (size_t n = 0; n < triangleIndices.size(); /*noop*/)
else
{
if (Numeric::isNan(perVertexNormals[triangleIndices[n + 0]].x())
|| Numeric::isNan(perVertexNormals[triangleIndices[n + 1]].x())
|| Numeric::isNan(perVertexNormals[triangleIndices[n + 2]].x()))
{
triangleIndices[n + 0] = triangleIndices[triangleIndices.size() - 3];
triangleIndices[n + 1] = triangleIndices[triangleIndices.size() - 2];
triangleIndices[n + 2] = triangleIndices[triangleIndices.size() - 1];

triangleIndices.resize(triangleIndices.size() - 3);
}
else
{
n += 3;
}
n += 3;
}
}

if (!triangleIndices.empty())
{
ocean_assert(meshId < numberTriangles_.size());
numberTriangles_[meshId] = triangleIndices.size() / 3;

meshes.emplace_back(std::make_shared<SceneElementMeshes::Mesh>(meshId, HomogenousMatrix4(world_T_mesh), std::move(vertices), std::move(perVertexNormals), std::move(triangleIndices)));
}
if (!triangleIndices.empty())
{
meshes.emplace_back(std::make_shared<SceneElementMeshes::Mesh>(meshId, HomogenousMatrix4(world_T_mesh), std::move(vertices), std::move(perVertexNormals), std::move(triangleIndices)));
}
}
}
Expand All @@ -320,6 +285,8 @@
}
}

updatedMeshAnchors_.clear();

if (sceneElements.empty())
{
sceneElements.emplace_back(nullptr); // adding a pure 6-DOF pose scene element
Expand Down Expand Up @@ -379,6 +346,36 @@
}
}

void AKSceneTracker6DOF::onAddedAnchors(const ARAnchors& anchors)
{
for (ARAnchor* anchor : anchors)
{
if (![anchor isKindOfClass:[ARMeshAnchor class]])
{
continue;
}

ARMeshAnchor* meshAnchor = (ARMeshAnchor*)(anchor);

updatedMeshAnchors_.insert(meshAnchor);
}
}

void AKSceneTracker6DOF::onUpdateAnchors(const ARAnchors& anchors)
{
for (ARAnchor* anchor : anchors)
{
if (![anchor isKindOfClass:[ARMeshAnchor class]])
{
continue;
}

ARMeshAnchor* meshAnchor = (ARMeshAnchor*)(anchor);

updatedMeshAnchors_.insert(meshAnchor);
}
}

bool AKSceneTracker6DOF::extractVectors3(ARGeometrySource* geometrySource, Vectors3& vectors)
{
ocean_assert(geometrySource != nullptr);
Expand Down

0 comments on commit 5936a1d

Please sign in to comment.