Bring over initial copy of the game and plugin

This commit is contained in:
Bryce Hutchings 2020-11-23 18:08:38 -08:00
Родитель a1189dddec
Коммит 800c19a0b7
111 изменённых файлов: 10910 добавлений и 10 удалений

12
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,12 @@
# Batch scripts need CR/LF line endings
*.bat eol=crlf
# Shell scripts need unix line endings
*.sh text eol=lf
# Binary files
*.png binary
*.jpg binary
*.umap binary
*.uasset binary
*.dll binary

Двоичные данные
Docs/Images/Banner.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 167 KiB

Просмотреть файл

@ -0,0 +1,128 @@
---
# File originally from https://gist.github.com/intinig/9bba3a3faee80250b781bf916a4ab8b7
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 132
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
FixNamespaceComments: true
ForEachMacros:
- for
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '.*\.generated\.h'
Priority: 100
- Regex: '.*(PCH).*'
Priority: -1
- Regex: '".*"'
Priority: 1
- Regex: '^<.*\.(h)>'
Priority: 3
- Regex: '^<.*>'
Priority: 4
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 4
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 4
UseTab: Always
...

41
MsftOpenXRGame/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,41 @@
# Visual Studio 2015 user specific files
.vs/
# These project files can be generated by the engine
*.sln
# Precompiled Assets
SourceArt/**/*.png
SourceArt/**/*.tga
# Binary Files
Binaries/*
Plugins/*/Binaries/*
# Builds
Build/*
# Whitelist PakBlacklist-<BuildConfiguration>.txt files
!Build/*/
Build/*/**
!Build/*/PakBlacklist*.txt
# Don't ignore icon files in Build
!Build/**/*.ico
# Built data for maps
# Not ignoring this beacuse it forces each person to regenerate it locally (by building lighting) and that leads to the correspoding .umap file being modified.
# *_BuiltData.uasset
# Configuration files generated by the Editor
Saved/*
# Compiled source files for the engine to use
Intermediate/*
Plugins/*/Intermediate/*
# Cache files for the editor to use
DerivedDataCache/*
Hololens/*
WindowsNoEditor/*

Просмотреть файл

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:63e70c898d49938c6920670806bc47263b652aec48b1728e511de12ddc0ca6a4
size 35735

Просмотреть файл

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e007f415760022ae05201c8d72cf3eadca634c872fd1820e30e504b67324992e
size 4345

Просмотреть файл

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6215495eccf992ddd5d27ad27a742379189a9e14712bdfe565a2812bbb2eda0c
size 240279

Просмотреть файл

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:284f073d7edd69de5ab4410bdb101967bd658c3cc321ddf449ec22f0c7ebd874
size 5351

Просмотреть файл

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fc5550f7e77df19eb040f7727313f896167965e635b6b8af6a3c1426a4badd06
size 68457

Двоичные данные
MsftOpenXRGame/Build/HoloLens/SigningCertificate.pfx Normal file

Двоичный файл не отображается.

Просмотреть файл

Просмотреть файл

@ -0,0 +1,140 @@
[/Script/HardwareTargeting.HardwareTargetingSettings]
TargetedHardwareClass=Mobile
AppliedTargetedHardwareClass=Mobile
DefaultGraphicsPerformance=Scalable
AppliedDefaultGraphicsPerformance=Scalable
[/Script/Engine.Engine]
[/Script/Engine.RendererSettings]
r.Mobile.DisableVertexFog=True
r.Shadow.CSM.MaxMobileCascades=1
r.MobileMSAA=1
r.Mobile.UseLegacyShadingModel=False
r.Mobile.AllowDitheredLODTransition=False
r.Mobile.AllowSoftwareOcclusion=False
r.Mobile.VirtualTextures=False
r.DiscardUnusedQuality=False
r.AllowOcclusionQueries=False
r.MinScreenRadiusForLights=0.030000
r.MinScreenRadiusForDepthPrepass=0.030000
r.MinScreenRadiusForCSMDepth=0.010000
r.PrecomputedVisibilityWarning=False
r.TextureStreaming=True
Compat.UseDXT5NormalMaps=False
r.VirtualTextures=False
r.VirtualTexturedLightmaps=False
r.VT.TileSize=128
r.VT.TileBorderSize=4
r.vt.FeedbackFactor=16
r.VT.EnableCompressZlib=True
r.VT.EnableCompressCrunch=False
r.ClearCoatNormal=False
r.AnisotropicBRDF=False
r.ReflectionCaptureResolution=128
r.ReflectionEnvironmentLightmapMixBasedOnRoughness=True
r.ForwardShading=True
r.VertexFoggingForOpaque=False
r.AllowStaticLighting=True
r.NormalMapsForStaticLighting=False
r.GenerateMeshDistanceFields=False
r.DistanceFieldBuild.EightBit=False
r.GenerateLandscapeGIData=False
r.DistanceFieldBuild.Compress=False
r.TessellationAdaptivePixelsPerTriangle=48.000000
r.SeparateTranslucency=False
r.TranslucentSortPolicy=0
TranslucentSortAxis=(X=0.000000,Y=-1.000000,Z=0.000000)
r.CustomDepth=0
r.CustomDepthTemporalAAJitter=True
r.PostProcessing.PropagateAlpha=0
r.DefaultFeature.Bloom=False
r.DefaultFeature.AmbientOcclusion=False
r.DefaultFeature.AmbientOcclusionStaticFraction=True
r.DefaultFeature.AutoExposure=False
r.DefaultFeature.AutoExposure.Method=0
r.DefaultFeature.AutoExposure.Bias=1.000000
r.DefaultFeature.AutoExposure.ExtendDefaultLuminanceRange=False
r.UsePreExposure=True
r.EyeAdaptation.EditorOnly=False
r.DefaultFeature.MotionBlur=False
r.DefaultFeature.LensFlare=False
r.TemporalAA.Upsampling=False
r.SSGI.Enable=False
r.DefaultFeature.AntiAliasing=0
r.DefaultFeature.LightUnits=1
r.DefaultBackBufferPixelFormat=4
r.Shadow.UnbuiltPreviewInGame=True
r.StencilForLODDither=False
r.EarlyZPass=3
r.EarlyZPassOnlyMaterialMasking=False
r.DBuffer=True
r.ClearSceneMethod=1
r.BasePassOutputsVelocity=False
r.VertexDeformationOutputsVelocity=False
r.SelectiveBasePassOutputs=False
bDefaultParticleCutouts=False
fx.GPUSimulationTextureSizeX=1024
fx.GPUSimulationTextureSizeY=1024
r.AllowGlobalClipPlane=False
r.GBufferFormat=1
r.MorphTarget.Mode=True
r.GPUCrashDebugging=False
vr.InstancedStereo=True
r.MobileHDR=False
vr.MobileMultiView=True
r.Mobile.UseHWsRGBEncoding=False
vr.RoundRobinOcclusion=False
vr.ODSCapture=False
r.MeshStreaming=False
r.WireframeCullThreshold=5.000000
r.RayTracing=False
r.RayTracing.UseTextureLod=False
r.SupportStationarySkylight=True
r.SupportLowQualityLightmaps=True
r.SupportPointLightWholeSceneShadows=True
r.SupportAtmosphericFog=True
r.SupportSkyAtmosphere=True
r.SupportSkyAtmosphereAffectsHeightFog=False
r.SkinCache.CompileShaders=False
r.SkinCache.DefaultBehavior=1
r.SkinCache.SceneMemoryLimitInMB=128.000000
r.Mobile.EnableStaticAndCSMShadowReceivers=True
r.Mobile.EnableMovableLightCSMShaderCulling=True
r.Mobile.AllowDistanceFieldShadows=True
r.Mobile.AllowMovableDirectionalLights=True
r.MobileNumDynamicPointLights=0
r.MobileDynamicPointLightsUseStaticBranch=True
r.Mobile.EnableMovableSpotlights=False
r.GPUSkin.Support16BitBoneIndex=False
r.GPUSkin.Limit2BoneInfluences=False
r.SupportDepthOnlyIndexBuffers=True
r.SupportReversedIndexBuffers=True
r.SupportMaterialLayers=False
r.LightPropagationVolume=False
bStreamSkeletalMeshLODs=(Default=False,PerPlatform=())
bDiscardSkeletalMeshOptionalLODs=(Default=False,PerPlatform=())
VisualizeCalibrationColorMaterialPath=None
VisualizeCalibrationCustomMaterialPath=None
VisualizeCalibrationGrayscaleMaterialPath=None
[/Script/EngineSettings.GameMapsSettings]
EditorStartupMap=/Game/Maps/DefaultMap.DefaultMap
LocalMapOptions=
TransitionMap=None
bUseSplitscreen=False
TwoPlayerSplitscreenLayout=Horizontal
ThreePlayerSplitscreenLayout=FavorTop
FourPlayerSplitscreenLayout=Grid
bOffsetPlayerGamepadIds=False
GameInstanceClass=/Script/Engine.GameInstance
GameDefaultMap=/Game/Maps/DefaultMap.DefaultMap
ServerDefaultMap=/Engine/Maps/Entry.Entry
GlobalDefaultGameMode=/Script/Engine.GameModeBase
GlobalDefaultServerGameMode=None
[/Script/Slate.SlateSettings]
bExplicitCanvasChildZOrder=True

Просмотреть файл

@ -0,0 +1,11 @@
[/Script/EngineSettings.GeneralProjectSettings]
ProjectID=99F0EDDB4B092C7CA6713EAA6EFCB918
CompanyName=Microsoft
CompanyDistinguishedName=CN=Microsoft
bStartInVR=True
ProjectName=MsftOpenXRGame
ProjectVersion=1.0.0.0
[/Script/EngineSettings.XRVisualizationSettings]
HandMeshMaterial=Material'/Game/Materials/M_BasicUnlit.M_BasicUnlit'

Просмотреть файл

@ -0,0 +1,114 @@
[/Script/Engine.InputSettings]
-AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
-AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
-AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
-AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.25,Exponent=1.f,Sensitivity=1.f))
-AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f))
-AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f))
-AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.f,Exponent=1.f,Sensitivity=0.07f))
+AxisConfig=(AxisKeyName="Vive_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MixedReality_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusGo_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusGo_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusGo_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusGo_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OculusTouch_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Left_Trackpad_Touch",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Grip_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Thumbstick_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="ValveIndex_Right_Trackpad_Force",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_LeftX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_LeftY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_RightX",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_RightY",AxisProperties=(DeadZone=0.250000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MouseX",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MouseY",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Mouse2D",AxisProperties=(DeadZone=0.000000,Sensitivity=0.070000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="MouseWheelAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_LeftTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_RightTriggerAxis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Gamepad_Special_Left_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Daydream_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Daydream_Right_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Left_Trigger_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_X",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="Vive_Left_Trackpad_Y",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OpenXRMsftHandInteraction_Left_Select_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OpenXRMsftHandInteraction_Right_Select_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OpenXRMsftHandInteraction_Left_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
+AxisConfig=(AxisKeyName="OpenXRMsftHandInteraction_Right_Grip_Axis",AxisProperties=(DeadZone=0.000000,Sensitivity=1.000000,Exponent=1.000000,bInvert=False))
bAltEnterTogglesFullscreen=True
bF11TogglesFullscreen=True
bUseMouseForTouch=False
bEnableMouseSmoothing=True
bEnableFOVScaling=True
bCaptureMouseOnLaunch=True
bAlwaysShowTouchInterface=False
bShowConsoleOnFourFingerTap=True
bEnableGestureRecognizer=False
bUseAutocorrect=False
DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown
DefaultViewportMouseLockMode=LockOnCapture
FOVScale=0.011110
DoubleClickTime=0.200000
+ActionMappings=(ActionName="Squeeze_Left",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OpenXRMsftHandInteraction_Left_Grip_Axis)
+ActionMappings=(ActionName="Squeeze_Right",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OpenXRMsftHandInteraction_Right_Grip_Axis)
+ActionMappings=(ActionName="Select_Left",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OpenXRMsftHandInteraction_Left_Select_Axis)
+ActionMappings=(ActionName="Select_Right",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OpenXRMsftHandInteraction_Right_Select_Axis)
+ActionMappings=(ActionName="Squeeze_Left",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Left_Grip_Click)
+ActionMappings=(ActionName="Squeeze_Right",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Right_Grip_Click)
+ActionMappings=(ActionName="Select_Left",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Left_Trigger_Axis)
+ActionMappings=(ActionName="Select_Right",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MixedReality_Right_Trigger_Axis)
+ActionMappings=(ActionName="Squeeze_Left",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Left_Grip_Axis)
+ActionMappings=(ActionName="Squeeze_Right",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Right_Grip_Axis)
+ActionMappings=(ActionName="Select_Left",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Left_Trigger_Axis)
+ActionMappings=(ActionName="Select_Right",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Right_Trigger_Axis)
+ActionMappings=(ActionName="Throw_Left",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Left_X_Click)
+ActionMappings=(ActionName="Throw_Left",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Left_Thumbstick_Click)
+ActionMappings=(ActionName="Throw_Right",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Right_A_Click)
+ActionMappings=(ActionName="Throw_Right",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=OculusTouch_Right_Thumbstick_Click)
+SpeechMappings=(ActionName="Next",SpeechKeyword="Next")
+SpeechMappings=(ActionName="ShowSpatialMapping",SpeechKeyword="ShowSpatialMapping")
+SpeechMappings=(ActionName="HideSpatialMapping",SpeechKeyword="HideSpatialMapping")
+SpeechMappings=(ActionName="StartSpatialMapping",SpeechKeyword="StartSpatialMapping")
+SpeechMappings=(ActionName="StopSpatialMapping",SpeechKeyword="StopSpatialMapping")
DefaultPlayerInputClass=/Script/Engine.PlayerInput
DefaultInputComponentClass=/Script/Engine.InputComponent
DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks
-ConsoleKeys=Tilde
+ConsoleKeys=Tilde

Просмотреть файл

@ -0,0 +1,34 @@
[/Script/HoloLensPlatformEditor.HoloLensTargetSettings]
bBuildForEmulation=False
bBuildForDevice=True
bUseNameForLogo=True
bBuildForRetailWindowsStore=False
bAutoIncrementVersion=False
bShouldCreateAppInstaller=False
AppInstallerInstallationURL=
HoursBetweenUpdateChecks=0
bEnablePIXProfiling=False
TileBackgroundColor=(B=64,G=0,R=0,A=255)
SplashScreenBackgroundColor=(B=64,G=0,R=0,A=255)
+PerCultureResources=(CultureId="",Strings=(PackageDisplayName="Unreal OpenXR Game",PublisherDisplayName="Microsoft Corporation",PackageDescription="Demonstrates the Microsoft OpenXR plugin for Unreal",ApplicationDisplayName="Unreal OpenXR Game",ApplicationDescription=""),Images=())
TargetDeviceFamily=Windows.Holographic
MinimumPlatformVersion=
MaximumPlatformVersionTested=10.0.18362.0
MaxTrianglesPerCubicMeter=500.000000
SpatialMeshingVolumeSize=20.000000
CompilerVersion=Default
Windows10SDKVersion=10.0.18362.0
+CapabilityList=internetClientServer
+CapabilityList=privateNetworkClientServer
+DeviceCapabilityList=gazeInput
+DeviceCapabilityList=webcam
+DeviceCapabilityList=microphone
+Uap2CapabilityList=spatialPerception
bSetDefaultCapabilities=False
SpatializationPlugin=
ReverbPlugin=
OcclusionPlugin=
SoundCueCookQualityIndex=-1

Двоичные данные
MsftOpenXRGame/Content/Blueprints/Pivot.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/CamCapture.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/EyeTrackingComponent.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/HandTrackingComponent.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/MRGameMode.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/MRPlayerPawn.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Maps/DefaultMap.umap Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Maps/DefaultMap_BuiltData.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/CamTextureMaterial.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/DefaultTextMaterialOpaque.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/Floor.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/InteractionSphere.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/MI_GlowPlastic.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/M_BasicUnlit.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/M_GlowPlastic.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/M_Plastic.uasset Normal file

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpatialMappingMaterial.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/Blue.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/ColorEnum.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/ColorMat.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/Green.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/Orange.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/Pink.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/Purple.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/Red.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/White.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Materials/SpeechMaterials/Yellow.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Meshes/SpawnArrow_Arrow.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Meshes/SpawnArrow_Base.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Meshes/SpawnArrow_GreenCircle.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/Meshes/SpawnArrow_RedEx.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/QRTracker.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/SpatialMappingActor.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/SpeechActor.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/TextActor.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/TextWidget.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/Content/WMRConfig.uasset Normal file

Двоичный файл не отображается.

Двоичные данные
MsftOpenXRGame/MsftOpenXRGame.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 54 KiB

Просмотреть файл

@ -0,0 +1,66 @@
{
"FileVersion": 3,
"EngineAssociation": "{B902521A-44AC-D40D-A44D-D684CFEBF4D2}",
"Category": "",
"Description": "",
"Modules": [
{
"Name": "MsftOpenXRGame",
"Type": "Runtime",
"LoadingPhase": "Default"
}
],
"Plugins": [
{
"Name": "SteamVR",
"Enabled": false,
"SupportedTargetPlatforms": [
"Win32",
"Win64",
"Linux",
"Mac",
"Android"
]
},
{
"Name": "MagicLeap",
"Enabled": false,
"SupportedTargetPlatforms": [
"Lumin",
"Mac",
"Win64"
]
},
{
"Name": "MagicLeapMedia",
"Enabled": false,
"SupportedTargetPlatforms": [
"Lumin"
]
},
{
"Name": "LuminPlatformFeatures",
"Enabled": false,
"SupportedTargetPlatforms": [
"Lumin"
]
},
{
"Name": "MLSDK",
"Enabled": false
},
{
"Name": "MagicLeapPassableWorld",
"Enabled": false,
"SupportedTargetPlatforms": [
"Lumin",
"Mac",
"Win64"
]
},
{
"Name": "XRVisualization",
"Enabled": true
}
]
}

Просмотреть файл

@ -0,0 +1,8 @@
[FilterPlugin]
; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and
; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively.
;
; Examples:
; /README.txt
; /Extras/...
; /Binaries/ThirdParty/*.dll

Просмотреть файл

@ -0,0 +1,74 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "Microsoft OpenXR",
"Description": "The Microsoft OpenXR plugin is a game plugin which provides additional features available on Microsoft's Mixed Reality devices like the HoloLens 2 when using OpenXR.",
"Category": "Augmented Reality",
"CreatedBy": "Microsoft",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/ef8930ca860148c498b46887da196239",
"SupportURL": "https://github.com/microsoft/Microsoft-OpenXR-Unreal",
"EngineVersion": "4.26.0",
"CanContainContent": true,
"IsBetaVersion": false,
"IsExperimentalVersion": false,
"Installed": false,
"SupportedTargetPlatforms": [
"Win64",
"HoloLens"
],
"Modules": [
{
"Name": "MicrosoftOpenXR",
"Type": "Runtime",
"LoadingPhase": "PostConfigInit"
},
{
"Name": "MicrosoftOpenXRRuntimeSettings",
"Type": "Runtime",
"LoadingPhase": "PostConfigInit",
"WhitelistPlatforms": [
"Win64"
]
},
{
"Name": "MicrosoftOpenXREditor",
"Type": "Editor",
"LoadingPhase": "PostEngineInit",
"WhitelistPlatforms": [
"Win64"
]
}
],
"Plugins": [
{
"Name": "OpenXR",
"Enabled": true
},
{
"Name": "OpenXREyeTracker",
"Enabled": true
},
{
"Name": "OpenXRHandTracking",
"Enabled": true
},
{
"Name": "OpenXRMsftHandInteraction",
"Enabled": true
},
{
"Name": "XRVisualization",
"Enabled": true
},
{
"Name": "HoloLensAR",
"Enabled": true,
"WhitelistPlatforms": [
"Win64"
]
}
]
}

Двоичные данные
MsftOpenXRGame/Plugins/MicrosoftOpenXR/Resources/Icon128.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 27 KiB

Просмотреть файл

@ -0,0 +1,225 @@
// Copyright (c) Microsoft Corporation.
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using UnrealBuildTool;
using Tools.DotNETCommon;
using System;
public class MicrosoftOpenXR : ModuleRules
{
public MicrosoftOpenXR(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PrivatePCHHeaderFile = @"Private\OpenXRCommon.h";
PrivateIncludePaths.AddRange(
new string[] {
// This private include path ensures our newer copy of the openxr headers take precedence over the engine's copy.
"MicrosoftOpenXR/Private/External"
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"ApplicationCore",
"Engine",
"Slate",
"SlateCore",
"InputCore",
"OpenXRHMD",
"MicrosoftOpenXRRuntimeSettings",
"HeadMountedDisplay",
"AugmentedReality",
"OpenXRAR",
"RHI",
"RenderCore",
"Projects",
}
);
if (Target.bBuildEditor)
{
PrivateDependencyModuleNames.AddRange(
new string[]
{
"UnrealEd"
}
);
}
PrivateIncludePathModuleNames.AddRange(
new string[]
{
"HeadMountedDisplay"
}
);
PublicIncludePathModuleNames.AddRange(
new string[]
{
"HeadMountedDisplay"
}
);
// WinRT with Nuget support
if (Target.Platform == UnrealTargetPlatform.Win64 || Target.Platform == UnrealTargetPlatform.HoloLens)
{
// these parameters mandatory for winrt support
bEnableExceptions = true;
bUseUnity = false;
CppStandard = CppStandardVersion.Cpp17;
PublicSystemLibraries.AddRange(new string [] { "shlwapi.lib", "runtimeobject.lib" });
// prepare everything for nuget
string MyModuleName = GetType().Name;
string NugetFolder = Path.Combine(PluginDirectory, "Intermediate", "Nuget", MyModuleName);
Directory.CreateDirectory(NugetFolder);
string BinariesSubFolder = Path.Combine("Binaries", "ThirdParty", Target.Type.ToString(), Target.Platform.ToString(), Target.Architecture);
PrivateDefinitions.Add(string.Format("THIRDPARTY_BINARY_SUBFOLDER=\"{0}\"", BinariesSubFolder.Replace(@"\", @"\\")));
string BinariesFolder = Path.Combine(PluginDirectory, BinariesSubFolder);
Directory.CreateDirectory(BinariesFolder);
// download nuget
string NugetExe = Path.Combine(NugetFolder, "nuget.exe");
if (!File.Exists(NugetExe))
{
using (System.Net.WebClient myWebClient = new System.Net.WebClient())
{
// we aren't focusing on a specific nuget version, we can use any of them but the latest one is preferable
myWebClient.DownloadFile(@"https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", NugetExe);
}
}
// run nuget to update the packages
{
var StartInfo = new System.Diagnostics.ProcessStartInfo(NugetExe, string.Format("install \"{0}\" -OutputDirectory \"{1}\"", Path.Combine(ModuleDirectory, "packages.config"), NugetFolder));
StartInfo.UseShellExecute = false;
StartInfo.CreateNoWindow = true;
var ExitCode = Utils.RunLocalProcessAndPrintfOutput(StartInfo);
if (ExitCode < 0)
{
throw new BuildException("Failed to get nuget packages. See log for details.");
}
}
// get list of the installed packages, that's needed because the code should get particular versions of the installed packages
string[] InstalledPackages = Utils.RunLocalProcessAndReturnStdOut(NugetExe, string.Format("list -Source \"{0}\"", NugetFolder)).Split(new char[] { '\r', '\n' });
// get WinRT package
string CppWinRTPackage = InstalledPackages.First(x => x.StartsWith("Microsoft.Windows.CppWinRT"));
if (!string.IsNullOrEmpty(CppWinRTPackage))
{
string CppWinRTName = CppWinRTPackage.Replace(" ", ".");
string CppWinRTExe = Path.Combine(NugetFolder, CppWinRTName, "bin", "cppwinrt.exe");
string CppWinRTFolder = Path.Combine(PluginDirectory, "Intermediate", CppWinRTName, MyModuleName);
Directory.CreateDirectory(CppWinRTFolder);
// search all downloaded packages for winmd files
string[] WinMDFiles = Directory.GetFiles(NugetFolder, "*.winmd", SearchOption.AllDirectories);
// all downloaded winmd file with WinSDK to be processed by cppwinrt.exe
var WinMDFilesStringbuilder = new System.Text.StringBuilder();
foreach (var winmd in WinMDFiles)
{
WinMDFilesStringbuilder.Append(" -input \"");
WinMDFilesStringbuilder.Append(winmd);
WinMDFilesStringbuilder.Append("\"");
}
// generate winrt headers and add them into include paths
var StartInfo = new System.Diagnostics.ProcessStartInfo(CppWinRTExe, string.Format("{0} -input \"{1}\" -output \"{2}\"", WinMDFilesStringbuilder, Target.WindowsPlatform.WindowsSdkVersion, CppWinRTFolder));
StartInfo.UseShellExecute = false;
StartInfo.CreateNoWindow = true;
var ExitCode = Utils.RunLocalProcessAndPrintfOutput(StartInfo);
if (ExitCode < 0)
{
throw new BuildException("Failed to get generate WinRT headers. See log for details.");
}
PrivateIncludePaths.Add(CppWinRTFolder);
}
else
{
// fall back to default WinSDK headers if no winrt package in our list
PrivateIncludePaths.Add(Path.Combine(Target.WindowsPlatform.WindowsSdkDir, "Include", Target.WindowsPlatform.WindowsSdkVersion, "cppwinrt"));
}
// WinRT lib for some job
string QRPackage = InstalledPackages.First(x => x.StartsWith("Microsoft.MixedReality.QR"));
if (!string.IsNullOrEmpty(QRPackage))
{
string QRFolderName = QRPackage.Replace(" ", ".");
// copying dll and winmd binaries to our local binaries folder
// !!!!! please make sure that you use the path of file! Unreal can't do it for you !!!!!
SafeCopy(Path.Combine(NugetFolder, QRFolderName, @"lib\uap10.0.18362\Microsoft.MixedReality.QR.winmd"),
Path.Combine(BinariesFolder, "Microsoft.MixedReality.QR.winmd"));
SafeCopy(Path.Combine(NugetFolder, QRFolderName, string.Format(@"runtimes\win10-{0}\native\Microsoft.MixedReality.QR.dll", Target.WindowsPlatform.Architecture.ToString())),
Path.Combine(BinariesFolder, "Microsoft.MixedReality.QR.dll"));
// also both both binaries must be in RuntimeDependencies, unless you get failures in Hololens platform
RuntimeDependencies.Add(Path.Combine(BinariesFolder, "Microsoft.MixedReality.QR.dll"));
RuntimeDependencies.Add(Path.Combine(BinariesFolder, "Microsoft.MixedReality.QR.winmd"));
}
if (Target.Platform == UnrealTargetPlatform.Win64)
{
// Microsoft.VCRTForwarders.140 is needed to run WinRT dlls in Win64 platforms
string VCRTForwardersPackage = InstalledPackages.First(x => x.StartsWith("Microsoft.VCRTForwarders.140"));
if (!string.IsNullOrEmpty(VCRTForwardersPackage))
{
string VCRTForwardersName = VCRTForwardersPackage.Replace(" ", ".");
foreach (var Dll in Directory.EnumerateFiles(Path.Combine(NugetFolder, VCRTForwardersName, "runtimes/win10-x64/native/release"), "*_app.dll"))
{
string newDll = Path.Combine(BinariesFolder, Path.GetFileName(Dll));
SafeCopy(Dll, newDll);
RuntimeDependencies.Add(newDll);
}
}
}
}
if (Target.Platform == UnrealTargetPlatform.Win64)
{
PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "ThirdParty", "HolographicAppRemoting"));
RuntimeDependencies.Add("$(PluginDir)/ThirdParty/HolographicAppRemoting/Windows/Win64/Microsoft.Holographic.AppRemoting.OpenXr.dll");
RuntimeDependencies.Add("$(PluginDir)/ThirdParty/HolographicAppRemoting/Windows/Win64/RemotingXR.json");
}
}
private void SafeCopy(string source, string destination)
{
if(!File.Exists(source))
{
Log.TraceError("Class {0} can't find {1} file for copying", this.GetType().Name, source);
return;
}
try
{
File.Copy(source, destination, true);
}
catch(IOException ex)
{
Log.TraceWarning("Failed to copy {0} to {1} with exception: {2}", source, destination, ex.Message);
if (!File.Exists(destination))
{
Log.TraceError("Destination file {0} does not exist", destination);
return;
}
Log.TraceWarning("Destination file {0} already existed and is probably in use. The old file will be used for the runtime dependency. This may happen when packaging a Win64 exe from the editor.", destination);
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,426 @@
#ifndef OPENXR_PLATFORM_H_
#define OPENXR_PLATFORM_H_ 1
/*
** Copyright (c) 2017-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
** This header is generated from the Khronos OpenXR XML API Registry.
**
*/
#include "openxr.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_thread_settings 1
#define XR_KHR_android_thread_settings_SPEC_VERSION 5
#define XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME "XR_KHR_android_thread_settings"
typedef enum XrAndroidThreadTypeKHR {
XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR = 1,
XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR = 2,
XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR = 3,
XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR = 4,
XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF
} XrAndroidThreadTypeKHR;
typedef XrResult (XRAPI_PTR *PFN_xrSetAndroidApplicationThreadKHR)(XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR(
XrSession session,
XrAndroidThreadTypeKHR threadType,
uint32_t threadId);
#endif
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_surface_swapchain 1
#define XR_KHR_android_surface_swapchain_SPEC_VERSION 4
#define XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME "XR_KHR_android_surface_swapchain"
typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR(
XrSession session,
const XrSwapchainCreateInfo* info,
XrSwapchain* swapchain,
jobject* surface);
#endif
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_create_instance 1
#define XR_KHR_android_create_instance_SPEC_VERSION 3
#define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance"
typedef struct XrInstanceCreateInfoAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
void* XR_MAY_ALIAS applicationVM;
void* XR_MAY_ALIAS applicationActivity;
} XrInstanceCreateInfoAndroidKHR;
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_swapchain_format_list 1
#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 2
#define XR_KHR_VULKAN_SWAPCHAIN_FORMAT_LIST_EXTENSION_NAME "XR_KHR_vulkan_swapchain_format_list"
typedef struct XrVulkanSwapchainFormatListCreateInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
uint32_t viewFormatCount;
const VkFormat* viewFormats;
} XrVulkanSwapchainFormatListCreateInfoKHR;
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_GRAPHICS_API_OPENGL
#define XR_KHR_opengl_enable 1
#define XR_KHR_opengl_enable_SPEC_VERSION 8
#define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable"
#ifdef XR_USE_PLATFORM_WIN32
typedef struct XrGraphicsBindingOpenGLWin32KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
HDC hDC;
HGLRC hGLRC;
} XrGraphicsBindingOpenGLWin32KHR;
#endif // XR_USE_PLATFORM_WIN32
#ifdef XR_USE_PLATFORM_XLIB
typedef struct XrGraphicsBindingOpenGLXlibKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
Display* xDisplay;
uint32_t visualid;
GLXFBConfig glxFBConfig;
GLXDrawable glxDrawable;
GLXContext glxContext;
} XrGraphicsBindingOpenGLXlibKHR;
#endif // XR_USE_PLATFORM_XLIB
#ifdef XR_USE_PLATFORM_XCB
typedef struct XrGraphicsBindingOpenGLXcbKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
xcb_connection_t* connection;
uint32_t screenNumber;
xcb_glx_fbconfig_t fbconfigid;
xcb_visualid_t visualid;
xcb_glx_drawable_t glxDrawable;
xcb_glx_context_t glxContext;
} XrGraphicsBindingOpenGLXcbKHR;
#endif // XR_USE_PLATFORM_XCB
#ifdef XR_USE_PLATFORM_WAYLAND
typedef struct XrGraphicsBindingOpenGLWaylandKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
struct wl_display* display;
} XrGraphicsBindingOpenGLWaylandKHR;
#endif // XR_USE_PLATFORM_WAYLAND
typedef struct XrSwapchainImageOpenGLKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t image;
} XrSwapchainImageOpenGLKHR;
typedef struct XrGraphicsRequirementsOpenGLKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsOpenGLKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_OPENGL */
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#define XR_KHR_opengl_es_enable 1
#define XR_KHR_opengl_es_enable_SPEC_VERSION 6
#define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable"
#ifdef XR_USE_PLATFORM_ANDROID
typedef struct XrGraphicsBindingOpenGLESAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
EGLDisplay display;
EGLConfig config;
EGLContext context;
} XrGraphicsBindingOpenGLESAndroidKHR;
#endif // XR_USE_PLATFORM_ANDROID
typedef struct XrSwapchainImageOpenGLESKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t image;
} XrSwapchainImageOpenGLESKHR;
typedef struct XrGraphicsRequirementsOpenGLESKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsOpenGLESKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_enable 1
#define XR_KHR_vulkan_enable_SPEC_VERSION 6
#define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable"
typedef struct XrGraphicsBindingVulkanKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkDevice device;
uint32_t queueFamilyIndex;
uint32_t queueIndex;
} XrGraphicsBindingVulkanKHR;
typedef struct XrSwapchainImageVulkanKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
VkImage image;
} XrSwapchainImageVulkanKHR;
typedef struct XrGraphicsRequirementsVulkanKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsVulkanKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanInstanceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanDeviceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDeviceKHR)(XrInstance instance, XrSystemId systemId, VkInstance vkInstance, VkPhysicalDevice* vkPhysicalDevice);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanDeviceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDeviceKHR(
XrInstance instance,
XrSystemId systemId,
VkInstance vkInstance,
VkPhysicalDevice* vkPhysicalDevice);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_GRAPHICS_API_D3D11
#define XR_KHR_D3D11_enable 1
#define XR_KHR_D3D11_enable_SPEC_VERSION 4
#define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable"
typedef struct XrGraphicsBindingD3D11KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
ID3D11Device* device;
} XrGraphicsBindingD3D11KHR;
typedef struct XrSwapchainImageD3D11KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
ID3D11Texture2D* texture;
} XrSwapchainImageD3D11KHR;
typedef struct XrGraphicsRequirementsD3D11KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
LUID adapterLuid;
D3D_FEATURE_LEVEL minFeatureLevel;
} XrGraphicsRequirementsD3D11KHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetD3D11GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D11KHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_D3D11 */
#ifdef XR_USE_GRAPHICS_API_D3D12
#define XR_KHR_D3D12_enable 1
#define XR_KHR_D3D12_enable_SPEC_VERSION 6
#define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable"
typedef struct XrGraphicsBindingD3D12KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
ID3D12Device* device;
ID3D12CommandQueue* queue;
} XrGraphicsBindingD3D12KHR;
typedef struct XrSwapchainImageD3D12KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
ID3D12Resource* texture;
} XrSwapchainImageD3D12KHR;
typedef struct XrGraphicsRequirementsD3D12KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
LUID adapterLuid;
D3D_FEATURE_LEVEL minFeatureLevel;
} XrGraphicsRequirementsD3D12KHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetD3D12GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D12KHR* graphicsRequirements);
#endif
#endif /* XR_USE_GRAPHICS_API_D3D12 */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_KHR_win32_convert_performance_counter_time 1
#define XR_KHR_win32_convert_performance_counter_time_SPEC_VERSION 1
#define XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME "XR_KHR_win32_convert_performance_counter_time"
typedef XrResult (XRAPI_PTR *PFN_xrConvertWin32PerformanceCounterToTimeKHR)(XrInstance instance, const LARGE_INTEGER* performanceCounter, XrTime* time);
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToWin32PerformanceCounterKHR)(XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR(
XrInstance instance,
const LARGE_INTEGER* performanceCounter,
XrTime* time);
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR(
XrInstance instance,
XrTime time,
LARGE_INTEGER* performanceCounter);
#endif
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_TIMESPEC
#define XR_KHR_convert_timespec_time 1
#define XR_KHR_convert_timespec_time_SPEC_VERSION 1
#define XR_KHR_CONVERT_TIMESPEC_TIME_EXTENSION_NAME "XR_KHR_convert_timespec_time"
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimespecTimeToTimeKHR)(XrInstance instance, const struct timespec* timespecTime, XrTime* time);
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToTimespecTimeKHR)(XrInstance instance, XrTime time, struct timespec* timespecTime);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR(
XrInstance instance,
const struct timespec* timespecTime,
XrTime* time);
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR(
XrInstance instance,
XrTime time,
struct timespec* timespecTime);
#endif
#endif /* XR_USE_TIMESPEC */
#ifdef XR_USE_PLATFORM_EGL
#define XR_MNDX_egl_enable 1
#define XR_MNDX_egl_enable_SPEC_VERSION 1
#define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable"
typedef struct XrGraphicsBindingEGLMNDX {
XrStructureType type;
const void* XR_MAY_ALIAS next;
PFNEGLGETPROCADDRESSPROC getProcAddress;
EGLDisplay display;
EGLConfig config;
EGLContext context;
} XrGraphicsBindingEGLMNDX;
#endif /* XR_USE_PLATFORM_EGL */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_MSFT_perception_anchor_interop_preview 1
#define XR_MSFT_perception_anchor_interop_preview_SPEC_VERSION 1
#define XR_MSFT_PERCEPTION_ANCHOR_INTEROP_PREVIEW_EXTENSION_NAME "XR_MSFT_perception_anchor_interop_preview"
typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT)(XrSession session, IUnknown* perceptionAnchor, XrSpatialAnchorMSFT* anchor);
typedef XrResult (XRAPI_PTR *PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT)(XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPerceptionAnchorMSFT(
XrSession session,
IUnknown* perceptionAnchor,
XrSpatialAnchorMSFT* anchor);
XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT(
XrSession session,
XrSpatialAnchorMSFT anchor,
IUnknown** perceptionAnchor);
#endif
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_MSFT_holographic_window_attachment 1
#define XR_MSFT_holographic_window_attachment_SPEC_VERSION 1
#define XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME "XR_MSFT_holographic_window_attachment"
#ifdef XR_USE_PLATFORM_WIN32
typedef struct XrHolographicWindowAttachmentMSFT {
XrStructureType type;
const void* XR_MAY_ALIAS next;
IUnknown* holographicSpace;
IUnknown* coreWindow;
} XrHolographicWindowAttachmentMSFT;
#endif // XR_USE_PLATFORM_WIN32
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef __cplusplus
}
#endif
#endif

Просмотреть файл

@ -0,0 +1,110 @@
/*
** Copyright (c) 2017-2020 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#ifndef OPENXR_PLATFORM_DEFINES_H_
#define OPENXR_PLATFORM_DEFINES_H_ 1
#ifdef __cplusplus
extern "C" {
#endif
/* Platform-specific calling convention macros.
*
* Platforms should define these so that OpenXR clients call OpenXR functions
* with the same calling conventions that the OpenXR implementation expects.
*
* XRAPI_ATTR - Placed before the return type in function declarations.
* Useful for C++11 and GCC/Clang-style function attribute syntax.
* XRAPI_CALL - Placed after the return type in function declarations.
* Useful for MSVC-style calling convention syntax.
* XRAPI_PTR - Placed between the '(' and '*' in function pointer types.
*
* Function declaration: XRAPI_ATTR void XRAPI_CALL xrFunction(void);
* Function pointer type: typedef void (XRAPI_PTR *PFN_xrFunction)(void);
*/
#if defined(_WIN32)
#define XRAPI_ATTR
// On Windows, functions use the stdcall convention
#define XRAPI_CALL __stdcall
#define XRAPI_PTR XRAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
#error "API not supported for the 'armeabi' NDK ABI"
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
// On Android 32-bit ARM targets, functions use the "hardfloat"
// calling convention, i.e. float parameters are passed in registers. This
// is true even if the rest of the application passes floats on the stack,
// as it does by default when compiling for the armeabi-v7a NDK ABI.
#define XRAPI_ATTR __attribute__((pcs("aapcs-vfp")))
#define XRAPI_CALL
#define XRAPI_PTR XRAPI_ATTR
#else
// On other platforms, use the default calling convention
#define XRAPI_ATTR
#define XRAPI_CALL
#define XRAPI_PTR
#endif
#include <stddef.h>
#if !defined(XR_NO_STDINT_H)
#if defined(_MSC_VER) && (_MSC_VER < 1600)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#endif // !defined( XR_NO_STDINT_H )
// XR_PTR_SIZE (in bytes)
#if (defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__))
#define XR_PTR_SIZE 8
#else
#define XR_PTR_SIZE 4
#endif
// Needed so we can use clang __has_feature portably.
#if !defined(XR_COMPILER_HAS_FEATURE)
#if defined(__clang__)
#define XR_COMPILER_HAS_FEATURE(x) __has_feature(x)
#else
#define XR_COMPILER_HAS_FEATURE(x) 0
#endif
#endif
// Identifies if the current compiler has C++11 support enabled.
// Does not by itself identify if any given C++11 feature is present.
#if !defined(XR_CPP11_ENABLED) && defined(__cplusplus)
#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__)
#define XR_CPP11_ENABLED 1
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
#define XR_CPP11_ENABLED 1
#elif (__cplusplus >= 201103L) // 201103 is the first C++11 version.
#define XR_CPP11_ENABLED 1
#endif
#endif
// Identifies if the current compiler supports C++11 nullptr.
#if !defined(XR_CPP_NULLPTR_SUPPORTED)
#if defined(XR_CPP11_ENABLED) && \
((defined(__clang__) && XR_COMPILER_HAS_FEATURE(cxx_nullptr)) || \
(defined(__GNUC__) && (((__GNUC__ * 1000) + __GNUC_MINOR__) >= 4006)) || \
(defined(_MSC_VER) && (_MSC_VER >= 1600)) || \
(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403)))
#define XR_CPP_NULLPTR_SUPPORTED 1
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,392 @@
#include "HandMeshPlugin.h"
#include "InputCoreTypes.h"
#include "OpenXRCore.h"
#include "IXRTrackingSystem.h"
#include "IOpenXRARModule.h"
#include "IOpenXRARTrackedGeometryHolder.h"
#include "ARSessionConfig.h"
#include "HeadMountedDisplayTypes.h"
#define LOCTEXT_NAMESPACE "FMicrosoftOpenXRModule"
namespace MicrosoftOpenXR
{
FHandMeshPlugin::FHandState::FHandState()
{
}
bool FHandMeshPlugin::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
{
OutExtensions.Add(XR_EXT_HAND_TRACKING_EXTENSION_NAME);
OutExtensions.Add(XR_MSFT_HAND_TRACKING_MESH_EXTENSION_NAME);
return true;
}
const void* FHandMeshPlugin::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
{
XrSystemHandTrackingMeshPropertiesMSFT HandMeshTrackingSystemProperties{ XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT };
XrSystemHandTrackingPropertiesEXT HandTrackingSystemProperties{ XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, &HandMeshTrackingSystemProperties };
XrSystemProperties systemProperties{ XR_TYPE_SYSTEM_PROPERTIES, &HandTrackingSystemProperties };
XR_ENSURE(xrGetSystemProperties(InInstance, InSystem, &systemProperties));
bool bHandMeshTrackingAvailable = HandTrackingSystemProperties.supportsHandTracking != XR_FALSE && HandMeshTrackingSystemProperties.supportsHandTrackingMesh != XR_FALSE;
if (bHandMeshTrackingAvailable)
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrCreateHandTrackerEXT", (PFN_xrVoidFunction*)&xrCreateHandTrackerEXT));
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrCreateHandMeshSpaceMSFT", (PFN_xrVoidFunction*)&xrCreateHandMeshSpaceMSFT));
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrUpdateHandMeshMSFT", (PFN_xrVoidFunction*)&xrUpdateHandMeshMSFT));
for (int i=0; i<HandCount; ++i)
{
FHandState& HandState = HandStates[i];
HandState.IndicesCount = 0;
HandState.VerticesCount = 0;
HandState.VerticesMaxAmount = HandMeshTrackingSystemProperties.maxHandMeshVertexCount;
HandState.IndicesMaxAmount = HandMeshTrackingSystemProperties.maxHandMeshIndexCount;
HandState.Guid = FGuid::NewGuid();
HandState.Vertices.resize(HandState.VerticesMaxAmount);
HandState.Indices.resize(HandState.IndicesMaxAmount);
}
HandMeshStatus = EHandMeshStatus::Disabled;
}
else
{
HandMeshStatus = EHandMeshStatus::NotInitialised;
}
return InNext;
}
const void* FHandMeshPlugin::OnBeginSession(XrSession InSession, const void* InNext)
{
if (HandMeshStatus == EHandMeshStatus::NotInitialised)
{
return InNext;
}
static FName SystemName(TEXT("OpenXR"));
if (GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName))
{
XRTrackingSystem = GEngine->XRSystem.Get();
}
else
{
HandMeshStatus = EHandMeshStatus::NotInitialised;
return InNext;
}
if (IOpenXRARModule::IsAvailable())
{
TrackedMeshHolder = IOpenXRARModule::Get().GetTrackedMeshHolder();
}
else
{
HandMeshStatus = EHandMeshStatus::NotInitialised;
return InNext;
}
for (int i = 0; i < HandCount; ++i)
{
FHandState& HandState = HandStates[i];
XrHandTrackerCreateInfoEXT CreateInfo{ XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT };
CreateInfo.hand = XrHandEXT(XR_HAND_LEFT_EXT + i);
CreateInfo.handJointSet = XR_HAND_JOINT_SET_DEFAULT_EXT;
XR_ENSURE(xrCreateHandTrackerEXT(InSession, &CreateInfo, &HandState.HandTracker));
XrHandMeshSpaceCreateInfoMSFT SpaceCreateInfo{ XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT };
SpaceCreateInfo.handPoseType = XR_HAND_POSE_TYPE_TRACKED_MSFT;
SpaceCreateInfo.poseInHandMeshSpace = ToXrPose(FTransform::Identity, XRTrackingSystem->GetWorldToMetersScale());
XR_ENSURE(xrCreateHandMeshSpaceMSFT(HandState.HandTracker, &SpaceCreateInfo, &HandState.Space));
}
return InNext;
}
void FHandMeshPlugin::UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace)
{
check(IsInGameThread());
if (HandMeshStatus <= EHandMeshStatus::Disabled)
{
return;
}
for (int i = 0; i < HandCount; ++i)
{
FHandState& HandState = HandStates[i];
XrSpaceLocation SpaceLocation { XR_TYPE_SPACE_LOCATION };
XR_ENSURE(xrLocateSpace(HandState.Space, TrackingSpace, DisplayTime, &SpaceLocation));
const XrSpaceLocationFlags ValidFlags = XR_SPACE_LOCATION_ORIENTATION_VALID_BIT | XR_SPACE_LOCATION_POSITION_VALID_BIT;
if ((SpaceLocation.locationFlags & ValidFlags) == ValidFlags)
{
HandState.TrackingState = EARTrackingState::Tracking;
HandState.LocalToTrackingTransform = ToFTransform(SpaceLocation.pose, XRTrackingSystem->GetWorldToMetersScale());
XrHandMeshUpdateInfoMSFT HandMeshUpdateInfo { XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT };
HandMeshUpdateInfo.time = DisplayTime;
HandMeshUpdateInfo.handPoseType = XR_HAND_POSE_TYPE_TRACKED_MSFT;
XrHandMeshMSFT HandMesh { XR_TYPE_HAND_MESH_MSFT };
HandMesh.indexBuffer.indexCapacityInput = HandState.Indices.size();
HandMesh.indexBuffer.indices = HandState.Indices.data();
HandMesh.vertexBuffer.vertexCapacityInput = HandState.Vertices.size();
HandMesh.vertexBuffer.vertices = HandState.Vertices.data();
XR_ENSURE(xrUpdateHandMeshMSFT(HandState.HandTracker, &HandMeshUpdateInfo, &HandMesh));
if (HandMesh.indexBufferChanged)
{
HandState.IndicesCount = HandMesh.indexBuffer.indexCountOutput;
//changes in index buffer can't be independent, if index buffer changes, vertex buffers changes as well
}
if (HandMesh.vertexBufferChanged)
{
HandState.VerticesCount = HandMesh.vertexBuffer.vertexCountOutput;
}
}
else
{
//tracking lost
HandState.TrackingState = EARTrackingState::NotTracking;
HandState.IndicesCount = 0;
HandState.VerticesCount = 0;
}
}
if (HandMeshStatus != EHandMeshStatus::EnabledTrackingGeometry)
{
return;
}
TrackedMeshHolder->StartMeshUpdates();
for (int i = 0; i < HandCount; ++i)
{
FHandState& HandState = HandStates[i];
FOpenXRMeshUpdate* MeshUpdate = TrackedMeshHolder->AllocateMeshUpdate(HandState.Guid);
MeshUpdate->Type = EARObjectClassification::HandMesh;
MeshUpdate->TrackingState = HandState.TrackingState;
if (HandState.TrackingState != EARTrackingState::Tracking)
{
continue;
}
MeshUpdate->LocalToTrackingTransform = HandState.LocalToTrackingTransform;
MeshUpdate->Indices.AddUninitialized(HandState.IndicesCount * 2);
size_t TriangleCount = (size_t)HandState.IndicesCount / 3;
auto DestIndices = MeshUpdate->Indices.GetData();
auto RawIndices = HandState.Indices.data();
for (size_t j = 0; j < TriangleCount; ++j)
{
//forward face
DestIndices[0] = RawIndices[2];
DestIndices[1] = RawIndices[1];
DestIndices[2] = RawIndices[0];
//backward face
DestIndices[3] = RawIndices[0];
DestIndices[4] = RawIndices[1];
DestIndices[5] = RawIndices[2];
DestIndices += 6;
RawIndices += 3;
}
MeshUpdate->Vertices.AddUninitialized(HandState.VerticesCount);
for (size_t j = 0; j < HandState.VerticesCount; ++j)
{
auto& destVert = MeshUpdate->Vertices[j];
const auto& srcVert = HandState.Vertices[j];
destVert = ToFVector(srcVert.position, XRTrackingSystem->GetWorldToMetersScale());
}
}
TrackedMeshHolder->EndMeshUpdates();
}
void FHandMeshPlugin::Register()
{
IModularFeatures::Get().RegisterModularFeature(IHandTracker::GetModularFeatureName(), static_cast<IHandTracker*>(this));
IModularFeatures::Get().RegisterModularFeature(IOpenXRExtensionPlugin::GetModularFeatureName(), static_cast<IOpenXRExtensionPlugin*>(this));
}
void FHandMeshPlugin::Unregister()
{
IModularFeatures::Get().UnregisterModularFeature(IHandTracker::GetModularFeatureName(), static_cast<IHandTracker*>(this));
IModularFeatures::Get().UnregisterModularFeature(IOpenXRExtensionPlugin::GetModularFeatureName(), static_cast<IOpenXRExtensionPlugin*>(this));
}
bool FHandMeshPlugin::Turn(EHandMeshStatus Mode)
{
check(IsInGameThread());
if (HandMeshStatus == EHandMeshStatus::NotInitialised)
{
return false;
}
if (Mode == EHandMeshStatus::Disabled)
{
for (int i = 0; i < HandCount; ++i)
{
FHandState& HandState = HandStates[i];
HandState.IndicesCount = 0;
HandState.VerticesCount = 0;
HandState.LocalToTrackingTransform.SetIdentity();
HandState.TrackingState = EARTrackingState::NotTracking;
if (HandMeshStatus == EHandMeshStatus::EnabledTrackingGeometry)
{
TrackedMeshHolder->RemoveMesh(HandState.Guid);
}
}
}
HandMeshStatus = Mode;
return true;
}
bool FHandMeshPlugin::IsHandTrackingStateValid() const
{
if (HandMeshStatus <= EHandMeshStatus::Disabled)
{
return false;
}
for (int i = 0; i < HandCount; ++i)
{
const FHandState& HandState = HandStates[i];
if (HandState.TrackingState == EARTrackingState::Tracking)
{
return true;
}
}
return false;
}
bool FHandMeshPlugin::HasHandMeshData() const
{
if (HandMeshStatus <= EHandMeshStatus::Disabled)
{
return false;
}
for (int i = 0; i < HandCount; ++i)
{
const FHandState& HandState = HandStates[i];
if (HandState.VerticesCount > 0)
{
return true;
}
}
return false;
}
bool FHandMeshPlugin::GetHandMeshData(EControllerHand Hand, TArray<struct FVector>& OutVertices, TArray<struct FVector>& OutNormals, TArray<int32>& OutIndices, FTransform& OutHandMeshTransform) const
{
check(IsInGameThread());
if (HandMeshStatus <= EHandMeshStatus::Disabled)
{
return false;
}
const FHandState* HandState = nullptr;
if (Hand == EControllerHand::Left)
{
HandState = HandStates + Left;
}
else if (Hand == EControllerHand::Right)
{
HandState = HandStates + Right;
}
else
{
//do nothing for an unknown controller
return false;
}
if (HandMeshStatus != EHandMeshStatus::EnabledXRVisualization)
{
OutIndices.Empty();
OutVertices.Empty();
OutNormals.Empty();
OutHandMeshTransform = FTransform::Identity;
return false;
}
//clear the data without deallocation
OutIndices.Reset(HandState->IndicesCount * 2);
OutVertices.Reset(HandState->VerticesCount);
OutNormals.Reset(HandState->VerticesCount);
if (HandState->TrackingState != EARTrackingState::Tracking)
{
return false;
}
OutHandMeshTransform = HandState->LocalToTrackingTransform * XRTrackingSystem->GetTrackingToWorldTransform();
OutIndices.AddUninitialized(HandState->IndicesCount * 2);
size_t TriangleCount = (size_t)HandState->IndicesCount / 3;
auto DestIndices = OutIndices.GetData();
auto RawIndices = HandState->Indices.data();
for (size_t j = 0; j < TriangleCount; ++j)
{
//forward face
DestIndices[0] = RawIndices[2];
DestIndices[1] = RawIndices[1];
DestIndices[2] = RawIndices[0];
//backward face
DestIndices[3] = RawIndices[0];
DestIndices[4] = RawIndices[1];
DestIndices[5] = RawIndices[2];
DestIndices += 6;
RawIndices += 3;
}
OutVertices.AddUninitialized(HandState->VerticesCount);
OutNormals.AddUninitialized(HandState->VerticesCount);
for (size_t j = 0; j < HandState->VerticesCount; ++j)
{
auto& destVert = OutVertices[j];
auto& destNorm = OutNormals[j];
const auto& srcVert = HandState->Vertices[j];
destVert = ToFVector(srcVert.position, XRTrackingSystem->GetWorldToMetersScale());
destNorm = -ToFVector(srcVert.normal);
}
return true;
}
} // namespace MicrosoftOpenXR

Просмотреть файл

@ -0,0 +1,86 @@
#pragma once
#include "OpenXRCommon.h"
#include "ARTypes.h"
#include "MicrosoftOpenXR.h"
#include "IHandTracker.h"
#include <vector>
class IOpenXRARTrackedMeshHolder;
namespace MicrosoftOpenXR
{
class FHandMeshPlugin : public IOpenXRExtensionPlugin, public IHandTracker
{
public:
static const int HandCount = 2;
enum Hand {Left = 0, Right = 1};
struct FHandState : public FNoncopyable
{
FHandState();
XrHandTrackerEXT HandTracker{};
XrSpace Space{};
std::vector<uint32_t> Indices;
std::vector<XrHandMeshVertexMSFT> Vertices;
size_t VerticesCount = 0;
size_t IndicesCount = 0;
size_t VerticesMaxAmount = 0;
size_t IndicesMaxAmount = 0;
FGuid Guid;
EARTrackingState TrackingState = EARTrackingState::Unknown;
FTransform LocalToTrackingTransform;
};
void Register();
void Unregister();
bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
const void* OnBeginSession(XrSession InSession, const void* InNext) override;
void UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace) override;
bool Turn(EHandMeshStatus Mode);
private:
FHandState HandStates[HandCount];
EHandMeshStatus HandMeshStatus = EHandMeshStatus::NotInitialised;
PFN_xrCreateHandTrackerEXT xrCreateHandTrackerEXT = nullptr;
PFN_xrCreateHandMeshSpaceMSFT xrCreateHandMeshSpaceMSFT = nullptr;
PFN_xrUpdateHandMeshMSFT xrUpdateHandMeshMSFT = nullptr;
class IXRTrackingSystem* XRTrackingSystem = nullptr;
IOpenXRARTrackedMeshHolder* TrackedMeshHolder = nullptr;
// Inherited via IHandTracker
virtual FName GetHandTrackerDeviceTypeName() const override
{
return FName(TEXT("MicrosoftOpenXRHandTracking"));
}
virtual bool IsHandTrackingStateValid() const override;
virtual bool GetKeypointState(EControllerHand Hand, EHandKeypoint Keypoint, FTransform& OutTransform, float& OutRadius) const override
{
return false;
}
virtual bool GetAllKeypointStates(EControllerHand Hand, TArray<struct FVector>& OutPositions, TArray<struct FQuat>& OutRotations, TArray<float>& OutRadii) const override
{
return false;
}
virtual bool HasHandMeshData() const override;
virtual bool GetHandMeshData(EControllerHand Hand, TArray<struct FVector>& OutVertices, TArray<struct FVector>& OutNormals, TArray<int32>& OutIndices, FTransform& OutHandMeshTransform) const override;
};
} // namespace MicrosoftOpenXR

Просмотреть файл

@ -0,0 +1,408 @@
#include "HolographicRemotingPlugin.h"
#if SUPPORTS_REMOTING
#include "InputCoreTypes.h"
namespace MicrosoftOpenXR
{
void FHolographicRemotingPlugin::Register()
{
IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this);
}
void FHolographicRemotingPlugin::Unregister()
{
IModularFeatures::Get().UnregisterModularFeature(GetModularFeatureName(), this);
if (UMicrosoftOpenXRRuntimeSettings::Get())
{
UMicrosoftOpenXRRuntimeSettings::Get()->OnRemotingConnect.Unbind();
UMicrosoftOpenXRRuntimeSettings::Get()->OnRemotingDisconnect.Unbind();
}
}
bool FHolographicRemotingPlugin::GetCustomLoader(PFN_xrGetInstanceProcAddr* OutGetProcAddr)
{
remotingEnabled = ParseRemotingCmdArgs();
if (remotingEnabled)
{
FString platformName = FPlatformProperties::IniPlatformName();
const FString RemotingJsonPath = FPaths::ProjectPluginsDir() / "MicrosoftOpenXR/ThirdParty/HolographicAppRemoting" /
platformName / "Win64/RemotingXR.json";
if (FPaths::FileExists(RemotingJsonPath))
{
// Set the XR_RUNTIME_JSON environment variable to point to the app remoting dll.
// This must be done before loading openxr_loader.dll.
SetEnvironmentVariableW(L"XR_RUNTIME_JSON", *RemotingJsonPath);
}
else
{
// RemotingXR.json could not be found. Do not attempt to use remoting.
remotingEnabled = false;
UE_LOG(LogHMD, Warning,
TEXT("Remoting is desired, but RemotingXR.json could not be found at expected location: %s"),
*RemotingJsonPath);
}
}
// Return false to use the intended OpenXR loader.
return false;
}
bool FHolographicRemotingPlugin::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
{
if (remotingEnabled)
{
OutExtensions.Add(XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME);
}
return true;
}
void FHolographicRemotingPlugin::OnEvent(XrSession InSession, const XrEventDataBaseHeader* InHeader)
{
switch ((XrRemotingStructureType)InHeader->type)
{
case XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT:
SetRemotingStatusText(FString("Connected"), FLinearColor::Green);
break;
case XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT:
UpdateDisconnectedText();
break;
}
}
// Attempt to create a connection between getting the system and the OpenXRHMD constructor.
// The OpenXRHMD ctor calls some OpenXR API's which will return default values for HoloLens if a connection has not been made.
// When connecting to a VR HMD, using default values will be fatal.
void FHolographicRemotingPlugin::PostGetSystem(XrInstance InInstance, XrSystemId InSystem)
{
Instance = InInstance;
System = InSystem;
// An app remoting player must be running on the remote device for this call to succeed.
// Otherwise a disconnect will fire and a connection can happen in the editor at runtime,
// but default HoloLens values will be used in the remoting runtime.
//
// When connecting from a packaged exe, the app remoting player must be running at this time.
// Otherwise there is no suitable fallback for connecting, since xrLocateSpace will be called
// before any other event gets a chance to make another connection, and will crash without a valid connection.
ConnectToRemoteDevice(remotingConnectionData);
}
// Bind delegates here, since UMicrosoftOpenXRRuntimeSettings will now be initialized.
const void* FHolographicRemotingPlugin::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
{
#if WITH_EDITOR
// If automatically connecting to the remote device, establish the connection now.
GConfig->GetBool(TEXT("/Script/MicrosoftOpenXRRuntimeSettings.MicrosoftOpenXRRuntimeSettings"), TEXT("bAutoConnectRemoting"),
autoConnectRemoting, GEditorPerProjectIni);
if (autoConnectRemoting)
{
ParseRemotingConfig();
ConnectToRemoteDevice(remotingConnectionData);
}
if (UMicrosoftOpenXRRuntimeSettings::Get())
{
UMicrosoftOpenXRRuntimeSettings::Get()->OnRemotingConnect.BindSP(this, &FHolographicRemotingPlugin::ConnectToRemoteDevice);
UMicrosoftOpenXRRuntimeSettings::Get()->OnRemotingDisconnect.BindSP(
this, &FHolographicRemotingPlugin::DisconnectFromRemoteDevice);
}
#endif
return InNext;
}
XrRemotingConnectionStateMSFT FHolographicRemotingPlugin::GetRemotingConnectionState()
{
if (!remotingEnabled
|| System == XR_NULL_SYSTEM_ID)
{
return XrRemotingConnectionStateMSFT::XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT;
}
PFN_xrRemotingGetConnectionStateMSFT getConnectionState;
if (XR_FAILED(
xrGetInstanceProcAddr(Instance, "xrRemotingGetConnectionStateMSFT", (PFN_xrVoidFunction*)&getConnectionState)))
{
return XrRemotingConnectionStateMSFT::XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT;
}
XrRemotingConnectionStateMSFT connectionState;
if (XR_FAILED(getConnectionState(Instance, System, &connectionState, nullptr)))
{
return XrRemotingConnectionStateMSFT::XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT;
}
return connectionState;
}
void FHolographicRemotingPlugin::ConnectToRemoteDevice(RemotingConnectionData data)
{
if (!remotingEnabled)
{
return;
}
if (GetRemotingConnectionState() !=
XrRemotingConnectionStateMSFT::XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT)
{
// Already connected.
return;
}
SetRemotingStatusText("Connecting...", FLinearColor::Yellow);
if (data.IP.IsEmpty())
{
SetRemotingStatusText("Cancelled, IP is not set.", FLinearColor::Red);
return;
}
PFN_xrRemotingSetContextPropertiesMSFT setContextProperties;
XR_ENSURE(
xrGetInstanceProcAddr(Instance, "xrRemotingSetContextPropertiesMSFT", (PFN_xrVoidFunction*)&setContextProperties));
// Set remoting properties - this must be done while disconnected.
XrRemotingRemoteContextPropertiesMSFT remoteContext;
remoteContext.type = (XrStructureType)XR_TYPE_REMOTING_REMOTE_CONTEXT_PROPERTIES_MSFT;
remoteContext.next = nullptr;
remoteContext.enableAudio = data.EnableAudio;
// Protect against negative or unsuitably low bitrates.
const int minBitrate = 1000;
if (data.Bitrate < minBitrate)
{
data.Bitrate = minBitrate;
}
remoteContext.maxBitrateKbps = data.Bitrate;
remoteContext.videoCodec = (XrRemotingVideoCodecMSFT)data.ConnectionCodec;
if (XR_FAILED(setContextProperties(Instance, System, &remoteContext)))
{
SetRemotingStatusText("xrRemotingSetContextPropertiesMSFT failed, check remoting inputs.", FLinearColor::Red);
return;
}
// Listen
if (data.ConnectionType == RemotingConnectionType::Listen)
{
XrRemotingListenInfoMSFT listenInfo{ static_cast<XrStructureType>(XR_TYPE_REMOTING_LISTEN_INFO_MSFT) };
listenInfo.listenInterface = TCHAR_TO_ANSI(*data.IP.TrimStartAndEnd());
listenInfo.handshakeListenPort = data.Port;
listenInfo.transportListenPort = data.Port + 1;
listenInfo.secureConnection = false;
PFN_xrRemotingListenMSFT remotingListen;
XR_ENSURE(xrGetInstanceProcAddr(Instance, "xrRemotingListenMSFT", (PFN_xrVoidFunction*)&remotingListen));
// Connect for remote connection.
if (XR_FAILED(remotingListen(Instance, System, &listenInfo)))
{
SetRemotingStatusText("xrRemotingListenMSFT failed.", FLinearColor::Red);
return;
}
}
else // Connect
{
XrRemotingConnectInfoMSFT connectInfo{ static_cast<XrStructureType>(XR_TYPE_REMOTING_CONNECT_INFO_MSFT) };
connectInfo.remoteHostName = TCHAR_TO_ANSI(*data.IP.TrimStartAndEnd());
connectInfo.remotePort = data.Port;
connectInfo.secureConnection = false;
PFN_xrRemotingConnectMSFT remotingConnect;
XR_ENSURE(xrGetInstanceProcAddr(Instance, "xrRemotingConnectMSFT", (PFN_xrVoidFunction*)&remotingConnect));
// Connect to remote device.
if (XR_FAILED(remotingConnect(Instance, System, &connectInfo)))
{
SetRemotingStatusText("xrRemotingConnectMSFT failed.", FLinearColor::Red);
return;
}
}
}
void FHolographicRemotingPlugin::DisconnectFromRemoteDevice()
{
if (!remotingEnabled)
{
return;
}
if (GetRemotingConnectionState() ==
XrRemotingConnectionStateMSFT::XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT)
{
// Already disconnected.
return;
}
PFN_xrRemotingDisconnectMSFT remotingDisconnect;
XR_ENSURE(xrGetInstanceProcAddr(Instance, "xrRemotingDisconnectMSFT", (PFN_xrVoidFunction*)&remotingDisconnect));
// Disconnect from remote device.
XrRemotingDisconnectInfoMSFT disconnectInfo{ static_cast<XrStructureType>(XR_TYPE_REMOTING_DISCONNECT_INFO_MSFT) };
if (XR_FAILED(remotingDisconnect(Instance, System, &disconnectInfo)))
{
SetRemotingStatusText("xrRemotingDisconnectMSFT failed.", FLinearColor::Red);
return;
}
}
void FHolographicRemotingPlugin::SetRemotingStatusText(FString message, FLinearColor statusColor)
{
#if WITH_EDITOR
if (UMicrosoftOpenXRRuntimeSettings::Get() != nullptr)
{
UMicrosoftOpenXRRuntimeSettings::Get()->OnRemotingStatusChanged.ExecuteIfBound(message, statusColor);
}
#endif
UE_LOG(LogHMD, Log, TEXT("HolographicRemotingPlugin::SetRemotingStatusText: %s"), *message);
}
void FHolographicRemotingPlugin::UpdateDisconnectedText()
{
PFN_xrRemotingGetConnectionStateMSFT getConnectionState;
FString disconnectText = FString("Disconnected");
if (System != XR_NULL_SYSTEM_ID && XR_SUCCEEDED(xrGetInstanceProcAddr(Instance, "xrRemotingGetConnectionStateMSFT",
(PFN_xrVoidFunction*)&getConnectionState)))
{
XrRemotingConnectionStateMSFT connectionState;
XrRemotingDisconnectReasonMSFT disconnectReason;
if (XR_SUCCEEDED(getConnectionState(Instance, System, &connectionState, &disconnectReason)))
{
disconnectText += FString(": ") + GetDisconnectedReason((int)disconnectReason);
}
}
SetRemotingStatusText(disconnectText, FLinearColor::Red);
}
FString FHolographicRemotingPlugin::GetDisconnectedReason(int index)
{
// Copied from the XrRemotingDisconnectReasonMSFT enum.
TArray<FString> disconnectedReasons
{
FString("XR_REMOTING_DISCONNECT_REASON_NONE_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_UNKNOWN_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_NO_SERVER_CERTIFICATE_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_PORT_BUSY_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_UNREACHABLE_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_CONNECTION_FAILED_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_AUTHENTICATION_FAILED_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_REMOTING_VERSION_MISMATCH_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_INCOMPATIBLE_TRANSPORT_PROTOCOLS_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_FAILED_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_TRANSPORT_PORT_BUSY_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_TRANSPORT_UNREACHABLE_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_TRANSPORT_CONNECTION_FAILED_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_PROTOCOL_VERSION_MISMATCH_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_PROTOCOL_ERROR_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_VIDEO_CODEC_NOT_AVAILABLE_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_CANCELED_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_CONNECTION_LOST_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_DEVICE_LOST_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_DISCONNECT_REQUEST_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_NETWORK_UNREACHABLE_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_CONNECTION_REFUSED_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_VIDEO_FORMAT_NOT_AVAILABLE_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_PEER_DISCONNECT_REQUEST_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_PEER_DISCONNECT_TIMEOUT_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_SESSION_OPEN_TIMEOUT_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_REMOTING_HANDSHAKE_TIMEOUT_MSFT"),
FString("XR_REMOTING_DISCONNECT_REASON_INTERNAL_ERROR_MSFT")
};
if (!disconnectedReasons.IsValidIndex(index))
{
return FString("disconnectedReason index out of bounds: ") + FString::FromInt(index);
}
return FString::Format(TEXT("{0} ({1})"), { disconnectedReasons[index], index });
}
void FHolographicRemotingPlugin::ParseRemotingConfig()
{
#if WITH_EDITOR
GConfig->GetBool(TEXT("/Script/MicrosoftOpenXRRuntimeSettings.MicrosoftOpenXRRuntimeSettings"), TEXT("bEnableRemotingForEditor"),
remotingEnabled, GEditorPerProjectIni);
GConfig->GetString(TEXT("/Script/MicrosoftOpenXRRuntimeSettings.MicrosoftOpenXRRuntimeSettings"), TEXT("RemoteHoloLensIP"),
remotingConnectionData.IP, GEditorPerProjectIni);
GConfig->GetInt(TEXT("/Script/MicrosoftOpenXRRuntimeSettings.MicrosoftOpenXRRuntimeSettings"), TEXT("MaxBitrate"),
remotingConnectionData.Bitrate, GEditorPerProjectIni);
GConfig->GetBool(TEXT("/Script/MicrosoftOpenXRRuntimeSettings.MicrosoftOpenXRRuntimeSettings"), TEXT("EnableAudio"),
remotingConnectionData.EnableAudio, GEditorPerProjectIni);
int connectionType;
GConfig->GetInt(TEXT("/Script/MicrosoftOpenXRRuntimeSettings.MicrosoftOpenXRRuntimeSettings"), TEXT("ConnectionType"),
connectionType, GEditorPerProjectIni);
remotingConnectionData.ConnectionType = (RemotingConnectionType)connectionType;
int connectionCodec;
GConfig->GetInt(TEXT("/Script/MicrosoftOpenXRRuntimeSettings.MicrosoftOpenXRRuntimeSettings"), TEXT("ConnectionCodec"),
connectionCodec, GEditorPerProjectIni);
remotingConnectionData.ConnectionCodec = (RemotingCodec)connectionCodec;
#endif
}
bool FHolographicRemotingPlugin::ParseRemotingCmdArgs()
{
#if WITH_EDITOR
ParseRemotingConfig();
#elif !SUPPORTS_REMOTING_IN_PACKAGED_BUILD
return false;
#endif
// Use cmd args for opting into remoting from a packaged exe.
// These can also be used from the editor, and will supersede values in MicrosoftOpenXRRuntimeSettings
// when connecting from OnGetSystem. Any connections at runtime will use the editor settings.
TArray<FString> tokens, switches;
FCommandLine::Parse(FCommandLine::Get(), tokens, switches);
remotingConnectionData.EnableAudio =
switches.Contains(FString("EnableAudio"));
remotingConnectionData.ConnectionType =
switches.Contains(FString("Listen")) ? RemotingConnectionType::Listen : RemotingConnectionType::Connect;
FString codecString;
FParse::Value(FCommandLine::Get(), TEXT("RemotingCodec="), codecString);
codecString = codecString.TrimStartAndEnd().ToLower();
RemotingCodec codec = RemotingCodec::Any;
if (codecString == FString("h264"))
{
codec = RemotingCodec::H264;
}
else if (codecString == FString("h265"))
{
codec = RemotingCodec::H265;
}
else
{
codec = RemotingCodec::Any;
}
remotingConnectionData.ConnectionCodec = codec;
FParse::Value(FCommandLine::Get(), TEXT("RemotingBitrate="), remotingConnectionData.Bitrate);
FString StringToParse;
if (FParse::Value(FCommandLine::Get(), TEXT("HoloLensRemoting="), StringToParse) &&
UMicrosoftOpenXRRuntimeSettings::ParseAddress(
StringToParse, remotingConnectionData.IP, remotingConnectionData.Port))
{
// An IP to remote to was set, remoting is desired.
return true;
}
return remotingEnabled;
}
} // namespace MicrosoftOpenXR
#endif

Просмотреть файл

@ -0,0 +1,64 @@
#pragma once
// Currently remoting only supports x64 Windows: Editor and Packaged Exe
#define SUPPORTS_REMOTING (PLATFORM_WINDOWS && PLATFORM_64BITS)
#if SUPPORTS_REMOTING
#include "OpenXRCommon.h"
#include "openxr_msft_holographic_remoting.h "
#include "Windows/AllowWindowsPlatformTypes.h"
#include <Windows.h>
#include "Windows/HideWindowsPlatformTypes.h"
#include "OpenXRCore.h"
#include "HeadMountedDisplayTypes.h"
#if WITH_EDITOR
#include "Editor.h"
#endif
#include "MicrosoftOpenXRRuntimeSettings.h"
// Microsoft.Holographic.AppRemoting binaries only exist for Win64.
#define SUPPORTS_REMOTING_IN_PACKAGED_BUILD (!WITH_EDITOR && PLATFORM_DESKTOP && PLATFORM_64BITS)
namespace MicrosoftOpenXR
{
class FHolographicRemotingPlugin : public IOpenXRExtensionPlugin, public TSharedFromThis<FHolographicRemotingPlugin>
{
public:
void Register();
void Unregister();
bool GetCustomLoader(PFN_xrGetInstanceProcAddr* OutGetProcAddr) override;
bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
void OnEvent(XrSession InSession, const XrEventDataBaseHeader* InHeader) override;
void PostGetSystem(XrInstance InInstance, XrSystemId InSystem) override;
const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
private:
void* LoaderHandle;
bool remotingEnabled = false;
bool autoConnectRemoting = false;
XrInstance Instance;
XrSystemId System = XR_NULL_SYSTEM_ID;
RemotingConnectionData remotingConnectionData;
XrRemotingConnectionStateMSFT GetRemotingConnectionState();
void ConnectToRemoteDevice(RemotingConnectionData data);
void DisconnectFromRemoteDevice();
void SetRemotingStatusText(FString message, FLinearColor statusColor);
void UpdateDisconnectedText();
FString GetDisconnectedReason(int index);
void ParseRemotingConfig();
bool ParseRemotingCmdArgs();
};
} // namespace MicrosoftOpenXR
#endif

Просмотреть файл

@ -0,0 +1,52 @@
#include "HolographicWindowAttachmentPlugin.h"
#if PLATFORM_HOLOLENS
#include "HoloLens/HoloLensApplication.h"
#include <Unknwn.h>
namespace MicrosoftOpenXR
{
void FHolographicWindowAttachmentPlugin::Register()
{
IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this);
}
void FHolographicWindowAttachmentPlugin::Unregister()
{
IModularFeatures::Get().UnregisterModularFeature(GetModularFeatureName(), this);
}
bool FHolographicWindowAttachmentPlugin::GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions)
{
OutExtensions.Add(XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME);
return true;
}
const void* FHolographicWindowAttachmentPlugin::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
{
// Ensure xrCreateSession is called from the game thread which is the main app view CoreWindow thread.
check(IsInGameThread());
if (IOpenXRHMDPlugin::Get().IsExtensionEnabled(XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME))
{
// If the app requests to start in VR then the XrSession should take over the main app view's CoreWindow and
// HolographicSpace. This ensures keyboard input and other things will still route to the engine. Otherwise the
// XrSession will create its own CoreWindow and HolographicSpace and it will take all focus. The HolographicSpace will
// only be available if start in VR is enabled.
Windows::Graphics::Holographic::HolographicSpace ^ holographicSpace =
FHoloLensApplication::GetHoloLensApplication()->GetHolographicSpace();
if (holographicSpace)
{
HolographicWindowAttachment.next = InNext;
HolographicWindowAttachment.holographicSpace = reinterpret_cast<::IUnknown*>(holographicSpace);
HolographicWindowAttachment.coreWindow =
reinterpret_cast<::IUnknown*>(Windows::UI::Core::CoreWindow::GetForCurrentThread());
return &HolographicWindowAttachment;
}
}
return InNext;
}
} // namespace MicrosoftOpenXR
#endif

Просмотреть файл

@ -0,0 +1,23 @@
#pragma once
#if PLATFORM_HOLOLENS
#include "OpenXRCommon.h"
namespace MicrosoftOpenXR
{
class FHolographicWindowAttachmentPlugin : public IOpenXRExtensionPlugin
{
public:
void Register();
void Unregister();
bool GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
private:
XrHolographicWindowAttachmentMSFT HolographicWindowAttachment{XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT};
};
} // namespace MicrosoftOpenXR
#endif

Просмотреть файл

@ -0,0 +1,565 @@
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "LocatableCamPlugin.h"
#include "InputCoreTypes.h"
#include "OpenXRCore.h"
#include "IOpenXRARModule.h"
#include "IOpenXRARTrackedGeometryHolder.h"
#include "IXRTrackingSystem.h"
#include "OpenXRCameraImageTexture.h"
#include "ARSessionConfig.h"
#include "WindowsMixedRealityInteropUtility.h"
#include "Windows/AllowWindowsPlatformTypes.h"
#include "Windows/AllowWindowsPlatformAtomics.h"
#include "Windows/PreWindowsApi.h"
#include <DXGI1_4.h>
#include <mfapi.h>
#include <Windows.Graphics.DirectX.Direct3D11.interop.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Graphics.DirectX.Direct3D11.h>
#include <winrt/windows.Perception.Spatial.Preview.h>
#include <winrt/Windows.Media.Devices.h>
#include <winrt/Windows.Media.Devices.Core.h>
#include "Windows/PostWindowsApi.h"
#include "Windows/HideWindowsPlatformAtomics.h"
#include "Windows/HideWindowsPlatformTypes.h"
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Foundation::Numerics;
using namespace winrt::Windows::Perception::Spatial;
using namespace winrt::Windows::Media::Capture;
using namespace winrt::Windows::Media::Capture::Frames;
namespace MicrosoftOpenXR
{
FLocatableCamPlugin::FLocatableCamPlugin()
{
}
FLocatableCamPlugin::~FLocatableCamPlugin()
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
if (AsyncInfo)
{
AsyncInfo.Cancel();
}
}
bool FLocatableCamPlugin::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
{
OutExtensions.Add(XR_MSFT_SPATIAL_GRAPH_BRIDGE_EXTENSION_NAME);
return true;
}
const void* FLocatableCamPlugin::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrCreateSpatialGraphNodeSpaceMSFT", (PFN_xrVoidFunction*)&xrCreateSpatialGraphNodeSpaceMSFT));
static FName SystemName(TEXT("OpenXR"));
if (GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName))
{
XRTrackingSystem = GEngine->XRSystem.Get();
}
ensure(XRTrackingSystem != nullptr);
return InNext;
}
void FLocatableCamPlugin::UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace)
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
check(IsInGameThread());
if (!SharedDXTexture)
{
return;
}
if (!SharedTextureHolder)
{
UE_LOG(LogHMD, Log, TEXT("ARSession isn't started, can't capture frames"));
return;
}
if (Space == XR_NULL_HANDLE && DynamicNode.IsSet())
{
XrSpatialGraphNodeSpaceCreateInfoMSFT SpatialGraphNodeSpaceCreateInfo{ XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT };
SpatialGraphNodeSpaceCreateInfo.nodeType = XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT;
SpatialGraphNodeSpaceCreateInfo.pose = ToXrPose(DynamicNode.GetValue().Value, XRTrackingSystem->GetWorldToMetersScale());
check(sizeof(SpatialGraphNodeSpaceCreateInfo.nodeId) == sizeof(FGuid));
FMemory::Memcpy(&SpatialGraphNodeSpaceCreateInfo.nodeId, &DynamicNode.GetValue().Key, sizeof(SpatialGraphNodeSpaceCreateInfo.nodeId));
XR_ENSURE(xrCreateSpatialGraphNodeSpaceMSFT(InSession, &SpatialGraphNodeSpaceCreateInfo, &Space));
}
// We leave our pointer null until there's an image to wrap around, so create on demand
if (SharedTextureHolder->CameraImage == nullptr)
{
SharedTextureHolder->CameraImage = NewObject<UOpenXRCameraImageTexture>();
}
// This will start the async update process
SharedTextureHolder->CameraImage->Init(SharedDXTexture);
SharedDXTexture = nullptr;
PVCameraToWorldMatrix = FTransform::Identity;
if (Space != XR_NULL_HANDLE)
{
XrSpaceLocation SpaceLocation{ XR_TYPE_SPACE_LOCATION };
XR_ENSURE(xrLocateSpace(Space, TrackingSpace, DisplayTime, &SpaceLocation));
const XrSpaceLocationFlags ValidFlags = XR_SPACE_LOCATION_ORIENTATION_VALID_BIT | XR_SPACE_LOCATION_POSITION_VALID_BIT;
if ((SpaceLocation.locationFlags & ValidFlags) == ValidFlags)
{
PVCameraToWorldMatrix = ToFTransform(SpaceLocation.pose, XRTrackingSystem->GetWorldToMetersScale()) * XRTrackingSystem->GetTrackingToWorldTransform();
}
}
}
void FLocatableCamPlugin::Register()
{
IModularFeatures::Get().RegisterModularFeature(IOpenXRExtensionPlugin::GetModularFeatureName(), static_cast<IOpenXRExtensionPlugin*>(this));
}
void FLocatableCamPlugin::Unregister()
{
StopCameraCapture();
IModularFeatures::Get().UnregisterModularFeature(IOpenXRExtensionPlugin::GetModularFeatureName(), static_cast<IOpenXRExtensionPlugin*>(this));
}
void FLocatableCamPlugin::StartCameraCapture(int DesiredWidth, int DesiredHeight, int DesiredFPS)
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
check(IsInGameThread());
if (CameraFrameReader)
{
UE_LOG(LogHMD, Log, TEXT("Camera is already capturing frames. Aborting."));
return;
}
auto FindAllAsyncOp = MediaFrameSourceGroup::FindAllAsync();
AsyncInfo = FindAllAsyncOp;
FindAllAsyncOp.Completed([=](auto&& asyncInfo, auto&& asyncStatus)
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
if (AsyncInfo.Status() != winrt::Windows::Foundation::AsyncStatus::Completed)
{
AsyncInfo = nullptr;
return;
}
AsyncInfo = nullptr;
auto DiscoveredGroups = asyncInfo.GetResults();
MediaFrameSourceGroup ChosenSourceGroup = nullptr;
MediaFrameSourceInfo ChosenSourceInfo = nullptr;
MediaCaptureInitializationSettings CaptureSettings = MediaCaptureInitializationSettings();
CaptureSettings.StreamingCaptureMode(StreamingCaptureMode::Video);
CaptureSettings.MemoryPreference(MediaCaptureMemoryPreference::Auto); // For GPU
CaptureSettings.VideoProfile(nullptr);
for(auto&& Group : DiscoveredGroups)
{
// For HoloLens, use the video conferencing video profile - this will give the best power consumption.
auto profileList = MediaCapture::FindKnownVideoProfiles(Group.Id(), KnownVideoProfile::VideoConferencing);
if (profileList.Size() == 0)
{
// No video conferencing profiles in this group, move to the next one.
continue;
}
// Cache the first valid group and profile in case we do not find a profile that matches the input description.
if (ChosenSourceGroup == nullptr)
{
ChosenSourceGroup = Group;
CaptureSettings.SourceGroup(ChosenSourceGroup);
CaptureSettings.VideoProfile(profileList.GetAt(0));
}
if (DesiredWidth > 0 && DesiredHeight > 0 && DesiredFPS > 0)
{
bool found = false;
for (auto&& profile : profileList)
{
for (auto&& desc : profile.SupportedRecordMediaDescription())
{
// Check for a profile that matches our desired dimensions.
if (desc.Width() == DesiredWidth && desc.Height() == DesiredHeight && desc.FrameRate() == DesiredFPS)
{
ChosenSourceGroup = Group;
CaptureSettings.SourceGroup(Group);
CaptureSettings.VideoProfile(profile);
CaptureSettings.RecordMediaDescription(desc);
found = true;
break;
}
}
if (found)
{
break;
}
}
}
}
// If there was no camera available, then log it and bail
if (ChosenSourceGroup == nullptr)
{
UE_LOG(LogHMD, Log, TEXT("No media frame source found, so no camera images will be delivered"));
return;
}
if (DesiredWidth > 0 && DesiredHeight > 0 && DesiredFPS > 0 && CaptureSettings.RecordMediaDescription() == nullptr)
{
UE_LOG(LogHMD, Log, TEXT("No matching video format found, using default profile instead."));
}
// Find the color camera source
// Search through the infos to determine if this is the color camera source
for (auto&& Info : ChosenSourceGroup.SourceInfos())
{
if (Info.SourceKind() == MediaFrameSourceKind::Color)
{
ChosenSourceInfo = Info;
break;
}
}
// If there was no camera available, then log it and bail
if (ChosenSourceInfo == nullptr)
{
UE_LOG(LogHMD, Log, TEXT("No media frame source info found, so no camera images will be delivered"));
return;
}
// Create our capture object with our settings
winrt::agile_ref < winrt::Windows::Media::Capture::MediaCapture > Capture{ MediaCapture() };
auto InitializeAsyncOp = Capture.get().InitializeAsync(CaptureSettings);
AsyncInfo = InitializeAsyncOp;
InitializeAsyncOp.Completed([=](auto&& asyncInfo, auto&& asyncStatus)
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
if (AsyncInfo.Status() != winrt::Windows::Foundation::AsyncStatus::Completed)
{
AsyncInfo = nullptr;
UE_LOG(LogHMD, Log, TEXT("Failed to open camera, please check Webcam capability"));
return;
}
AsyncInfo = nullptr;
// Get the frame source from the source info we got earlier
MediaFrameSource FrameSource = Capture.get().FrameSources().Lookup(ChosenSourceInfo.Id());
// Now create and start the frame reader
auto CreateFrameReaderAsyncOp = Capture.get().CreateFrameReaderAsync(FrameSource);
AsyncInfo = CreateFrameReaderAsyncOp;
CreateFrameReaderAsyncOp.Completed([=](auto&& asyncInfo, auto&& asyncStatus)
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
if (AsyncInfo.Status() != winrt::Windows::Foundation::AsyncStatus::Completed)
{
AsyncInfo = nullptr;
return;
}
AsyncInfo = nullptr;
MediaFrameReader FrameReader = asyncInfo.GetResults();
auto StartAsyncOp = FrameReader.StartAsync();
AsyncInfo = StartAsyncOp;
StartAsyncOp.Completed([=](auto&& asyncInfo, auto&& asyncStatus)
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
// Finally, copy to our object
if (AsyncInfo.Status() != winrt::Windows::Foundation::AsyncStatus::Completed)
{
AsyncInfo = nullptr;
return;
}
AsyncInfo = nullptr;
MediaFrameReaderStartStatus StartStatus = asyncInfo.GetResults();
if (StartStatus == MediaFrameReaderStartStatus::Success)
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
CameraCapture = std::move(Capture);
CameraFrameReader = std::move(FrameReader);
CameraFrameSource = std::move(FrameSource);
UE_LOG(LogHMD, Log, TEXT("Successfully created the camera reader"));
// Subscribe the inbound frame event
OnFrameArrivedEvent = CameraFrameReader.FrameArrived(winrt::auto_revoke, [this](auto&& sender, auto&& args) { OnFrameArrived(sender, args); });
}
else
{
UE_LOG(LogHMD, Log, TEXT("Failed to start the frame reader with status = %d"), static_cast<int>(StartStatus));
}
});
});
});
});
}
void FLocatableCamPlugin::StopCameraCapture()
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
check(IsInGameThread());
OnFrameArrivedEvent.revoke();
if (AsyncInfo)
{
AsyncInfo.Cancel();
}
CameraIntrinsics = nullptr;
DynamicNode.Reset();
SharedDXTexture = nullptr;
if (Space != XR_NULL_HANDLE)
{
xrDestroySpace(Space);
Space = XR_NULL_HANDLE;
}
if (CameraFrameReader)
{
auto StopAsyncOp = CameraFrameReader.StopAsync();
AsyncInfo = StopAsyncOp;
StopAsyncOp.Completed([=](auto&& asyncInfo, auto&& asyncStatus)
{
if (asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed)
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
AsyncInfo = nullptr;
CameraCapture = nullptr;
CameraFrameReader = nullptr;
CameraFrameSource = nullptr;
}
});
}
}
void FLocatableCamPlugin::OnStartARSession(class UARSessionConfig* SessionConfig)
{
Format = SessionConfig->GetDesiredVideoFormat();
SharedTextureHolder = MakeShared<FSharedTextureHolder>();
}
void FLocatableCamPlugin::OnStopARSession()
{
SharedTextureHolder = nullptr;
}
TOptional<TPair<FGuid, FTransform>> FindDynamicNode(const MediaFrameReference& frame, float WorldToMetersScale)
{
// Copied MFStreamExtension_CameraExtrinsics's value from mfapi.h so that we don't have to link against Mfplat.lib.
// mfapi.h is still needed for the MFCameraExtrinsics struct.
constexpr winrt::guid CameraExtrinsicsGuid(0x6b761658, 0xb7ec, 0x4c3b, { 0x82, 0x25, 0x86, 0x23, 0xca, 0xbe, 0xc3, 0x1d });
if (auto inspectable = frame.Properties().TryLookup(CameraExtrinsicsGuid))
{
auto propertyValue = inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
if (propertyValue && propertyValue.Type() == winrt::Windows::Foundation::PropertyType::UInt8Array)
{
winrt::com_array<uint8_t> bytes;
propertyValue.GetUInt8Array(bytes);
if (bytes.size() >= sizeof(MFCameraExtrinsics))
{
const auto* const extrinsics = reinterpret_cast<const MFCameraExtrinsics*>(bytes.data());
if (extrinsics->TransformCount > 0)
{
const MFCameraExtrinsic_CalibratedTransform& transform = extrinsics->CalibratedTransforms[0];
DirectX::XMFLOAT4 rot(transform.Orientation.x, transform.Orientation.y, transform.Orientation.z, transform.Orientation.w);
DirectX::XMFLOAT3 pos(transform.Position.x, transform.Position.y, transform.Position.z);
FTransform TrackingSpaceTransform(WMRUtility::FromMixedRealityQuaternion(rot), WMRUtility::FromMixedRealityVector(pos) * WorldToMetersScale);
return MakeTuple(WMRUtility::GUIDToFGuid(transform.CalibrationId), TrackingSpaceTransform);
}
}
}
}
return {};
}
void FLocatableCamPlugin::OnFrameArrived(MediaFrameReader SendingFrameReader, MediaFrameArrivedEventArgs FrameArrivedArgs)
{
MediaFrameReference CurrentFrame = SendingFrameReader.TryAcquireLatestFrame();
if (CurrentFrame == nullptr)
{
return;
}
// Drill down through the objects to get the underlying D3D texture
VideoMediaFrame VideoFrame = CurrentFrame.VideoMediaFrame();
auto ManagedSurface = VideoFrame.Direct3DSurface();
if (ManagedSurface == nullptr)
{
UE_LOG(LogHMD, Log, TEXT("OnFrameArrived() : VideoMediaFrame->Direct3DSurface was null, so no image to process"));
return;
}
winrt::com_ptr<IDXGIResource1> srcResource = nullptr;
winrt::com_ptr<Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess> DxgiInterfaceAccess =
ManagedSurface.as<Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess>();
if (DxgiInterfaceAccess == nullptr)
{
UE_LOG(LogHMD, Log, TEXT("OnFrameArrived() : Failed to get DxgiInterfaceAccess from ManagedSurface. Cannot process image."));
return;
}
DxgiInterfaceAccess->GetInterface(IID_PPV_ARGS(srcResource.put()));
if (srcResource == nullptr)
{
UE_LOG(LogHMD, Log, TEXT("Unable to get the underlying video texture"));
return;
}
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
if (CameraFrameReader == nullptr)
{
return;
}
// Get camera intrinsics, since we just have the one camera, cache the intrinsics.
if (CameraIntrinsics == nullptr)
{
CameraIntrinsics = VideoFrame.CameraIntrinsics();
}
// Find current frame's tracking information from the frame's coordinate system.
if (!DynamicNode)
{
DynamicNode = FindDynamicNode(CurrentFrame, XRTrackingSystem->GetWorldToMetersScale());
}
auto OutSharedDXTexture = std::make_shared<winrt::handle>();
if (FAILED(srcResource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, OutSharedDXTexture->put())))
{
UE_LOG(LogHMD, Log, TEXT("Unable to create shared handler of the video texture"));
return;
}
SharedDXTexture = OutSharedDXTexture;
}
}
void FLocatableCamPlugin::FSharedTextureHolder::AddReferencedObjects(FReferenceCollector& Collector)
{
Collector.AddReferencedObject(CameraImage);
}
FTransform FLocatableCamPlugin::GetCameraTransform() const
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
return PVCameraToWorldMatrix;
}
bool FLocatableCamPlugin::GetPVCameraIntrinsics(FVector2D& focalLength, int& width, int& height, FVector2D& principalPoint, FVector& radialDistortion, FVector2D& tangentialDistortion) const
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
if (CameraIntrinsics == nullptr)
{
return false;
}
focalLength = WMRUtility::FromFloat2(CameraIntrinsics.FocalLength());
width = CameraIntrinsics.ImageWidth();
height = CameraIntrinsics.ImageHeight();
principalPoint = WMRUtility::FromFloat2(CameraIntrinsics.PrincipalPoint());
radialDistortion = WMRUtility::FromFloat3(CameraIntrinsics.RadialDistortion(), XRTrackingSystem->GetWorldToMetersScale());
tangentialDistortion = WMRUtility::FromFloat2(CameraIntrinsics.TangentialDistortion());
return true;
}
FVector FLocatableCamPlugin::GetWorldSpaceRayFromCameraPoint(FVector2D pixelCoordinate) const
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
if (CameraIntrinsics == nullptr)
{
return FVector::ZeroVector;
}
auto unprojectedPointAtUnitDepth = CameraIntrinsics.UnprojectAtUnitDepth(winrt::Windows::Foundation::Point(pixelCoordinate.X, pixelCoordinate.Y));
FVector ray = WMRUtility::FromFloat3(
winrt::Windows::Foundation::Numerics::float3(
unprojectedPointAtUnitDepth,
-1.0f // Unprojection happened at 1 meter
)
, XRTrackingSystem->GetWorldToMetersScale());
ray.Normalize();
return PVCameraToWorldMatrix.TransformVector(ray);
}
bool FLocatableCamPlugin::OnGetCameraIntrinsics(FARCameraIntrinsics& OutCameraIntrinsics) const
{
FVector radialDistortion;
FVector2D tangentialDistortion;
return GetPVCameraIntrinsics(OutCameraIntrinsics.FocalLength, OutCameraIntrinsics.ImageResolution.X, OutCameraIntrinsics.ImageResolution.Y, OutCameraIntrinsics.PrincipalPoint, radialDistortion, tangentialDistortion);
}
UARTexture* FLocatableCamPlugin::OnGetARTexture(EARTextureType TextureType) const
{
if (TextureType == EARTextureType::CameraImage)
{
return SharedTextureHolder->CameraImage;
}
return nullptr;
}
bool FLocatableCamPlugin::OnToggleARCapture(const bool bOnOff)
{
if (bOnOff)
{
StartCameraCapture(Format.Width, Format.Height, Format.FPS);
}
else
{
StopCameraCapture();
}
return true;
}
bool FLocatableCamPlugin::IsEnabled() const
{
std::lock_guard<std::recursive_mutex> lock(RefsLock);
return CameraFrameReader != nullptr;
}
IOpenXRCustomCaptureSupport* FLocatableCamPlugin::GetCustomCaptureSupport(const EARCaptureType CaptureType)
{
if (CaptureType == EARCaptureType::Camera)
{
return this;
}
return nullptr;
}
} // namespace MicrosoftOpenXR
#endif //PLATFORM_WINDOWS || PLATFORM_HOLOLENS

Просмотреть файл

@ -0,0 +1,105 @@
#pragma once
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "OpenXRCommon.h"
#include "ARTypes.h"
#include "MicrosoftOpenXR.h"
#include "ARTextures.h"
#include "Windows/AllowWindowsPlatformTypes.h"
#include "Windows/AllowWindowsPlatformAtomics.h"
#include "Windows/PreWindowsApi.h"
#include <string>
#include <sstream>
#include <mutex>
#include <memory>
#include <unknwn.h>
#include <winrt/Windows.Media.Capture.h>
#include <winrt/Windows.Media.Capture.Frames.h>
#include <winrt/Windows.Perception.Spatial.h>
#include "Windows/PostWindowsApi.h"
#include "Windows/HideWindowsPlatformAtomics.h"
#include "Windows/HideWindowsPlatformTypes.h"
class UOpenXRCameraImageTexture;
namespace MicrosoftOpenXR
{
class FLocatableCamPlugin : public IOpenXRExtensionPlugin, public IOpenXRCustomCaptureSupport
{
public:
FLocatableCamPlugin();
~FLocatableCamPlugin();
void Register();
void Unregister();
bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
void UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace) override;
virtual void OnStartARSession(class UARSessionConfig* SessionConfig) override;
virtual void OnStopARSession() override;
virtual IOpenXRCustomCaptureSupport* GetCustomCaptureSupport(const EARCaptureType CaptureType) override;
FTransform GetCameraTransform() const override;
bool GetPVCameraIntrinsics(FVector2D& focalLength, int& width, int& height, FVector2D& principalPoint, FVector& radialDistortion, FVector2D& tangentialDistortion) const;
FVector GetWorldSpaceRayFromCameraPoint(FVector2D pixelCoordinate) const override;
virtual bool OnGetCameraIntrinsics(FARCameraIntrinsics& OutCameraIntrinsics) const override;
virtual class UARTexture* OnGetARTexture(EARTextureType TextureType) const override;
virtual bool OnToggleARCapture(const bool bOnOff) override;
bool IsEnabled() const override;
private:
class FSharedTextureHolder : public FGCObject
{
public:
virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
UOpenXRCameraImageTexture* CameraImage = nullptr;
};
PFN_xrCreateSpatialGraphNodeSpaceMSFT xrCreateSpatialGraphNodeSpaceMSFT;
void StartCameraCapture(int DesiredWidth, int DesiredHeight, int DesiredFPS);
void StopCameraCapture();
void OnFrameArrived(winrt::Windows::Media::Capture::Frames::MediaFrameReader SendingFrameReader, winrt::Windows::Media::Capture::Frames::MediaFrameArrivedEventArgs FrameArrivedArgs);
/** Controls access to our references */
mutable std::recursive_mutex RefsLock;
/** The objects we need in order to receive frames of camera data */
winrt::agile_ref<winrt::Windows::Media::Capture::MediaCapture> CameraCapture = nullptr;
winrt::Windows::Media::Capture::Frames::MediaFrameReader CameraFrameReader = nullptr;
winrt::Windows::Media::Capture::Frames::MediaFrameSource CameraFrameSource = nullptr;
winrt::Windows::Media::Devices::Core::CameraIntrinsics CameraIntrinsics = nullptr;
TOptional<TPair<FGuid, FTransform>> DynamicNode;
winrt::Windows::Media::Capture::Frames::MediaFrameReader::FrameArrived_revoker OnFrameArrivedEvent;
winrt::Windows::Foundation::IAsyncInfo AsyncInfo;
std::shared_ptr<winrt::handle> SharedDXTexture;
XrSpace Space = XR_NULL_HANDLE;
class IXRTrackingSystem* XRTrackingSystem = nullptr;
FARVideoFormat Format;
FTransform PVCameraToWorldMatrix;
TSharedPtr< FSharedTextureHolder> SharedTextureHolder;
};
} // namespace MicrosoftOpenXR
#endif //PLATFORM_WINDOWS || PLATFORM_HOLOLENS

Просмотреть файл

@ -0,0 +1,159 @@
// Copyright (c) Microsoft Corporation.
#include "MicrosoftOpenXR.h"
#include "CoreMinimal.h"
#include "HolographicWindowAttachmentPlugin.h"
#include "HolographicRemotingPlugin.h"
#include "SpatialAnchorPlugin.h"
#include "Modules/ModuleManager.h"
#include "HandMeshPlugin.h"
#include "QRTrackingPlugin.h"
#include "LocatableCamPlugin.h"
#include "Interfaces/IPluginManager.h"
#include "ShaderCore.h"
#include "SpeechPlugin.h"
#include "SpatialMappingPlugin.h"
#define LOCTEXT_NAMESPACE "FMicrosoftOpenXRModule"
namespace MicrosoftOpenXR
{
static class FMicrosoftOpenXRModule * g_MicrosoftOpenXRModule;
class FMicrosoftOpenXRModule : public IModuleInterface
{
public:
void StartupModule() override
{
SpatialAnchorPlugin.Register();
HandMeshPlugin.Register();
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
QRTrackingPlugin.Register();
LocatableCamPlugin.Register();
SpeechPlugin.Register();
SpatialMappingPlugin.Register();
#endif
#if SUPPORTS_REMOTING
HolographicRemotingPlugin = MakeShared<FHolographicRemotingPlugin>();
HolographicRemotingPlugin->Register();
#endif
#if PLATFORM_HOLOLENS
HolographicWindowAttachmentPlugin.Register();
#endif
g_MicrosoftOpenXRModule = this;
}
void ShutdownModule() override
{
g_MicrosoftOpenXRModule = nullptr;
SpatialAnchorPlugin.Unregister();
HandMeshPlugin.Unregister();
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
QRTrackingPlugin.Unregister();
LocatableCamPlugin.Unregister();
SpeechPlugin.Unregister();
SpatialMappingPlugin.Unregister();
#endif
#if SUPPORTS_REMOTING
HolographicRemotingPlugin->Unregister();
#endif
#if PLATFORM_HOLOLENS
HolographicWindowAttachmentPlugin.Unregister();
#endif
}
FHandMeshPlugin HandMeshPlugin;
FSpatialAnchorPlugin SpatialAnchorPlugin;
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
FQRTrackingPlugin QRTrackingPlugin;
FLocatableCamPlugin LocatableCamPlugin;
FSpeechPlugin SpeechPlugin;
FSpatialMappingPlugin SpatialMappingPlugin;
#endif
#if SUPPORTS_REMOTING
TSharedPtr<FHolographicRemotingPlugin> HolographicRemotingPlugin;
#endif
#if PLATFORM_HOLOLENS
FHolographicWindowAttachmentPlugin HolographicWindowAttachmentPlugin;
#endif
};
} // namespace MicrosoftOpenXR
bool UMicrosoftOpenXRFunctionLibrary::SetUseHandMesh(EHandMeshStatus Mode)
{
return MicrosoftOpenXR::g_MicrosoftOpenXRModule->HandMeshPlugin.Turn(Mode);
}
bool UMicrosoftOpenXRFunctionLibrary::IsQREnabled()
{
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
return MicrosoftOpenXR::g_MicrosoftOpenXRModule->QRTrackingPlugin.IsEnabled();
#else
return false;
#endif
}
FTransform UMicrosoftOpenXRFunctionLibrary::GetPVCameraToWorldTransform()
{
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
return MicrosoftOpenXR::g_MicrosoftOpenXRModule->LocatableCamPlugin.GetCameraTransform();
#else
return FTransform::Identity;
#endif
}
bool UMicrosoftOpenXRFunctionLibrary::GetPVCameraIntrinsics(FVector2D& focalLength, int& width, int& height, FVector2D& principalPoint, FVector& radialDistortion, FVector2D& tangentialDistortion)
{
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
return MicrosoftOpenXR::g_MicrosoftOpenXRModule->LocatableCamPlugin.GetPVCameraIntrinsics(focalLength, width, height, principalPoint, radialDistortion, tangentialDistortion);
#else
return false;
#endif
}
FVector UMicrosoftOpenXRFunctionLibrary::GetWorldSpaceRayFromCameraPoint(FVector2D pixelCoordinate)
{
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
return MicrosoftOpenXR::g_MicrosoftOpenXRModule->LocatableCamPlugin.GetWorldSpaceRayFromCameraPoint(pixelCoordinate);
#else
return FVector::ZeroVector;
#endif
}
bool UMicrosoftOpenXRFunctionLibrary::IsSpeechRecognitionAvailable()
{
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
return true;
#endif
return false;
}
void UMicrosoftOpenXRFunctionLibrary::AddKeywords(TArray<FKeywordInput> Keywords)
{
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
MicrosoftOpenXR::g_MicrosoftOpenXRModule->SpeechPlugin.AddKeywords(Keywords);
#endif
}
void UMicrosoftOpenXRFunctionLibrary::RemoveKeywords(TArray<FString> Keywords)
{
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
MicrosoftOpenXR::g_MicrosoftOpenXRModule->SpeechPlugin.RemoveKeywords(Keywords);
#endif
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(MicrosoftOpenXR::FMicrosoftOpenXRModule, MicrosoftOpenXR)

Просмотреть файл

@ -0,0 +1,308 @@
#include "OpenXRCameraImageTexture.h"
#include "GlobalShader.h"
#include "RenderUtils.h"
#include "RHIStaticStates.h"
#include "PipelineStateCache.h"
#include "ShaderParameterUtils.h"
#include "SceneUtils.h"
#include "MediaShaders.h"
#include "HeadMountedDisplayTypes.h"
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "Windows/AllowWindowsPlatformTypes.h"
THIRD_PARTY_INCLUDES_START
#include <windows.h>
#include <D3D11.h>
#include <d3d11_1.h>
#include <dxgi1_2.h>
THIRD_PARTY_INCLUDES_END
#include "Windows/COMPointer.h"
#include "Windows/HideWindowsPlatformTypes.h"
#endif
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
/** Resource class to do all of the setup work on the render thread */
class FOpenXRCameraImageResource :
public FTextureResource
{
public:
FOpenXRCameraImageResource(UOpenXRCameraImageTexture* InOwner)
: LastFrameNumber(0)
, Owner(InOwner)
{
}
virtual ~FOpenXRCameraImageResource()
{
}
/**
* Called when the resource is initialized. This is only called by the rendering thread.
*/
virtual void InitRHI() override
{
check(IsInRenderingThread());
FString RHIString = FApp::GetGraphicsRHI();
if (RHIString.IsEmpty())
{
return;
}
if (RHIString != TEXT("DirectX 11"))
{
return;
}
FSamplerStateInitializerRHI SamplerStateInitializer(SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp);
SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer);
bool bDidConvert = false;
if (CameraImageHandle)
{
// Open the shared texture from the HoloLens camera on Unreal's d3d device.
ID3D11Device* D3D11Device = static_cast<ID3D11Device*>(GDynamicRHI->RHIGetNativeDevice());
TComPtr<ID3D11DeviceContext> D3D11DeviceContext = nullptr;
D3D11Device->GetImmediateContext(&D3D11DeviceContext);
if (D3D11DeviceContext == nullptr)
{
CameraImageHandle = nullptr;
return;
}
TComPtr<ID3D11Texture2D> cameraImageTexture;
TComPtr<IDXGIResource1> cameraImageResource(NULL);
if (FAILED(((ID3D11Device1*)D3D11Device)->OpenSharedResource1(CameraImageHandle->get(), __uuidof(IDXGIResource1), (void**)&cameraImageResource)))
{
UE_LOG(LogHMD, Log, TEXT("ID3D11Device1::OpenSharedResource1 failed in FOpenXRCameraImageResource::InitRHI"));
return;
}
if (FAILED(cameraImageResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)(&cameraImageTexture))))
{
UE_LOG(LogHMD, Log, TEXT("IDXGIResource1::QueryInterface failed in FOpenXRCameraImageResource::InitRHI"));
return;
}
D3D11_TEXTURE2D_DESC Desc;
cameraImageTexture->GetDesc(&Desc);
Size.X = Desc.Width;
Size.Y = Desc.Height;
// Create the copy target
{
FRHIResourceCreateInfo CreateInfo;
CopyTextureRef = RHICreateTexture2D(Size.X, Size.Y, PF_NV12, 1, 1, TexCreate_Dynamic | TexCreate_ShaderResource, CreateInfo);
}
// Create the render target
{
FRHIResourceCreateInfo CreateInfo;
TRefCountPtr<FRHITexture2D> DummyTexture2DRHI;
// Create our render target that we'll convert to
RHICreateTargetableShaderResource2D(Size.X, Size.Y, PF_B8G8R8A8, 1, TexCreate_Dynamic, TexCreate_RenderTargetable, false, CreateInfo, DecodedTextureRef, DummyTexture2DRHI);
}
if (PerformCopy(cameraImageTexture, D3D11DeviceContext))
{
PerformConversion();
bDidConvert = true;
}
// Now that the conversion is done, we can get rid of our refs
CameraImageHandle = nullptr;
CopyTextureRef.SafeRelease();
}
// Default to an empty 1x1 texture if we don't have a camera image or failed to convert
if (!bDidConvert)
{
FRHIResourceCreateInfo CreateInfo;
Size.X = Size.Y = 1;
DecodedTextureRef = RHICreateTexture2D(Size.X, Size.Y, PF_B8G8R8A8, 1, 1, TexCreate_ShaderResource, CreateInfo);
}
TextureRHI = DecodedTextureRef;
TextureRHI->SetName(Owner->GetFName());
RHIBindDebugLabelName(TextureRHI, *Owner->GetName());
RHIUpdateTextureReference(Owner->TextureReference.TextureReferenceRHI, TextureRHI);
}
virtual void ReleaseRHI() override
{
RHIUpdateTextureReference(Owner->TextureReference.TextureReferenceRHI, nullptr);
CameraImageHandle = nullptr;
CopyTextureRef.SafeRelease();
DecodedTextureRef.SafeRelease();
FTextureResource::ReleaseRHI();
}
/** Returns the width of the texture in pixels. */
virtual uint32 GetSizeX() const override
{
return Size.X;
}
/** Returns the height of the texture in pixels. */
virtual uint32 GetSizeY() const override
{
return Size.Y;
}
/** Render thread update of the texture so we don't get 2 updates per frame on the render thread */
void Init_RenderThread(std::shared_ptr<winrt::handle> handle)
{
check(IsInRenderingThread());
if (LastFrameNumber != GFrameNumber)
{
LastFrameNumber = GFrameNumber;
ReleaseRHI();
CameraImageHandle = handle;
InitRHI();
}
}
private:
/** Copy CameraImage to our CopyTextureRef using the GPU */
bool PerformCopy(const TComPtr<ID3D11Texture2D>& texture, const TComPtr<ID3D11DeviceContext>& context)
{
// These must already be prepped
if (texture == nullptr
|| context == nullptr
|| !CopyTextureRef.IsValid())
{
return false;
}
// Get the underlying interface for the texture we are copying to
TComPtr<ID3D11Resource> CopyTexture = reinterpret_cast<ID3D11Resource*>(CopyTextureRef->GetNativeResource());
if (CopyTexture == nullptr)
{
return false;
}
context->CopyResource(CopyTexture.Get(), texture);
return true;
}
/** Runs a shader to convert YUV to RGB */
void PerformConversion()
{
FRHICommandListImmediate& CommandList = FRHICommandListExecutor::GetImmediateCommandList();
SCOPED_DRAW_EVENT(CommandList, HoloLensCameraImageConversion);
FGraphicsPipelineStateInitializer GraphicsPSOInit;
FRHITexture* RenderTarget = DecodedTextureRef.GetReference();
CommandList.Transition(FRHITransitionInfo(RenderTarget, ERHIAccess::Unknown, ERHIAccess::RTV));
FIntPoint OutputDim(RenderTarget->GetSizeXYZ().X, RenderTarget->GetSizeXYZ().Y);
FRHIRenderPassInfo RPInfo(RenderTarget, ERenderTargetActions::DontLoad_Store);
CommandList.BeginRenderPass(RPInfo, TEXT("HoloLensCameraImageConversion"));
{
CommandList.ApplyCachedRenderTargets(GraphicsPSOInit);
CommandList.SetViewport(0, 0, 0.0f, OutputDim.X, OutputDim.Y, 1.0f);
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI();
GraphicsPSOInit.BlendState = TStaticBlendStateWriteMask<CW_RGBA, CW_NONE, CW_NONE, CW_NONE, CW_NONE, CW_NONE, CW_NONE, CW_NONE>::GetRHI();
GraphicsPSOInit.PrimitiveType = PT_TriangleStrip;
// configure media shaders
auto ShaderMap = GetGlobalShaderMap(GMaxRHIFeatureLevel);
TShaderMapRef<FMediaShadersVS> VertexShader(ShaderMap);
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GMediaVertexDeclaration.VertexDeclarationRHI;
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
// Use the sample format to choose the conversion path
TShaderMapRef<FNV12ConvertPS> ConvertShader(ShaderMap);
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = ConvertShader.GetPixelShader();
SetGraphicsPipelineState(CommandList, GraphicsPSOInit);
FShaderResourceViewRHIRef Y_SRV = RHICreateShaderResourceView(CopyTextureRef, 0, 1, PF_G8);
FShaderResourceViewRHIRef UV_SRV = RHICreateShaderResourceView(CopyTextureRef, 0, 1, PF_R8G8);
ConvertShader->SetParameters(CommandList, CopyTextureRef->GetSizeXY(), Y_SRV, UV_SRV, OutputDim, MediaShaders::YuvToSrgbDefault, MediaShaders::YUVOffset8bits, false);
// draw full size quad into render target
FVertexBufferRHIRef VertexBuffer = CreateTempMediaVertexBuffer();
CommandList.SetStreamSource(0, VertexBuffer, 0);
// set viewport to RT size
CommandList.SetViewport(0, 0, 0.0f, OutputDim.X, OutputDim.Y, 1.0f);
CommandList.DrawPrimitive(0, 2, 1);
}
CommandList.EndRenderPass();
CommandList.Transition(FRHITransitionInfo(RenderTarget, ERHIAccess::RTV, ERHIAccess::SRVGraphics));
}
/** The size we get from the incoming camera image */
FIntPoint Size;
/** The raw camera image from the HoloLens which we copy to our texture to allow it to be quickly released */
std::shared_ptr<winrt::handle> CameraImageHandle;
/** The nv12 texture that we copy into so we don't block the camera from being able to send frames */
FTexture2DRHIRef CopyTextureRef;
/** The texture that we actually render with which is populated via a shader that converts nv12 to rgba */
FTexture2DRHIRef DecodedTextureRef;
/** The last frame we were updated on */
uint32 LastFrameNumber;
const UOpenXRCameraImageTexture* Owner;
};
#endif
UOpenXRCameraImageTexture::UOpenXRCameraImageTexture(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, LastUpdateFrame(0)
{
}
void UOpenXRCameraImageTexture::BeginDestroy()
{
Super::BeginDestroy();
}
FTextureResource* UOpenXRCameraImageTexture::CreateResource()
{
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
return new FOpenXRCameraImageResource(this);
#else
return nullptr;
#endif
}
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
/** Forces the reconstruction of the texture data and conversion from Nv12 to RGB */
void UOpenXRCameraImageTexture::Init(std::shared_ptr<winrt::handle> handle)
{
// It's possible that we get more than one queued thread update per game frame
// Skip any additional frames because it will cause the recursive flush rendering commands ensure
if (LastUpdateFrame != GFrameCounter)
{
LastUpdateFrame = GFrameCounter;
if (Resource != nullptr)
{
FOpenXRCameraImageResource* LambdaResource = static_cast<FOpenXRCameraImageResource*>(Resource);
ENQUEUE_RENDER_COMMAND(Init_RenderThread)(
[LambdaResource, handle](FRHICommandListImmediate&)
{
LambdaResource->Init_RenderThread(handle);
});
}
else
{
// This should end up only being called once, the first time we get a texture update
UpdateResource();
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,39 @@
#pragma once
#include "ARTextures.h"
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include <memory>
#include <winrt/base.h>
#endif
#include "OpenXRCameraImageTexture.generated.h"
/**
* Provides access to the camera's image data as a texture
*/
UCLASS(NotBlueprintType)
class UOpenXRCameraImageTexture :
public UARTextureCameraImage
{
GENERATED_UCLASS_BODY()
public:
// UTexture interface implementation
virtual void BeginDestroy() override;
virtual FTextureResource* CreateResource() override;
virtual EMaterialValueType GetMaterialType() const override { return MCT_Texture2D; }
// End UTexture interface
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
/** Forces the reconstruction of the texture data and conversion from Nv12 to RGB */
virtual void Init(std::shared_ptr<winrt::handle> handle);
#endif
friend class FOpenXRCameraImageResource;
private:
/** Used to prevent two updates of the texture in the same game frame */
uint64 LastUpdateFrame;
};

Просмотреть файл

@ -0,0 +1,14 @@
#include "OpenXRCommon.h"
#include "CoreMinimal.h"
#include "OpenXRCore.h"
namespace MicrosoftOpenXR
{
XrPath GetXrPath(XrInstance Instance, const char* PathString)
{
XrPath Path = XR_NULL_PATH;
XrResult Result = xrStringToPath(Instance, PathString, &Path);
check(XR_SUCCEEDED(Result));
return Path;
}
} // namespace MicrosoftOpenXR

Просмотреть файл

@ -0,0 +1,35 @@
#pragma once
#include <openxr/openxr.h>
#include "HAL/Platform.h"
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#pragma warning(disable : 5205 4265 4268 4946)
#define XR_USE_PLATFORM_WIN32 1
#include "Windows/AllowWindowsPlatformTypes.h"
#include "Windows/AllowWindowsPlatformAtomics.h"
#include "Windows/PreWindowsApi.h"
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#endif
#include <openxr/openxr_platform.h>
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "Windows/PostWindowsApi.h"
#include "Windows/HideWindowsPlatformAtomics.h"
#include "Windows/HideWindowsPlatformTypes.h"
#endif
#include "IOpenXRHMDPlugin.h"
#include "IOpenXRExtensionPlugin.h"
namespace MicrosoftOpenXR
{
XrPath GetXrPath(XrInstance Instance, const char* PathString);
}

Просмотреть файл

@ -0,0 +1,292 @@
#include "QRTrackingPlugin.h"
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "OpenXRCore.h"
#include "IOpenXRARTrackedGeometryHolder.h"
#include "IXRTrackingSystem.h"
#include "WindowsMixedRealityInteropUtility.h"
#include <winrt/Windows.Foundation.Collections.h>
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Perception::Spatial;
using namespace winrt::Windows::Perception::Spatial::Surfaces;
using namespace winrt::Microsoft::MixedReality::QR;
namespace MicrosoftOpenXR
{
void FQRTrackingPlugin::Register()
{
IModularFeatures::Get().RegisterModularFeature(IOpenXRExtensionPlugin::GetModularFeatureName(), this);
#if PLATFORM_WINDOWS
const FString DllName = "Microsoft.MixedReality.QR.dll";
const FString LibrariesDir = FPaths::ProjectPluginsDir() / "MicrosoftOpenXR"/ THIRDPARTY_BINARY_SUBFOLDER;
FPlatformProcess::PushDllDirectory(*LibrariesDir);
if (!FPlatformProcess::GetDllHandle(*DllName))
{
UE_LOG(LogHMD, Warning, TEXT("Dll \'%s\' can't be loaded from \'%s\'"), *DllName, *LibrariesDir);
}
FPlatformProcess::PopDllDirectory(*LibrariesDir);
#endif
}
void FQRTrackingPlugin::Unregister()
{
IModularFeatures::Get().UnregisterModularFeature(IOpenXRExtensionPlugin::GetModularFeatureName(), this);
StopQRCodeWatcher();
}
bool FQRTrackingPlugin::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
{
OutExtensions.Add(XR_MSFT_SPATIAL_GRAPH_BRIDGE_EXTENSION_NAME);
return true;
}
const void* FQRTrackingPlugin::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrCreateSpatialGraphNodeSpaceMSFT", (PFN_xrVoidFunction*)&xrCreateSpatialGraphNodeSpaceMSFT));
QRCodeHolder = IModularFeatures::Get().GetModularFeatureImplementations<IOpenXRARTrackedGeometryHolder>(IOpenXRARTrackedGeometryHolder::GetModularFeatureName())[0];
ensure(QRCodeHolder != nullptr);
static FName SystemName(TEXT("OpenXR"));
if (GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName))
{
XRTrackingSystem = GEngine->XRSystem.Get();
}
ensure(XRTrackingSystem != nullptr);
return InNext;
}
bool FQRTrackingPlugin::OnToggleARCapture(const bool On)
{
if (On)
{
return StartQRCodeWatcher();
}
else
{
StopQRCodeWatcher();
}
return true;
}
bool FQRTrackingPlugin::IsEnabled() const
{
std::lock_guard<std::recursive_mutex> lock(QRCodeRefsLock);
return QRTrackerInstance != nullptr;
}
bool FQRTrackingPlugin::StartQRCodeWatcher()
{
std::lock_guard<std::recursive_mutex> lock(QRCodeRefsLock);
// Create the tracker and register the callbacks
if (QRTrackerInstance == nullptr)
{
try
{
if (!QRCodeWatcher::IsSupported())
{
UE_LOG(LogHMD, Log, TEXT("QRCodeWatcher is not supported."));
return false;
}
}
catch (winrt::hresult_error e)
{
UE_LOG(LogHMD, Error, TEXT("QRCodeWatcher::IsSupported failed with error: %d"), e.code().value);
return false;
}
m_QRTrackerAsyncOperation = QRCodeWatcher::RequestAccessAsync();
m_QRTrackerAsyncOperation.Completed([=](auto&& asyncInfo, auto&& asyncStatus)
{
if (asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed)
{
if (asyncInfo.GetResults() == QRCodeWatcherAccessStatus::Allowed)
{
std::lock_guard<std::recursive_mutex> lock(QRCodeRefsLock);
QRTrackerInstance = QRCodeWatcher();
OnAddedEventToken = QRTrackerInstance.Added(winrt::auto_revoke, [=](auto&& sender, auto&& args) { OnAdded(sender, args); });
OnUpdatedEventToken = QRTrackerInstance.Updated(winrt::auto_revoke, [=](auto&& sender, auto&& args) { OnUpdated(sender, args); });
OnRemovedEventToken = QRTrackerInstance.Removed(winrt::auto_revoke, [=](auto&& sender, auto&& args) { OnRemoved(sender, args); });
OnEnumerationCompletedToken = QRTrackerInstance.EnumerationCompleted(winrt::auto_revoke, [=](auto&& sender, auto&& args) { OnEnumerationCompleted(sender, args); });
// Start the tracker
QRTrackerInstance.Start();
m_QRTrackerAsyncOperation = nullptr;
}
else
{
UE_LOG(LogHMD, Log, TEXT("QRTracker access request returns error: %d"), asyncInfo.GetResults());
}
}
});
}
return true;
}
void FQRTrackingPlugin::StopQRCodeWatcher()
{
std::lock_guard<std::recursive_mutex> lock(QRCodeRefsLock);
if (m_QRTrackerAsyncOperation != nullptr && m_QRTrackerAsyncOperation.Status() != winrt::Windows::Foundation::AsyncStatus::Completed)
{
m_QRTrackerAsyncOperation.Cancel();
}
if (QRTrackerInstance != nullptr)
{
OnAddedEventToken.revoke();
OnUpdatedEventToken.revoke();
OnRemovedEventToken.revoke();
OnEnumerationCompletedToken.revoke();
// Stop the tracker
QRTrackerInstance.Stop();
QRTrackerInstance = nullptr;
}
{
FScopeLock Lock(&QRCodeContextsMutex);
QRCodeContexts.Empty();
}
}
void FQRTrackingPlugin::OnAdded(QRCodeWatcher sender, QRCodeAddedEventArgs args)
{
auto QRCode = new FOpenXRQRCodeData;
auto InCode = args.Code();
QRCode->Id = WMRUtility::GUIDToFGuid(InCode.Id());
QRCode->Version = (int32_t)InCode.Version();
QRCode->QRCode = InCode.Data().c_str();
QRCode->Size = FVector2D(InCode.PhysicalSideLength()) * XRTrackingSystem->GetWorldToMetersScale();
QRCode->Timestamp = FPlatformTime::Seconds();
QRCode->TrackingState = EARTrackingState::NotTracking;
QRCode->LocalToTrackingTransform = FTransform::Identity; //OnAdded returns no actual pose
auto Context = MakeShared<QRCodeContext, ESPMode::ThreadSafe>();
Context->SpatialGraphNodeId = WMRUtility::GUIDToFGuid(InCode.SpatialGraphNodeId());
{
FScopeLock Lock(&QRCodeContextsMutex);
QRCodeContexts.FindOrAdd(QRCode->Id) = Context;
}
QRCodeHolder->ARTrackedGeometryAdded(QRCode);
}
void FQRTrackingPlugin::OnUpdated(QRCodeWatcher sender, QRCodeUpdatedEventArgs args)
{
//OnUpdated works not good, so it's replaced by loop in UpdateDeviceLocations
}
void FQRTrackingPlugin::OnRemoved(QRCodeWatcher sender, QRCodeRemovedEventArgs args)
{
auto QRCode = new FOpenXRQRCodeData;
auto InCode = args.Code();
QRCode->Id = WMRUtility::GUIDToFGuid(InCode.Id());
QRCode->Timestamp = FPlatformTime::Seconds();
{
FScopeLock Lock(&QRCodeContextsMutex);
QRCodeContexts.Remove(QRCode->Id);
}
QRCodeHolder->ARTrackedGeometryRemoved(QRCode);
}
void FQRTrackingPlugin::OnEnumerationCompleted(QRCodeWatcher sender, winrt::Windows::Foundation::IInspectable args)
{
}
void FQRTrackingPlugin::UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace)
{
std::lock_guard<std::recursive_mutex> lock(QRCodeRefsLock);
if (QRTrackerInstance == nullptr) { return; }
for(auto&& InCode : QRTrackerInstance.GetList())
{
FGuid OutGuid = WMRUtility::GUIDToFGuid(InCode.Id());
QRCodeContextPtr Context;
{
FScopeLock Lock(&QRCodeContextsMutex);
if (auto PtrPtr = QRCodeContexts.Find(OutGuid))
{
Context = *PtrPtr;
}
else
{
continue; //QRCode is being deleted
}
}
auto OutCode = new FOpenXRQRCodeData;
OutCode->Id = OutGuid;
OutCode->Version = (int32_t)InCode.Version();
OutCode->QRCode = InCode.Data().c_str();
OutCode->Size = FVector2D(InCode.PhysicalSideLength()) * XRTrackingSystem->GetWorldToMetersScale();
OutCode->Timestamp = FPlatformTime::Seconds();
if (Context->Space == XR_NULL_HANDLE)
{
XrSpatialGraphNodeSpaceCreateInfoMSFT SpatialGraphNodeSpaceCreateInfo{ XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT };
SpatialGraphNodeSpaceCreateInfo.nodeType = XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT;
SpatialGraphNodeSpaceCreateInfo.pose = ToXrPose(FTransform::Identity, XRTrackingSystem->GetWorldToMetersScale());
check(sizeof(SpatialGraphNodeSpaceCreateInfo.nodeId) == sizeof(FGuid));
FMemory::Memcpy(&SpatialGraphNodeSpaceCreateInfo.nodeId, &Context->SpatialGraphNodeId, sizeof(SpatialGraphNodeSpaceCreateInfo.nodeId));
XR_ENSURE(xrCreateSpatialGraphNodeSpaceMSFT(InSession, &SpatialGraphNodeSpaceCreateInfo, &Context->Space));
}
XrSpaceLocation SpaceLocation{ XR_TYPE_SPACE_LOCATION };
XR_ENSURE(xrLocateSpace(Context->Space, TrackingSpace, DisplayTime, &SpaceLocation));
const XrSpaceLocationFlags ValidFlags = XR_SPACE_LOCATION_ORIENTATION_VALID_BIT | XR_SPACE_LOCATION_POSITION_VALID_BIT;
if ((SpaceLocation.locationFlags & ValidFlags) == ValidFlags)
{
OutCode->LocalToTrackingTransform = ToFTransform(SpaceLocation.pose, XRTrackingSystem->GetWorldToMetersScale());
OutCode->TrackingState = EARTrackingState::Tracking;
}
else
{
OutCode->TrackingState = EARTrackingState::NotTracking;
}
QRCodeHolder->ARTrackedGeometryUpdated(OutCode);
}
}
IOpenXRCustomCaptureSupport* FQRTrackingPlugin::GetCustomCaptureSupport(const EARCaptureType CaptureType)
{
if (CaptureType == EARCaptureType::QRCode)
{
return this;
}
return nullptr;
}
FQRTrackingPlugin::QRCodeContext::~QRCodeContext()
{
if (Space != XR_NULL_HANDLE)
{
xrDestroySpace(Space);
}
}
} // namespace MicrosoftOpenXR
#endif //PLATFORM_WINDOWS || PLATFORM_HOLOLENS

Просмотреть файл

@ -0,0 +1,87 @@
#pragma once
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "OpenXRCommon.h"
#include "ARTypes.h"
#include "Windows/AllowWindowsPlatformTypes.h"
#include "Windows/AllowWindowsPlatformAtomics.h"
#include "Windows/PreWindowsApi.h"
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Perception.Spatial.h>
#include <winrt/Windows.Perception.Spatial.Surfaces.h>
#include <winrt/Microsoft.MixedReality.QR.h>
#include <mutex>
#include "Windows/PostWindowsApi.h"
#include "Windows/HideWindowsPlatformAtomics.h"
#include "Windows/HideWindowsPlatformTypes.h"
class IOpenXRARTrackedGeometryHolder;
struct FOpenXRQRCodeData;
namespace MicrosoftOpenXR
{
class FQRTrackingPlugin : public IOpenXRExtensionPlugin, public IOpenXRCustomCaptureSupport
{
public:
void Register();
void Unregister();
virtual bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
virtual const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
virtual void UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace) override;
virtual IOpenXRCustomCaptureSupport* GetCustomCaptureSupport(const EARCaptureType CaptureType) override;
bool OnToggleARCapture(const bool bOnOff);
bool IsEnabled() const;
private:
PFN_xrCreateSpatialGraphNodeSpaceMSFT xrCreateSpatialGraphNodeSpaceMSFT;
bool StartQRCodeWatcher();
void StopQRCodeWatcher();
// WinRT handlers
void OnAdded(winrt::Microsoft::MixedReality::QR::QRCodeWatcher sender, winrt::Microsoft::MixedReality::QR::QRCodeAddedEventArgs args);
void OnUpdated(winrt::Microsoft::MixedReality::QR::QRCodeWatcher sender, winrt::Microsoft::MixedReality::QR::QRCodeUpdatedEventArgs args);
void OnRemoved(winrt::Microsoft::MixedReality::QR::QRCodeWatcher sender, winrt::Microsoft::MixedReality::QR::QRCodeRemovedEventArgs args);
void OnEnumerationCompleted(winrt::Microsoft::MixedReality::QR::QRCodeWatcher sender, winrt::Windows::Foundation::IInspectable args);
winrt::Microsoft::MixedReality::QR::QRCodeWatcher QRTrackerInstance = nullptr;
winrt::Windows::Foundation::IAsyncOperation < winrt::Microsoft::MixedReality::QR::QRCodeWatcherAccessStatus > m_QRTrackerAsyncOperation = nullptr;
winrt::Microsoft::MixedReality::QR::QRCodeWatcher::Added_revoker OnAddedEventToken;
winrt::Microsoft::MixedReality::QR::QRCodeWatcher::Updated_revoker OnUpdatedEventToken;
winrt::Microsoft::MixedReality::QR::QRCodeWatcher::Removed_revoker OnRemovedEventToken;
winrt::Microsoft::MixedReality::QR::QRCodeWatcher::EnumerationCompleted_revoker OnEnumerationCompletedToken;
mutable std::recursive_mutex QRCodeRefsLock;
struct QRCodeContext
{
EARTrackingState TrackingState = EARTrackingState::Unknown;
FGuid SpatialGraphNodeId;
XrSpace Space = XR_NULL_HANDLE;
~QRCodeContext();
};
typedef TSharedPtr<QRCodeContext, ESPMode::ThreadSafe> QRCodeContextPtr;
IOpenXRARTrackedGeometryHolder* QRCodeHolder;
class IXRTrackingSystem* XRTrackingSystem = nullptr;
TMap<FGuid, QRCodeContextPtr > QRCodeContexts;
FCriticalSection QRCodeContextsMutex;
};
} // namespace MicrosoftOpenXR
#endif //PLATFORM_WINDOWS || PLATFORM_HOLOLENS

Просмотреть файл

@ -0,0 +1,287 @@
#include "SpatialAnchorPlugin.h"
#include "OpenXRCore.h"
#include "ARPin.h"
#if HL_ANCHOR_STORE_AVAILABLE
using namespace winrt::Windows::Perception::Spatial;
using namespace winrt::Windows::Foundation;
#endif
namespace MicrosoftOpenXR
{
void FSpatialAnchorPlugin::Register()
{
IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this);
}
void FSpatialAnchorPlugin::Unregister()
{
#if HL_ANCHOR_STORE_AVAILABLE
{
std::lock_guard<std::mutex> lock(m_spatialAnchorStoreLock);
if (m_spatialAnchorStoreAsyncOperation != nullptr && m_spatialAnchorStoreAsyncOperation.Status() != winrt::Windows::Foundation::AsyncStatus::Completed)
{
m_spatialAnchorStoreAsyncOperation.Cancel();
}
m_spatialAnchorStore = nullptr;
}
#endif
IModularFeatures::Get().UnregisterModularFeature(GetModularFeatureName(), this);
}
bool FSpatialAnchorPlugin::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
{
OutExtensions.Add(XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME);
return true;
}
bool FSpatialAnchorPlugin::GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions)
{
#if HL_ANCHOR_STORE_AVAILABLE
OutExtensions.Add(XR_MSFT_PERCEPTION_ANCHOR_INTEROP_PREVIEW_EXTENSION_NAME);
#endif
return true;
}
const void* FSpatialAnchorPlugin::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrCreateSpatialAnchorMSFT", (PFN_xrVoidFunction*) &xrCreateSpatialAnchorMSFT));
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrCreateSpatialAnchorSpaceMSFT",(PFN_xrVoidFunction*) &xrCreateSpatialAnchorSpaceMSFT));
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrDestroySpatialAnchorMSFT", (PFN_xrVoidFunction*) &xrDestroySpatialAnchorMSFT));
#if HL_ANCHOR_STORE_AVAILABLE
bIsLocalAnchorStoreSupported = IOpenXRHMDPlugin::Get().IsExtensionEnabled(XR_MSFT_PERCEPTION_ANCHOR_INTEROP_PREVIEW_EXTENSION_NAME);
if (bIsLocalAnchorStoreSupported)
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrCreateSpatialAnchorFromPerceptionAnchorMSFT", (PFN_xrVoidFunction*) &xrCreateSpatialAnchorFromPerceptionAnchorMSFT));
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrTryGetPerceptionAnchorFromSpatialAnchorMSFT", (PFN_xrVoidFunction*) &xrTryGetPerceptionAnchorFromSpatialAnchorMSFT));
{
std::lock_guard<std::mutex> lock(m_spatialAnchorStoreLock);
m_spatialAnchorStoreAsyncOperation = SpatialAnchorManager::RequestStoreAsync();
m_spatialAnchorStoreAsyncOperation.Completed([this](IAsyncOperation<SpatialAnchorStore> asyncOperation, AsyncStatus status)
{
std::lock_guard<std::mutex> lock(m_spatialAnchorStoreLock);
if (asyncOperation.Status() == AsyncStatus::Completed)
{
m_spatialAnchorStore = asyncOperation.GetResults();
}
m_spatialAnchorStoreAsyncOperation = nullptr;
});
}
}
#endif
return InNext;
}
IOpenXRCustomAnchorSupport* FSpatialAnchorPlugin::GetCustomAnchorSupport()
{
return this;
}
bool FSpatialAnchorPlugin::OnPinComponent(class UARPin* NewPin, XrSession InSession, XrSpace TrackingSpace, XrTime DisplayTime, float worldToMeterScale)
{
XrResult result;
XrSpatialAnchorCreateInfoMSFT AnchorCreateDesc = {};
AnchorCreateDesc.type = XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT;
AnchorCreateDesc.next = nullptr;
AnchorCreateDesc.pose = ToXrPose(NewPin->GetLocalToTrackingTransform(), worldToMeterScale);
AnchorCreateDesc.space = TrackingSpace;
AnchorCreateDesc.time = DisplayTime;
XrSpatialAnchorMSFT AnchorId = {};
result = xrCreateSpatialAnchorMSFT(InSession, &AnchorCreateDesc, &AnchorId);
if (XR_FAILED(result))
{
return false;
}
XrSpatialAnchorSpaceCreateInfoMSFT AnchorSpaceCreateDesc = {};
AnchorSpaceCreateDesc.type = XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT;
AnchorSpaceCreateDesc.next = nullptr;
AnchorSpaceCreateDesc.poseInAnchorSpace = ToXrPose(FTransform::Identity);
AnchorSpaceCreateDesc.anchor = AnchorId;
XrSpace AnchorSpace = {};
result = xrCreateSpatialAnchorSpaceMSFT(InSession, &AnchorSpaceCreateDesc, &AnchorSpace);
if (XR_FAILED(result))
{
xrDestroySpatialAnchorMSFT(AnchorId);
return false;
}
SAnchorMSFT* AnchorMSFT = new SAnchorMSFT;
AnchorMSFT->AnchorId = AnchorId;
AnchorMSFT->Space = AnchorSpace;
NewPin->SetNativeResource(reinterpret_cast<void*>(AnchorMSFT));
return true;
}
void FSpatialAnchorPlugin::OnRemovePin(class UARPin* Pin)
{
if (void* nativeResource = Pin->GetNativeResource())
{
SAnchorMSFT* AnchorMSFT = reinterpret_cast<SAnchorMSFT*>(nativeResource);
xrDestroySpatialAnchorMSFT(AnchorMSFT->AnchorId);
xrDestroySpace(AnchorMSFT->Space);
delete AnchorMSFT;
}
}
void FSpatialAnchorPlugin::OnUpdatePin(class UARPin* Pin, XrSession InSession, XrSpace TrackingSpace, XrTime DisplayTime, float worldToMeterScale)
{
if (void* nativeResource = Pin->GetNativeResource())
{
SAnchorMSFT* AnchorMSFT = reinterpret_cast<SAnchorMSFT*>(nativeResource);
XrResult result;
XrSpaceLocation SpaceLocation = {};
SpaceLocation.type = XR_TYPE_SPACE_LOCATION;
SpaceLocation.next = nullptr;
result = xrLocateSpace(AnchorMSFT->Space, TrackingSpace, DisplayTime, &SpaceLocation);
const XrSpaceLocationFlags ValidFlags = XR_SPACE_LOCATION_ORIENTATION_VALID_BIT | XR_SPACE_LOCATION_POSITION_VALID_BIT;
if (XR_SUCCEEDED(result) && ((SpaceLocation.locationFlags & ValidFlags) == ValidFlags))
{
FTransform Transform = ToFTransform(SpaceLocation.pose, worldToMeterScale);
Pin->OnTransformUpdated(Transform);
Pin->OnTrackingStateChanged(EARTrackingState::Tracking);
}
else
{
Pin->OnTrackingStateChanged(EARTrackingState::NotTracking);
}
}
}
bool FSpatialAnchorPlugin::IsLocalPinSaveSupported() const
{
return bIsLocalAnchorStoreSupported;
}
bool FSpatialAnchorPlugin::ArePinsReadyToLoad()
{
#if HL_ANCHOR_STORE_AVAILABLE
std::lock_guard<std::mutex> lock(m_spatialAnchorStoreLock);
return m_spatialAnchorStore != nullptr;
#else
return false;
#endif
}
void FSpatialAnchorPlugin::LoadARPins(XrSession InSession, TFunction<UARPin*(FName)> OnCreatePin)
{
#if HL_ANCHOR_STORE_AVAILABLE
std::lock_guard<std::mutex> lock(m_spatialAnchorStoreLock);
if (m_spatialAnchorStore == nullptr) { return; }
for(auto p : m_spatialAnchorStore.GetAllSavedAnchors())
{
XrResult result;
auto name = p.Key();
auto wmrAnchor = p.Value();
auto NewPin = OnCreatePin(FName(name.c_str()));
if (NewPin == nullptr)
{
//the anchor is already loaded
continue;
}
XrSpatialAnchorMSFT AnchorId = {};
result = xrCreateSpatialAnchorFromPerceptionAnchorMSFT(InSession, winrt::get_unknown(wmrAnchor), &AnchorId);
if (XR_FAILED(result))
{
continue;
}
XrSpatialAnchorSpaceCreateInfoMSFT AnchorSpaceCreateDesc = {};
AnchorSpaceCreateDesc.type = XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT;
AnchorSpaceCreateDesc.next = nullptr;
AnchorSpaceCreateDesc.poseInAnchorSpace = ToXrPose(FTransform::Identity);
AnchorSpaceCreateDesc.anchor = AnchorId;
XrSpace AnchorSpace = {};
result = xrCreateSpatialAnchorSpaceMSFT(InSession, &AnchorSpaceCreateDesc, &AnchorSpace);
if (XR_FAILED(result))
{
xrDestroySpatialAnchorMSFT(AnchorId);
continue;
}
SAnchorMSFT* AnchorMSFT = new SAnchorMSFT;
AnchorMSFT->AnchorId = AnchorId;
AnchorMSFT->Space = AnchorSpace;
NewPin->SetNativeResource(reinterpret_cast<void*>(AnchorMSFT));
}
#endif
}
bool FSpatialAnchorPlugin::SaveARPin(XrSession InSession, FName InName, UARPin* Pin)
{
#if HL_ANCHOR_STORE_AVAILABLE
std::lock_guard<std::mutex> lock(m_spatialAnchorStoreLock);
if (m_spatialAnchorStore == nullptr) { return false; }
void* nativeResource = Pin->GetNativeResource();
if (nativeResource == nullptr) { return false; }
SAnchorMSFT* AnchorMSFT = reinterpret_cast<SAnchorMSFT*>(nativeResource);
XrResult result;
SpatialAnchor wmrAnchor = nullptr;
result = xrTryGetPerceptionAnchorFromSpatialAnchorMSFT(InSession, AnchorMSFT->AnchorId, reinterpret_cast<::IUnknown**>(winrt::put_abi(wmrAnchor)));
if (XR_FAILED(result))
{
return false;
}
const FString SaveId = InName.ToString().ToLower();
return m_spatialAnchorStore.TrySave(*SaveId, wmrAnchor);
#else
return false;
#endif
}
void FSpatialAnchorPlugin::RemoveSavedARPin(XrSession InSession, FName InName)
{
#if HL_ANCHOR_STORE_AVAILABLE
std::lock_guard<std::mutex> lock(m_spatialAnchorStoreLock);
if (m_spatialAnchorStore == nullptr) { return; }
const FString SaveId = InName.ToString().ToLower();
m_spatialAnchorStore.Remove(*SaveId);
#endif
}
void FSpatialAnchorPlugin::RemoveAllSavedARPins(XrSession InSession)
{
#if HL_ANCHOR_STORE_AVAILABLE
std::lock_guard<std::mutex> lock(m_spatialAnchorStoreLock);
if (m_spatialAnchorStore == nullptr) { return; }
m_spatialAnchorStore.Clear();
#endif
}
} // namespace MicrosoftOpenXR

Просмотреть файл

@ -0,0 +1,83 @@
#pragma once
#include "OpenXRCommon.h"
#if (PLATFORM_WINDOWS || PLATFORM_HOLOLENS)
#include "Windows/AllowWindowsPlatformTypes.h"
#include "Windows/AllowWindowsPlatformAtomics.h"
#include "Windows/PreWindowsApi.h"
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Perception.Spatial.h>
#include <winrt/Windows.Foundation.Collections.h>
#include "Windows/PostWindowsApi.h"
#include "Windows/HideWindowsPlatformAtomics.h"
#include "Windows/HideWindowsPlatformTypes.h"
#include <mutex>
#define HL_ANCHOR_STORE_AVAILABLE 1
#else
#define HL_ANCHOR_STORE_AVAILABLE 0
#endif
namespace MicrosoftOpenXR
{
class FSpatialAnchorPlugin : public IOpenXRExtensionPlugin, public IOpenXRCustomAnchorSupport
{
public:
void Register();
void Unregister();
virtual bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
virtual bool GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
virtual const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
virtual IOpenXRCustomAnchorSupport* GetCustomAnchorSupport() override;
virtual bool OnPinComponent(class UARPin* Pin, XrSession InSession, XrSpace TrackingSpace, XrTime DisplayTime, float worldToMeterScale) override;
virtual void OnRemovePin(class UARPin* Pin) override;
virtual void OnUpdatePin(class UARPin* Pin, XrSession InSession, XrSpace TrackingSpace, XrTime DisplayTime, float worldToMeterScale) override;
virtual bool IsLocalPinSaveSupported() const override;
virtual bool ArePinsReadyToLoad() override;
virtual void LoadARPins(XrSession InSession, TFunction<UARPin*(FName)> OnCreatePin) override;
virtual bool SaveARPin(XrSession InSession, FName InName, UARPin* InPin) override;
virtual void RemoveSavedARPin(XrSession InSession, FName InName) override;
virtual void RemoveAllSavedARPins(XrSession InSession) override;
private:
struct SAnchorMSFT
{
XrSpatialAnchorMSFT AnchorId;
XrSpace Space;
};
PFN_xrCreateSpatialAnchorMSFT xrCreateSpatialAnchorMSFT;
PFN_xrDestroySpatialAnchorMSFT xrDestroySpatialAnchorMSFT;
PFN_xrCreateSpatialAnchorSpaceMSFT xrCreateSpatialAnchorSpaceMSFT;
bool bIsLocalAnchorStoreSupported = false;
#if HL_ANCHOR_STORE_AVAILABLE
PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT xrCreateSpatialAnchorFromPerceptionAnchorMSFT;
PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT xrTryGetPerceptionAnchorFromSpatialAnchorMSFT;
std::mutex m_spatialAnchorStoreLock;
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Perception::Spatial::SpatialAnchorStore> m_spatialAnchorStoreAsyncOperation;
winrt::Windows::Perception::Spatial::SpatialAnchorStore m_spatialAnchorStore{ nullptr };
#endif
};
} // namespace MicrosoftOpenXR

Просмотреть файл

@ -0,0 +1,570 @@
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "SpatialMappingPlugin.h"
#include "ARBlueprintLibrary.h"
using namespace winrt::Windows::Perception::Spatial;
using namespace winrt::Windows::Perception::Spatial::Surfaces;
namespace MicrosoftOpenXR
{
void FSpatialMappingPlugin::Register()
{
IModularFeatures::Get().RegisterModularFeature(IOpenXRExtensionPlugin::GetModularFeatureName(), static_cast<IOpenXRExtensionPlugin*>(this));
MeshOptions = SpatialSurfaceMeshOptions();
MeshOptions.IncludeVertexNormals(false);
MeshOptions.VertexPositionFormat(winrt::Windows::Graphics::DirectX::DirectXPixelFormat::R16G16B16A16IntNormalized);
MeshOptions.TriangleIndexFormat(winrt::Windows::Graphics::DirectX::DirectXPixelFormat::R16UInt);
}
void FSpatialMappingPlugin::Unregister()
{
IModularFeatures::Get().UnregisterModularFeature(IOpenXRExtensionPlugin::GetModularFeatureName(), static_cast<IOpenXRExtensionPlugin*>(this));
StopMeshObserver();
AnchorLocalizationData.clear();
}
bool FSpatialMappingPlugin::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
{
OutExtensions.Add(XR_MSFT_PERCEPTION_ANCHOR_INTEROP_PREVIEW_EXTENSION_NAME);
OutExtensions.Add(XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME);
return true;
}
const void* FSpatialMappingPlugin::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
{
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrCreateSpatialAnchorFromPerceptionAnchorMSFT", (PFN_xrVoidFunction*)&xrCreateSpatialAnchorFromPerceptionAnchorMSFT));
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrCreateSpatialAnchorSpaceMSFT", (PFN_xrVoidFunction*)&xrCreateSpatialAnchorSpaceMSFT));
XR_ENSURE(xrGetInstanceProcAddr(InInstance, "xrDestroySpatialAnchorMSFT", (PFN_xrVoidFunction*)&xrDestroySpatialAnchorMSFT));
return InNext;
}
const void* FSpatialMappingPlugin::OnBeginSession(XrSession InSession, const void* InNext)
{
static FName SystemName(TEXT("OpenXR"));
if (GEngine->XRSystem.IsValid() && (GEngine->XRSystem->GetSystemName() == SystemName))
{
XRTrackingSystem = GEngine->XRSystem.Get();
}
else
{
return InNext;
}
if (IOpenXRARModule::IsAvailable())
{
TrackedMeshHolder = IOpenXRARModule::Get().GetTrackedMeshHolder();
}
else
{
return InNext;
}
return InNext;
}
bool FSpatialMappingPlugin::FindMeshTransform(XrSpace AnchorSpace, XrTime DisplayTime, XrSpace TrackingSpace, FTransform MeshToCachedAnchorTransform, FTransform& Transform, bool& IsTracking)
{
auto Scale = XRTrackingSystem->GetWorldToMetersScale();
IsTracking = false;
XrSpaceLocation SpaceLocation{ XR_TYPE_SPACE_LOCATION };
XrResult result = xrLocateSpace(AnchorSpace, TrackingSpace, DisplayTime, &SpaceLocation);
if (XR_FAILED(result))
{
return false;
}
constexpr XrSpaceLocationFlags TrackingFlags =
XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT | XR_SPACE_LOCATION_POSITION_TRACKED_BIT;
IsTracking = ((SpaceLocation.locationFlags & TrackingFlags) == TrackingFlags);
constexpr XrSpaceLocationFlags ValidFlags =
XR_SPACE_LOCATION_ORIENTATION_VALID_BIT | XR_SPACE_LOCATION_POSITION_VALID_BIT;
if ((SpaceLocation.locationFlags & ValidFlags) == ValidFlags)
{
FTransform LocalToTrackingTransform = ToFTransform(SpaceLocation.pose, Scale);
Transform = MeshToCachedAnchorTransform * LocalToTrackingTransform;
return true;
}
return false;
}
bool FSpatialMappingPlugin::GetTransformBetweenCoordinateSystems(SpatialCoordinateSystem From, SpatialCoordinateSystem To, FTransform& Transform)
{
auto transform = From.TryGetTransformTo(To);
if (!transform)
{
return false;
}
auto meshToCached = transform.Value();
Transform = WMRUtility::FromMixedRealityTransform(DirectX::XMLoadFloat4x4(&meshToCached), XRTrackingSystem->GetWorldToMetersScale());
return true;
}
bool FSpatialMappingPlugin::LocateSpatialMeshInTrackingSpace(const FGuid& MeshID, SpatialCoordinateSystem MeshCoordinateSystem, XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace, FTransform& Transform)
{
bool IsTracking = false;
// If a known anchor exists for this mesh, use it to locate the mesh transform.
auto cachedAnchorDataForThisMesh = AnchorLocalizationData.find(MeshID);
if (cachedAnchorDataForThisMesh != AnchorLocalizationData.end())
{
// This mesh could be localizing against another mesh's coordinate system, apply the offset when getting the mesh transform.
FTransform MeshToCachedAnchorTransform;
if (GetTransformBetweenCoordinateSystems(MeshCoordinateSystem, cachedAnchorDataForThisMesh->second->CoordinateSystem, MeshToCachedAnchorTransform)
&& FindMeshTransform(cachedAnchorDataForThisMesh->second->AnchorSpace, DisplayTime, TrackingSpace, MeshToCachedAnchorTransform, Transform, IsTracking))
{
return true;
}
// If we failed to locate the mesh and are not tracking, return now. The meshes will continue to be localized after tracking is regained.
// However, if we do have tracking, we may have a new coordinate system for the mesh and should recreate it's localization data.
if (!IsTracking)
{
return false;
}
}
// If we get here with cached anchor data, The device is tracking, but we have failed to localize against the known cached data.
// This likely happens when the mesh gets a new coordinate system. Skip looking at existing localization data, and create new data instead.
if (cachedAnchorDataForThisMesh == AnchorLocalizationData.end())
{
// Otherwise, attempt to locate the SpatialSurfaceMesh from all cached coordinate systems.
for (const auto& data : AnchorLocalizationData)
{
// This mesh will be localizing against another mesh's coordinate system, apply the offset when getting the mesh transform.
FTransform MeshToCachedAnchorTransform;
if (!GetTransformBetweenCoordinateSystems(MeshCoordinateSystem, data.second->CoordinateSystem, MeshToCachedAnchorTransform))
{
continue;
}
if (FindMeshTransform(data.second->AnchorSpace, DisplayTime, TrackingSpace, MeshToCachedAnchorTransform, Transform, IsTracking))
{
// Add to the anchor localization data, so the next time this mesh is updated it will have a direct entry in the map.
AnchorLocalizationData.insert({ MeshID, data.second });
return true;
}
}
}
// If no cached anchor exists that can locate the mesh, create a new anchor.
// Each spatial mapping mesh is positioned in its own space relative to its coordinate system.
// Create a temporary anchor at this coordinate system to localize against the TrackingSpace.
auto wmrAnchor = SpatialAnchor::TryCreateRelativeTo(MeshCoordinateSystem);
if (wmrAnchor == nullptr)
{
// If the new anchor and all cached anchors cannot find the mesh, ignore it.
return false;
}
XrSpatialAnchorMSFT Anchor;
XrResult result = xrCreateSpatialAnchorFromPerceptionAnchorMSFT(InSession, winrt::get_unknown(wmrAnchor), &Anchor);
if (XR_FAILED(result))
{
return false;
}
XrSpatialAnchorSpaceCreateInfoMSFT AnchorSpaceCreateDesc{ XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT };
AnchorSpaceCreateDesc.poseInAnchorSpace = ToXrPose(FTransform::Identity);
AnchorSpaceCreateDesc.anchor = Anchor;
bool MeshLocated = true;
XrSpace AnchorSpace = XR_NULL_HANDLE;
result = xrCreateSpatialAnchorSpaceMSFT(InSession, &AnchorSpaceCreateDesc, &AnchorSpace);
if (XR_FAILED(result))
{
wmrAnchor = nullptr;
xrDestroySpatialAnchorMSFT(Anchor);
return false;
}
if (!FindMeshTransform(AnchorSpace, DisplayTime, TrackingSpace, FTransform::Identity, Transform, IsTracking))
{
// The mesh has not been located in tracking space, but this anchor space may still be locatable in the future.
MeshLocated = false;
}
if (cachedAnchorDataForThisMesh == AnchorLocalizationData.end())
{
// Cache localization data to compare against future meshes.
AnchorLocalizationData.insert({ MeshID, MakeShared<WMRAnchorLocalizationData>(AnchorSpace, MeshCoordinateSystem) });
}
else
{
// Overwrite existing anchor localization data.
cachedAnchorDataForThisMesh->second = MakeShared<WMRAnchorLocalizationData>(AnchorSpace, MeshCoordinateSystem);
}
if (AnchorLocalizationData.size() > WarnAfterThisManyMeshes)
{
UE_LOG(LogHMD, Warning,
TEXT("Spatial mapping has recognized %d spaces, performance may be impacted."),
AnchorLocalizationData.size());
}
wmrAnchor = nullptr;
xrDestroySpatialAnchorMSFT(Anchor);
return MeshLocated;
}
void FSpatialMappingPlugin::UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace)
{
std::map<FGuid, MeshLocalizationData>::iterator Mesh;
{
// Since UpdateDeviceLocations is performed on the game thread, update a single spatial mesh per frame.
// This prevents stalls when the number of spatial meshes is large.
std::lock_guard<std::mutex> lock(MeshRefsLock);
if (UniqueMeshes.empty())
{
return;
}
if (MeshToLocalizeThisFrame >= UniqueMeshes.size())
{
MeshToLocalizeThisFrame = 0;
}
Mesh = UniqueMeshes.begin();
std::advance(Mesh, MeshToLocalizeThisFrame);
MeshToLocalizeThisFrame++;
if (Mesh == UniqueMeshes.end())
{
return;
}
}
auto MeshUpdate = new FOpenXRMeshUpdate;
MeshUpdate->TrackingState = EARTrackingState::Tracking;
FTransform Transform;
if (!LocateSpatialMeshInTrackingSpace(Mesh->first, Mesh->second.CoordinateSystem, InSession, DisplayTime, TrackingSpace, Transform))
{
Transform = Mesh->second.LastKnownTransform;
MeshUpdate->TrackingState = EARTrackingState::NotTracking;
}
Mesh->second.LastKnownTrackingState = MeshUpdate->TrackingState;
MeshUpdate->Id = Mesh->first;
MeshUpdate->LocalToTrackingTransform = Transform;
TrackedMeshHolder->ObjectUpdated(MeshUpdate);
Mesh->second.LastKnownTransform = Transform;
// Move the SurfaceObserver's bounding volume so it is always centered on the user.
UpdateBoundingVolume();
}
IOpenXRCustomCaptureSupport* FSpatialMappingPlugin::GetCustomCaptureSupport(const EARCaptureType CaptureType)
{
if (CaptureType == EARCaptureType::SpatialMapping)
{
return this;
}
return nullptr;
}
bool FSpatialMappingPlugin::OnToggleARCapture(const bool On)
{
if (On)
{
if (!bGenerateSRMeshes)
{
UE_LOG(LogHMD, Log, TEXT("Must enable Generate Mesh Data From Tracked Geometry in the ARSessionConfig to use Spatial Mapping."));
return false;
}
return StartMeshObserver();
}
else
{
StopMeshObserver();
}
return true;
}
// Perform a raycast against the spatial meshes.
TArray<FARTraceResult> FSpatialMappingPlugin::OnLineTraceTrackedObjects(const TSharedPtr<FARSupportInterface, ESPMode::ThreadSafe> ARCompositionComponent, const FVector Start, const FVector End, const EARLineTraceChannels TraceChannels)
{
TArray<FARTraceResult> Results;
// Iterate over the tracked MeshGeometries rather than UniqueMeshes since the output TraceResult needs the MeshGeometry.
TArray<UARMeshGeometry*> Meshes = UARBlueprintLibrary::GetAllGeometriesByClass<UARMeshGeometry>();
std::lock_guard<std::mutex> lock(MeshRefsLock);
for (UARMeshGeometry* Mesh : Meshes)
{
// Get the saved mesh data from the tracked mesh Guid.
const auto& it = UniqueMeshes.find(Mesh->UniqueId);
if (it != UniqueMeshes.end())
{
FVector HitPoint, HitNormal;
float HitDistance;
if (it->second.CollisionInfo.Collides(Start, End, Mesh->GetLocalToWorldTransform(), HitPoint, HitNormal, HitDistance))
{
// Append a hit. The calling function will then sort by HitDistance.
Results.Add(FARTraceResult(ARCompositionComponent,
HitDistance,
TraceChannels,
FTransform(HitNormal.ToOrientationQuat(), HitPoint),
Mesh));
}
}
}
return Results;
}
void FSpatialMappingPlugin::OnStartARSession(class UARSessionConfig* SessionConfig)
{
GConfig->GetFloat(TEXT("/Script/HoloLensPlatformEditor.HoloLensTargetSettings"), TEXT("SpatialMeshingVolumeSize"), VolumeSize, GEngineIni);
GConfig->GetFloat(TEXT("/Script/HoloLensPlatformEditor.HoloLensTargetSettings"), TEXT("MaxTrianglesPerCubicMeter"), TriangleDensity, GEngineIni);
bGenerateSRMeshes = SessionConfig->bGenerateMeshDataFromTrackedGeometry;
}
bool FSpatialMappingPlugin::StartMeshObserver()
{
if (TrackedMeshHolder == nullptr)
{
return false;
}
std::lock_guard<std::mutex> lock(MeshRefsLock);
if (SurfaceObserver != nullptr ||
(RequestAccessOperation != nullptr &&
RequestAccessOperation.Status() == winrt::Windows::Foundation::AsyncStatus::Started))
{
UE_LOG(LogHMD, Log, TEXT("Attempting to call StartMeshObserver more than once."));
return true;
}
if (!SpatialSurfaceObserver::IsSupported())
{
UE_LOG(LogHMD, Warning, TEXT("SpatialSurfaceObserver::IsSupported() returned false. No updates will occur."));
return false;
}
RequestAccessOperation = SpatialSurfaceObserver::RequestAccessAsync();
RequestAccessOperation.Completed([=](auto&& asyncInfo, auto&& asyncStatus)
{
if (asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed &&
asyncInfo.GetResults() == SpatialPerceptionAccessStatus::Allowed)
{
SurfaceObserver = SpatialSurfaceObserver();
if (SurfaceObserver != nullptr)
{
UpdateBoundingVolume();
check(!OnChangeEventToken);
OnChangeEventToken = SurfaceObserver.ObservedSurfacesChanged([this](auto&& sender, auto&& obj) { OnSurfacesChanged(sender, obj); });
}
else
{
UE_LOG(LogHMD, Warning, TEXT("Failed to create spatial observer. No updates will occur."));
}
}
else
{
UE_LOG(LogHMD, Warning, TEXT("User denied permission for spatial mapping. No updates will occur."));
}
});
return true;
}
void FSpatialMappingPlugin::StopMeshObserver()
{
std::lock_guard<std::mutex> lock(MeshRefsLock);
if (SurfaceObserver != nullptr)
{
SurfaceObserver.ObservedSurfacesChanged(OnChangeEventToken);
OnChangeEventToken = winrt::event_token();
SurfaceObserver = nullptr;
}
if (RequestAccessOperation != nullptr && RequestAccessOperation.Status() != winrt::Windows::Foundation::AsyncStatus::Completed)
{
RequestAccessOperation.Cancel();
}
RequestAccessOperation = nullptr;
}
void FSpatialMappingPlugin::UpdateBoundingVolume()
{
if (SurfaceObserver == nullptr)
{
return;
}
SpatialBoundingBox AABB =
{
{ 0.0f, 0.0f, 0.0f },
{ VolumeSize, VolumeSize, VolumeSize }
};
const auto coordinateSystem = SpatialLocator::GetDefault().CreateStationaryFrameOfReferenceAtCurrentLocation().CoordinateSystem();
if (coordinateSystem == nullptr)
{
return;
}
SpatialBoundingVolume BoundingVolume = SpatialBoundingVolume::FromBox(coordinateSystem, AABB);
if (BoundingVolume == nullptr)
{
return;
}
SurfaceObserver.SetBoundingVolume(BoundingVolume);
}
void FSpatialMappingPlugin::CopyMeshData(FOpenXRMeshUpdate* MeshUpdate, SpatialSurfaceMesh SurfaceMesh)
{
int VertexCount = SurfaceMesh.VertexPositions().ElementCount();
int IndexCount = SurfaceMesh.TriangleIndices().ElementCount();
MeshUpdate->Vertices.AddUninitialized(VertexCount);
MeshUpdate->Indices.AddUninitialized(IndexCount);
FVector MeshScale = WMRUtility::FromMixedRealityScale(SurfaceMesh.VertexPositionScale());
DirectX::PackedVector::XMSHORTN4* RawVertices = reinterpret_cast<DirectX::PackedVector::XMSHORTN4*>(SurfaceMesh.VertexPositions().Data().data());
check(SurfaceMesh.TriangleIndices().Format() == winrt::Windows::Graphics::DirectX::DirectXPixelFormat::R16UInt);
unsigned short* RawIndices = reinterpret_cast<unsigned short*>(SurfaceMesh.TriangleIndices().Data().data());
float Scale = XRTrackingSystem->GetWorldToMetersScale();
for (int Index = 0; Index < VertexCount; Index++)
{
// Match alignment with MeshOptions->VertexPositionFormat
DirectX::PackedVector::XMSHORTN4 packedSource = RawVertices[Index];
DirectX::XMVECTOR Source = DirectX::PackedVector::XMLoadShortN4(&packedSource);
MeshUpdate->Vertices[Index] = WMRUtility::FromXMVectorTranslation(Source, Scale) * MeshScale;
}
int TriangleCount = IndexCount / 3;
MRMESH_INDEX_TYPE* DestIndices = (MRMESH_INDEX_TYPE*)MeshUpdate->Indices.GetData();
// Reverse triangle order
for (int Index = 0; Index < TriangleCount; Index++)
{
DestIndices[0] = RawIndices[2];
DestIndices[1] = RawIndices[1];
DestIndices[2] = RawIndices[0];
DestIndices += 3;
RawIndices += 3;
}
}
void FSpatialMappingPlugin::OnSurfacesChanged(SpatialSurfaceObserver Observer, winrt::Windows::Foundation::IInspectable)
{
auto SurfaceCollection = Observer.GetObservedSurfaces();
std::vector<FGuid> ObservedSurfacesThisUpdate;
ObservedSurfacesThisUpdate.clear();
for (auto Iter = SurfaceCollection.First(); Iter.HasCurrent(); Iter.MoveNext())
{
auto KVPair = Iter.Current();
winrt::guid Id = KVPair.Key();
FGuid MeshId = WMRUtility::GUIDToFGuid(Id);
ObservedSurfacesThisUpdate.push_back(MeshId);
SpatialSurfaceInfo SurfaceInfo = KVPair.Value();
winrt::Windows::Foundation::IAsyncOperation<SpatialSurfaceMesh> ComputeMeshAsyncOperation =
SurfaceInfo.TryComputeLatestMeshAsync(TriangleDensity, MeshOptions);
if (ComputeMeshAsyncOperation == nullptr)
{
continue;
}
ComputeMeshAsyncOperation.Completed([this, MeshId](winrt::Windows::Foundation::IAsyncOperation<SpatialSurfaceMesh> asyncOperation, winrt::Windows::Foundation::AsyncStatus status)
{
if (asyncOperation.Status() == winrt::Windows::Foundation::AsyncStatus::Completed)
{
auto SurfaceMesh = asyncOperation.GetResults();
if (SurfaceMesh != nullptr)
{
TrackedMeshHolder->StartMeshUpdates();
FOpenXRMeshUpdate* MeshUpdate = TrackedMeshHolder->AllocateMeshUpdate(MeshId);
MeshUpdate->Type = EARObjectClassification::World;
CopyMeshData(MeshUpdate, SurfaceMesh);
const auto& it = UniqueMeshes.find(MeshId);
if (it != UniqueMeshes.end())
{
// If a mesh entry already existed for this spatial mesh, use the last known transform for the first update to keep it close to where it was previously.
MeshUpdate->LocalToTrackingTransform = it->second.LastKnownTransform;
MeshUpdate->TrackingState = it->second.LastKnownTrackingState;
// Update the cached mesh data
std::lock_guard<std::mutex> lock(MeshRefsLock);
it->second.CoordinateSystem = SurfaceMesh.CoordinateSystem();
it->second.CollisionInfo.UpdateVertices(MeshUpdate->Vertices, MeshUpdate->Indices);
}
else
{
// This is the first time observing this mesh
std::lock_guard<std::mutex> lock(MeshRefsLock);
// Guarantee the mesh is not seen until a valid transform has been found.
FTransform TempTransform = FTransform::Identity;
TempTransform.SetScale3D(FVector::ZeroVector);
// Don't set the tracking state until the LocalToTrackingTransform is identified in UpdateDeviceLocations.
MeshUpdate->TrackingState = EARTrackingState::NotTracking;
UniqueMeshes.insert({ MeshId, MeshLocalizationData {
TempTransform,
EARTrackingState::NotTracking,
SurfaceMesh.CoordinateSystem(),
TrackedGeometryCollision(MeshUpdate->Vertices, MeshUpdate->Indices)
} });
MeshUpdate->LocalToTrackingTransform = TempTransform;
}
TrackedMeshHolder->EndMeshUpdates();
}
}
});
}
// Check for removed meshes
if (UniqueMeshes.size() != ObservedSurfacesThisUpdate.size())
{
std::lock_guard<std::mutex> lock(MeshRefsLock);
std::vector<FGuid> MeshesToRemove = std::vector<FGuid>();
for (const auto& Mesh : UniqueMeshes)
{
if (std::find(ObservedSurfacesThisUpdate.begin(),
ObservedSurfacesThisUpdate.end(), Mesh.first) == ObservedSurfacesThisUpdate.end())
{
// Cached mesh was not found, it has been disposed.
MeshesToRemove.push_back(Mesh.first);
TrackedMeshHolder->RemoveMesh(Mesh.first);
}
}
for (const auto& MeshId : MeshesToRemove)
{
UniqueMeshes.erase(MeshId);
}
}
}
}
#endif //PLATFORM_WINDOWS || PLATFORM_HOLOLENS

Просмотреть файл

@ -0,0 +1,124 @@
#pragma once
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "OpenXRCommon.h"
#include "OpenXRCore.h"
#include "IOpenXRARModule.h"
#include "IOpenXRARTrackedGeometryHolder.h"
#include "HeadMountedDisplayTypes.h"
#include "ARTypes.h"
#include "ARSessionConfig.h"
#include "WindowsMixedRealityInteropUtility.h"
#include "IXRTrackingSystem.h"
#include "TrackedGeometryCollision.h"
#include "Windows/AllowWindowsPlatformTypes.h"
#include "Windows/AllowWindowsPlatformAtomics.h"
#include "Windows/PreWindowsApi.h"
#include <mutex>
#include <map>
#include <winrt/windows.foundation.Collections.h>
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Perception.Spatial.h>
#include <winrt/Windows.Perception.Spatial.Surfaces.h>
#include "Windows/PostWindowsApi.h"
#include "Windows/HideWindowsPlatformAtomics.h"
#include "Windows/HideWindowsPlatformTypes.h"
namespace MicrosoftOpenXR
{
class WMRAnchorLocalizationData : public TSharedFromThis<WMRAnchorLocalizationData>
{
public:
WMRAnchorLocalizationData(XrSpace AnchorSpace, winrt::Windows::Perception::Spatial::SpatialCoordinateSystem CoordinateSystem)
: AnchorSpace(AnchorSpace)
, CoordinateSystem(CoordinateSystem)
{
}
~WMRAnchorLocalizationData()
{
xrDestroySpace(AnchorSpace);
}
XrSpace AnchorSpace;
winrt::Windows::Perception::Spatial::SpatialCoordinateSystem CoordinateSystem;
};
struct MeshLocalizationData
{
FTransform LastKnownTransform = FTransform::Identity;
EARTrackingState LastKnownTrackingState = EARTrackingState::NotTracking;
winrt::Windows::Perception::Spatial::SpatialCoordinateSystem CoordinateSystem;
TrackedGeometryCollision CollisionInfo;
};
class FSpatialMappingPlugin : public IOpenXRExtensionPlugin, public IOpenXRCustomCaptureSupport
{
public:
void Register();
void Unregister();
bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
const void* OnBeginSession(XrSession InSession, const void* InNext) override;
void UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace) override;
bool OnToggleARCapture(const bool On) override;
TArray<FARTraceResult> OnLineTraceTrackedObjects(const TSharedPtr<FARSupportInterface, ESPMode::ThreadSafe> ARCompositionComponent, const FVector Start, const FVector End, const EARLineTraceChannels TraceChannels) override;
IOpenXRCustomCaptureSupport* GetCustomCaptureSupport(const EARCaptureType CaptureType) override;
private:
std::mutex MeshRefsLock;
winrt::event_token OnChangeEventToken;
bool bGenerateSRMeshes = false;
float VolumeSize = 20.0f;
float TriangleDensity = 500.0f;
unsigned int MeshToLocalizeThisFrame = 0;
const int WarnAfterThisManyMeshes = 100;
PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT xrCreateSpatialAnchorFromPerceptionAnchorMSFT;
PFN_xrCreateSpatialAnchorSpaceMSFT xrCreateSpatialAnchorSpaceMSFT;
PFN_xrDestroySpatialAnchorMSFT xrDestroySpatialAnchorMSFT;
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Perception::Spatial::SpatialPerceptionAccessStatus> RequestAccessOperation = nullptr;
// Map of all observed mesh ID's to their coordinate systems. Used for localizing previously observed meshes.
std::map<FGuid, MeshLocalizationData> UniqueMeshes;
// Map of anchor data to use when localizing new spatial mapping meshes.
std::map<FGuid, TSharedPtr<WMRAnchorLocalizationData>> AnchorLocalizationData;
IXRTrackingSystem* XRTrackingSystem = nullptr;
IOpenXRARTrackedMeshHolder* TrackedMeshHolder = nullptr;
winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver SurfaceObserver = nullptr;
winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceMeshOptions MeshOptions = nullptr;
void OnStartARSession(class UARSessionConfig* SessionConfig) override;
bool StartMeshObserver();
void StopMeshObserver();
bool FindMeshTransform(XrSpace AnchorSpace, XrTime DisplayTime, XrSpace TrackingSpace, FTransform MeshToCachedAnchorTransform, FTransform& Transform, bool& IsTracking);
bool GetTransformBetweenCoordinateSystems(winrt::Windows::Perception::Spatial::SpatialCoordinateSystem From, winrt::Windows::Perception::Spatial::SpatialCoordinateSystem To, FTransform& Transform);
bool LocateSpatialMeshInTrackingSpace(const FGuid& MeshID, winrt::Windows::Perception::Spatial::SpatialCoordinateSystem MeshCoordinateSystem, XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace, FTransform& Transform);
void UpdateBoundingVolume();
void CopyMeshData(FOpenXRMeshUpdate* MeshUpdate, winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceMesh SurfaceMesh);
void OnSurfacesChanged(winrt::Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver Observer, winrt::Windows::Foundation::IInspectable);
};
} // namespace MicrosoftOpenXR
#endif //PLATFORM_WINDOWS || PLATFORM_HOLOLENS

Просмотреть файл

@ -0,0 +1,290 @@
#include "SpeechPlugin.h"
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "Engine\Engine.h"
using namespace winrt::Windows::Media::SpeechRecognition;
namespace MicrosoftOpenXR
{
void FSpeechPlugin::Register()
{
IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this);
}
void FSpeechPlugin::Unregister()
{
IModularFeatures::Get().UnregisterModularFeature(GetModularFeatureName(), this);
}
void FSpeechPlugin::OnStartARSession(class UARSessionConfig* SessionConfig)
{
// Add all speech keywords from the input system
const TArray <FInputActionSpeechMapping>& SpeechMappings = GetDefault<UInputSettings>()->GetSpeechMappings();
for (const FInputActionSpeechMapping& SpeechMapping : SpeechMappings)
{
FKey Key(SpeechMapping.GetKeyName());
FString Keyword = SpeechMapping.GetSpeechKeyword().ToString();
RegisterKeyword(Key, Keyword);
}
if (SpeechMappings.Num() > 0)
{
StartSpeechRecognizer();
}
}
void FSpeechPlugin::OnStopARSession()
{
//remove keys from "speech" namespace
EKeys::RemoveKeysWithCategory(FInputActionSpeechMapping::GetKeyCategory());
StopSpeechRecognizer();
KeywordMap.Empty();
}
void FSpeechPlugin::AddKeywords(TArray<FKeywordInput> KeywordsToAdd)
{
APlayerController* PlayerController = nullptr;
UInputSettings* InputSettings = nullptr;
UInputComponent* InputComponent = nullptr;
if (KeywordsToAdd.Num() == 0
|| (PlayerController = GetPlayerController()) == nullptr
|| (InputSettings = GetMutableDefault<UInputSettings>()) == nullptr
|| (InputComponent = PlayerController->InputComponent) == nullptr)
{
FString WarningText;
KeywordsToAdd.Num() == 0 ?
WarningText = FString("FSpeechPlugin::AddKeywords failed: No keywords to register.") :
WarningText = FString("FSpeechPlugin::AddKeywords failed: Required engine components are null.");
UE_LOG(LogHMD, Warning, TEXT("%s"), *WarningText);
return;
}
StopSpeechRecognizer();
for (FKeywordInput InputKeyword : KeywordsToAdd)
{
if (InputKeyword.Keyword.IsEmpty() || !InputKeyword.Callback.GetFunctionName().IsValid())
{
UE_LOG(LogHMD, Warning, TEXT("Attempting to add an invalid Keyword: %s or Function: %s"), *InputKeyword.Keyword, *InputKeyword.Callback.GetFunctionName().ToString());
continue;
}
FString Keyword = InputKeyword.Keyword;
// Key name must match FInputActionSpeechMapping::GetKeyName to cleanup correctly.
FKey Key(FName(*FString::Printf(TEXT("%s_%s"), *FInputActionSpeechMapping::GetKeyCategory().ToString(), *Keyword)));
// Bind speech delegate to the player's UInputComponent to use the same key events as the input system.
FInputActionUnifiedDelegate KeywordHandler;
KeywordHandler.BindDelegate(InputKeyword.Callback.GetUObject(), InputKeyword.Callback.GetFunctionName());
// Trigger keywords on pressed events.
FInputActionBinding ActionBinding(Key.GetFName(), IE_Pressed);
ActionBinding.ActionDelegate = (FInputActionUnifiedDelegate)KeywordHandler;
// Update input system with new binding.
InputComponent->AddActionBinding(ActionBinding);
InputSettings->AddActionMapping(FInputActionKeyMapping(Key.GetFName(), Key));
RegisterKeyword(Key, Keyword);
}
StartSpeechRecognizer();
}
void FSpeechPlugin::RemoveKeywords(TArray<FString> KeywordsToRemove)
{
if (KeywordsToRemove.Num() == 0)
{
UE_LOG(LogHMD, Warning, TEXT("FSpeechPlugin::RemoveKeywords failed: No keywords to remove."));
return;
}
StopSpeechRecognizer();
for (FString InputKeyword : KeywordsToRemove)
{
InputKeyword = InputKeyword.ToLower();
// Remove local keyword so it is not included in the next recognizer.
bool KeywordRemoved = false;
for (int i = 0; i < Keywords.size(); i++)
{
if (Keywords.at(i) == winrt::hstring(*InputKeyword))
{
Keywords.erase(Keywords.begin() + i);
KeywordRemoved = true;
break;
}
}
if (!KeywordRemoved)
{
UE_LOG(LogHMD, Warning, TEXT("FSpeechPlugin::RemoveKeywords failed to remove Keyword: %s"), *InputKeyword);
}
// Remove from the keyword map.
if (KeywordMap.Contains(InputKeyword))
{
KeywordMap.Remove(InputKeyword);
}
else
{
UE_LOG(LogHMD, Warning, TEXT("FSpeechPlugin::RemoveKeywords failed to remove Keyword from Key Map: %s"), *InputKeyword);
}
}
StartSpeechRecognizer();
}
APlayerController* FSpeechPlugin::GetPlayerController()
{
for (const FWorldContext& Context : GEngine->GetWorldContexts())
{
if (Context.WorldType == EWorldType::Game || Context.WorldType == EWorldType::PIE)
{
UWorld* World = Context.World();
if (World && World->GetGameInstance())
{
return World->GetGameInstance()->GetFirstLocalPlayerController();
}
}
}
return nullptr;
}
void FSpeechPlugin::RegisterKeyword(FKey Key, FString Keyword)
{
TArray<FKey> Keys;
EKeys::GetAllKeys(Keys);
// Only add key if it doesn't already exist.
if (!Keys.Contains(Key))
{
EKeys::AddKey(FKeyDetails(Key, FText(), FKeyDetails::NotBlueprintBindableKey, FInputActionSpeechMapping::GetKeyCategory()));
}
Keyword = Keyword.ToLower();
if (KeywordMap.Contains(Keyword))
{
UE_LOG(LogHMD, Warning, TEXT("Adding duplicate keyword: %s. Multiple events may be called for this keyword."), *Keyword);
}
Keywords.push_back(winrt::hstring(*Keyword));
KeywordMap.Add(Keyword, Key);
}
void FSpeechPlugin::CallSpeechCallback(FKey InKey)
{
APlayerController* PlayerController = GetPlayerController();
if (PlayerController == nullptr)
{
UE_LOG(LogHMD, Warning, TEXT("Attempting to call speech keyword, but PlayerController is not valid"));
return;
}
AsyncTask(ENamedThreads::GameThread, [InKey, PlayerController]()
{
PlayerController->InputKey(InKey, IE_Pressed, 1.0f, false);
});
}
void FSpeechPlugin::StartSpeechRecognizer()
{
SpeechRecognitionListConstraint constraint = SpeechRecognitionListConstraint(Keywords);
SpeechRecognizer = winrt::Windows::Media::SpeechRecognition::SpeechRecognizer();
SpeechRecognizer.Constraints().Clear();
SpeechRecognizer.Constraints().Append(constraint);
CompileConstraintsAsyncOperation = SpeechRecognizer.CompileConstraintsAsync();
CompileConstraintsAsyncOperation.Completed([this](winrt::Windows::Foundation::IAsyncOperation<SpeechRecognitionCompilationResult> asyncOperation, winrt::Windows::Foundation::AsyncStatus status)
{
if (asyncOperation.Status() == winrt::Windows::Foundation::AsyncStatus::Completed)
{
SpeechRecognitionCompilationResult result = asyncOperation.GetResults();
if (result.Status() == SpeechRecognitionResultStatus::Success)
{
try
{
SpeechContinuousRecognitionSession session = SpeechRecognizer.ContinuousRecognitionSession();
SessionStartAction = session.StartAsync();
}
catch (winrt::hresult_error e)
{
// We may see an exception if the microphone capability is not enabled.
UE_LOG(LogHMD, Warning, TEXT("SpeechRecognizer failed to start with error: %s"), e.message().c_str());
StopSpeechRecognizer();
}
}
else
{
UE_LOG(LogHMD, Warning, TEXT("SpeechRecognizer access request returns error: %d"), result.Status());
StopSpeechRecognizer();
}
}
else if (asyncOperation.Status() != winrt::Windows::Foundation::AsyncStatus::Canceled)
{
UE_LOG(LogHMD, Warning, TEXT("SpeechRecognizer.CompileConstraintsAsync returns error: %d"), asyncOperation.Status());
StopSpeechRecognizer();
}
});
ResultsGeneratedToken = SpeechRecognizer.ContinuousRecognitionSession().ResultGenerated(
[&](SpeechContinuousRecognitionSession sender, SpeechContinuousRecognitionResultGeneratedEventArgs args)
{
if (args.Result().Status() == SpeechRecognitionResultStatus::Success &&
args.Result().Confidence() != SpeechRecognitionConfidence::Rejected)
{
FString keyword = FString(args.Result().Text().c_str());
CallSpeechCallback(KeywordMap.FindRef(keyword));
}
});
}
void FSpeechPlugin::StopSpeechRecognizer()
{
if (CompileConstraintsAsyncOperation && CompileConstraintsAsyncOperation.Status() != winrt::Windows::Foundation::AsyncStatus::Completed)
{
CompileConstraintsAsyncOperation.Cancel();
}
if (SpeechRecognizer != nullptr &&
ResultsGeneratedToken.value != 0)
{
SpeechRecognizer.ContinuousRecognitionSession().ResultGenerated(ResultsGeneratedToken);
ResultsGeneratedToken.value = 0;
}
if (SpeechRecognizer != nullptr &&
CompileConstraintsAsyncOperation.Status() == winrt::Windows::Foundation::AsyncStatus::Completed)
{
// If the SpeechRecognizer is idle, it is not capturing. Stopping while idle will throw an exception.
if ((SessionStartAction != nullptr && SessionStartAction.Status() == winrt::Windows::Foundation::AsyncStatus::Completed) &&
SpeechRecognizer.State() != winrt::Windows::Media::SpeechRecognition::SpeechRecognizerState::Idle)
{
try
{
SpeechRecognizer.ContinuousRecognitionSession().StopAsync();
}
catch (winrt::hresult_error e)
{
// We may see an exception if no microphone was attached.
UE_LOG(LogHMD, Warning, TEXT("ContinuousRecognitionSession failed to stop with error: %d"), e.code().value);
}
}
SpeechRecognizer.Constraints().Clear();
SpeechRecognizer.Close();
SpeechRecognizer = nullptr;
}
}
} // namespace MicrosoftOpenXR
#endif //PLATFORM_WINDOWS || PLATFORM_HOLOLENS

Просмотреть файл

@ -0,0 +1,61 @@
#pragma once
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "OpenXRCommon.h"
#include "MicrosoftOpenXR.h"
#include "HeadMountedDisplayTypes.h"
#include "GameFramework/PlayerInput.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/InputSettings.h"
#include "UObject/NameTypes.h"
#include "UObject/UObjectGlobals.h"
#include "Async/Async.h"
#include "Windows/AllowWindowsPlatformTypes.h"
#include "Windows/AllowWindowsPlatformAtomics.h"
#include "Windows/PreWindowsApi.h"
#include <unknwn.h>
#include <winrt/Windows.Media.SpeechRecognition.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include "Windows/PostWindowsApi.h"
#include "Windows/HideWindowsPlatformAtomics.h"
#include "Windows/HideWindowsPlatformTypes.h"
namespace MicrosoftOpenXR
{
class FSpeechPlugin : public IOpenXRExtensionPlugin
{
public:
void Register();
void Unregister();
void OnStartARSession(class UARSessionConfig* SessionConfig) override;
void OnStopARSession() override;
void AddKeywords(TArray<FKeywordInput> KeywordsToAdd);
void RemoveKeywords(TArray<FString> KeywordsToRemove);
private:
winrt::Windows::Media::SpeechRecognition::SpeechRecognizer SpeechRecognizer = nullptr;
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Media::SpeechRecognition::SpeechRecognitionCompilationResult> CompileConstraintsAsyncOperation;
winrt::Windows::Foundation::IAsyncAction SessionStartAction;
winrt::event_token ResultsGeneratedToken;
std::vector<winrt::hstring> Keywords;
TMap<FString, FKey> KeywordMap;
APlayerController* GetPlayerController();
void RegisterKeyword(FKey Key, FString Keyword);
void CallSpeechCallback(FKey InKey);
void StartSpeechRecognizer();
void StopSpeechRecognizer();
};
} // namespace MicrosoftOpenXR
#endif //PLATFORM_WINDOWS || PLATFORM_HOLOLENS

Просмотреть файл

@ -0,0 +1,65 @@
#include "TrackedGeometryCollision.h"
namespace MicrosoftOpenXR
{
TrackedGeometryCollision::TrackedGeometryCollision(const TArray<FVector> InVertices, const TArray<MRMESH_INDEX_TYPE> InIndices)
{
if (InVertices.Num() == 0)
{
return;
}
Vertices = std::move(InVertices);
Indices = std::move(InIndices);
// Create a bounding box from the input vertices to reduce the number of full meshes that need to be hit-tested.
BoundingBox = FBox(&Vertices[0], Vertices.Num());
}
void TrackedGeometryCollision::UpdateVertices(const TArray<FVector> InVertices, const TArray<MRMESH_INDEX_TYPE> InIndices)
{
Vertices = InVertices;
Indices = InIndices;
// Create a bounding box from the input vertices to reduce the number of full meshes that need to be hit-tested.
BoundingBox = FBox(&Vertices[0], Vertices.Num());
}
bool TrackedGeometryCollision::Collides(const FVector Start, const FVector End, const FTransform MeshToWorld, FVector& OutHitPoint, FVector& OutHitNormal, float& OutHitDistance)
{
if (MeshToWorld.GetScale3D().IsNearlyZero())
{
return false;
}
// Check bounding box collision first so we don't check triangles for meshes we definitely won't collide with.
if (!FMath::LineBoxIntersection(BoundingBox.TransformBy(MeshToWorld), Start, End, End - Start))
{
return false;
}
// Check for triangle collision and set the output hit position, normal, and distance.
for (int i = 0; i < Indices.Num(); i += 3)
{
// Ignore this triangle if it has indices out of range.
if ((unsigned int)Indices[i] > (unsigned int)Vertices.Num()
|| (unsigned int)Indices[i + 1] > (unsigned int)Vertices.Num()
|| (unsigned int)Indices[i + 2] > (unsigned int)Vertices.Num())
{
continue;
}
if (FMath::SegmentTriangleIntersection(Start, End,
MeshToWorld.TransformPosition(Vertices[Indices[i]]),
MeshToWorld.TransformPosition(Vertices[Indices[i + 1]]),
MeshToWorld.TransformPosition(Vertices[Indices[i + 2]]),
OutHitPoint, OutHitNormal))
{
OutHitDistance = (OutHitPoint - Start).Size();
return true;
}
}
return false;
}
} // namespace MicrosoftOpenXR

Просмотреть файл

@ -0,0 +1,37 @@
#pragma once
#include "OpenXRCommon.h"
#include "OpenXRCore.h"
#include "IOpenXRARModule.h"
#include "IOpenXRARTrackedGeometryHolder.h"
#include "HeadMountedDisplayTypes.h"
#include "ARTypes.h"
namespace MicrosoftOpenXR
{
class TrackedGeometryCollision
{
public:
TrackedGeometryCollision(const TArray<FVector> InVertices, const TArray<MRMESH_INDEX_TYPE> InIndices);
void UpdateVertices(const TArray<FVector> InVertices, const TArray<MRMESH_INDEX_TYPE> InIndices);
/// <summary>
/// Hit test a ray against tracked mesh data.
/// </summary>
/// <param name="Start">Start of collision ray in world space</param>
/// <param name="End">End of collision ray in world space</param>
/// <param name="TrackingToWorld">Transform from mesh local space to world space. The mesh may not be in tracking space.</param>
/// <param name="OutHitPoint">Position of hit in world space</param>
/// <param name="OutHitNormal">Normal of hit in world space</param>
/// <param name="OutHitDistance">Distance from ray start</param>
/// <returns>True if the input ray collides with this mesh.</returns>
bool Collides(const FVector Start, const FVector End, const FTransform MeshToWorld, FVector& OutHitPoint, FVector& OutHitNormal, float& OutHitDistance);
private:
TArray<FVector> Vertices;
TArray<MRMESH_INDEX_TYPE> Indices;
FBox BoundingBox;
};
} // namespace MicrosoftOpenXR

Просмотреть файл

@ -0,0 +1,184 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Simple type conversion functions for working with the WindowsMixedRealityInterop
#pragma once
#if PLATFORM_WINDOWS || PLATFORM_HOLOLENS
#include "CoreMinimal.h"
#include "HAL\UnrealMemory.h"
#include "Windows/WindowsHWrapper.h"
#include "HeadMountedDisplayTypes.h"
#include <DirectXMath.h>
#include <unknwn.h>
#include <winrt/base.h>
namespace MicrosoftOpenXR
{
class WMRUtility
{
public:
// Convert between DirectX XMMatrix to Unreal FMatrix.
static FORCEINLINE FMatrix ToFMatrix(DirectX::XMMATRIX& M)
{
DirectX::XMFLOAT4X4 dst;
DirectX::XMStoreFloat4x4(&dst, M);
return FMatrix(
FPlane(dst._11, dst._21, dst._31, dst._41),
FPlane(dst._12, dst._22, dst._32, dst._42),
FPlane(dst._13, dst._23, dst._33, dst._43),
FPlane(dst._14, dst._24, dst._34, dst._44));
}
static FORCEINLINE FMatrix ToFMatrix(DirectX::XMFLOAT4X4& M)
{
return FMatrix(
FPlane(M._11, M._21, M._31, M._41),
FPlane(M._12, M._22, M._32, M._42),
FPlane(M._13, M._23, M._33, M._43),
FPlane(M._14, M._24, M._34, M._44));
}
static FORCEINLINE FTransform FromMixedRealityTransform(const DirectX::XMMATRIX& M, float InScale = 1.0f)
{
DirectX::XMVECTOR Scale;
DirectX::XMVECTOR Rotation;
DirectX::XMVECTOR Translation;
DirectX::XMMatrixDecompose(&Scale, &Rotation, &Translation, M);
return FTransform(FromXMVectorRotation(Rotation), FromXMVectorTranslation(Translation, InScale), FromXMVectorScale(Scale));
}
static FORCEINLINE FVector FromMixedRealityVector(DirectX::XMFLOAT3 pos)
{
return FVector(
-1.0f * pos.z,
pos.x,
pos.y);
}
static FORCEINLINE DirectX::XMFLOAT3 ToMixedRealityVector(FVector pos)
{
return DirectX::XMFLOAT3(
pos.Y,
pos.Z,
-1.0f * pos.X);
}
static FORCEINLINE FVector FromMixedRealityScale(DirectX::XMFLOAT3 pos)
{
return FVector(
pos.z,
pos.x,
pos.y);
}
static FORCEINLINE FVector FromMixedRealityScale(winrt::Windows::Foundation::Numerics::float3 pos)
{
return FVector(
pos.z,
pos.x,
pos.y);
}
static FORCEINLINE DirectX::XMFLOAT3 ToMixedRealityScale(FVector pos)
{
return DirectX::XMFLOAT3(
pos.Y,
pos.Z,
pos.X);
}
static FORCEINLINE FQuat FromMixedRealityQuaternion(DirectX::XMFLOAT4 rot)
{
FQuat quaternion(
-1.0f * rot.z,
rot.x,
rot.y,
-1.0f * rot.w);
quaternion.Normalize();
return quaternion;
}
static FORCEINLINE DirectX::XMFLOAT4 ToMixedRealityQuaternion(FQuat rot)
{
// Windows api IsNormalized checks fail on a negative identity quaternion.
if (rot == FQuat::Identity)
{
return DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f);
}
DirectX::XMVECTOR v = DirectX::XMVectorSet(
rot.Y,
rot.Z,
-1.0f * rot.X,
-1.0f * rot.W);
DirectX::XMQuaternionNormalize(v);
DirectX::XMFLOAT4 quatf4out;
DirectX::XMStoreFloat4(&quatf4out, v);
return quatf4out;
}
static FORCEINLINE FVector FromFloat3(winrt::Windows::Foundation::Numerics::float3 pos, float scale = 1.0f)
{
return FVector(
-1.0f * pos.z,
pos.x,
pos.y) * scale;
}
static FORCEINLINE FVector FromXMVectorTranslation(DirectX::XMVECTOR InValue, float scale = 1.0f)
{
InValue = DirectX::XMVectorMultiply(InValue, DirectX::XMVectorSet(scale, scale, -1 * scale, scale));
InValue = DirectX::XMVectorSwizzle(InValue, 2, 0, 1, 3);
DirectX::XMFLOAT3 Dest;
DirectX::XMStoreFloat3(&Dest, InValue);
return FVector(Dest.x, Dest.y, Dest.z);
}
static FORCEINLINE FQuat FromXMVectorRotation(DirectX::XMVECTOR InValue)
{
DirectX::XMFLOAT4 Dest;
DirectX::XMStoreFloat4(&Dest, InValue);
return FromMixedRealityQuaternion(Dest);
}
static FORCEINLINE FVector FromXMVectorScale(DirectX::XMVECTOR InValue)
{
InValue = DirectX::XMVectorSwizzle(InValue, 2, 0, 1, 3);
DirectX::XMFLOAT3 Dest;
DirectX::XMStoreFloat3(&Dest, InValue);
return FVector(Dest.x, Dest.y, Dest.z);
}
static FORCEINLINE FVector2D FromFloat2(winrt::Windows::Foundation::Numerics::float2 pos)
{
return FVector2D(pos.x, pos.y);
}
static FORCEINLINE FGuid GUIDToFGuid(const winrt::guid& InGuid)
{
check(sizeof(FGuid) == sizeof(winrt::guid));
FGuid OutGuid;
FMemory::Memcpy(&OutGuid, &InGuid, sizeof(FGuid));
return OutGuid;
}
};
}
#endif

Просмотреть файл

@ -0,0 +1,101 @@
// Copyright (c) Microsoft Corporation.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Components/InputComponent.h"
#include "MicrosoftOpenXR.generated.h"
USTRUCT(BlueprintType, Category = "MicrosoftOpenXR|OpenXR")
struct FKeywordInput
{
GENERATED_USTRUCT_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Keyword;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FInputActionHandlerDynamicSignature Callback;
};
UENUM(BlueprintType, Category = "MicrosoftOpenXR|OpenXR")
enum class EHandMeshStatus : uint8
{
NotInitialised = 0 UMETA(Hidden),
Disabled = 1,
EnabledTrackingGeometry = 2,
EnabledXRVisualization = 3
};
UCLASS(ClassGroup = OpenXR)
class MICROSOFTOPENXR_API UMicrosoftOpenXRFunctionLibrary :
public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/**
Turn Hand Mesh
@param On true if enable
@return true if the command successes
*/
UFUNCTION(BlueprintCallable, Category = "MicrosoftOpenXR|OpenXR")
static bool SetUseHandMesh(EHandMeshStatus Mode);
/**
Is QR Tracking enabled
@return true if the command successes
*/
UFUNCTION(BlueprintPure, Category = "MicrosoftOpenXR|OpenXR")
static bool IsQREnabled();
/**
* Get the transform from PV camera space to Unreal world space.
*/
UFUNCTION(BlueprintPure, Category = "MicrosoftOpenXR|OpenXR")
static FTransform GetPVCameraToWorldTransform();
/**
* Get the PV Camera intrinsics.
*/
UFUNCTION(BlueprintPure, Category = "MicrosoftOpenXR|OpenXR")
static bool GetPVCameraIntrinsics(FVector2D& focalLength, int& width, int& height, FVector2D& principalPoint, FVector& radialDistortion, FVector2D& tangentialDistortion);
/**
* Get a ray into the scene from a camera point.
* X is left/right
* Y is up/down
*/
UFUNCTION(BlueprintPure, Category = "MicrosoftOpenXR|OpenXR")
static FVector GetWorldSpaceRayFromCameraPoint(FVector2D pixelCoordinate);
/**
Check if the current platform supports speech recognition.
*/
UFUNCTION(BlueprintPure, Category = "MicrosoftOpenXR|OpenXR")
static bool IsSpeechRecognitionAvailable();
/**
Add new speech keywords with associated callbacks.
@param Keywords list of keyword and callbacks to add.
*/
UFUNCTION(BlueprintCallable, Category = "MicrosoftOpenXR|OpenXR")
static void AddKeywords(TArray<FKeywordInput> Keywords);
/**
Remove speech keywords.
@param Keywords list of keyword to remove.
*/
UFUNCTION(BlueprintCallable, Category = "MicrosoftOpenXR|OpenXR")
static void RemoveKeywords(TArray<FString> Keywords);
};

Просмотреть файл

@ -0,0 +1,282 @@
#pragma once
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) Microsoft Corporation. All Rights Reserved
#ifdef __cplusplus
extern "C" {
#endif
#define XR_MSFT_holographic_remoting 1
#define XR_MSFT_holographic_remoting_SPEC_VERSION 1
#define XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME "XR_MSFT_holographic_remoting"
// Extension number: 66 / Enum subrange base: 65000
// extends XrStructureType
typedef enum XrRemotingStructureType {
XR_TYPE_REMOTING_REMOTE_CONTEXT_PROPERTIES_MSFT = 1000065000,
XR_TYPE_REMOTING_CONNECT_INFO_MSFT = 1000065001,
XR_TYPE_REMOTING_LISTEN_INFO_MSFT = 1000065002,
XR_TYPE_REMOTING_DISCONNECT_INFO_MSFT = 1000065003,
XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT = 1000065004,
XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT = 1000065005,
XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT = 1000065006,
XR_TYPE_REMOTING_AUTHENTICATION_TOKEN_REQUEST_MSFT = 1000065007,
XR_TYPE_REMOTING_CERTIFICATE_DATA_MSFT = 1000065008,
XR_TYPE_REMOTING_CERTIFICATE_VALIDATION_RESULT_MSFT = 1000065009,
XR_TYPE_REMOTING_SERVER_CERTIFICATE_VALIDATION_MSFT = 1000065010,
XR_TYPE_REMOTING_AUTHENTICATION_TOKEN_VALIDATION_MSFT = 1000065011,
XR_TYPE_REMOTING_SERVER_CERTIFICATE_REQUEST_MSFT = 1000065012,
XR_TYPE_REMOTING_SECURE_CONNECTION_CLIENT_CALLBACKS_MSFT = 1000065013,
XR_TYPE_REMOTING_SECURE_CONNECTION_SERVER_CALLBACKS_MSFT = 1000065014,
XR_TYPE_REMOTING_MAX_ENUM = 0x7FFFFFFF
} XrRemotingStructureType;
// extends XrResult
typedef enum XrRemotingResult {
XR_ERROR_REMOTING_NOT_DISCONNECTED_MSFT = -1000065000,
XR_ERROR_REMOTING_CODEC_NOT_FOUND_MSFT = -1000065001,
XR_ERROR_REMOTING_CALLBACK_ERROR_MSFT = -1000065002,
XR_ERROR_REMOTING_MAX_ENUM = 0x7FFFFFFF
} XrRemotingResult;
typedef enum XrRemotingDisconnectReasonMSFT {
XR_REMOTING_DISCONNECT_REASON_NONE_MSFT = 0,
XR_REMOTING_DISCONNECT_REASON_UNKNOWN_MSFT = 1,
XR_REMOTING_DISCONNECT_REASON_NO_SERVER_CERTIFICATE_MSFT = 2,
XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_PORT_BUSY_MSFT = 3,
XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_UNREACHABLE_MSFT = 4,
XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_CONNECTION_FAILED_MSFT = 5,
XR_REMOTING_DISCONNECT_REASON_AUTHENTICATION_FAILED_MSFT = 6,
XR_REMOTING_DISCONNECT_REASON_REMOTING_VERSION_MISMATCH_MSFT = 7,
XR_REMOTING_DISCONNECT_REASON_INCOMPATIBLE_TRANSPORT_PROTOCOLS_MSFT = 8,
XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_FAILED_MSFT = 9,
XR_REMOTING_DISCONNECT_REASON_TRANSPORT_PORT_BUSY_MSFT = 10,
XR_REMOTING_DISCONNECT_REASON_TRANSPORT_UNREACHABLE_MSFT = 11,
XR_REMOTING_DISCONNECT_REASON_TRANSPORT_CONNECTION_FAILED_MSFT = 12,
XR_REMOTING_DISCONNECT_REASON_PROTOCOL_VERSION_MISMATCH_MSFT = 13,
XR_REMOTING_DISCONNECT_REASON_PROTOCOL_ERROR_MSFT = 14,
XR_REMOTING_DISCONNECT_REASON_VIDEO_CODEC_NOT_AVAILABLE_MSFT = 15,
XR_REMOTING_DISCONNECT_REASON_CANCELED_MSFT = 16,
XR_REMOTING_DISCONNECT_REASON_CONNECTION_LOST_MSFT = 17,
XR_REMOTING_DISCONNECT_REASON_DEVICE_LOST_MSFT = 18,
XR_REMOTING_DISCONNECT_REASON_DISCONNECT_REQUEST_MSFT = 19,
XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_NETWORK_UNREACHABLE_MSFT = 20,
XR_REMOTING_DISCONNECT_REASON_HANDSHAKE_CONNECTION_REFUSED_MSFT = 21,
XR_REMOTING_DISCONNECT_REASON_VIDEO_FORMAT_NOT_AVAILABLE_MSFT = 22,
XR_REMOTING_DISCONNECT_REASON_PEER_DISCONNECT_REQUEST_MSFT = 23,
XR_REMOTING_DISCONNECT_REASON_PEER_DISCONNECT_TIMEOUT_MSFT = 24,
XR_REMOTING_DISCONNECT_REASON_SESSION_OPEN_TIMEOUT_MSFT = 25,
XR_REMOTING_DISCONNECT_REASON_REMOTING_HANDSHAKE_TIMEOUT_MSFT = 26,
XR_REMOTING_DISCONNECT_REASON_INTERNAL_ERROR_MSFT = 27,
XR_REMOTING_DISCONNECT_REASON_MAX_ENUM = 0x7FFFFFFF
} XrRemotingDisconnectReasonMSFT;
typedef enum XrRemotingConnectionStateMSFT {
XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT = 0,
XR_REMOTING_CONNECTION_STATE_CONNECTING_MSFT = 1,
XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT = 2,
XR_REMOTING_CONNECTION_STATE_MAX_ENUM = 0x7FFFFFFF
} XrRemotingConnectionStateMSFT;
typedef enum XrRemotingVideoCodecMSFT {
XR_REMOTING_VIDEO_CODEC_ANY_MSFT = 0,
XR_REMOTING_VIDEO_CODEC_H264_MSFT = 1,
XR_REMOTING_VIDEO_CODEC_H265_MSFT = 2,
XR_REMOTING_VIDEO_CODEC_MAX_ENUM = 0x7FFFFFFF
} XrRemotingVideoCodecMSFT;
typedef enum XrRemotingCertificateNameValidationResultMSFT {
XR_REMOTING_CERTIFICATE_NAME_VALIDATION_RESULT_NOT_CHECKED_MSFT = 0,
XR_REMOTING_CERTIFICATE_NAME_VALIDATION_RESULT_MATCH_MSFT = 1,
XR_REMOTING_CERTIFICATE_NAME_VALIDATION_RESULT_MISMATCH_MSFT = 2,
XR_REMOTING_CERTIFICATE_NAME_VALIDATION_RESULT_MAX_ENUM = 0x7FFFFFFF
} XrRemotingCertificateNameValidationResultMSFT;
typedef struct XrRemotingRemoteContextPropertiesMSFT {
XrStructureType type;
void* next;
uint32_t maxBitrateKbps;
XrBool32 enableAudio;
XrRemotingVideoCodecMSFT videoCodec;
} XrRemotingRemoteContextPropertiesMSFT;
typedef struct XrRemotingConnectInfoMSFT {
XrStructureType type;
void* next;
const char* remoteHostName;
uint16_t remotePort;
XrBool32 secureConnection;
} XrRemotingConnectInfoMSFT;
typedef struct XrRemotingListenInfoMSFT {
XrStructureType type;
void* next;
const char* listenInterface;
uint16_t handshakeListenPort;
uint16_t transportListenPort;
XrBool32 secureConnection;
} XrRemotingListenInfoMSFT;
typedef struct XrRemotingDisconnectInfoMSFT {
XrStructureType type;
const void* next;
} XrRemotingDisconnectInfoMSFT;
typedef struct XrRemotingEventDataListeningMSFT {
XrStructureType type;
const void* next;
uint16_t listeningPort;
} XrEventDataRemoteContextListeningMSFT;
typedef struct XrRemotingEventDataConnectedMSFT {
XrStructureType type;
const void* next;
} XrEventDataRemoteContextConnectedMSFT;
typedef struct XrRemotingEventDataDisconnectedMSFT {
XrStructureType type;
const void* next;
XrRemotingDisconnectReasonMSFT disconnectReason;
} XrEventDataRemoteContextDisconnectedMSFT;
typedef struct XrRemotingAuthenticationTokenRequestMSFT {
XrStructureType type;
const void* next;
void* context;
uint32_t tokenCapacityIn;
uint32_t tokenSizeOut;
char* tokenBuffer;
} XrRemotingAuthenticationTokenRequestMSFT;
typedef struct XrRemotingCertificateDataMSFT {
XrStructureType type;
const void* next;
uint32_t size;
const uint8_t* data;
} XrRemotingCertificateDataMSFT;
typedef struct XrRemotingCertificateValidationResultMSFT {
XrStructureType type;
const void* next;
XrBool32 trustedRoot;
XrBool32 revoked;
XrBool32 expired;
XrBool32 wrongUsage;
XrRemotingCertificateNameValidationResultMSFT nameValidationResult;
XrBool32 revocationCheckFailed;
XrBool32 invalidCertOrChain;
} XrRemotingCertificateValidationResultMSFT;
typedef struct XrRemotingServerCertificateValidationMSFT {
XrStructureType type;
const void* next;
void* context;
const char* hostName;
XrBool32 forceRevocationCheck;
uint32_t numCertificates;
const XrRemotingCertificateDataMSFT* certificates;
XrRemotingCertificateValidationResultMSFT* systemValidationResult;
XrRemotingCertificateValidationResultMSFT validationResultOut;
} XrRemotingServerCertificateValidationMSFT;
typedef struct XrRemotingAuthenticationTokenValidationMSFT {
XrStructureType type;
const void* next;
void* context;
const char* token;
XrBool32 tokenValidOut;
} XrRemotingAuthenticationTokenValidationMSFT;
typedef struct XrRemotingServerCertificateRequestMSFT {
XrStructureType type;
const void* next;
void* context;
uint32_t certStoreCapacityIn;
uint32_t certStoreSizeOut;
uint8_t* certStoreBuffer;
uint32_t keyPassphraseCapacityIn;
uint32_t keyPassphraseSizeOut;
char* keyPassphraseBuffer;
uint32_t subjectNameCapacityIn;
uint32_t subjectNameSizeOut;
char* subjectNameBuffer;
} XrRemotingServerCertificateRequestMSFT;
// Secure connection callback functions (typedef only, no prototype)
typedef XrResult(XRAPI_PTR* PFN_xrRemotingRequestAuthenticationTokenCallbackMSFT)(XrRemotingAuthenticationTokenRequestMSFT* authenticationTokenRequest);
typedef XrResult(XRAPI_PTR* PFN_xrRemotingValidateServerCertificateCallbackMSFT)(XrRemotingServerCertificateValidationMSFT* serverCertificateValidation);
typedef XrResult(XRAPI_PTR* PFN_xrRemotingValidateAuthenticationTokenCallbackMSFT)(XrRemotingAuthenticationTokenValidationMSFT* authenticationTokenValidation);
typedef XrResult(XRAPI_PTR* PFN_xrRemotingRequestServerCertificateCallbackMSFT)(XrRemotingServerCertificateRequestMSFT* serverCertificateRequest);
typedef struct XrRemotingSecureConnectionClientCallbacksMSFT {
XrStructureType type;
void* next;
void* context;
PFN_xrRemotingRequestAuthenticationTokenCallbackMSFT requestAuthenticationTokenCallback;
PFN_xrRemotingValidateServerCertificateCallbackMSFT validateServerCertificateCallback;
XrBool32 performSystemValidation;
} XrRemotingSecureConnectionClientCallbacksMSFT;
typedef struct XrRemotingSecureConnectionServerCallbacksMSFT {
XrStructureType type;
void* next;
void* context;
PFN_xrRemotingRequestServerCertificateCallbackMSFT requestServerCertificateCallback;
PFN_xrRemotingValidateAuthenticationTokenCallbackMSFT validateAuthenticationTokenCallback;
const char* authenticationRealm;
} XrRemotingSecureConnectionServerCallbacksMSFT;
// Remoting extension callable functions
typedef XrResult(XRAPI_PTR* PFN_xrRemotingSetContextPropertiesMSFT)(XrInstance instance, XrSystemId systemId, const XrRemotingRemoteContextPropertiesMSFT* contextProperties);
typedef XrResult(XRAPI_PTR* PFN_xrRemotingConnectMSFT)(XrInstance instance, XrSystemId systemId, const XrRemotingConnectInfoMSFT* connectInfo);
typedef XrResult(XRAPI_PTR* PFN_xrRemotingListenMSFT)(XrInstance instance, XrSystemId systemId, const XrRemotingListenInfoMSFT* listenInfo);
typedef XrResult(XRAPI_PTR* PFN_xrRemotingDisconnectMSFT)(XrInstance instance, XrSystemId systemId, const XrRemotingDisconnectInfoMSFT* disconnectInfo);
typedef XrResult(XRAPI_PTR* PFN_xrRemotingGetConnectionStateMSFT)(XrInstance instance, XrSystemId systemId, XrRemotingConnectionStateMSFT* connectionState, XrRemotingDisconnectReasonMSFT* lastDisconnectReason);
typedef XrResult(XRAPI_PTR* PFN_xrRemotingSetSecureConnectionClientCallbacksMSFT)(XrInstance instance, XrSystemId systemId, const XrRemotingSecureConnectionClientCallbacksMSFT* secureConnectionClientCallbacks);
typedef XrResult(XRAPI_PTR* PFN_xrRemotingSetSecureConnectionServerCallbacksMSFT)(XrInstance instance, XrSystemId systemId, const XrRemotingSecureConnectionServerCallbacksMSFT* secureConnectionServerCallbacks);
#ifndef XR_NO_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrRemotingSetContextPropertiesMSFT(
XrInstance instance,
XrSystemId systemId,
const XrRemotingRemoteContextPropertiesMSFT* contextProperties);
XRAPI_ATTR XrResult XRAPI_CALL xrRemotingConnectMSFT(
XrInstance instance,
XrSystemId systemId,
const XrRemotingConnectInfoMSFT* connectInfo);
XRAPI_ATTR XrResult XRAPI_CALL xrRemotingListenMSFT(
XrInstance instance,
XrSystemId systemId,
const XrRemotingListenInfoMSFT* listenInfo);
XRAPI_ATTR XrResult XRAPI_CALL xrRemotingDisconnectMSFT(
XrInstance instance,
XrSystemId systemId,
const XrRemotingDisconnectInfoMSFT* disconnectInfo);
XRAPI_ATTR XrResult XRAPI_CALL xrRemotingGetConnectionStateMSFT(
XrInstance instance,
XrSystemId systemId,
XrRemotingConnectionStateMSFT* connectionState,
XrRemotingDisconnectReasonMSFT* lastDisconnectReason);
XRAPI_ATTR XrResult XRAPI_CALL xrRemotingSetSecureConnectionClientCallbacksMSFT(
XrInstance instance,
XrSystemId systemId,
const XrRemotingSecureConnectionClientCallbacksMSFT* secureConnectionClientCallbacks);
XRAPI_ATTR XrResult XRAPI_CALL xrRemotingSetSecureConnectionServerCallbacksMSFT(
XrInstance instance,
XrSystemId systemId,
const XrRemotingSecureConnectionServerCallbacksMSFT* secureConnectionServerCallbacks);
#endif
#ifdef __cplusplus
}
#endif

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.MixedReality.QR" version="0.5.2102" targetFramework="native" />
<package id="Microsoft.VCRTForwarders.140" version="1.0.6" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
</packages>

Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
using UnrealBuildTool;
public class MicrosoftOpenXREditor : ModuleRules
{
public MicrosoftOpenXREditor(ReadOnlyTargetRules Target) : base(Target)
{
PrivateDependencyModuleNames.AddRange(
new string[] {
"Core",
"CoreUObject",
"InputCore",
"Engine",
"Slate",
"SlateCore",
"EditorStyle",
"EditorWidgets",
"DesktopWidgets",
"PropertyEditor",
"UnrealEd",
"SharedSettingsWidgets",
"TargetPlatform",
"RenderCore",
"MicrosoftOpenXRRuntimeSettings"
}
);
PrivateIncludePathModuleNames.AddRange(
new string[] {
"Settings"
}
);
}
}

Просмотреть файл

@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "MicrosoftOpenXRDetails.h"
#define LOCTEXT_NAMESPACE "FMicrosoftOpenXRDetails"
TSharedRef<IDetailCustomization> FMicrosoftOpenXRDetails::MakeInstance()
{
return MakeShareable(new FMicrosoftOpenXRDetails);
}
void FMicrosoftOpenXRDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
statusTextWidget = SNew(STextBlock);
UMicrosoftOpenXRRuntimeSettings::Get()->OnRemotingStatusChanged.BindSP(this, &FMicrosoftOpenXRDetails::SetStatusText);
IDetailCategoryBuilder& remotingCategory = DetailBuilder.EditCategory(TEXT("OpenXR Holographic Remoting"));
remotingCategory.AddCustomRow(LOCTEXT("Connect Button", "Connect Button"))
[
SNew(SButton)
.Text(LOCTEXT("Connect", "Connect"))
.OnClicked_Raw(this, &FMicrosoftOpenXRDetails::OnConnectButtonClicked)
.IsEnabled_Raw(this, &FMicrosoftOpenXRDetails::AreButtonsEnabled)
];
remotingCategory.AddCustomRow(LOCTEXT("Disconnect Button", "Disconnect Button"))
[
SNew(SButton)
.Text(LOCTEXT("Disconnect", "Disconnect"))
.OnClicked_Raw(this, &FMicrosoftOpenXRDetails::OnDisconnectButtonClicked)
.IsEnabled_Raw(this, &FMicrosoftOpenXRDetails::AreButtonsEnabled)
];
remotingCategory.AddCustomRow(LOCTEXT("Status Text", "Status Text"))[statusTextWidget.ToSharedRef()];
}
void FMicrosoftOpenXRDetails::SetStatusText(FString message, FLinearColor statusColor)
{
if (statusTextWidget == nullptr)
{
return;
}
statusTextWidget->SetText(FText::FromString(message));
statusTextWidget->SetColorAndOpacity(FSlateColor(statusColor));
}
FReply FMicrosoftOpenXRDetails::OnConnectButtonClicked()
{
MicrosoftOpenXR::RemotingConnectionData data;
UMicrosoftOpenXRRuntimeSettings::ParseAddress(
UMicrosoftOpenXRRuntimeSettings::Get()->RemoteHoloLensIP,
data.IP, data.Port);
data.Bitrate = UMicrosoftOpenXRRuntimeSettings::Get()->MaxBitrate;
data.EnableAudio = UMicrosoftOpenXRRuntimeSettings::Get()->EnableAudio;
data.ConnectionType = UMicrosoftOpenXRRuntimeSettings::Get()->ConnectionType;
data.ConnectionCodec = UMicrosoftOpenXRRuntimeSettings::Get()->ConnectionCodec;
UMicrosoftOpenXRRuntimeSettings::Get()->OnRemotingConnect.ExecuteIfBound(data);
return FReply::Handled();
}
FReply FMicrosoftOpenXRDetails::OnDisconnectButtonClicked()
{
UMicrosoftOpenXRRuntimeSettings::Get()->OnRemotingDisconnect.ExecuteIfBound();
return FReply::Handled();
}
bool FMicrosoftOpenXRDetails::AreButtonsEnabled() const
{
UMicrosoftOpenXRRuntimeSettings* settings = UMicrosoftOpenXRRuntimeSettings::Get();
return settings->bEnableRemotingForEditor;
}
#undef LOCTEXT_NAMESPACE

Просмотреть файл

@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#pragma once
#include "IDetailCustomNodeBuilder.h"
#include "PropertyHandle.h"
#include "IDetailCustomization.h"
#include "IPropertyTypeCustomization.h"
#include "PropertyCustomizationHelpers.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Input/SButton.h"
#include "DetailLayoutBuilder.h"
#include "DetailCategoryBuilder.h"
#include "IDetailPropertyRow.h"
#include "DetailWidgetRow.h"
#include "IDetailGroup.h"
#include "MicrosoftOpenXRRuntimeSettings.h"
class FMicrosoftOpenXRDetails : public IDetailCustomization
{
public:
static TSharedRef<IDetailCustomization> MakeInstance();
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
private:
FString StatusText;
TSharedPtr<STextBlock> statusTextWidget;
void SetStatusText(FString message, FLinearColor statusColor);
FReply OnConnectButtonClicked();
FReply OnDisconnectButtonClicked();
bool AreButtonsEnabled() const;
};

Просмотреть файл

@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "MicrosoftOpenXRRuntimeSettings.h"
#include "Modules/ModuleInterface.h"
#include "ISettingsModule.h"
#include "Modules/ModuleManager.h"
#include "PropertyEditorModule.h"
#include "MicrosoftOpenXRDetails.h"
#define LOCTEXT_NAMESPACE "FMicrosoftOpenXREditorModule"
/**
* Module for MicrosoftOpenXR platform editor utilities
*/
class FMicrosoftOpenXREditorModule
: public IModuleInterface
{
virtual void StartupModule() override
{
FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
PropertyModule.RegisterCustomClassLayout(FName("MicrosoftOpenXRRuntimeSettings"), FOnGetDetailCustomizationInstance::CreateStatic(&FMicrosoftOpenXRDetails::MakeInstance));
PropertyModule.NotifyCustomizationModuleChanged();
// register settings
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
if (SettingsModule != nullptr)
{
SettingsModule->RegisterSettings("Project", "Platforms", "MicrosoftOpenXR",
// Using "Windows Mixed Reality" here to preserve the remoting location from legacy WMR in Project Settings/ Windows Mixed Reality
LOCTEXT("RuntimeSettingsName", "Windows Mixed Reality"),
LOCTEXT("RuntimeSettingsDescription", "Project settings for Mixed Reality Platform Extensions"),
GetMutableDefault<UMicrosoftOpenXRRuntimeSettings>()
);
}
}
virtual void ShutdownModule() override
{
ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings");
if (SettingsModule != nullptr)
{
SettingsModule->UnregisterSettings("Project", "Platforms", "MicrosoftOpenXR");
}
}
};
IMPLEMENT_MODULE(FMicrosoftOpenXREditorModule, MicrosoftOpenXREditor);
#undef LOCTEXT_NAMESPACE

Просмотреть файл

@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
using UnrealBuildTool;
public class MicrosoftOpenXRRuntimeSettings : ModuleRules
{
public MicrosoftOpenXRRuntimeSettings(ReadOnlyTargetRules Target) : base(Target)
{
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine"
}
);
if (Target.Type == TargetRules.TargetType.Editor || Target.Type == TargetRules.TargetType.Program)
{
PrivateDependencyModuleNames.AddRange(
new string[]
{
"TargetPlatform"
}
);
}
}
}

Просмотреть файл

@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "MicrosoftOpenXRRuntimeSettings.h"
#include "Misc/ConfigCacheIni.h"
#include "CoreGlobals.h"
#include "UObject/Package.h"
UMicrosoftOpenXRRuntimeSettings* UMicrosoftOpenXRRuntimeSettings::MicrosoftOpenXRSettingsSingleton = nullptr;
#if WITH_EDITOR
void UMicrosoftOpenXRRuntimeSettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
GConfig->Flush(false);
}
#endif
UMicrosoftOpenXRRuntimeSettings* UMicrosoftOpenXRRuntimeSettings::Get()
{
if (MicrosoftOpenXRSettingsSingleton == nullptr && GetTransientPackage() != nullptr)
{
static const TCHAR* SettingsContainerName = TEXT("MicrosoftOpenXRRuntimeSettingsContainer");
MicrosoftOpenXRSettingsSingleton = FindObject<UMicrosoftOpenXRRuntimeSettings>(GetTransientPackage(), SettingsContainerName);
if (MicrosoftOpenXRSettingsSingleton == nullptr)
{
MicrosoftOpenXRSettingsSingleton = NewObject<UMicrosoftOpenXRRuntimeSettings>(
GetTransientPackage(), UMicrosoftOpenXRRuntimeSettings::StaticClass(), SettingsContainerName);
MicrosoftOpenXRSettingsSingleton->AddToRoot();
}
}
return MicrosoftOpenXRSettingsSingleton;
}
bool UMicrosoftOpenXRRuntimeSettings::ParseAddress(const FString& StringToParse, FString& Address, uint32& Port)
{
FString PortStr;
if (StringToParse.Len() == 0)
{
return false;
}
if (StringToParse.Split(TEXT(":"), &Address, &PortStr))
{
// Parse the input in format "IP:Port"
Port = FCString::Atoi(*PortStr);
}
else if (!StringToParse.Contains("."))
{
// If the given ip is not valid, try using it as a port for a listen connection to the remoting player.
Address = TEXT("0.0.0.0");
Port = FCString::Atoi(*StringToParse);
}
else
{
// Otherwise only an IP is set. Use the default port.
Address = StringToParse;
Port = 8265;
}
return true;
}

Просмотреть файл

@ -0,0 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
IMPLEMENT_MODULE(FDefaultModuleImpl, MicrosoftOpenXRRuntimeSettings);

Просмотреть файл

@ -0,0 +1,90 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "UObject/Object.h"
#include "Engine/EngineTypes.h"
#include "MicrosoftOpenXRRuntimeSettings.generated.h"
UENUM()
enum class RemotingConnectionType
{
Connect = 0,
Listen = 1
};
// This will be cast to XrRemotingVideoCodecMSFT, IDs must match
UENUM()
enum class RemotingCodec
{
Any = 0,
H264 = 1,
H265 = 2
};
namespace MicrosoftOpenXR
{
struct RemotingConnectionData
{
FString IP;
uint32 Port = 8265;
int Bitrate = 8000;
bool EnableAudio = false;
RemotingConnectionType ConnectionType = RemotingConnectionType::Connect;
RemotingCodec ConnectionCodec = RemotingCodec::Any;
};
} // namespace MicrosoftOpenXR
DECLARE_DELEGATE_TwoParams(FMicrosoftOpenXRRemotingStatusChanged, FString /*RemotingMessage*/, FLinearColor /*StatusColor*/);
DECLARE_DELEGATE_OneParam(FMicrosoftOpenXRRemotingConnect, MicrosoftOpenXR::RemotingConnectionData);
DECLARE_DELEGATE(FMicrosoftOpenXRRemotingDisconnect);
/**
* Implements the settings for the WindowsMixedReality runtime platform.
*/
UCLASS(config=EditorPerProjectUserSettings)
class MICROSOFTOPENXRRUNTIMESETTINGS_API UMicrosoftOpenXRRuntimeSettings : public UObject
{
public:
GENERATED_BODY()
FMicrosoftOpenXRRemotingStatusChanged OnRemotingStatusChanged;
FMicrosoftOpenXRRemotingConnect OnRemotingConnect;
FMicrosoftOpenXRRemotingDisconnect OnRemotingDisconnect;
static UMicrosoftOpenXRRuntimeSettings* Get();
static bool ParseAddress(const FString& StringToParse, FString& Address, uint32& Port);
#if WITH_EDITOR
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
#endif // WITH_EDITOR
UPROPERTY(GlobalConfig, EditAnywhere, Category = "OpenXR Holographic Remoting", Meta = (ConfigRestartRequired = true, DisplayName = "Enable Remoting For Editor (Requires Restart)", Tooltip = "If true, start with a valid HMD to enable connecting via remoting. Editor restart required."))
bool bEnableRemotingForEditor = false;
/** The IP of the HoloLens to remote to. */
UPROPERTY(GlobalConfig, EditAnywhere, Category = "OpenXR Holographic Remoting", Meta = (EditCondition = "bEnableRemotingForEditor", DisplayName = "IP of HoloLens to remote to."))
FString RemoteHoloLensIP;
UPROPERTY(GlobalConfig, EditAnywhere, Category = "OpenXR Holographic Remoting", Meta = (EditCondition = "bEnableRemotingForEditor", DisplayName = "Automatically connect to remote device."))
bool bAutoConnectRemoting = false;
UPROPERTY(GlobalConfig, EditAnywhere, Category = "OpenXR Holographic Remoting", Meta = (EditCondition = "bEnableRemotingForEditor", DisplayName = "Max network transfer rate (kb/s)."))
unsigned int MaxBitrate = 8000;
UPROPERTY(GlobalConfig, EditAnywhere, Category = "OpenXR Holographic Remoting", Meta = (EditCondition = "bEnableRemotingForEditor", DisplayName = "Use audio from PC when remoting."))
bool EnableAudio = false;
UPROPERTY(GlobalConfig, EditAnywhere, Category = "OpenXR Holographic Remoting", Meta = (EditCondition = "bEnableRemotingForEditor", DisplayName = "Connection Type."))
RemotingConnectionType ConnectionType = RemotingConnectionType::Connect;
UPROPERTY(GlobalConfig, EditAnywhere, Category = "OpenXR Holographic Remoting", Meta = (EditCondition = "bEnableRemotingForEditor", DisplayName = "Connection Codec."))
RemotingCodec ConnectionCodec = RemotingCodec::Any;
private:
static class UMicrosoftOpenXRRuntimeSettings* MicrosoftOpenXRSettingsSingleton;
};

Просмотреть файл

@ -0,0 +1,223 @@
MICROSOFT SOFTWARE LICENSE TERMS
MICROSOFT HOLOGRAPHIC REMOTING
IF YOU LIVE IN (OR ARE A BUSINESS WITH YOUR PRINCIPAL PLACE OF BUSINESS IN) THE
UNITED STATES, PLEASE READ THE “BINDING ARBITRATION AND CLASS ACTION WAIVER”
SECTION BELOW. IT AFFECTS HOW DISPUTES ARE RESOLVED.
These license terms are an agreement between you and Microsoft Corporation (or one of its affiliates). They
apply to the software named above and any Microsoft services or software updates (except to the extent such
services or updates are accompanied by new or additional terms, in which case those different terms apply
prospectively and do not alter your or Microsofts rights relating to pre-updated software or services). IF YOU
COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.
1. INSTALLATION AND USE RIGHTS.
a) General. You may install and use any number of copies of the software to develop and test your
applications.
b) Third Party Software. The software may include third party applications that are licensed to you
under this agreement or under their own terms. License terms, notices, and acknowledgements, if
any, for the third party applications may be accessible online at http://aka.ms/thirdpartynotices or in
an accompanying notices file. Even if such applications are governed by other agreements, the
disclaimer, limitations on, and exclusions of damages below also apply to the extent allowed by
applicable law.
c) Competitive Benchmarking. If you are a direct competitor, and you access or use the software for
purposes of competitive benchmarking, analysis, or intelligence gathering, you waive as against
Microsoft, its subsidiaries, and its affiliated companies (including prospectively) any competitive use,
access, and benchmarking test restrictions in the terms governing your software to the extent your
terms of use are, or purport to be, more restrictive than Microsofts terms. If you do not waive any
such purported restrictions in the terms governing your software, you are not allowed to access or use
this software, and will not do so.
2. DISTRIBUTABLE CODE. The software may contain code you are permitted to distribute (i.e. make
available for third parties) in applications you develop, as described in this Section.
a) Distribution Rights. The code and test files described below are distributable if included with the
software.
i. REDIST.TXT Files. You may copy and distribute the object code form of code listed on the REDIST
list in the software, if any, or listed at redist.txt;
ii. Sample Code, Templates, and Styles. You may copy, modify, and distribute the source and object
code form of code marked as “sample”, “template”, “simple styles”, and “sketch styles”; and
iii. Third Party Distribution. You may permit distributors of your applications to copy and distribute
any of this distributable code you elect to distribute with your applications.
b) Distribution Requirements. For any code you distribute, you must:
i. add significant primary functionality to it in your applications;
ii. require distributors and external end users to agree to terms that protect it and Microsoft at least
as much as this agreement; and
iii. indemnify, defend, and hold harmless Microsoft from any claims, including attorneys fees, related
to the distribution or use of your applications, except to the extent that any claim is based solely
on the unmodified distributable code.
c) Distribution Restrictions. You may not:
i. use Microsofts trademarks or trade dress in your application in any way that suggests your
application comes from or is endorsed by Microsoft; or
ii. modify or distribute the source code of any distributable code so that any part of it becomes
subject to any license that requires that the distributable code, any other part of the software, or
any of Microsofts other intellectual property be disclosed or distributed in source code form, or
that others have the right to modify it.
3. DATA COLLECTION. The software may collect information about you and your use of the software and
send that to Microsoft. Microsoft may use this information to provide services and improve Microsofts
products and services. Your opt-out rights, if any, are described in the product documentation. Some
features in the software may enable collection of data from users of your applications that access or use
the software. If you use these features to enable data collection in your applications, you must comply
with applicable law, including getting any required user consent, and maintain a prominent privacy policy
that accurately informs users about how you use, collect, and share their data. You can learn more about
Microsofts data collection and use in the product documentation and the Microsoft Privacy Statement at https://go.microsoft.com/fwlink/?LinkId=521839. You agree to comply with all applicable provisions of the
Microsoft Privacy Statement.
4. SCOPE OF LICENSE. The software is licensed, not sold. Microsoft reserves all other rights. Unless
applicable law gives you more rights despite this limitation, you will not (and have no right to):
a) work around any technical limitations in the software that only allow you to use it in certain ways;
b) reverse engineer, decompile, or disassemble the software, or attempt to do so, except and only to the
extent permitted by licensing terms governing the use of open-source components that may be
included with the software;
c) remove, minimize, block, or modify any notices of Microsoft or its suppliers in the software;
d) use the software in any way that is against the law or to create or propagate malware; or
e) share, publish, distribute, or lend the software (except for any distributable code, subject to the terms
above), provide the software as a stand-alone hosted solution for others to use, or transfer the
software or this agreement to any third party.
5. EXPORT RESTRICTIONS. You must comply with all domestic and international export laws and
regulations that apply to the software, which include restrictions on destinations, end users, and end use.
For further information on export restrictions, visit http://aka.ms/exporting.
6. SUPPORT SERVICES. Microsoft is not obligated under this agreement to provide any support services for
the software. Any support provided is “as is”, “with all faults”, and without warranty of any kind.
7. UPDATES. The software may periodically check for updates, and download and install them for you. You
may obtain updates only from Microsoft or authorized sources. Microsoft may need to update your system
to provide you with updates. You agree to receive these automatic updates without any additional notice.
Updates may not include or support all existing software features, services, or peripheral devices.
8. BINDING ARBITRATION AND CLASS ACTION WAIVER. This Section applies if you live in (or, if
a business, your principal place of business is in) the United States. If you and Microsoft have a
dispute, you and Microsoft agree to try for 60 days to resolve it informally. If you and Microsoft cant, you
and Microsoft agree to binding individual arbitration before the American Arbitration Association
under the Federal Arbitration Act (“FAA”), and not to sue in court in front of a judge or jury. Instead,
a neutral arbitrator will decide. Class action lawsuits, class-wide arbitrations, private attorney-
general actions, and any other proceeding where someone acts in a representative capacity are not
allowed; nor is combining individual proceedings without the consent of all parties. The complete
Arbitration Agreement contains more terms and is at http://aka.ms/arb-agreement-1. You and Microsoft
agree to these terms.
9. ENTIRE AGREEMENT. This agreement, and any other terms Microsoft may provide for supplements,
updates, or third-party applications, is the entire agreement for the software.
10. APPLICABLE LAW AND PLACE TO RESOLVE DISPUTES. If you acquired the software in the United
States or Canada, the laws of the state or province where you live (or, if a business, where your principal
place of business is located) govern the interpretation of this agreement, claims for its breach, and all
other claims (including consumer protection, unfair competition, and tort claims), regardless of conflict of
laws principles, except that the FAA governs everything related to arbitration. If you acquired the software
in any other country, its laws apply, except that the FAA governs everything related to arbitration. If U.S.
federal jurisdiction exists, you and Microsoft consent to exclusive jurisdiction and venue in the federal court
in King County, Washington for all disputes heard in court (excluding arbitration). If not, you and Microsoft
consent to exclusive jurisdiction and venue in the Superior Court of King County, Washington for all
disputes heard in court (excluding arbitration).
11. CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal rights. You
may have other rights, including consumer rights, under the laws of your state or country. Separate and
apart from your relationship with Microsoft, you may also have rights with respect to the party from which
you acquired the software. This agreement does not change those other rights if the laws of your state or
country do not permit it to do so. For example, if you acquired the software in one of the below regions, or
mandatory country law applies, then the following provisions apply to you:
a) Australia. You have statutory guarantees under the Australian Consumer Law and nothing in this
agreement is intended to affect those rights.
b) Canada. If you acquired this software in Canada, you may stop receiving updates by turning off the
automatic update feature, disconnecting your device from the Internet (if and when you re-connect to
the Internet, however, the software will resume checking for and installing updates), or uninstalling
the software. The product documentation, if any, may also specify how to turn off updates for your
specific device or software.
c) Germany and Austria.
i. Warranty. The properly licensed software will perform substantially as described in any Microsoft
materials that accompany the software. However, Microsoft gives no contractual guarantee in
relation to the licensed software.
ii. Limitation of Liability. In case of intentional conduct, gross negligence, claims based on the
Product Liability Act, as well as, in case of death or personal or physical injury, Microsoft is liable
according to the statutory law.
Subject to the foregoing clause ii., Microsoft will only be liable for slight negligence if Microsoft is in
breach of such material contractual obligations, the fulfillment of which facilitate the due performance
of this agreement, the breach of which would endanger the purpose of this agreement and the
compliance with which a party may constantly trust in (so-called "cardinal obligations"). In other cases
of slight negligence, Microsoft will not be liable for slight negligence.
12. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF
USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS.
TO THE EXTENT PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED
WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
NON-INFRINGEMENT.
13. LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY BASIS FOR RECOVERING
DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM
MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT
RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL,
INDIRECT, OR INCIDENTAL DAMAGES.
This limitation applies to (a) anything related to the software, services, content (including
code) on third party Internet sites, or third party applications; and (b) claims for breach of
contract, warranty, guarantee, or condition; strict liability, negligence, or other tort; or any
other claim; in each case to the extent permitted by applicable law.
It also applies even if Microsoft knew or should have known about the possibility of the
damages. The above limitation or exclusion may not apply to you because your state,
province, or country may not allow the exclusion or limitation of incidental, consequential, or
other damages.
Please note: As this software is distributed in Canada, some of the clauses in this agreement are
provided below in French.
Remarque: Ce logiciel étant distribué au Canada, certaines des clauses dans ce contrat sont
fournies ci-dessous en français.
EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute
utilisation de ce logiciel est à votre seule risque et péril. Microsoft naccorde aucune autre
garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la
protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le
droit locale, les garanties implicites de qualité marchande, dadéquation à un usage particulier et
dabsence de contrefaçon sont exclues.
LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES
DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de
dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune
indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou
accessoires et pertes de bénéfices.
Cette limitation concerne:
• tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur
des sites Internet tiers ou dans des programmes tiers; et
• les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité
stricte, de négligence ou dune autre faute dans la limite autorisée par la loi en vigueur.
Elle sapplique également, même si Microsoft connaissait ou devrait connaître léventualité dun
tel dommage. Si votre pays nautorise pas lexclusion ou la limitation de responsabilité pour les
dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou
lexclusion ci-dessus ne sappliquera pas à votre égard.
EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir
dautres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que
vous confèrent les lois de votre pays si celles-ci ne le permettent pas.

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше