October3d55/Matain/ViveOpenXR/Source/ViveOpenXRPlaneDetection/Private/ViveOpenXRPlaneDetectionFun...

258 lines
10 KiB
C++

// Copyright HTC Corporation. All Rights Reserved.
#include "ViveOpenXRPlaneDetectionFunctionLibrary.h"
#include "ViveOpenXRPlaneDetectionModule.h"
#include "OpenXRCore.h"
bool UViveOpenXRPlaneDetectionFunctionLibrary::IsPlaneDetectionSupported()
{
auto mod = FViveOpenXRPlaneDetection::Instance();
if (!mod || !mod->IsSupportPlaneDetection()) return false;
return true;
}
bool UViveOpenXRPlaneDetectionFunctionLibrary::CreatePlaneDetector(int64& planeDetector)
{
auto mod = FViveOpenXRPlaneDetection::Instance();
if (!mod) return false;
XrPlaneDetectorCreateInfoEXT createInfo{};
createInfo.type = XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT;
createInfo.next = nullptr;
createInfo.flags = XR_PLANE_DETECTOR_ENABLE_CONTOUR_BIT_EXT;
XrPlaneDetectorEXT planeDetectorExt{};
planeDetector = 0;
if (!mod->CreatePlaneDetector(&createInfo, &planeDetectorExt)) return false;
planeDetector = (int64)planeDetectorExt;
return true;
}
bool UViveOpenXRPlaneDetectionFunctionLibrary::DestroyPlaneDetector(int64 planeDetector)
{
auto mod = FViveOpenXRPlaneDetection::Instance();
if (!mod) return false;
return mod->DestroyPlaneDetector((XrPlaneDetectorEXT)planeDetector);
}
bool UViveOpenXRPlaneDetectionFunctionLibrary::BeginPlaneDetection(int64 planeDetector)
{
auto mod = FViveOpenXRPlaneDetection::Instance();
auto hmd = FViveOpenXRPlaneDetection::HMD();
if (!mod || !hmd) return false;
XrPlaneDetectorBeginInfoEXT beginInfoExt{};
beginInfoExt.type = XR_TYPE_PLANE_DETECTOR_BEGIN_INFO_EXT;
beginInfoExt.next = nullptr;
beginInfoExt.baseSpace = hmd->GetTrackingSpace();
beginInfoExt.time = hmd->GetDisplayTime();
beginInfoExt.orientationCount = 4;
const XrPlaneDetectorOrientationEXT orientations[4] = {
XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_UPWARD_EXT,
XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_DOWNWARD_EXT,
XR_PLANE_DETECTOR_ORIENTATION_VERTICAL_EXT,
XR_PLANE_DETECTOR_ORIENTATION_ARBITRARY_EXT,
};
beginInfoExt.orientationCount = sizeof(orientations);
beginInfoExt.orientations = orientations;
const XrPlaneDetectorSemanticTypeEXT semanticTypes[5] = {
XR_PLANE_DETECTOR_SEMANTIC_TYPE_UNDEFINED_EXT,
XR_PLANE_DETECTOR_SEMANTIC_TYPE_CEILING_EXT,
XR_PLANE_DETECTOR_SEMANTIC_TYPE_FLOOR_EXT,
XR_PLANE_DETECTOR_SEMANTIC_TYPE_WALL_EXT,
XR_PLANE_DETECTOR_SEMANTIC_TYPE_PLATFORM_EXT,
};
beginInfoExt.semanticTypeCount = sizeof(semanticTypes);
beginInfoExt.semanticTypes = semanticTypes;
beginInfoExt.maxPlanes = 100;
beginInfoExt.minArea = 0.01f;
beginInfoExt.boundingBoxPose = { { 0, 0, 0, 1 }, { 0, 0, 0 } };
beginInfoExt.boundingBoxExtent = { 100, 100, 100 };
return mod->BeginPlaneDetection((XrPlaneDetectorEXT)planeDetector, &beginInfoExt);
}
bool UViveOpenXRPlaneDetectionFunctionLibrary::GetPlaneDetectionState(int64 planeDetector, EViveOpenXRPlaneDetectionState& state)
{
auto mod = FViveOpenXRPlaneDetection::Instance();
if (!mod) return false;
XrPlaneDetectionStateEXT stateExt;
if (!mod->GetPlaneDetectionState((XrPlaneDetectorEXT)planeDetector, &stateExt)) return false;
state = (EViveOpenXRPlaneDetectionState)stateExt;
return true;
}
bool UViveOpenXRPlaneDetectionFunctionLibrary::GetPlaneDetections(int64 planeDetector, TArray<FViveOpenXRPlaneDetectorLocation>& locations)
{
auto mod = FViveOpenXRPlaneDetection::Instance();
auto hmd = FViveOpenXRPlaneDetection::HMD();
locations.Empty();
if (!mod || !hmd) return false;
XrPlaneDetectorGetInfoEXT infoExt{};
infoExt.type = XR_TYPE_PLANE_DETECTOR_GET_INFO_EXT;
infoExt.next = nullptr;
infoExt.baseSpace = hmd->GetTrackingSpace();
infoExt.time = hmd->GetDisplayTime();
XrPlaneDetectorLocationsEXT locationsExt{};
locationsExt.type = XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT;
locationsExt.next = nullptr;
locationsExt.planeLocationCapacityInput = 0;
locationsExt.planeLocationCountOutput = 0;
locationsExt.planeLocations = nullptr;
if (!mod->GetPlaneDetections((XrPlaneDetectorEXT)planeDetector, &infoExt, &locationsExt)) return false;
if (locationsExt.planeLocationCountOutput == 0) return true;
locationsExt.planeLocations = new XrPlaneDetectorLocationEXT[locationsExt.planeLocationCountOutput];
locationsExt.planeLocationCapacityInput = locationsExt.planeLocationCountOutput;
if (!mod->GetPlaneDetections((XrPlaneDetectorEXT)planeDetector, &infoExt, &locationsExt))
{
delete[] locationsExt.planeLocations;
return false;
}
locations.SetNum(locationsExt.planeLocationCountOutput);
auto forwardRot = FQuat(FRotator(0, 180, 0));
for (int i = 0; i < (int)locationsExt.planeLocationCountOutput; i++)
{
auto& locationExt = locationsExt.planeLocations[i];
locations[i].planeId = locationExt.planeId;
locations[i].locationFlags = locationExt.locationFlags;
auto& rot = locationExt.pose.orientation;
auto& pos = locationExt.pose.position;
auto& extents = locationExt.extents;
float w2m = hmd->GetWorldToMetersScale();
locations[i].transform = FTransform(ToFQuat(rot) * forwardRot, ToFVector(pos, w2m), FVector::OneVector);
locations[i].size = FVector(extents.height * w2m, extents.width * w2m, 0);
locations[i].orientation = (EViveOpenXRPlaneDetectorOrientation)locationExt.orientation;
locations[i].semanticType = (EViveOpenXRPlaneDetectorSemanticType)locationExt.semanticType;
locations[i].polygonBufferCount = locationExt.polygonBufferCount;
}
delete[] locationsExt.planeLocations;
return true;
}
bool UViveOpenXRPlaneDetectionFunctionLibrary::GetPlanePolygonBufferRaw(int64 planeDetector, int64 planeId, int32 polygonBufferIndex, TArray<FVector>& vertices)
{
auto mod = FViveOpenXRPlaneDetection::Instance();
auto hmd = FViveOpenXRPlaneDetection::HMD();
if (!mod || !hmd) return false;
XrPlaneDetectorPolygonBufferEXT polygonBuffer{};
polygonBuffer.type = XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT;
polygonBuffer.next = nullptr;
polygonBuffer.vertexCapacityInput = 0;
polygonBuffer.vertexCountOutput = 0;
polygonBuffer.vertices = nullptr;
if (!mod->GetPlanePolygonBuffer((XrPlaneDetectorEXT)planeDetector, planeId, polygonBufferIndex, &polygonBuffer)) return false;
// ViveOpenXR AIO only support quad
if (polygonBuffer.vertexCountOutput != 4) return true;
polygonBuffer.vertices = new XrVector2f[polygonBuffer.vertexCountOutput];
polygonBuffer.vertexCapacityInput = polygonBuffer.vertexCountOutput;
if (!mod->GetPlanePolygonBuffer((XrPlaneDetectorEXT)planeDetector, planeId, polygonBufferIndex, &polygonBuffer))
{
delete[] polygonBuffer.vertices;
return false;
}
vertices.SetNum(polygonBuffer.vertexCountOutput);
for (int i = 0; i < (int)polygonBuffer.vertexCountOutput; i++)
{
vertices[i] = FVector(0, polygonBuffer.vertices[i].x, polygonBuffer.vertices[i].y);
}
delete[] polygonBuffer.vertices;
return true;
}
bool UViveOpenXRPlaneDetectionFunctionLibrary::GetPlanePolygon(int64 planeDetector, int64 planeId, int32 polygonBufferIndex, TArray<FVector>& vertices, TArray<int32>& indices, TArray<FVector>& normals, TArray<FVector2D>& uvs, TArray<FLinearColor>& colors)
{
auto mod = FViveOpenXRPlaneDetection::Instance();
auto hmd = FViveOpenXRPlaneDetection::HMD();
if (!mod || !hmd) return false;
XrPlaneDetectorPolygonBufferEXT polygonBuffer{};
polygonBuffer.type = XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT;
polygonBuffer.next = nullptr;
polygonBuffer.vertexCapacityInput = 0;
polygonBuffer.vertexCountOutput = 0;
polygonBuffer.vertices = nullptr;
if (!mod->GetPlanePolygonBuffer((XrPlaneDetectorEXT)planeDetector, planeId, polygonBufferIndex, &polygonBuffer)) return false;
// ViveOpenXR AIO only support quad
if (polygonBuffer.vertexCountOutput != 4) return true;
polygonBuffer.vertices = new XrVector2f[polygonBuffer.vertexCountOutput];
polygonBuffer.vertexCapacityInput = polygonBuffer.vertexCountOutput;
if (!mod->GetPlanePolygonBuffer((XrPlaneDetectorEXT)planeDetector, planeId, polygonBufferIndex, &polygonBuffer))
{
delete [] polygonBuffer.vertices;
return false;
}
float w2m = hmd->GetWorldToMetersScale();
float minX = FLT_MAX;
float maxX = -FLT_MAX;
float minY = FLT_MAX;
float maxY = -FLT_MAX;
for (int i = 0; i < (int)polygonBuffer.vertexCountOutput; i++)
{
minX = FMath::Min(minX, polygonBuffer.vertices[i].x);
maxX = FMath::Max(maxX, polygonBuffer.vertices[i].x);
minY = FMath::Min(minY, polygonBuffer.vertices[i].y);
maxY = FMath::Max(maxY, polygonBuffer.vertices[i].y);
}
delete[] polygonBuffer.vertices;
// Output generated vertices not the orignal vertices
vertices.SetNum(4);
// In Unreal, plane actor is horizontal, and In this OpenXR extension, plane is also horizontal.
// Thus, in Unreal, only the X and Y axis are used, and the Z axis is always 0.
// 3-----2 3-----2 3-----2
// +Y / / +X +Z \ \ +Z / /
// | / / \| \ \ | / /
// *-->+X 0-----1 *-->+Y 0-----1 +Y<--* 0-----1
// / OpenXR Unreal / Unreal
// +Z Model space Tracking space +X Model space
// With Rot 180 With Rot 0
// Because the pose will contained the 180 degree rotation, we should make the vertices in Unreal's tracking space.
vertices[0] = FVector(-minY, minX, 0) * w2m;
vertices[1] = FVector(-minY, maxX, 0) * w2m;
vertices[2] = FVector(-maxY, maxX, 0) * w2m;
vertices[3] = FVector(-maxY, minX, 0) * w2m;
indices.SetNum(6);
// In Unreal, the indices are clockwise.
indices[0] = 0;
indices[1] = 2;
indices[2] = 1;
indices[3] = 0;
indices[4] = 3;
indices[5] = 2;
normals.SetNum(4);
normals[0] = FVector(0, 0, 1);
normals[1] = FVector(0, 0, 1);
normals[2] = FVector(0, 0, 1);
normals[3] = FVector(0, 0, 1);
uvs.SetNum(4);
// In Unreal, the UVs are lower-left origin.
uvs[0] = FVector2D(0, 0);
uvs[1] = FVector2D(1, 0);
uvs[2] = FVector2D(1, 1);
uvs[3] = FVector2D(0, 1);
colors.SetNum(4);
colors[0] = FLinearColor::Gray;
colors[1] = FLinearColor::Red;
colors[2] = FLinearColor::White;
colors[3] = FLinearColor::Green;
return true;
}
FViveOpenXRPlaneDetectorLocation::FViveOpenXRPlaneDetectorLocation()
: planeId(0)
, locationFlags(0)
, transform(FRotator::ZeroRotator, FVector::ZeroVector, FVector::OneVector)
, size(FVector::ZeroVector)
, orientation(EViveOpenXRPlaneDetectorOrientation::Arbitrary)
, semanticType(EViveOpenXRPlaneDetectorSemanticType::Undefined)
, polygonBufferCount(0)
{
}