├── .gitattributes ├── .gitignore ├── HoloLensCppModules.sln ├── Modules ├── HoloLensCppModulesPch.cpp ├── HoloLensCppModulesPch.h ├── LocatableCamera │ ├── LocatableCameraFrame.cpp │ ├── LocatableCameraFrame.h │ ├── LocatableCameraModule.cpp │ └── LocatableCameraModule.h ├── Logger.cpp ├── Logger.h ├── Modules.vcxproj ├── Modules.vcxproj.filters ├── RayCast │ ├── RayCastResult.cpp │ ├── RayCastResult.h │ ├── RayCaster.cpp │ └── RayCaster.h ├── SpatialMapping │ ├── SpatialMappingFrame.cpp │ ├── SpatialMappingFrame.h │ ├── SpatialMappingFrameEntry.cpp │ ├── SpatialMappingFrameEntry.h │ ├── SpatialMappingModule.cpp │ └── SpatialMappingModule.h ├── Utility.cpp ├── Utility.h ├── packages.config └── targetver.h ├── README.md └── Sample ├── AppView.cpp ├── AppView.h ├── Assets ├── LockScreenLogo.scale-200.png ├── SplashScreen.scale-200.png ├── Square150x150Logo.scale-200.png ├── Square44x44Logo.scale-200.png ├── Square44x44Logo.targetsize-24_altform-unplated.png ├── StoreLogo.png └── Wide310x150Logo.scale-200.png ├── Common ├── CameraResources.cpp ├── CameraResources.h ├── DeviceResources.cpp ├── DeviceResources.h ├── DirectXHelper.h └── StepTimer.h ├── Content ├── GeometryShader.hlsl ├── PixelShader.hlsl ├── ShaderStructures.h ├── VPRTVertexShader.hlsl └── VertexShader.hlsl ├── Package.appxmanifest ├── Sample.vcxproj ├── Sample.vcxproj.filters ├── SampleMain.cpp ├── SampleMain.h ├── SamplePch.cpp ├── SamplePch.h └── packages.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | -------------------------------------------------------------------------------- /HoloLensCppModules.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 14 3 | VisualStudioVersion = 14.0.25420.1 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sample", "Sample\Sample.vcxproj", "{D8F6E702-734F-4264-B1CD-0D09C6564D34}" 6 | EndProject 7 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Modules", "Modules\Modules.vcxproj", "{385E63DB-5879-4601-9F27-28C5089956FB}" 8 | EndProject 9 | Global 10 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 11 | Debug|ARM = Debug|ARM 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|ARM = Release|ARM 15 | Release|x64 = Release|x64 16 | Release|x86 = Release|x86 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Debug|ARM.ActiveCfg = Debug|Win32 20 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Debug|x64.ActiveCfg = Debug|Win32 21 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Debug|x86.ActiveCfg = Debug|Win32 22 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Debug|x86.Build.0 = Debug|Win32 23 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Debug|x86.Deploy.0 = Debug|Win32 24 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Release|ARM.ActiveCfg = Release|Win32 25 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Release|x64.ActiveCfg = Release|Win32 26 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Release|x86.ActiveCfg = Release|Win32 27 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Release|x86.Build.0 = Release|Win32 28 | {D8F6E702-734F-4264-B1CD-0D09C6564D34}.Release|x86.Deploy.0 = Release|Win32 29 | {385E63DB-5879-4601-9F27-28C5089956FB}.Debug|ARM.ActiveCfg = Debug|ARM 30 | {385E63DB-5879-4601-9F27-28C5089956FB}.Debug|ARM.Build.0 = Debug|ARM 31 | {385E63DB-5879-4601-9F27-28C5089956FB}.Debug|x64.ActiveCfg = Debug|x64 32 | {385E63DB-5879-4601-9F27-28C5089956FB}.Debug|x64.Build.0 = Debug|x64 33 | {385E63DB-5879-4601-9F27-28C5089956FB}.Debug|x86.ActiveCfg = Debug|Win32 34 | {385E63DB-5879-4601-9F27-28C5089956FB}.Debug|x86.Build.0 = Debug|Win32 35 | {385E63DB-5879-4601-9F27-28C5089956FB}.Release|ARM.ActiveCfg = Release|ARM 36 | {385E63DB-5879-4601-9F27-28C5089956FB}.Release|ARM.Build.0 = Release|ARM 37 | {385E63DB-5879-4601-9F27-28C5089956FB}.Release|x64.ActiveCfg = Release|x64 38 | {385E63DB-5879-4601-9F27-28C5089956FB}.Release|x64.Build.0 = Release|x64 39 | {385E63DB-5879-4601-9F27-28C5089956FB}.Release|x86.ActiveCfg = Release|Win32 40 | {385E63DB-5879-4601-9F27-28C5089956FB}.Release|x86.Build.0 = Release|Win32 41 | EndGlobalSection 42 | GlobalSection(SolutionProperties) = preSolution 43 | HideSolutionNode = FALSE 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /Modules/HoloLensCppModulesPch.cpp: -------------------------------------------------------------------------------- 1 | #include "HoloLensCppModulesPch.h" 2 | -------------------------------------------------------------------------------- /Modules/HoloLensCppModulesPch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "targetver.h" 4 | 5 | #ifndef WIN32_LEAN_AND_MEAN 6 | #define WIN32_LEAN_AND_MEAN 7 | #endif 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "Logger.h" -------------------------------------------------------------------------------- /Modules/LocatableCamera/LocatableCameraFrame.cpp: -------------------------------------------------------------------------------- 1 | #include "HololensCppModulesPch.h" 2 | #include "LocatableCameraFrame.h" 3 | 4 | namespace HoloLensCppModules 5 | { 6 | LocatableCameraFrame::LocatableCameraFrame( 7 | unsigned int id, 8 | Windows::Graphics::Imaging::SoftwareBitmap^ softwareBitmap, 9 | Windows::Perception::Spatial::SpatialCoordinateSystem^ coordinateSystem, 10 | DirectX::SimpleMath::Matrix viewTransform, 11 | DirectX::SimpleMath::Matrix projectionTransform) 12 | : m_id(id) 13 | , m_softwareBitmap(softwareBitmap) 14 | , m_coordinateSystem(coordinateSystem) 15 | , m_viewTransform(viewTransform) 16 | , m_projectionTransform(projectionTransform) 17 | { 18 | } 19 | 20 | LocatableCameraFrame::~LocatableCameraFrame() 21 | { 22 | } 23 | } -------------------------------------------------------------------------------- /Modules/LocatableCamera/LocatableCameraFrame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HoloLensCppModules 6 | { 7 | class LocatableCameraFrame 8 | { 9 | public: 10 | LocatableCameraFrame( 11 | unsigned int id, 12 | Windows::Graphics::Imaging::SoftwareBitmap^ softwareBitmap, 13 | Windows::Perception::Spatial::SpatialCoordinateSystem^ coordinateSystem, 14 | DirectX::SimpleMath::Matrix viewTransform, 15 | DirectX::SimpleMath::Matrix projectionTransform); 16 | ~LocatableCameraFrame(); 17 | unsigned int GetId() { return m_id; } 18 | Windows::Graphics::Imaging::SoftwareBitmap^ GetSoftwareBitmap() { return m_softwareBitmap; } 19 | Windows::Perception::Spatial::SpatialCoordinateSystem^ GetCoordinateSystem() { return m_coordinateSystem; } 20 | DirectX::SimpleMath::Matrix GetViewTransform() { return m_viewTransform; } 21 | DirectX::SimpleMath::Matrix GetProjectionTransform() { return m_projectionTransform; } 22 | 23 | private: 24 | unsigned int m_id; 25 | Windows::Graphics::Imaging::SoftwareBitmap^ m_softwareBitmap; 26 | Windows::Perception::Spatial::SpatialCoordinateSystem^ m_coordinateSystem; 27 | DirectX::SimpleMath::Matrix m_viewTransform; 28 | DirectX::SimpleMath::Matrix m_projectionTransform; 29 | }; 30 | } -------------------------------------------------------------------------------- /Modules/LocatableCamera/LocatableCameraModule.cpp: -------------------------------------------------------------------------------- 1 |  2 | //********************************************************* 3 | // 4 | // Copyright (c) Microsoft. All rights reserved. 5 | // This code is licensed under the MIT License (MIT). 6 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 7 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 8 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 9 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 10 | // 11 | //********************************************************* 12 | 13 | #include "HoloLensCppModulesPch.h" 14 | #include "LocatableCameraModule.h" 15 | 16 | #include "Utility.h" 17 | 18 | namespace HoloLensCppModules 19 | { 20 | // strings for GUIDs are from https://developer.microsoft.com/ko-kr/windows/holographic/locatable_camera 21 | LocatableCameraModule::LocatableCameraModule( 22 | Platform::Agile mediaCapture, 23 | Windows::Media::Capture::Frames::MediaFrameReader^ reader, 24 | Windows::Media::Capture::Frames::MediaFrameSource^ source) 25 | : m_coordinateSystemGuid(Utility::StringToGuid(L"{9D13C82F-2199-4E67-91CD-D1A4181F2534}")) 26 | , m_viewTransformGuid(Utility::StringToGuid(L"{4E251FA4-830F-4770-859A-4B8D99AA809B}")) 27 | , m_projectionTransformGuid(Utility::StringToGuid(L"{47F9FCB5-2A02-4F26-A477-792FDF95886A}")) 28 | , m_mediaCapture(std::move(mediaCapture)) 29 | , m_mediaFrameReader(std::move(reader)) 30 | , m_mediaFrameSource(std::move(source)) 31 | , m_frameId(0) 32 | { 33 | using Windows::Foundation::TypedEventHandler; 34 | using Windows::Media::Capture::Frames::MediaFrameArrivedEventArgs; 35 | using Windows::Media::Capture::Frames::MediaFrameReader; 36 | using std::placeholders::_1; 37 | using std::placeholders::_2; 38 | 39 | // Listen for new frames, so we know when to update our m_latestFrame 40 | m_mediaFrameReader->FrameArrived += 41 | ref new TypedEventHandler( 42 | std::bind(&LocatableCameraModule::OnFrameArrived, this, _1, _2)); 43 | } 44 | 45 | Concurrency::task> LocatableCameraModule::CreateAsync() 46 | { 47 | using Windows::Media::Capture::MediaCapture; 48 | using Windows::Media::Capture::MediaCaptureInitializationSettings; 49 | using Windows::Media::Capture::MediaCaptureMemoryPreference; 50 | using Windows::Media::Capture::StreamingCaptureMode; 51 | using Windows::Media::Capture::Frames::MediaFrameSource; 52 | using Windows::Media::Capture::Frames::MediaFrameSourceGroup; 53 | using Windows::Media::Capture::Frames::MediaFrameSourceInfo; 54 | using Windows::Media::Capture::Frames::MediaFrameSourceKind; 55 | using Windows::Media::Capture::Frames::MediaFrameReader; 56 | using Windows::Media::Capture::Frames::MediaFrameReaderStartStatus; 57 | 58 | return Concurrency::create_task(MediaFrameSourceGroup::FindAllAsync()) 59 | .then([](Windows::Foundation::Collections::IVectorView^ groups) 60 | { 61 | MediaFrameSourceGroup^ selectedGroup = nullptr; 62 | MediaFrameSourceInfo^ selectedSourceInfo = nullptr; 63 | 64 | // Pick first color source. 65 | for (auto sourceGroup : groups) 66 | { 67 | for (auto sourceInfo : sourceGroup->SourceInfos) 68 | { 69 | if (sourceInfo->SourceKind == MediaFrameSourceKind::Color) 70 | { 71 | selectedSourceInfo = sourceInfo; 72 | break; 73 | } 74 | } 75 | 76 | if (selectedSourceInfo != nullptr) 77 | { 78 | selectedGroup = sourceGroup; 79 | break; 80 | } 81 | } 82 | 83 | // No valid camera was found. This will happen on the emulator. 84 | if (selectedGroup == nullptr || selectedSourceInfo == nullptr) 85 | { 86 | return concurrency::task_from_result(std::shared_ptr(nullptr)); 87 | } 88 | 89 | auto settings = ref new MediaCaptureInitializationSettings(); 90 | settings->MemoryPreference = MediaCaptureMemoryPreference::Cpu; // Need SoftwareBitmaps for FaceAnalysis 91 | settings->StreamingCaptureMode = StreamingCaptureMode::Video; // Only need to stream video 92 | settings->SourceGroup = selectedGroup; 93 | 94 | Platform::Agile mediaCapture(ref new MediaCapture()); 95 | 96 | return concurrency::create_task(mediaCapture->InitializeAsync(settings)) 97 | .then([=] 98 | { 99 | MediaFrameSource^ selectedSource = mediaCapture->FrameSources->Lookup(selectedSourceInfo->Id); 100 | 101 | return concurrency::create_task(mediaCapture->CreateFrameReaderAsync(selectedSource)) 102 | .then([=](MediaFrameReader^ reader) 103 | { 104 | return concurrency::create_task(reader->StartAsync()) 105 | .then([=](MediaFrameReaderStartStatus status) 106 | { 107 | // Only create a VideoFrameProcessor if the reader successfully started 108 | if (status == MediaFrameReaderStartStatus::Success) 109 | { 110 | return std::make_shared(mediaCapture, reader, selectedSource); 111 | } 112 | else 113 | { 114 | return std::shared_ptr(nullptr); 115 | } 116 | }); 117 | }); 118 | }); 119 | }); 120 | } 121 | 122 | std::shared_ptr LocatableCameraModule::GetFrame() 123 | { 124 | auto lock = std::shared_lock(m_propertiesLock); 125 | return m_frame; 126 | } 127 | 128 | void LocatableCameraModule::OnFrameArrived( 129 | Windows::Media::Capture::Frames::MediaFrameReader^ sender, 130 | Windows::Media::Capture::Frames::MediaFrameArrivedEventArgs^ args) 131 | { 132 | using Windows::Graphics::Imaging::BitmapPixelFormat; 133 | using Windows::Graphics::Imaging::SoftwareBitmap; 134 | using Windows::Media::Capture::Frames::MediaFrameReference; 135 | using Windows::Perception::Spatial::SpatialCoordinateSystem; 136 | 137 | if (MediaFrameReference^ frame = sender->TryAcquireLatestFrame()) 138 | { 139 | if (auto videoMediaFrame = frame->VideoMediaFrame) 140 | { 141 | if (auto softwareBitmap = videoMediaFrame->SoftwareBitmap) 142 | { 143 | try 144 | { 145 | // Accessing properties can result in throwing an exception since mediaFrameReference can be disposed inside the VideoFrameProcessor. 146 | // Handling this part before performance demanding processes tends to prevent throw exceptions. 147 | 148 | // cameraSpatialCoordinateSystem only contains translation 149 | auto cameraSpatialCoordinateSystemObject(frame->Properties->Lookup(m_coordinateSystemGuid)); 150 | auto cameraSpatialCoordinateSystem(safe_cast(cameraSpatialCoordinateSystemObject)); 151 | // cameraViewTransform consists of rotation and translation 152 | auto cameraViewTransformBox(safe_cast^>(frame->Properties->Lookup(m_viewTransformGuid))); 153 | auto cameraProjectionTransformBox = safe_cast^>(frame->Properties->Lookup(m_projectionTransformGuid)); 154 | auto cameraViewTransform(Utility::IBoxArrayToMatrix(cameraViewTransformBox)); 155 | auto cameraProjectionTransform = Utility::IBoxArrayToMatrix(cameraProjectionTransformBox); 156 | 157 | softwareBitmap = SoftwareBitmap::Convert(softwareBitmap, BitmapPixelFormat::Bgra8); 158 | 159 | { 160 | std::lock_guard lock(m_propertiesLock); 161 | 162 | m_frame = std::make_shared( 163 | ++m_frameId, softwareBitmap, cameraSpatialCoordinateSystem, 164 | cameraViewTransform, cameraProjectionTransform); 165 | } 166 | } 167 | catch (Platform::InvalidCastException^ e) 168 | { 169 | Logger::Log(L"InvalidCastException occured while using mediaFrameReference->Properties in VideoFrameProcessor::OnFrameArrived"); 170 | Logger::Log(e->Message); 171 | // Remove this exception throw when not debugging. 172 | throw e; 173 | } 174 | } 175 | } 176 | 177 | } 178 | } 179 | } -------------------------------------------------------------------------------- /Modules/LocatableCamera/LocatableCameraModule.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "LocatableCameraFrame.h" 15 | 16 | namespace HoloLensCppModules 17 | { 18 | class LocatableCameraModule 19 | { 20 | public: 21 | static Concurrency::task> CreateAsync(); 22 | 23 | LocatableCameraModule( 24 | Platform::Agile mediaCapture, 25 | Windows::Media::Capture::Frames::MediaFrameReader^ reader, 26 | Windows::Media::Capture::Frames::MediaFrameSource^ source); 27 | std::shared_ptr GetFrame(); 28 | 29 | private: 30 | void OnFrameArrived( 31 | Windows::Media::Capture::Frames::MediaFrameReader^ sender, 32 | Windows::Media::Capture::Frames::MediaFrameArrivedEventArgs^ args); 33 | 34 | Platform::Guid m_coordinateSystemGuid; 35 | Platform::Guid m_viewTransformGuid; 36 | Platform::Guid m_projectionTransformGuid; 37 | 38 | Platform::Agile m_mediaCapture; 39 | Windows::Media::Capture::Frames::MediaFrameReader^ m_mediaFrameReader; 40 | 41 | std::shared_mutex m_propertiesLock; 42 | Windows::Media::Capture::Frames::MediaFrameSource^ m_mediaFrameSource; 43 | std::shared_ptr m_frame; 44 | uint32 m_frameId; 45 | }; 46 | } -------------------------------------------------------------------------------- /Modules/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "HoloLensCppModulesPch.h" 2 | #include "Logger.h" 3 | 4 | namespace HoloLensCppModules 5 | { 6 | void Logger::Log(const char* message) 7 | { 8 | std::string str = std::string(message); 9 | std::wstring wstr = std::wstring(str.begin(), str.end()); 10 | OutputDebugString(wstr.c_str()); 11 | } 12 | 13 | void Logger::Log(std::string message) 14 | { 15 | std::wstring wstr = std::wstring(message.begin(), message.end()); 16 | OutputDebugString(wstr.c_str()); 17 | } 18 | 19 | void Logger::Log(std::wstring message) 20 | { 21 | OutputDebugString(message.c_str()); 22 | } 23 | 24 | void Logger::Log(Platform::String^ message) 25 | { 26 | auto wstr = std::wstring(message->Data()).append(L"\r\n"); 27 | OutputDebugString(wstr.c_str()); 28 | } 29 | 30 | void Logger::Log(int message) 31 | { 32 | auto wstr = std::wstring(message.ToString()->Data()).append(L"\r\n"); 33 | OutputDebugString(wstr.c_str()); 34 | } 35 | } -------------------------------------------------------------------------------- /Modules/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HoloLensCppModules 6 | { 7 | class Logger 8 | { 9 | private: 10 | Logger() 11 | { 12 | } 13 | 14 | public: 15 | static void Log(const char* message); 16 | static void Log(std::string message); 17 | static void Log(std::wstring message); 18 | static void Log(Platform::String^ message); 19 | static void Log(int message); 20 | }; 21 | } -------------------------------------------------------------------------------- /Modules/Modules.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | ARM 8 | 9 | 10 | Debug 11 | Win32 12 | 13 | 14 | Debug 15 | x64 16 | 17 | 18 | Release 19 | ARM 20 | 21 | 22 | Release 23 | Win32 24 | 25 | 26 | Release 27 | x64 28 | 29 | 30 | 31 | {385e63db-5879-4601-9f27-28c5089956fb} 32 | StaticLibrary 33 | Modules 34 | en-US 35 | 14.0 36 | true 37 | Windows Store 38 | 10.0.14393.0 39 | 10.0.10586.0 40 | 10.0 41 | 42 | 43 | 44 | StaticLibrary 45 | true 46 | v140 47 | 48 | 49 | StaticLibrary 50 | true 51 | v140 52 | 53 | 54 | StaticLibrary 55 | true 56 | v140 57 | 58 | 59 | StaticLibrary 60 | false 61 | true 62 | v140 63 | 64 | 65 | StaticLibrary 66 | false 67 | true 68 | v140 69 | 70 | 71 | StaticLibrary 72 | false 73 | true 74 | v140 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | false 103 | 104 | 105 | false 106 | 107 | 108 | false 109 | 110 | 111 | false 112 | 113 | 114 | false 115 | 116 | 117 | false 118 | 119 | 120 | 121 | Use 122 | true 123 | true 124 | HoloLensCppModulesPch.h 125 | 126 | 127 | Console 128 | false 129 | false 130 | 131 | 132 | 133 | 134 | Use 135 | true 136 | true 137 | HoloLensCppModulesPch.h 138 | 139 | 140 | Console 141 | false 142 | false 143 | 144 | 145 | 146 | 147 | Use 148 | false 149 | true 150 | 151 | 152 | Console 153 | false 154 | false 155 | 156 | 157 | 158 | 159 | Use 160 | false 161 | true 162 | 163 | 164 | Console 165 | false 166 | false 167 | 168 | 169 | 170 | 171 | Use 172 | false 173 | true 174 | 175 | 176 | Console 177 | false 178 | false 179 | 180 | 181 | 182 | 183 | Use 184 | false 185 | true 186 | 187 | 188 | Console 189 | false 190 | false 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | Create 209 | Create 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 231 | 232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /Modules/Modules.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | {9b36e254-eee8-44da-adb8-2369e74c3a21} 10 | 11 | 12 | {f6210898-9494-4818-bdc6-9089328be6ff} 13 | 14 | 15 | {48d40d60-98d3-4fa0-af55-24ef64e5a292} 16 | 17 | 18 | 19 | 20 | 21 | 22 | LocatableCamera 23 | 24 | 25 | LocatableCamera 26 | 27 | 28 | 29 | SpatialMapping 30 | 31 | 32 | SpatialMapping 33 | 34 | 35 | SpatialMapping 36 | 37 | 38 | RayCast 39 | 40 | 41 | RayCast 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | LocatableCamera 50 | 51 | 52 | LocatableCamera 53 | 54 | 55 | 56 | SpatialMapping 57 | 58 | 59 | SpatialMapping 60 | 61 | 62 | SpatialMapping 63 | 64 | 65 | RayCast 66 | 67 | 68 | RayCast 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Modules/RayCast/RayCastResult.cpp: -------------------------------------------------------------------------------- 1 | #include "HoloLensCppModulesPch.h" 2 | #include "RayCastResult.h" 3 | 4 | namespace HoloLensCppModules 5 | { 6 | RayCastResult::RayCastResult( 7 | bool hit, 8 | DirectX::SimpleMath::Ray ray, 9 | DirectX::SimpleMath::Vector3 position) 10 | : m_hit(hit) 11 | , m_ray(ray) 12 | , m_position(position) 13 | { 14 | } 15 | 16 | RayCastResult::~RayCastResult() 17 | { 18 | } 19 | } -------------------------------------------------------------------------------- /Modules/RayCast/RayCastResult.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace HoloLensCppModules 4 | { 5 | // Contains a result from RayCaster. 6 | class RayCastResult 7 | { 8 | public: 9 | RayCastResult( 10 | bool hit, 11 | DirectX::SimpleMath::Ray ray, 12 | DirectX::SimpleMath::Vector3 position); 13 | ~RayCastResult(); 14 | // Whether the raycast hit anything. 15 | bool IsHit() { return m_hit; } 16 | // The ray that has been casted. 17 | DirectX::SimpleMath::Ray GetRay() { return m_ray; } 18 | // Where the raycast hit. 19 | DirectX::SimpleMath::Vector3 GetPosition() { return m_position; } 20 | // How far the ray was casted to hit something. 21 | float GetDistance() { return DirectX::SimpleMath::Vector3::Distance(m_ray.position, m_position); } 22 | 23 | private: 24 | bool m_hit; 25 | DirectX::SimpleMath::Ray m_ray; 26 | DirectX::SimpleMath::Vector3 m_position; 27 | }; 28 | } -------------------------------------------------------------------------------- /Modules/RayCast/RayCaster.cpp: -------------------------------------------------------------------------------- 1 | #include "HoloLensCppModulesPch.h" 2 | #include "RayCaster.h" 3 | 4 | #include "Utility.h" 5 | 6 | namespace HoloLensCppModules 7 | { 8 | std::shared_ptr RayCaster::RayCast( 9 | DirectX::SimpleMath::Vector2 pixel, 10 | std::shared_ptr locatableCameraFrame, 11 | std::shared_ptr spatialMappingFrame, 12 | Windows::Perception::Spatial::SpatialCoordinateSystem^ currentCoordinateSystem) 13 | { 14 | using DirectX::SimpleMath::Vector3; 15 | 16 | // Converts a SpatialCoordinateSystem to a matrix. 17 | auto locatableCameraModelMatrix = Utility::CalculateLocatableCameraModelMatrix( 18 | currentCoordinateSystem, 19 | locatableCameraFrame->GetCoordinateSystem(), 20 | locatableCameraFrame->GetViewTransform()); 21 | 22 | // Gets the ray using camera's intrinsic parameters. 23 | auto locatableCameraRayDirection = CalculateHololensPreviewCameraDirection(pixel, locatableCameraFrame); 24 | 25 | // The ray in the locatable camera's coordinate system. 26 | DirectX::SimpleMath::Ray locatableCameraRay(Vector3::Zero, locatableCameraRayDirection); 27 | 28 | // The ray in the world coordinate system (in other words, baseCoordinateSystem). 29 | auto worldRay = Utility::GetTransformedRay(locatableCameraRay, locatableCameraModelMatrix); 30 | 31 | return RayCast(worldRay, spatialMappingFrame, currentCoordinateSystem); 32 | } 33 | 34 | std::shared_ptr RayCaster::RayCast( 35 | DirectX::SimpleMath::Ray ray, 36 | std::shared_ptr spatialMappingFrame, 37 | Windows::Perception::Spatial::SpatialCoordinateSystem^ currentCoordinateSystem) 38 | { 39 | using DirectX::SimpleMath::Vector3; 40 | using DirectX::SimpleMath::Ray; 41 | 42 | std::vector worldRayCastHitPositions; 43 | 44 | // Iterates through all containers in the group and saves a result (raycast's destination) from each of them. 45 | for (auto& entryPair : spatialMappingFrame->GetEntries()) 46 | { 47 | auto spatialSurfaceContainer = entryPair.second; 48 | 49 | // Gets the surface's bounding box and raycast to it. 50 | auto boundsBox = spatialSurfaceContainer->GetSurfaceInfo()->TryGetBounds(currentCoordinateSystem); 51 | auto bounds = boundsBox->Value; 52 | 53 | DirectX::BoundingOrientedBox boundingOrientedBox( 54 | Utility::LoadVector3(bounds.Center), 55 | Utility::LoadVector3(bounds.Extents), 56 | Utility::LoadQuaternion(bounds.Orientation)); 57 | float boundsDistance; 58 | 59 | bool boundsIntersect = boundingOrientedBox.Intersects(ray.position, ray.direction, boundsDistance); 60 | // If the ray does not meet the bounding box, skip this surface for better performance. 61 | if (!boundsIntersect) 62 | { 63 | continue; 64 | } 65 | 66 | auto spatialSurfaceModelMatrix = Utility::CalculateSpatialSurfaceModelMatrix( 67 | currentCoordinateSystem, 68 | spatialSurfaceContainer->GetCoordinateSystem(), 69 | spatialSurfaceContainer->GetVertexPositionScale() 70 | ); 71 | 72 | // The ray in the spatialSurfaceContainer's coordinate system. 73 | auto spatialSurfaceRay = Utility::GetTransformedRay(ray, spatialSurfaceModelMatrix.Invert()); 74 | 75 | auto positions = spatialSurfaceContainer->GetPositions(); 76 | auto indices = spatialSurfaceContainer->GetIndices(); 77 | size_t triangleCount = indices.size() / 3; 78 | 79 | for (size_t i = 0; i < triangleCount; ++i) 80 | { 81 | float distance; 82 | // This is possible since the address of Vector4's x, y, and z coincides those of Vector3. 83 | if (spatialSurfaceRay.Intersects( 84 | *reinterpret_cast(&positions[indices[i * 3]]), 85 | *reinterpret_cast(&positions[indices[i * 3 + 1]]), 86 | *reinterpret_cast(&positions[indices[i * 3 + 2]]), 87 | distance)) 88 | { 89 | auto intersectionPosition = spatialSurfaceRay.position + spatialSurfaceRay.direction * distance; 90 | auto worldRayCastHitPosition = Vector3::Transform(intersectionPosition, spatialSurfaceModelMatrix); 91 | worldRayCastHitPositions.push_back(worldRayCastHitPosition); 92 | } 93 | } 94 | } 95 | RayCastResult result(false, Ray(Vector3::Zero, Vector3::Zero), Vector3::Zero); 96 | for (auto worldRayCastHitPosition : worldRayCastHitPositions) 97 | { 98 | float distance = Vector3::Distance(worldRayCastHitPosition, ray.position); 99 | 100 | if (!result.IsHit() 101 | || (distance < result.GetDistance())) 102 | { 103 | result = RayCastResult(true, ray, worldRayCastHitPosition); 104 | } 105 | } 106 | 107 | return std::make_shared(result); 108 | } 109 | 110 | // The projection matrix P of Hololens' preview camera is given as below. 111 | // s_x 0 c_x 0 112 | // 0 s_y c_y 0 113 | // 0 0 -1 0 114 | // 0 0 -1 0 115 | // Since, [u, v, 1, 1]^T ~= [a, b, -z, -z] = P * [x, y, z, 1]^T, (the range of u and v is [-1, 1]) 116 | // we have 117 | // s_x * x / z + c_x = -u * z 118 | // s_y * y / z + c_y = -v * z. 119 | // Therefore, 120 | // x = -(u + c_x) * z / s_x, y = -(v + c_y) * z / s_y. 121 | // To get the center point, put u = 0 and v = 0. 122 | // The width and height can be obtained as 123 | // (width) = x|u=1 - x|u=-1 124 | // (height) = y|v=1 - y|v=-1 125 | // where x|u=1 means the value of x when u is 1. 126 | DirectX::SimpleMath::Vector3 RayCaster::CalculateHololensPreviewCameraDirection( 127 | DirectX::SimpleMath::Vector2 pixel, 128 | std::shared_ptr locatableCameraFrame) 129 | { 130 | float sx = locatableCameraFrame->GetProjectionTransform()._11; 131 | float sy = locatableCameraFrame->GetProjectionTransform()._22; 132 | float cx = locatableCameraFrame->GetProjectionTransform()._13; 133 | float cy = locatableCameraFrame->GetProjectionTransform()._23; 134 | 135 | const float z = -1.0f; 136 | float x = -(pixel.x + cx) * z / sx; 137 | float y = -(pixel.y + cy) * z / sy; 138 | 139 | DirectX::SimpleMath::Vector3 direction(x, y, z); 140 | direction.Normalize(); 141 | 142 | return direction; 143 | } 144 | } -------------------------------------------------------------------------------- /Modules/RayCast/RayCaster.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RayCastResult.h" 4 | #include "..\LocatableCamera\LocatableCameraFrame.h" 5 | #include "..\SpatialMapping\SpatialMappingFrame.h" 6 | 7 | namespace HoloLensCppModules 8 | { 9 | class RayCaster 10 | { 11 | private: 12 | RayCaster() {} 13 | 14 | public: 15 | static std::shared_ptr RayCast( 16 | DirectX::SimpleMath::Vector2 pixel, 17 | std::shared_ptr locatableCameraFrame, 18 | std::shared_ptr spatialMappingFrame, 19 | Windows::Perception::Spatial::SpatialCoordinateSystem^ currentCoordinateSystem); 20 | 21 | static std::shared_ptr RayCast( 22 | DirectX::SimpleMath::Ray ray, 23 | std::shared_ptr spatialMappingFrame, 24 | Windows::Perception::Spatial::SpatialCoordinateSystem^ currentCoordinateSystem); 25 | 26 | private: 27 | static DirectX::SimpleMath::Vector3 CalculateHololensPreviewCameraDirection( 28 | DirectX::SimpleMath::Vector2 pixel, 29 | std::shared_ptr locatableCameraFrame); 30 | }; 31 | } -------------------------------------------------------------------------------- /Modules/SpatialMapping/SpatialMappingFrame.cpp: -------------------------------------------------------------------------------- 1 | #include "HoloLensCppModulesPch.h" 2 | #include "SpatialMappingFrame.h" 3 | 4 | #include "Utility.h" 5 | 6 | namespace HoloLensCppModules 7 | { 8 | SpatialMappingFrame::SpatialMappingFrame( 9 | unsigned int id, 10 | std::map> containers) 11 | : m_id(id) 12 | , m_entries(containers) 13 | { 14 | } 15 | 16 | SpatialMappingFrame::~SpatialMappingFrame() 17 | { 18 | } 19 | 20 | bool SpatialMappingFrame::HasEntry(Platform::Guid guid) 21 | { 22 | return Utility::MapContainsKey(m_entries, guid); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Modules/SpatialMapping/SpatialMappingFrame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SpatialMappingFrameEntry.h" 4 | 5 | namespace HoloLensCppModules 6 | { 7 | // It contains information from SpatialSurfaceProcessor. 8 | // It is a group since the SpatialSurfaceProcessor retrives sptial data this way. 9 | class SpatialMappingFrame 10 | { 11 | public: 12 | SpatialMappingFrame( 13 | unsigned int id, 14 | std::map> containers); 15 | ~SpatialMappingFrame(); 16 | bool HasEntry(Platform::Guid guid); 17 | unsigned int GetId() { return m_id; } 18 | std::shared_ptr GetEntry(Platform::Guid guid) { return m_entries.at(guid); } 19 | const std::map>& GetEntries() { return m_entries; } 20 | 21 | private: 22 | unsigned int m_id; 23 | std::map> m_entries; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /Modules/SpatialMapping/SpatialMappingFrameEntry.cpp: -------------------------------------------------------------------------------- 1 | #include "HoloLensCppModulesPch.h" 2 | #include "SpatialMappingFrameEntry.h" 3 | 4 | namespace HoloLensCppModules 5 | { 6 | SpatialMappingFrameEntry::SpatialMappingFrameEntry( 7 | std::vector positions, 8 | std::vector normals, 9 | std::vector indices, 10 | long long updateTime, 11 | Windows::Perception::Spatial::SpatialCoordinateSystem^ coordinateSystem, 12 | DirectX::SimpleMath::Vector3 vertexPositionScale, 13 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceInfo^ surfaceInfo) 14 | : m_positions(positions) 15 | , m_normals(normals) 16 | , m_indices(indices) 17 | , m_updateTime(updateTime) 18 | , m_coordinateSystem(coordinateSystem) 19 | , m_vertexPositionScale(vertexPositionScale) 20 | , m_surfaceInfo(surfaceInfo) 21 | { 22 | } 23 | 24 | SpatialMappingFrameEntry::~SpatialMappingFrameEntry() 25 | { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Modules/SpatialMapping/SpatialMappingFrameEntry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HoloLensCppModules 6 | { 7 | class Mesh; 8 | 9 | // This class contains the preprocessed data of a SpaitalSurface. 10 | // A list of instances of this class consists SpatialSurfaceContainerGroup. 11 | // Details of creating this class can be found in SpatialSurfaceProcessor::CreateSpatialSurfaceContainer(). 12 | class SpatialMappingFrameEntry 13 | { 14 | public: 15 | SpatialMappingFrameEntry( 16 | std::vector positions, 17 | std::vector normals, 18 | std::vector indices, 19 | long long updateTime, 20 | Windows::Perception::Spatial::SpatialCoordinateSystem^ coordinateSystem, 21 | DirectX::SimpleMath::Vector3 vertexPositionScale, 22 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceInfo^ surfaceInfo); 23 | ~SpatialMappingFrameEntry(); 24 | const std::vector& GetPositions() { return m_positions; } 25 | const std::vector& GetNormals() { return m_normals; } 26 | const std::vector& GetIndices() { return m_indices; } 27 | long long GetUpdateTime() { return m_updateTime; } 28 | Windows::Perception::Spatial::SpatialCoordinateSystem^ GetCoordinateSystem() { return m_coordinateSystem; } 29 | DirectX::SimpleMath::Vector3 GetVertexPositionScale() { return m_vertexPositionScale; } 30 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceInfo^ GetSurfaceInfo() { return m_surfaceInfo; } 31 | 32 | private: 33 | // Vertex positions of the surface. 34 | std::vector m_positions; 35 | // Normal vectors of the surface. 36 | std::vector m_normals; 37 | // Indices of surface's triangles. 38 | std::vector m_indices; 39 | long long m_updateTime; 40 | // The surface's SpatialCoordinateSystem. 41 | // Needed to obtain the model matrix. 42 | Windows::Perception::Spatial::SpatialCoordinateSystem^ m_coordinateSystem; 43 | // A scaling factor for the vertex positions. 44 | // Also needed to obtain the model matrix. 45 | // Though the existance of this may seem akward, in my (Hanseul's) opinion, 46 | // this was included by Microsoft for a memory optimizaion issue. 47 | // They use short instead of float to store vertex positions. 48 | DirectX::SimpleMath::Vector3 m_vertexPositionScale; 49 | // The instance containing other infos of the surface. 50 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceInfo^ m_surfaceInfo; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /Modules/SpatialMapping/SpatialMappingModule.cpp: -------------------------------------------------------------------------------- 1 | #include "HoloLensCppModulesPch.h" 2 | #include "SpatialMappingModule.h" 3 | 4 | #include "Utility.h" 5 | 6 | namespace HoloLensCppModules 7 | { 8 | SpatialMappingModule::SpatialMappingModule() 9 | : m_observer(ref new Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver()) 10 | , m_maxTrianglesPerCubicMeters(1000.0) 11 | , m_options(ref new Windows::Perception::Spatial::Surfaces::SpatialSurfaceMeshOptions()) 12 | , m_frameId(0) 13 | { 14 | using std::placeholders::_1; 15 | using std::placeholders::_2; 16 | using Windows::Foundation::TypedEventHandler; 17 | using Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver; 18 | 19 | m_options->IncludeVertexNormals = true; 20 | m_options->VertexPositionFormat = Windows::Graphics::DirectX::DirectXPixelFormat::R32G32B32A32Float; 21 | m_options->VertexNormalFormat = Windows::Graphics::DirectX::DirectXPixelFormat::R32G32B32A32Float; 22 | m_options->TriangleIndexFormat = Windows::Graphics::DirectX::DirectXPixelFormat::R16UInt; 23 | 24 | m_observer->ObservedSurfacesChanged += 25 | ref new TypedEventHandler( 26 | std::bind(&SpatialMappingModule::OnSurfacesChanged, this, _1, _2) 27 | ); 28 | } 29 | 30 | SpatialMappingModule::~SpatialMappingModule() 31 | { 32 | } 33 | 34 | void SpatialMappingModule::UpdateBoundingVolume( 35 | Windows::Perception::Spatial::SpatialCoordinateSystem^ currentCoordinateSystem) 36 | { 37 | using Windows::Perception::Spatial::SpatialBoundingBox; 38 | using Windows::Perception::Spatial::SpatialBoundingVolume; 39 | 40 | SpatialBoundingBox axisAlignedBoundingBox = { 41 | { 0.f, 0.f, 0.f }, 42 | { 20.f, 20.f, 5.f }, 43 | }; 44 | 45 | auto volume(SpatialBoundingVolume::FromBox(currentCoordinateSystem, axisAlignedBoundingBox)); 46 | 47 | // Keep the surface observer positioned at the device's location. 48 | m_observer->SetBoundingVolume(volume); 49 | } 50 | 51 | std::shared_ptr SpatialMappingModule::GetFrame() 52 | { 53 | std::lock_guard lock(m_propertiesLock); 54 | return m_frame; 55 | } 56 | 57 | void SpatialMappingModule::OnSurfacesChanged( 58 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver^ sender, 59 | Platform::Object^ args) 60 | { 61 | using Windows::Perception::Spatial::Surfaces::SpatialSurfaceMesh; 62 | 63 | auto observedSurfaces = sender->GetObservedSurfaces(); 64 | auto saveLatestMeshTaskGroup(concurrency::task_from_result()); 65 | 66 | m_entries.clear(); 67 | 68 | for (auto& surfaceInfoPair : observedSurfaces) 69 | { 70 | auto guid(surfaceInfoPair->Key); 71 | auto surfaceInfo(surfaceInfoPair->Value); 72 | 73 | bool duplicated = false; 74 | // If the detected mesh is found and not updated since then, reuse the processed one. 75 | if (m_frame != nullptr && m_frame->HasEntry(guid)) 76 | { 77 | auto latestUpdateTime = m_frame->GetEntry(guid)->GetUpdateTime(); 78 | auto updateTime = surfaceInfo->UpdateTime.UniversalTime; 79 | 80 | if (latestUpdateTime == updateTime) 81 | { 82 | duplicated = true; 83 | } 84 | } 85 | 86 | if (duplicated) 87 | { 88 | auto container = m_frame->GetEntry(guid); 89 | m_entries[guid] = container; 90 | } 91 | else 92 | { 93 | auto computeLatestMeshTask(concurrency::create_task(surfaceInfo->TryComputeLatestMeshAsync(m_maxTrianglesPerCubicMeters, m_options))); 94 | 95 | auto saveLatestMeshTask(computeLatestMeshTask.then([this](SpatialSurfaceMesh^ spatialSurfaceMesh) 96 | { 97 | if (spatialSurfaceMesh != nullptr) 98 | { 99 | auto guid = spatialSurfaceMesh->SurfaceInfo->Id; 100 | m_entries[guid] = CreateFrameEntry(spatialSurfaceMesh); 101 | } 102 | })); 103 | 104 | saveLatestMeshTaskGroup = saveLatestMeshTaskGroup && saveLatestMeshTask; 105 | } 106 | 107 | } 108 | 109 | saveLatestMeshTaskGroup.wait(); 110 | 111 | { 112 | std::lock_guard lock(m_propertiesLock); 113 | m_frame = std::make_shared(++m_frameId, m_entries); 114 | } 115 | } 116 | 117 | //reference: https://forums.hololens.com/discussion/2070/world-coordinates-from-meshes-vertexpositions-data 118 | std::shared_ptr SpatialMappingModule::CreateFrameEntry( 119 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceMesh^ spatialSurfaceMesh) 120 | { 121 | // Read mesh data from IBuffers and move them to a vector. 122 | auto positionPointer = Utility::ConvertIBufferToPointer(spatialSurfaceMesh->VertexPositions->Data); 123 | std::vector positions(positionPointer, positionPointer + spatialSurfaceMesh->VertexPositions->ElementCount); 124 | 125 | auto normalPointer = Utility::ConvertIBufferToPointer(spatialSurfaceMesh->VertexNormals->Data); 126 | std::vector normals(normalPointer, normalPointer + spatialSurfaceMesh->VertexNormals->ElementCount); 127 | 128 | auto indexPointer = Utility::ConvertIBufferToPointer(spatialSurfaceMesh->TriangleIndices->Data); 129 | std::vector indices(indexPointer, indexPointer + spatialSurfaceMesh->TriangleIndices->ElementCount); 130 | 131 | long long updateTime = spatialSurfaceMesh->SurfaceInfo->UpdateTime.UniversalTime; 132 | auto coordinateSystem = spatialSurfaceMesh->CoordinateSystem; 133 | auto vertexPositionScale = Utility::LoadVector3(spatialSurfaceMesh->VertexPositionScale); 134 | auto surfaceInfo = spatialSurfaceMesh->SurfaceInfo; 135 | 136 | return std::make_shared( 137 | positions, 138 | normals, 139 | indices, 140 | updateTime, 141 | coordinateSystem, 142 | vertexPositionScale, 143 | surfaceInfo); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Modules/SpatialMapping/SpatialMappingModule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "SpatialMappingFrame.h" 4 | 5 | namespace HoloLensCppModules 6 | { 7 | // Asynchronouslly obtains spatial data that is needed by HoloLens applications. 8 | class SpatialMappingModule 9 | { 10 | public: 11 | SpatialMappingModule(); 12 | ~SpatialMappingModule(); 13 | void UpdateBoundingVolume(Windows::Perception::Spatial::SpatialCoordinateSystem^ currentCoordinateSystem); 14 | std::shared_ptr GetFrame(); 15 | 16 | private: 17 | void OnSurfacesChanged( 18 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver^ sender, 19 | Platform::Object^ args); 20 | std::shared_ptr CreateFrameEntry( 21 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceMesh^ spatialSurfaceMesh); 22 | 23 | private: 24 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver^ m_observer; 25 | double m_maxTrianglesPerCubicMeters; 26 | Windows::Perception::Spatial::Surfaces::SpatialSurfaceMeshOptions^ m_options; 27 | 28 | std::shared_mutex m_propertiesLock; 29 | std::map> m_entries; 30 | std::shared_ptr m_frame; 31 | uint32 m_frameId; 32 | }; 33 | } -------------------------------------------------------------------------------- /Modules/Utility.cpp: -------------------------------------------------------------------------------- 1 | #include "HoloLensCppModulesPch.h" 2 | #include "Utility.h" 3 | 4 | #include 5 | 6 | namespace HoloLensCppModules 7 | { 8 | bool Utility::IsEmulator() 9 | { 10 | auto eas = ref new Windows::Security::ExchangeActiveSyncProvisioning::EasClientDeviceInformation; 11 | return eas->SystemProductName != L"HoloLens"; 12 | } 13 | 14 | Platform::Guid Utility::StringToGuid(Platform::String^ str) 15 | { 16 | GUID rawguid; 17 | HRESULT hr = IIDFromString(str->Data(), &rawguid); 18 | if (SUCCEEDED(hr)) 19 | { 20 | Platform::Guid guid(rawguid); 21 | return guid; 22 | } 23 | 24 | Logger::Log(L"failed to create a Guid"); 25 | throw new std::exception("failed to create Guid"); 26 | } 27 | 28 | int Utility::GetGuidHashcode(Platform::Guid guid) 29 | { 30 | return guid.GetHashCode(); 31 | } 32 | 33 | DirectX::SimpleMath::Matrix Utility::IBoxArrayToMatrix(Platform::IBoxArray^ array) 34 | { 35 | float* matrixData = reinterpret_cast(array->Value->Data); 36 | return DirectX::SimpleMath::Matrix( 37 | matrixData[0], matrixData[1], matrixData[2], matrixData[3], 38 | matrixData[4], matrixData[5], matrixData[6], matrixData[7], 39 | matrixData[8], matrixData[9], matrixData[10], matrixData[11], 40 | matrixData[12], matrixData[13], matrixData[14], matrixData[15]); 41 | } 42 | 43 | Platform::String^ Utility::Vector3ToString(DirectX::SimpleMath::Vector3 vector3) 44 | { 45 | return vector3.x + ", " + vector3.y + ", " + vector3.z; 46 | } 47 | 48 | Platform::String^ Utility::Float3ToString(Windows::Foundation::Numerics::float3 float3) 49 | { 50 | return float3.x + ", " + float3.y + ", " + float3.z; 51 | } 52 | 53 | Platform::String^ Utility::Vector4ToString(DirectX::SimpleMath::Vector4 vector4) 54 | { 55 | return vector4.x + ", " + vector4.y + ", " + vector4.z + ", " + vector4.w; 56 | } 57 | 58 | Platform::String^ Utility::MatrixToString(DirectX::SimpleMath::Matrix matrix) 59 | { 60 | Platform::String^ str = 61 | matrix.m[0][0] + ", " + matrix.m[0][1] + ", " + matrix.m[0][2] + ", " + matrix.m[0][3] + "\n" + 62 | matrix.m[1][0] + ", " + matrix.m[1][1] + ", " + matrix.m[1][2] + ", " + matrix.m[1][3] + "\n" + 63 | matrix.m[2][0] + ", " + matrix.m[2][1] + ", " + matrix.m[2][2] + ", " + matrix.m[2][3] + "\n" + 64 | matrix.m[3][0] + ", " + matrix.m[3][1] + ", " + matrix.m[3][2] + ", " + matrix.m[3][3] + "\n"; 65 | 66 | return str; 67 | } 68 | 69 | DirectX::SimpleMath::Vector3 Utility::LoadVector3(Windows::Foundation::Numerics::float3 float3) 70 | { 71 | return DirectX::SimpleMath::Vector3(DirectX::XMLoadFloat3(&float3)); 72 | } 73 | 74 | DirectX::SimpleMath::Quaternion Utility::LoadQuaternion(Windows::Foundation::Numerics::quaternion quaternion) 75 | { 76 | return DirectX::SimpleMath::Quaternion(DirectX::XMLoadQuaternion(&quaternion)); 77 | } 78 | 79 | DirectX::SimpleMath::Matrix Utility::LoadMatrix(Windows::Foundation::Numerics::float4x4 float4x4) 80 | { 81 | return DirectX::SimpleMath::Matrix(DirectX::XMLoadFloat4x4(&float4x4)); 82 | } 83 | 84 | // Assumes that w is 1. 85 | DirectX::SimpleMath::Vector3 Utility::ConvertVector4ToVector3(DirectX::SimpleMath::Vector4 vector4) 86 | { 87 | float x = vector4.x; 88 | float y = vector4.y; 89 | float z = vector4.z; 90 | float w = vector4.w; 91 | 92 | if (w != 1.0f) 93 | { 94 | Logger::Log(L"non-zero w found: " + w); 95 | } 96 | 97 | return DirectX::SimpleMath::Vector3(x, y, z); 98 | } 99 | 100 | DirectX::SimpleMath::Matrix Utility::CalculateLocatableCameraModelMatrix( 101 | Windows::Perception::Spatial::SpatialCoordinateSystem^ baseCoordinateSystem, 102 | Windows::Perception::Spatial::SpatialCoordinateSystem^ locatableCameraCoordinateSystem, 103 | DirectX::SimpleMath::Matrix locatableCameraViewMatrix) 104 | { 105 | auto cameraCoordinateSystemTransformBox(locatableCameraCoordinateSystem->TryGetTransformTo(baseCoordinateSystem)); 106 | auto cameraCoordinateSystemTransform = Utility::LoadMatrix(cameraCoordinateSystemTransformBox->Value); 107 | return locatableCameraViewMatrix.Invert() * cameraCoordinateSystemTransform; 108 | } 109 | 110 | DirectX::SimpleMath::Matrix Utility::CalculateSpatialSurfaceModelMatrix( 111 | Windows::Perception::Spatial::SpatialCoordinateSystem^ baseCoordinateSystem, 112 | Windows::Perception::Spatial::SpatialCoordinateSystem^ spatialSurfaceCoordinateSystem, 113 | DirectX::SimpleMath::Vector3 vertexPositionScale) 114 | { 115 | auto spatialSurfaceCoordinateSystemTransformBox = spatialSurfaceCoordinateSystem->TryGetTransformTo(baseCoordinateSystem); 116 | auto spatialSurfaceCoordinateSystemTransform = Utility::LoadMatrix(spatialSurfaceCoordinateSystemTransformBox->Value); 117 | 118 | return DirectX::SimpleMath::Matrix::CreateScale(vertexPositionScale) * spatialSurfaceCoordinateSystemTransform; 119 | } 120 | 121 | DirectX::SimpleMath::Matrix Utility::GetTransformWithoutTranslation(DirectX::SimpleMath::Matrix transform) 122 | { 123 | auto transformWithoutTranslation(transform); 124 | transformWithoutTranslation._41 = 0.0f; 125 | transformWithoutTranslation._42 = 0.0f; 126 | transformWithoutTranslation._43 = 0.0f; 127 | 128 | return transformWithoutTranslation; 129 | } 130 | 131 | DirectX::SimpleMath::Ray Utility::GetTransformedRay(DirectX::SimpleMath::Ray ray, DirectX::SimpleMath::Matrix transform) 132 | { 133 | using DirectX::SimpleMath::Vector3; 134 | 135 | auto position = Vector3::Transform(ray.position, transform); 136 | auto direction = Vector3::TransformNormal(ray.direction, transform); 137 | if (direction.Length() == 0) 138 | { 139 | Logger::Log(L"zero length direction"); 140 | throw std::exception("zero length direction"); 141 | } 142 | direction.Normalize(); 143 | 144 | return DirectX::SimpleMath::Ray(position, direction); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /Modules/Utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace HoloLensCppModules 7 | { 8 | // All the utility functions for AR-handwriting is here. 9 | class Utility 10 | { 11 | private: 12 | Utility() {} 13 | 14 | public: 15 | static bool IsEmulator(); 16 | static Platform::Guid StringToGuid(Platform::String^ str); 17 | static int GetGuidHashcode(Platform::Guid guid); 18 | static DirectX::SimpleMath::Matrix IBoxArrayToMatrix(Platform::IBoxArray^ array); 19 | static Platform::String^ Vector3ToString(DirectX::SimpleMath::Vector3 vector3); 20 | static Platform::String^ Float3ToString(Windows::Foundation::Numerics::float3 float3); 21 | static Platform::String^ Vector4ToString(DirectX::SimpleMath::Vector4 vector4); 22 | static Platform::String^ MatrixToString(DirectX::SimpleMath::Matrix matrix); 23 | static DirectX::SimpleMath::Vector3 LoadVector3(Windows::Foundation::Numerics::float3 float3); 24 | static DirectX::SimpleMath::Quaternion LoadQuaternion(Windows::Foundation::Numerics::quaternion quaternion); 25 | static DirectX::SimpleMath::Matrix LoadMatrix(Windows::Foundation::Numerics::float4x4 float4x4); 26 | static DirectX::SimpleMath::Vector3 ConvertVector4ToVector3(DirectX::SimpleMath::Vector4 vector4); 27 | static DirectX::SimpleMath::Matrix CalculateLocatableCameraModelMatrix( 28 | Windows::Perception::Spatial::SpatialCoordinateSystem^ baseCoordinateSystem, 29 | Windows::Perception::Spatial::SpatialCoordinateSystem^ locatableCameraCoordinateSystem, 30 | DirectX::SimpleMath::Matrix locatableCameraViewMatrix); 31 | static DirectX::SimpleMath::Matrix CalculateSpatialSurfaceModelMatrix( 32 | Windows::Perception::Spatial::SpatialCoordinateSystem^ baseCoordinateSystem, 33 | Windows::Perception::Spatial::SpatialCoordinateSystem^ spatialSurfaceCoordinateSystem, 34 | DirectX::SimpleMath::Vector3 vertexPositionScale); 35 | static DirectX::SimpleMath::Matrix GetTransformWithoutTranslation(DirectX::SimpleMath::Matrix transform); 36 | static DirectX::SimpleMath::Ray GetTransformedRay(DirectX::SimpleMath::Ray ray, DirectX::SimpleMath::Matrix transform); 37 | 38 | /* 39 | * Template functions should be implemented in a header file. 40 | */ 41 | 42 | template 43 | static void RemoveFromVector(std::vector& vector, const T& element) 44 | { 45 | vector.erase(std::remove(vector.begin(), vector.end(), element), vector.end()); 46 | } 47 | 48 | template 49 | static bool MapContainsKey(const std::map& map, K key) 50 | { 51 | return map.find(key) != map.end(); 52 | } 53 | 54 | // reference: https://github.com/Microsoft/Windows-universal-samples/blob/9e7fa281b4a4c208992ce22385ebcf57d37f9175/Samples/HolographicSpatialMapping/cpp/Content/GetDataFromIBuffer.h 55 | template 56 | static T* ConvertIBufferToPointer(Windows::Storage::Streams::IBuffer^ buffer) 57 | { 58 | using Microsoft::WRL::ComPtr; 59 | using Windows::Storage::Streams::IBufferByteAccess; 60 | 61 | if (buffer == nullptr) 62 | { 63 | return nullptr; 64 | } 65 | 66 | if (buffer->Length <= 0) 67 | { 68 | return nullptr; 69 | } 70 | 71 | ComPtr pUnknown = reinterpret_cast(buffer); 72 | ComPtr spByteAccess; 73 | if (FAILED(pUnknown.As(&spByteAccess))) 74 | { 75 | return nullptr; 76 | } 77 | 78 | byte* pRawData = nullptr; 79 | if (FAILED(spByteAccess->Buffer(&pRawData))) 80 | { 81 | return nullptr; 82 | } 83 | 84 | return reinterpret_cast(pRawData); 85 | } 86 | 87 | template 88 | static size_t GetByteSizeOfVector(const std::vector& vector) 89 | { 90 | return vector.size() * sizeof(T); 91 | } 92 | 93 | template 94 | static size_t GetByteSizeOfElement(const std::vector& vector) 95 | { 96 | return sizeof(T); 97 | } 98 | 99 | template 100 | static void CreateD3D11VertexBuffer( 101 | ID3D11Device* context, 102 | std::vector vector, 103 | Microsoft::WRL::ComPtr& buffer) 104 | { 105 | D3D11_SUBRESOURCE_DATA bufferData = { vector.data(), 0, 0 }; 106 | const CD3D11_BUFFER_DESC bufferDescription(Utility::GetByteSizeOfVector(vector), D3D11_BIND_VERTEX_BUFFER); 107 | DX::ThrowIfFailed( 108 | context->CreateBuffer( 109 | &bufferDescription, 110 | &bufferData, 111 | &buffer) 112 | ); 113 | } 114 | 115 | template 116 | static void CreateD3D11VertexBuffer( 117 | ID3D11Device* context, 118 | Windows::Storage::Streams::IBuffer^ iBuffer, 119 | Microsoft::WRL::ComPtr& buffer) 120 | { 121 | auto length = iBuffer->Length; 122 | 123 | D3D11_SUBRESOURCE_DATA bufferData = { ConvertIBufferToPointer(iBuffer), 0, 0 }; 124 | CD3D11_BUFFER_DESC bufferDescription(iBuffer->Length, D3D11_BIND_VERTEX_BUFFER); 125 | DX::ThrowIfFailed( 126 | context->CreateBuffer( 127 | &bufferDescription, 128 | &bufferData, 129 | &buffer) 130 | ); 131 | } 132 | 133 | template 134 | static void CreateD3D11IndexBuffer( 135 | ID3D11Device* context, 136 | std::vector vector, 137 | Microsoft::WRL::ComPtr& buffer) 138 | { 139 | D3D11_SUBRESOURCE_DATA bufferData = { vector.data(), 0, 0 }; 140 | const CD3D11_BUFFER_DESC bufferDescription(Utility::GetByteSizeOfVector(vector), D3D11_BIND_INDEX_BUFFER); 141 | DX::ThrowIfFailed( 142 | context->CreateBuffer( 143 | &bufferDescription, 144 | &bufferData, 145 | &buffer) 146 | ); 147 | } 148 | 149 | template 150 | static void CreateD3D11IndexBuffer( 151 | ID3D11Device* context, 152 | Windows::Storage::Streams::IBuffer^ iBuffer, 153 | Microsoft::WRL::ComPtr& buffer) 154 | { 155 | auto length = iBuffer->Length; 156 | 157 | D3D11_SUBRESOURCE_DATA bufferData = { ConvertIBufferToPointer(iBuffer), 0, 0 }; 158 | CD3D11_BUFFER_DESC bufferDescription(iBuffer->Length, D3D11_BIND_INDEX_BUFFER); 159 | DX::ThrowIfFailed( 160 | context->CreateBuffer( 161 | &bufferDescription, 162 | &bufferData, 163 | &buffer) 164 | ); 165 | } 166 | }; 167 | } -------------------------------------------------------------------------------- /Modules/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Modules/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hololens-cpp-modules 2 | 3 | Since it was difficult to find any reusable code for UWP based C++ HoloLens applications, I would like to share mine. 4 | 5 | Currently, this repository has 2 modules: LocatableCameraModule and SpatialMappingModule. 6 | 7 | Some of the codes are from https://github.com/Microsoft/Windows-universal-samples. 8 | 9 | # LocatableCameraModule 10 | 11 | This module lets you access to the HoloLens's locatable camera easily. Create it, then access it using GetFrame(). 12 | 13 | # SpatialMappingModule 14 | 15 | This module lets you access to the spatial information that your HoloLens provides. Create it, then use it by GetFrame(). 16 | 17 | # RayCaster 18 | 19 | There is also a raycaster using frames of both modules. You can use it in 2 ways. 20 | 21 | By choosing a preview camera's pixel, or by a ray in the psudo-world coordinate system. 22 | 23 | Psudo-world cooridnate system means the "currentCoordinateSystem" in SimpleMain. 24 | 25 | There are some known issues in the raycaster, for example, it crashes when HoloLens fails to find its own position. 26 | 27 | They should be removed, but I no longer have a HoloLens. Sorry. 28 | 29 | # Sample 30 | 31 | This repository, which does not have enough comments, includes a sample project to introduce you how to use the modules. 32 | 33 | Thus, I recommend you to read SampleMain.h and SampleMain.cpp before using the modules. 34 | 35 | The sample project creates the modules then leaves simple logs. 36 | 37 | # Team 38 | 39 | These codes were written while I have worked in HCIL, Seoul National University (http://hcil.snu.ac.kr) with 40 | 41 | - Youli Chang 42 | - Han Joo Chae 43 | - Jungin Hwang 44 | -------------------------------------------------------------------------------- /Sample/AppView.cpp: -------------------------------------------------------------------------------- 1 | #include "SamplePch.h" 2 | #include "AppView.h" 3 | 4 | #include 5 | 6 | // The main function is only used to initialize our IFrameworkView class. 7 | // Under most circumstances, you should not need to modify this function. 8 | [Platform::MTAThread] 9 | int main(Platform::Array^) 10 | { 11 | using HoloLensCppModules::AppViewSource; 12 | 13 | AppViewSource^ appViewSource = ref new AppViewSource(); 14 | Windows::ApplicationModel::Core::CoreApplication::Run(appViewSource); 15 | return 0; 16 | } 17 | 18 | namespace HoloLensCppModules 19 | { 20 | Windows::ApplicationModel::Core::IFrameworkView^ AppViewSource::CreateView() 21 | { 22 | return ref new AppView(); 23 | } 24 | 25 | AppView::AppView() 26 | { 27 | } 28 | 29 | 30 | // IFrameworkView methods 31 | 32 | // The first method called when the IFrameworkView is being created. 33 | // Use this method to subscribe for Windows shell events and to initialize your app. 34 | void AppView::Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView) 35 | { 36 | using Windows::ApplicationModel::SuspendingEventArgs; 37 | using Windows::ApplicationModel::Activation::IActivatedEventArgs; 38 | using Windows::ApplicationModel::Core::CoreApplication; 39 | using Windows::ApplicationModel::Core::CoreApplicationView; 40 | using Windows::Foundation::EventHandler; 41 | using Windows::Foundation::TypedEventHandler; 42 | 43 | applicationView->Activated += 44 | ref new TypedEventHandler(this, &AppView::OnViewActivated); 45 | 46 | // Register event handlers for app lifecycle. 47 | CoreApplication::Suspending += 48 | ref new EventHandler(this, &AppView::OnSuspending); 49 | 50 | CoreApplication::Resuming += 51 | ref new EventHandler(this, &AppView::OnResuming); 52 | 53 | // At this point we have access to the device and we can create device-dependent 54 | // resources. 55 | m_deviceResources = std::make_shared(); 56 | 57 | m_main = std::make_unique(m_deviceResources); 58 | } 59 | 60 | // Called when the CoreWindow object is created (or re-created). 61 | void AppView::SetWindow(Windows::UI::Core::CoreWindow^ window) 62 | { 63 | using Windows::Foundation::TypedEventHandler; 64 | using Windows::Graphics::Holographic::HolographicSpace; 65 | using Windows::UI::Core::CoreWindow; 66 | using Windows::UI::Core::CoreWindowEventArgs; 67 | using Windows::UI::Core::KeyEventArgs; 68 | using Windows::UI::Core::VisibilityChangedEventArgs; 69 | 70 | // Register for keypress notifications. 71 | window->KeyDown += 72 | ref new TypedEventHandler(this, &AppView::OnKeyPressed); 73 | 74 | // Register for notification that the app window is being closed. 75 | window->Closed += 76 | ref new TypedEventHandler(this, &AppView::OnWindowClosed); 77 | 78 | // Register for notifications that the app window is losing focus. 79 | window->VisibilityChanged += 80 | ref new TypedEventHandler(this, &AppView::OnVisibilityChanged); 81 | 82 | // Create a holographic space for the core window for the current view. 83 | // Presenting holographic frames that are created by this holographic space will put 84 | // the app into exclusive mode. 85 | m_holographicSpace = HolographicSpace::CreateForCoreWindow(window); 86 | 87 | // The DeviceResources class uses the preferred DXGI adapter ID from the holographic 88 | // space (when available) to create a Direct3D device. The HolographicSpace 89 | // uses this ID3D11Device to create and manage device-based resources such as 90 | // swap chains. 91 | m_deviceResources->SetHolographicSpace(m_holographicSpace); 92 | 93 | // The main class uses the holographic space for updates and rendering. 94 | m_main->SetHolographicSpace(m_holographicSpace); 95 | } 96 | 97 | // The Load method can be used to initialize scene resources or to load a 98 | // previously saved app state. 99 | void AppView::Load(Platform::String^ entryPoint) 100 | { 101 | } 102 | 103 | // This method is called after the window becomes active. It oversees the 104 | // update, draw, and present loop, and it also oversees window message processing. 105 | void AppView::Run() 106 | { 107 | using Windows::Graphics::Holographic::HolographicFrame; 108 | using Windows::UI::Core::CoreProcessEventsOption; 109 | using Windows::UI::Core::CoreWindow; 110 | 111 | while (!m_windowClosed) 112 | { 113 | if (m_windowVisible && (m_holographicSpace != nullptr)) 114 | { 115 | CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); 116 | 117 | HolographicFrame^ holographicFrame = m_main->Update(); 118 | 119 | if (m_main->Render(holographicFrame)) 120 | { 121 | // The holographic frame has an API that presents the swap chain for each 122 | // holographic camera. 123 | m_deviceResources->Present(holographicFrame); 124 | } 125 | } 126 | else 127 | { 128 | CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); 129 | } 130 | } 131 | } 132 | 133 | // Terminate events do not cause Uninitialize to be called. It will be called if your IFrameworkView 134 | // class is torn down while the app is in the foreground. 135 | // This method is not often used, but IFrameworkView requires it and it will be called for 136 | // holographic apps. 137 | void AppView::Uninitialize() 138 | { 139 | 140 | } 141 | 142 | 143 | // Application lifecycle event handlers 144 | 145 | // Called when the app view is activated. Activates the app's CoreWindow. 146 | void AppView::OnViewActivated(Windows::ApplicationModel::Core::CoreApplicationView^ sender, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args) 147 | { 148 | // Run() won't start until the CoreWindow is activated. 149 | sender->CoreWindow->Activate(); 150 | } 151 | 152 | void AppView::OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args) 153 | { 154 | using Windows::ApplicationModel::SuspendingDeferral; 155 | 156 | // Save app state asynchronously after requesting a deferral. Holding a deferral 157 | // indicates that the application is busy performing suspending operations. Be 158 | // aware that a deferral may not be held indefinitely; after about five seconds, 159 | // the app will be forced to exit. 160 | SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral(); 161 | 162 | Concurrency::create_task([this, deferral]() 163 | { 164 | m_deviceResources->Trim(); 165 | 166 | if (m_main != nullptr) 167 | { 168 | m_main->SaveAppState(); 169 | } 170 | 171 | // 172 | // TODO: Insert code here to save your app state. 173 | // 174 | 175 | deferral->Complete(); 176 | }); 177 | } 178 | 179 | void AppView::OnResuming(Platform::Object^ sender, Platform::Object^ args) 180 | { 181 | // Restore any data or state that was unloaded on suspend. By default, data 182 | // and state are persisted when resuming from suspend. Note that this event 183 | // does not occur if the app was previously terminated. 184 | 185 | if (m_main != nullptr) 186 | { 187 | m_main->LoadAppState(); 188 | } 189 | 190 | // 191 | // TODO: Insert code here to load your app state. 192 | // 193 | } 194 | 195 | 196 | // Window event handlers 197 | 198 | void AppView::OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args) 199 | { 200 | m_windowVisible = args->Visible; 201 | } 202 | 203 | void AppView::OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args) 204 | { 205 | m_windowClosed = true; 206 | } 207 | 208 | 209 | // Input event handlers 210 | 211 | void AppView::OnKeyPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) 212 | { 213 | // 214 | // TODO: Bluetooth keyboards are supported by HoloLens. You can use this method for 215 | // keyboard input if you want to support it as an optional input method for 216 | // your holographic app. 217 | // 218 | } 219 | } -------------------------------------------------------------------------------- /Sample/AppView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Common\DeviceResources.h" 4 | #include "SampleMain.h" 5 | 6 | namespace HoloLensCppModules 7 | { 8 | // IFrameworkView class. Connects the app with the Windows shell and handles application lifecycle events. 9 | ref class AppView sealed : public Windows::ApplicationModel::Core::IFrameworkView 10 | { 11 | public: 12 | AppView(); 13 | 14 | // IFrameworkView methods. 15 | virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView); 16 | virtual void SetWindow(Windows::UI::Core::CoreWindow^ window); 17 | virtual void Load(Platform::String^ entryPoint); 18 | virtual void Run(); 19 | virtual void Uninitialize(); 20 | 21 | protected: 22 | // Application lifecycle event handlers. 23 | void OnViewActivated(Windows::ApplicationModel::Core::CoreApplicationView^ sender, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args); 24 | void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args); 25 | void OnResuming(Platform::Object^ sender, Platform::Object^ args); 26 | 27 | // Window event handlers. 28 | void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args); 29 | void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args); 30 | 31 | // CoreWindow input event handlers. 32 | void OnKeyPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); 33 | 34 | private: 35 | std::unique_ptr m_main; 36 | 37 | std::shared_ptr m_deviceResources; 38 | bool m_windowClosed = false; 39 | bool m_windowVisible = true; 40 | 41 | // The holographic space the app will use for rendering. 42 | Windows::Graphics::Holographic::HolographicSpace^ m_holographicSpace = nullptr; 43 | }; 44 | 45 | // The entry point for the app. 46 | ref class AppViewSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource 47 | { 48 | public: 49 | virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView(); 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /Sample/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanseuljun/hololens-cpp-modules/06c5087303347e16464aebcaa7a473476001ca24/Sample/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /Sample/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanseuljun/hololens-cpp-modules/06c5087303347e16464aebcaa7a473476001ca24/Sample/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Sample/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanseuljun/hololens-cpp-modules/06c5087303347e16464aebcaa7a473476001ca24/Sample/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /Sample/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanseuljun/hololens-cpp-modules/06c5087303347e16464aebcaa7a473476001ca24/Sample/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /Sample/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanseuljun/hololens-cpp-modules/06c5087303347e16464aebcaa7a473476001ca24/Sample/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /Sample/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanseuljun/hololens-cpp-modules/06c5087303347e16464aebcaa7a473476001ca24/Sample/Assets/StoreLogo.png -------------------------------------------------------------------------------- /Sample/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanseuljun/hololens-cpp-modules/06c5087303347e16464aebcaa7a473476001ca24/Sample/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /Sample/Common/CameraResources.cpp: -------------------------------------------------------------------------------- 1 | #include "SamplePch.h" 2 | 3 | #include "CameraResources.h" 4 | #include "Common\DirectXHelper.h" 5 | #include "DeviceResources.h" 6 | #include 7 | 8 | using namespace DirectX; 9 | using namespace Microsoft::WRL; 10 | using namespace Windows::Graphics::DirectX::Direct3D11; 11 | using namespace Windows::Graphics::Holographic; 12 | using namespace Windows::Perception::Spatial; 13 | 14 | DX::CameraResources::CameraResources(HolographicCamera^ camera) : 15 | m_holographicCamera(camera), 16 | m_isStereo(camera->IsStereo), 17 | m_d3dRenderTargetSize(camera->RenderTargetSize) 18 | { 19 | m_d3dViewport = CD3D11_VIEWPORT( 20 | 0.f, 0.f, 21 | m_d3dRenderTargetSize.Width, 22 | m_d3dRenderTargetSize.Height 23 | ); 24 | }; 25 | 26 | // Updates resources associated with a holographic camera's swap chain. 27 | // The app does not access the swap chain directly, but it does create 28 | // resource views for the back buffer. 29 | void DX::CameraResources::CreateResourcesForBackBuffer( 30 | DX::DeviceResources* pDeviceResources, 31 | HolographicCameraRenderingParameters^ cameraParameters 32 | ) 33 | { 34 | const auto device = pDeviceResources->GetD3DDevice(); 35 | 36 | // Get the WinRT object representing the holographic camera's back buffer. 37 | IDirect3DSurface^ surface = cameraParameters->Direct3D11BackBuffer; 38 | 39 | // Get a DXGI interface for the holographic camera's back buffer. 40 | // Holographic cameras do not provide the DXGI swap chain, which is owned 41 | // by the system. The Direct3D back buffer resource is provided using WinRT 42 | // interop APIs. 43 | ComPtr resource; 44 | ThrowIfFailed( 45 | GetDXGIInterfaceFromObject(surface, IID_PPV_ARGS(&resource)) 46 | ); 47 | 48 | // Get a Direct3D interface for the holographic camera's back buffer. 49 | ComPtr cameraBackBuffer; 50 | ThrowIfFailed( 51 | resource.As(&cameraBackBuffer) 52 | ); 53 | 54 | // Determine if the back buffer has changed. If so, ensure that the render target view 55 | // is for the current back buffer. 56 | if (m_d3dBackBuffer.Get() != cameraBackBuffer.Get()) 57 | { 58 | // This can change every frame as the system moves to the next buffer in the 59 | // swap chain. This mode of operation will occur when certain rendering modes 60 | // are activated. 61 | m_d3dBackBuffer = cameraBackBuffer; 62 | 63 | // Create a render target view of the back buffer. 64 | // Creating this resource is inexpensive, and is better than keeping track of 65 | // the back buffers in order to pre-allocate render target views for each one. 66 | DX::ThrowIfFailed( 67 | device->CreateRenderTargetView( 68 | m_d3dBackBuffer.Get(), 69 | nullptr, 70 | &m_d3dRenderTargetView 71 | ) 72 | ); 73 | 74 | // Get the DXGI format for the back buffer. 75 | // This information can be accessed by the app using CameraResources::GetBackBufferDXGIFormat(). 76 | D3D11_TEXTURE2D_DESC backBufferDesc; 77 | m_d3dBackBuffer->GetDesc(&backBufferDesc); 78 | m_dxgiFormat = backBufferDesc.Format; 79 | 80 | // Check for render target size changes. 81 | Windows::Foundation::Size currentSize = m_holographicCamera->RenderTargetSize; 82 | if (m_d3dRenderTargetSize != currentSize) 83 | { 84 | // Set render target size. 85 | m_d3dRenderTargetSize = currentSize; 86 | 87 | // A new depth stencil view is also needed. 88 | m_d3dDepthStencilView.Reset(); 89 | } 90 | } 91 | 92 | // Refresh depth stencil resources, if needed. 93 | if (m_d3dDepthStencilView == nullptr) 94 | { 95 | // Create a depth stencil view for use with 3D rendering if needed. 96 | CD3D11_TEXTURE2D_DESC depthStencilDesc( 97 | DXGI_FORMAT_D16_UNORM, 98 | static_cast(m_d3dRenderTargetSize.Width), 99 | static_cast(m_d3dRenderTargetSize.Height), 100 | m_isStereo ? 2 : 1, // Create two textures when rendering in stereo. 101 | 1, // Use a single mipmap level. 102 | D3D11_BIND_DEPTH_STENCIL 103 | ); 104 | 105 | ComPtr depthStencil; 106 | DX::ThrowIfFailed( 107 | device->CreateTexture2D( 108 | &depthStencilDesc, 109 | nullptr, 110 | &depthStencil 111 | ) 112 | ); 113 | 114 | CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc( 115 | m_isStereo ? D3D11_DSV_DIMENSION_TEXTURE2DARRAY : D3D11_DSV_DIMENSION_TEXTURE2D 116 | ); 117 | DX::ThrowIfFailed( 118 | device->CreateDepthStencilView( 119 | depthStencil.Get(), 120 | &depthStencilViewDesc, 121 | &m_d3dDepthStencilView 122 | ) 123 | ); 124 | } 125 | 126 | // Create the constant buffer, if needed. 127 | if (m_viewProjectionConstantBuffer == nullptr) 128 | { 129 | // Create a constant buffer to store view and projection matrices for the camera. 130 | CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER); 131 | DX::ThrowIfFailed( 132 | device->CreateBuffer( 133 | &constantBufferDesc, 134 | nullptr, 135 | &m_viewProjectionConstantBuffer 136 | ) 137 | ); 138 | } 139 | } 140 | 141 | // Releases resources associated with a back buffer. 142 | void DX::CameraResources::ReleaseResourcesForBackBuffer(DX::DeviceResources* pDeviceResources) 143 | { 144 | const auto context = pDeviceResources->GetD3DDeviceContext(); 145 | 146 | // Release camera-specific resources. 147 | m_d3dBackBuffer.Reset(); 148 | m_d3dRenderTargetView.Reset(); 149 | m_d3dDepthStencilView.Reset(); 150 | m_viewProjectionConstantBuffer.Reset(); 151 | 152 | // Ensure system references to the back buffer are released by clearing the render 153 | // target from the graphics pipeline state, and then flushing the Direct3D context. 154 | ID3D11RenderTargetView* nullViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { nullptr }; 155 | context->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr); 156 | context->Flush(); 157 | } 158 | 159 | // Updates the view/projection constant buffer for a holographic camera. 160 | void DX::CameraResources::UpdateViewProjectionBuffer( 161 | std::shared_ptr deviceResources, 162 | HolographicCameraPose^ cameraPose, 163 | SpatialCoordinateSystem^ coordinateSystem 164 | ) 165 | { 166 | // The system changes the viewport on a per-frame basis for system optimizations. 167 | m_d3dViewport = CD3D11_VIEWPORT( 168 | cameraPose->Viewport.Left, 169 | cameraPose->Viewport.Top, 170 | cameraPose->Viewport.Width, 171 | cameraPose->Viewport.Height 172 | ); 173 | 174 | // The projection transform for each frame is provided by the HolographicCameraPose. 175 | HolographicStereoTransform cameraProjectionTransform = cameraPose->ProjectionTransform; 176 | 177 | // Get a container object with the view and projection matrices for the given 178 | // pose in the given coordinate system. 179 | Platform::IBox^ viewTransformContainer = cameraPose->TryGetViewTransform(coordinateSystem); 180 | 181 | // If TryGetViewTransform returns a null pointer, that means the pose and coordinate 182 | // system cannot be understood relative to one another; content cannot be rendered 183 | // in this coordinate system for the duration of the current frame. 184 | // This usually means that positional tracking is not active for the current frame, in 185 | // which case it is possible to use a SpatialLocatorAttachedFrameOfReference to render 186 | // content that is not world-locked instead. 187 | DX::ViewProjectionConstantBuffer viewProjectionConstantBufferData; 188 | bool viewTransformAcquired = viewTransformContainer != nullptr; 189 | if (viewTransformAcquired) 190 | { 191 | // Otherwise, the set of view transforms can be retrieved. 192 | HolographicStereoTransform viewCoordinateSystemTransform = viewTransformContainer->Value; 193 | 194 | // Update the view matrices. Holographic cameras (such as Microsoft HoloLens) are 195 | // constantly moving relative to the world. The view matrices need to be updated 196 | // every frame. 197 | XMStoreFloat4x4( 198 | &viewProjectionConstantBufferData.viewProjection[0], 199 | XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Left) * XMLoadFloat4x4(&cameraProjectionTransform.Left)) 200 | ); 201 | XMStoreFloat4x4( 202 | &viewProjectionConstantBufferData.viewProjection[1], 203 | XMMatrixTranspose(XMLoadFloat4x4(&viewCoordinateSystemTransform.Right) * XMLoadFloat4x4(&cameraProjectionTransform.Right)) 204 | ); 205 | } 206 | 207 | // Use the D3D device context to update Direct3D device-based resources. 208 | const auto context = deviceResources->GetD3DDeviceContext(); 209 | 210 | // Loading is asynchronous. Resources must be created before they can be updated. 211 | if (context == nullptr || m_viewProjectionConstantBuffer == nullptr || !viewTransformAcquired) 212 | { 213 | m_framePending = false; 214 | } 215 | else 216 | { 217 | // Update the view and projection matrices. 218 | context->UpdateSubresource( 219 | m_viewProjectionConstantBuffer.Get(), 220 | 0, 221 | nullptr, 222 | &viewProjectionConstantBufferData, 223 | 0, 224 | 0 225 | ); 226 | 227 | m_framePending = true; 228 | } 229 | } 230 | 231 | // Gets the view-projection constant buffer for the HolographicCamera and attaches it 232 | // to the shader pipeline. 233 | bool DX::CameraResources::AttachViewProjectionBuffer( 234 | std::shared_ptr deviceResources 235 | ) 236 | { 237 | // This method uses Direct3D device-based resources. 238 | const auto context = deviceResources->GetD3DDeviceContext(); 239 | 240 | // Loading is asynchronous. Resources must be created before they can be updated. 241 | // Cameras can also be added asynchronously, in which case they must be initialized 242 | // before they can be used. 243 | if (context == nullptr || m_viewProjectionConstantBuffer == nullptr || m_framePending == false) 244 | { 245 | return false; 246 | } 247 | 248 | // Set the viewport for this camera. 249 | context->RSSetViewports(1, &m_d3dViewport); 250 | 251 | // Send the constant buffer to the vertex shader. 252 | context->VSSetConstantBuffers( 253 | 1, 254 | 1, 255 | m_viewProjectionConstantBuffer.GetAddressOf() 256 | ); 257 | 258 | // The template includes a pass-through geometry shader that is used by 259 | // default on systems that don't support the D3D11_FEATURE_D3D11_OPTIONS3:: 260 | // VPAndRTArrayIndexFromAnyShaderFeedingRasterizer extension. The shader 261 | // will be enabled at run-time on systems that require it. 262 | // If your app will also use the geometry shader for other tasks and those 263 | // tasks require the view/projection matrix, uncomment the following line 264 | // of code to send the constant buffer to the geometry shader as well. 265 | /*context->GSSetConstantBuffers( 266 | 1, 267 | 1, 268 | m_viewProjectionConstantBuffer.GetAddressOf() 269 | );*/ 270 | 271 | m_framePending = false; 272 | 273 | return true; 274 | } 275 | -------------------------------------------------------------------------------- /Sample/Common/CameraResources.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace DX 4 | { 5 | class DeviceResources; 6 | 7 | // Constant buffer used to send the view-projection matrices to the shader pipeline. 8 | struct ViewProjectionConstantBuffer 9 | { 10 | DirectX::XMFLOAT4X4 viewProjection[2]; 11 | }; 12 | 13 | // Assert that the constant buffer remains 16-byte aligned (best practice). 14 | static_assert((sizeof(ViewProjectionConstantBuffer) % (sizeof(float) * 4)) == 0, "ViewProjection constant buffer size must be 16-byte aligned (16 bytes is the length of four floats)."); 15 | 16 | // Manages DirectX device resources that are specific to a holographic camera, such as the 17 | // back buffer, ViewProjection constant buffer, and viewport. 18 | class CameraResources 19 | { 20 | public: 21 | CameraResources(Windows::Graphics::Holographic::HolographicCamera^ holographicCamera); 22 | 23 | void CreateResourcesForBackBuffer( 24 | DX::DeviceResources* pDeviceResources, 25 | Windows::Graphics::Holographic::HolographicCameraRenderingParameters^ cameraParameters 26 | ); 27 | void ReleaseResourcesForBackBuffer( 28 | DX::DeviceResources* pDeviceResources 29 | ); 30 | 31 | void UpdateViewProjectionBuffer( 32 | std::shared_ptr deviceResources, 33 | Windows::Graphics::Holographic::HolographicCameraPose^ cameraPose, 34 | Windows::Perception::Spatial::SpatialCoordinateSystem^ coordinateSystem); 35 | 36 | bool AttachViewProjectionBuffer( 37 | std::shared_ptr deviceResources); 38 | 39 | // Direct3D device resources. 40 | ID3D11RenderTargetView* GetBackBufferRenderTargetView() const { return m_d3dRenderTargetView.Get(); } 41 | ID3D11DepthStencilView* GetDepthStencilView() const { return m_d3dDepthStencilView.Get(); } 42 | ID3D11Texture2D* GetBackBufferTexture2D() const { return m_d3dBackBuffer.Get(); } 43 | D3D11_VIEWPORT GetViewport() const { return m_d3dViewport; } 44 | DXGI_FORMAT GetBackBufferDXGIFormat() const { return m_dxgiFormat; } 45 | 46 | // Render target properties. 47 | Windows::Foundation::Size GetRenderTargetSize() const { return m_d3dRenderTargetSize; } 48 | bool IsRenderingStereoscopic() const { return m_isStereo; } 49 | 50 | // The holographic camera these resources are for. 51 | Windows::Graphics::Holographic::HolographicCamera^ GetHolographicCamera() const { return m_holographicCamera; } 52 | 53 | private: 54 | // Direct3D rendering objects. Required for 3D. 55 | Microsoft::WRL::ComPtr m_d3dRenderTargetView; 56 | Microsoft::WRL::ComPtr m_d3dDepthStencilView; 57 | Microsoft::WRL::ComPtr m_d3dBackBuffer; 58 | 59 | // Device resource to store view and projection matrices. 60 | Microsoft::WRL::ComPtr m_viewProjectionConstantBuffer; 61 | 62 | // Direct3D rendering properties. 63 | DXGI_FORMAT m_dxgiFormat; 64 | Windows::Foundation::Size m_d3dRenderTargetSize; 65 | D3D11_VIEWPORT m_d3dViewport; 66 | 67 | // Indicates whether the camera supports stereoscopic rendering. 68 | bool m_isStereo = false; 69 | 70 | // Indicates whether this camera has a pending frame. 71 | bool m_framePending = false; 72 | 73 | // Pointer to the holographic camera these resources are for. 74 | Windows::Graphics::Holographic::HolographicCamera^ m_holographicCamera = nullptr; 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /Sample/Common/DeviceResources.cpp: -------------------------------------------------------------------------------- 1 | #include "SamplePch.h" 2 | #include "DeviceResources.h" 3 | #include "DirectXHelper.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace D2D1; 9 | using namespace Microsoft::WRL; 10 | using namespace Windows::Graphics::DirectX::Direct3D11; 11 | using namespace Windows::Graphics::Display; 12 | using namespace Windows::Graphics::Holographic; 13 | 14 | // Constructor for DeviceResources. 15 | DX::DeviceResources::DeviceResources() 16 | { 17 | CreateDeviceIndependentResources(); 18 | } 19 | 20 | // Configures resources that don't depend on the Direct3D device. 21 | void DX::DeviceResources::CreateDeviceIndependentResources() 22 | { 23 | // Initialize Direct2D resources. 24 | D2D1_FACTORY_OPTIONS options {}; 25 | 26 | #if defined(_DEBUG) 27 | // If the project is in a debug build, enable Direct2D debugging via SDK Layers. 28 | options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; 29 | #endif 30 | 31 | // Initialize the Direct2D Factory. 32 | DX::ThrowIfFailed( 33 | D2D1CreateFactory( 34 | D2D1_FACTORY_TYPE_SINGLE_THREADED, 35 | __uuidof(ID2D1Factory2), 36 | &options, 37 | &m_d2dFactory 38 | ) 39 | ); 40 | 41 | // Initialize the DirectWrite Factory. 42 | DX::ThrowIfFailed( 43 | DWriteCreateFactory( 44 | DWRITE_FACTORY_TYPE_SHARED, 45 | __uuidof(IDWriteFactory2), 46 | &m_dwriteFactory 47 | ) 48 | ); 49 | 50 | // Initialize the Windows Imaging Component (WIC) Factory. 51 | DX::ThrowIfFailed( 52 | CoCreateInstance( 53 | CLSID_WICImagingFactory2, 54 | nullptr, 55 | CLSCTX_INPROC_SERVER, 56 | IID_PPV_ARGS(&m_wicFactory) 57 | ) 58 | ); 59 | } 60 | 61 | void DX::DeviceResources::SetHolographicSpace(HolographicSpace^ holographicSpace) 62 | { 63 | // Cache the holographic space. Used to re-initalize during device-lost scenarios. 64 | m_holographicSpace = holographicSpace; 65 | 66 | InitializeUsingHolographicSpace(); 67 | } 68 | 69 | void DX::DeviceResources::InitializeUsingHolographicSpace() 70 | { 71 | // The holographic space might need to determine which adapter supports 72 | // holograms, in which case it will specify a non-zero PrimaryAdapterId. 73 | LUID id = 74 | { 75 | m_holographicSpace->PrimaryAdapterId.LowPart, 76 | m_holographicSpace->PrimaryAdapterId.HighPart 77 | }; 78 | 79 | // When a primary adapter ID is given to the app, the app should find 80 | // the corresponding DXGI adapter and use it to create Direct3D devices 81 | // and device contexts. Otherwise, there is no restriction on the DXGI 82 | // adapter the app can use. 83 | if ((id.HighPart != 0) && (id.LowPart != 0)) 84 | { 85 | UINT createFlags = 0; 86 | #ifdef DEBUG 87 | if (DX::SdkLayersAvailable()) 88 | { 89 | createFlags |= DXGI_CREATE_FACTORY_DEBUG; 90 | } 91 | #endif 92 | // Create the DXGI factory. 93 | ComPtr dxgiFactory; 94 | DX::ThrowIfFailed( 95 | CreateDXGIFactory2( 96 | createFlags, 97 | IID_PPV_ARGS(&dxgiFactory) 98 | ) 99 | ); 100 | ComPtr dxgiFactory4; 101 | DX::ThrowIfFailed(dxgiFactory.As(&dxgiFactory4)); 102 | 103 | // Retrieve the adapter specified by the holographic space. 104 | DX::ThrowIfFailed( 105 | dxgiFactory4->EnumAdapterByLuid( 106 | id, 107 | IID_PPV_ARGS(&m_dxgiAdapter) 108 | ) 109 | ); 110 | } 111 | else 112 | { 113 | m_dxgiAdapter.Reset(); 114 | } 115 | 116 | CreateDeviceResources(); 117 | 118 | m_holographicSpace->SetDirect3D11Device(m_d3dInteropDevice); 119 | } 120 | 121 | // Configures the Direct3D device, and stores handles to it and the device context. 122 | void DX::DeviceResources::CreateDeviceResources() 123 | { 124 | // This flag adds support for surfaces with a different color channel ordering 125 | // than the API default. It is required for compatibility with Direct2D. 126 | UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; 127 | 128 | #if defined(_DEBUG) 129 | if (DX::SdkLayersAvailable()) 130 | { 131 | // If the project is in a debug build, enable debugging via SDK Layers with this flag. 132 | creationFlags |= D3D11_CREATE_DEVICE_DEBUG; 133 | } 134 | #endif 135 | 136 | // This array defines the set of DirectX hardware feature levels this app will support. 137 | // Note the ordering should be preserved. 138 | // Note that HoloLens supports feature level 11.1. The HoloLens emulator is also capable 139 | // of running on graphics cards starting with feature level 10.0. 140 | D3D_FEATURE_LEVEL featureLevels [] = 141 | { 142 | D3D_FEATURE_LEVEL_12_1, 143 | D3D_FEATURE_LEVEL_12_0, 144 | D3D_FEATURE_LEVEL_11_1, 145 | D3D_FEATURE_LEVEL_11_0, 146 | D3D_FEATURE_LEVEL_10_1, 147 | D3D_FEATURE_LEVEL_10_0 148 | }; 149 | 150 | // Create the Direct3D 11 API device object and a corresponding context. 151 | ComPtr device; 152 | ComPtr context; 153 | 154 | const HRESULT hr = D3D11CreateDevice( 155 | m_dxgiAdapter.Get(), // Either nullptr, or the primary adapter determined by Windows Holographic. 156 | D3D_DRIVER_TYPE_HARDWARE, // Create a device using the hardware graphics driver. 157 | 0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE. 158 | creationFlags, // Set debug and Direct2D compatibility flags. 159 | featureLevels, // List of feature levels this app can support. 160 | ARRAYSIZE(featureLevels), // Size of the list above. 161 | D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. 162 | &device, // Returns the Direct3D device created. 163 | &m_d3dFeatureLevel, // Returns feature level of device created. 164 | &context // Returns the device immediate context. 165 | ); 166 | 167 | if (FAILED(hr)) 168 | { 169 | // If the initialization fails, fall back to the WARP device. 170 | // For more information on WARP, see: 171 | // http://go.microsoft.com/fwlink/?LinkId=286690 172 | DX::ThrowIfFailed( 173 | D3D11CreateDevice( 174 | nullptr, // Use the default DXGI adapter for WARP. 175 | D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device. 176 | 0, 177 | creationFlags, 178 | featureLevels, 179 | ARRAYSIZE(featureLevels), 180 | D3D11_SDK_VERSION, 181 | &device, 182 | &m_d3dFeatureLevel, 183 | &context 184 | ) 185 | ); 186 | } 187 | 188 | // Store pointers to the Direct3D device and immediate context. 189 | DX::ThrowIfFailed( 190 | device.As(&m_d3dDevice) 191 | ); 192 | 193 | DX::ThrowIfFailed( 194 | context.As(&m_d3dContext) 195 | ); 196 | 197 | // Acquire the DXGI interface for the Direct3D device. 198 | ComPtr dxgiDevice; 199 | DX::ThrowIfFailed( 200 | m_d3dDevice.As(&dxgiDevice) 201 | ); 202 | 203 | // Wrap the native device using a WinRT interop object. 204 | m_d3dInteropDevice = CreateDirect3DDevice(dxgiDevice.Get()); 205 | 206 | // Cache the DXGI adapter. 207 | // This is for the case of no preferred DXGI adapter, or fallback to WARP. 208 | ComPtr dxgiAdapter; 209 | DX::ThrowIfFailed( 210 | dxgiDevice->GetAdapter(&dxgiAdapter) 211 | ); 212 | DX::ThrowIfFailed( 213 | dxgiAdapter.As(&m_dxgiAdapter) 214 | ); 215 | 216 | // Check for device support for the optional feature that allows setting the render target array index from the vertex shader stage. 217 | D3D11_FEATURE_DATA_D3D11_OPTIONS3 options; 218 | m_d3dDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS3, &options, sizeof(options)); 219 | if (options.VPAndRTArrayIndexFromAnyShaderFeedingRasterizer) 220 | { 221 | m_supportsVprt = true; 222 | } 223 | } 224 | 225 | // Validates the back buffer for each HolographicCamera and recreates 226 | // resources for back buffers that have changed. 227 | // Locks the set of holographic camera resources until the function exits. 228 | void DX::DeviceResources::EnsureCameraResources( 229 | HolographicFrame^ frame, 230 | HolographicFramePrediction^ prediction) 231 | { 232 | UseHolographicCameraResources([this, frame, prediction](std::map>& cameraResourceMap) 233 | { 234 | for (HolographicCameraPose^ pose : prediction->CameraPoses) 235 | { 236 | HolographicCameraRenderingParameters^ renderingParameters = frame->GetRenderingParameters(pose); 237 | CameraResources* pCameraResources = cameraResourceMap[pose->HolographicCamera->Id].get(); 238 | 239 | pCameraResources->CreateResourcesForBackBuffer(this, renderingParameters); 240 | } 241 | }); 242 | } 243 | 244 | // Prepares to allocate resources and adds resource views for a camera. 245 | // Locks the set of holographic camera resources until the function exits. 246 | void DX::DeviceResources::AddHolographicCamera(HolographicCamera^ camera) 247 | { 248 | UseHolographicCameraResources([this, camera](std::map>& cameraResourceMap) 249 | { 250 | cameraResourceMap[camera->Id] = std::make_unique(camera); 251 | }); 252 | } 253 | 254 | // Deallocates resources for a camera and removes the camera from the set. 255 | // Locks the set of holographic camera resources until the function exits. 256 | void DX::DeviceResources::RemoveHolographicCamera(HolographicCamera^ camera) 257 | { 258 | UseHolographicCameraResources([this, camera](std::map>& cameraResourceMap) 259 | { 260 | CameraResources* pCameraResources = cameraResourceMap[camera->Id].get(); 261 | 262 | if (pCameraResources != nullptr) 263 | { 264 | pCameraResources->ReleaseResourcesForBackBuffer(this); 265 | cameraResourceMap.erase(camera->Id); 266 | } 267 | }); 268 | } 269 | 270 | // Recreate all device resources and set them back to the current state. 271 | // Locks the set of holographic camera resources until the function exits. 272 | void DX::DeviceResources::HandleDeviceLost() 273 | { 274 | if (m_deviceNotify != nullptr) 275 | { 276 | m_deviceNotify->OnDeviceLost(); 277 | } 278 | 279 | UseHolographicCameraResources([this](std::map>& cameraResourceMap) 280 | { 281 | for (auto& pair : cameraResourceMap) 282 | { 283 | CameraResources* pCameraResources = pair.second.get(); 284 | pCameraResources->ReleaseResourcesForBackBuffer(this); 285 | } 286 | }); 287 | 288 | InitializeUsingHolographicSpace(); 289 | 290 | if (m_deviceNotify != nullptr) 291 | { 292 | m_deviceNotify->OnDeviceRestored(); 293 | } 294 | } 295 | 296 | // Register our DeviceNotify to be informed on device lost and creation. 297 | void DX::DeviceResources::RegisterDeviceNotify(DX::IDeviceNotify* deviceNotify) 298 | { 299 | m_deviceNotify = deviceNotify; 300 | } 301 | 302 | // Call this method when the app suspends. It provides a hint to the driver that the app 303 | // is entering an idle state and that temporary buffers can be reclaimed for use by other apps. 304 | void DX::DeviceResources::Trim() 305 | { 306 | m_d3dContext->ClearState(); 307 | 308 | ComPtr dxgiDevice; 309 | DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice)); 310 | dxgiDevice->Trim(); 311 | } 312 | 313 | // Present the contents of the swap chain to the screen. 314 | // Locks the set of holographic camera resources until the function exits. 315 | void DX::DeviceResources::Present(HolographicFrame^ frame) 316 | { 317 | // By default, this API waits for the frame to finish before it returns. 318 | // Holographic apps should wait for the previous frame to finish before 319 | // starting work on a new frame. This allows for better results from 320 | // holographic frame predictions. 321 | HolographicFramePresentResult presentResult = frame->PresentUsingCurrentPrediction(); 322 | 323 | HolographicFramePrediction^ prediction = frame->CurrentPrediction; 324 | UseHolographicCameraResources([this, prediction](std::map>& cameraResourceMap) 325 | { 326 | for (auto cameraPose : prediction->CameraPoses) 327 | { 328 | // This represents the device-based resources for a HolographicCamera. 329 | DX::CameraResources* pCameraResources = cameraResourceMap[cameraPose->HolographicCamera->Id].get(); 330 | 331 | // Discard the contents of the render target. 332 | // This is a valid operation only when the existing contents will be 333 | // entirely overwritten. If dirty or scroll rects are used, this call 334 | // should be removed. 335 | m_d3dContext->DiscardView(pCameraResources->GetBackBufferRenderTargetView()); 336 | 337 | // Discard the contents of the depth stencil. 338 | m_d3dContext->DiscardView(pCameraResources->GetDepthStencilView()); 339 | } 340 | }); 341 | 342 | // The PresentUsingCurrentPrediction API will detect when the graphics device 343 | // changes or becomes invalid. When this happens, it is considered a Direct3D 344 | // device lost scenario. 345 | if (presentResult == HolographicFramePresentResult::DeviceRemoved) 346 | { 347 | // The Direct3D device, context, and resources should be recreated. 348 | HandleDeviceLost(); 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /Sample/Common/DeviceResources.h: -------------------------------------------------------------------------------- 1 |  2 | #pragma once 3 | 4 | #include "CameraResources.h" 5 | 6 | namespace DX 7 | { 8 | // Provides an interface for an application that owns DeviceResources to be notified of the device being lost or created. 9 | interface IDeviceNotify 10 | { 11 | virtual void OnDeviceLost() = 0; 12 | virtual void OnDeviceRestored() = 0; 13 | }; 14 | 15 | // Creates and manages a Direct3D device and immediate context, Direct2D device and context (for debug), and the holographic swap chain. 16 | class DeviceResources 17 | { 18 | public: 19 | DeviceResources(); 20 | 21 | // Public methods related to Direct3D devices. 22 | void HandleDeviceLost(); 23 | void RegisterDeviceNotify(IDeviceNotify* deviceNotify); 24 | void Trim(); 25 | void Present(Windows::Graphics::Holographic::HolographicFrame^ frame); 26 | 27 | // Public methods related to holographic devices. 28 | void SetHolographicSpace(Windows::Graphics::Holographic::HolographicSpace^ space); 29 | void EnsureCameraResources( 30 | Windows::Graphics::Holographic::HolographicFrame^ frame, 31 | Windows::Graphics::Holographic::HolographicFramePrediction^ prediction); 32 | 33 | void AddHolographicCamera(Windows::Graphics::Holographic::HolographicCamera^ camera); 34 | void RemoveHolographicCamera(Windows::Graphics::Holographic::HolographicCamera^ camera); 35 | 36 | // Holographic accessors. 37 | template 38 | RetType UseHolographicCameraResources(const LCallback& callback); 39 | 40 | Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice^ 41 | GetD3DInteropDevice() const { return m_d3dInteropDevice; } 42 | 43 | // D3D accessors. 44 | ID3D11Device4* GetD3DDevice() const { return m_d3dDevice.Get(); } 45 | ID3D11DeviceContext3* GetD3DDeviceContext() const { return m_d3dContext.Get(); } 46 | D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; } 47 | bool GetDeviceSupportsVprt() const { return m_supportsVprt; } 48 | 49 | // DXGI acessors. 50 | IDXGIAdapter3* GetDXGIAdapter() const { return m_dxgiAdapter.Get(); } 51 | 52 | // D2D accessors. 53 | ID2D1Factory2* GetD2DFactory() const { return m_d2dFactory.Get(); } 54 | IDWriteFactory2* GetDWriteFactory() const { return m_dwriteFactory.Get(); } 55 | IWICImagingFactory2* GetWicImagingFactory() const { return m_wicFactory.Get(); } 56 | 57 | private: 58 | // Private methods related to the Direct3D device, and resources based on that device. 59 | void CreateDeviceIndependentResources(); 60 | void InitializeUsingHolographicSpace(); 61 | void CreateDeviceResources(); 62 | 63 | // Direct3D objects. 64 | Microsoft::WRL::ComPtr m_d3dDevice; 65 | Microsoft::WRL::ComPtr m_d3dContext; 66 | Microsoft::WRL::ComPtr m_dxgiAdapter; 67 | 68 | // Direct3D interop objects. 69 | Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice^ m_d3dInteropDevice; 70 | 71 | // Direct2D factories. 72 | Microsoft::WRL::ComPtr m_d2dFactory; 73 | Microsoft::WRL::ComPtr m_dwriteFactory; 74 | Microsoft::WRL::ComPtr m_wicFactory; 75 | 76 | // The holographic space provides a preferred DXGI adapter ID. 77 | Windows::Graphics::Holographic::HolographicSpace^ m_holographicSpace = nullptr; 78 | 79 | // Properties of the Direct3D device currently in use. 80 | D3D_FEATURE_LEVEL m_d3dFeatureLevel = D3D_FEATURE_LEVEL_10_0; 81 | 82 | // The IDeviceNotify can be held directly as it owns the DeviceResources. 83 | IDeviceNotify* m_deviceNotify = nullptr; 84 | 85 | // Whether or not the current Direct3D device supports the optional feature 86 | // for setting the render target array index from the vertex shader stage. 87 | bool m_supportsVprt = false; 88 | 89 | // Back buffer resources, etc. for attached holographic cameras. 90 | std::map> m_cameraResources; 91 | std::mutex m_cameraResourcesLock; 92 | }; 93 | } 94 | 95 | // Device-based resources for holographic cameras are stored in a std::map. Access this list by providing a 96 | // callback to this function, and the std::map will be guarded from add and remove 97 | // events until the callback returns. The callback is processed immediately and must 98 | // not contain any nested calls to UseHolographicCameraResources. 99 | // The callback takes a parameter of type std::map>& 100 | // through which the list of cameras will be accessed. 101 | template 102 | RetType DX::DeviceResources::UseHolographicCameraResources(const LCallback& callback) 103 | { 104 | std::lock_guard guard(m_cameraResourcesLock); 105 | return callback(m_cameraResources); 106 | } 107 | 108 | -------------------------------------------------------------------------------- /Sample/Common/DirectXHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // For create_task 4 | 5 | namespace DX 6 | { 7 | inline void ThrowIfFailed(HRESULT hr) 8 | { 9 | if (FAILED(hr)) 10 | { 11 | // Set a breakpoint on this line to catch Win32 API errors. 12 | throw Platform::Exception::CreateException(hr); 13 | } 14 | } 15 | 16 | // Function that reads from a binary file asynchronously. 17 | inline Concurrency::task> ReadDataAsync(const std::wstring& filename) 18 | { 19 | using namespace Windows::Storage; 20 | using namespace Concurrency; 21 | 22 | return create_task(PathIO::ReadBufferAsync(Platform::StringReference(filename.c_str()))).then( 23 | [] (Streams::IBuffer^ fileBuffer) -> std::vector 24 | { 25 | std::vector returnBuffer; 26 | returnBuffer.resize(fileBuffer->Length); 27 | Streams::DataReader::FromBuffer(fileBuffer)->ReadBytes(Platform::ArrayReference(returnBuffer.data(), returnBuffer.size())); 28 | return returnBuffer; 29 | }); 30 | } 31 | 32 | // Converts a length in device-independent pixels (DIPs) to a length in physical pixels. 33 | inline float ConvertDipsToPixels(float dips, float dpi) 34 | { 35 | constexpr float dipsPerInch = 96.0f; 36 | return floorf(dips * dpi / dipsPerInch + 0.5f); // Round to nearest integer. 37 | } 38 | 39 | #if defined(_DEBUG) 40 | // Check for SDK Layer support. 41 | inline bool SdkLayersAvailable() 42 | { 43 | HRESULT hr = D3D11CreateDevice( 44 | nullptr, 45 | D3D_DRIVER_TYPE_NULL, // There is no need to create a real hardware device. 46 | 0, 47 | D3D11_CREATE_DEVICE_DEBUG, // Check for the SDK layers. 48 | nullptr, // Any feature level will do. 49 | 0, 50 | D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. 51 | nullptr, // No need to keep the D3D device reference. 52 | nullptr, // No need to know the feature level. 53 | nullptr // No need to keep the D3D device context reference. 54 | ); 55 | 56 | return SUCCEEDED(hr); 57 | } 58 | #endif 59 | } 60 | -------------------------------------------------------------------------------- /Sample/Common/StepTimer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace DX 4 | { 5 | // Helper class for animation and simulation timing. 6 | class StepTimer 7 | { 8 | public: 9 | StepTimer() : 10 | m_elapsedTicks(0), 11 | m_totalTicks(0), 12 | m_leftOverTicks(0), 13 | m_frameCount(0), 14 | m_framesPerSecond(0), 15 | m_framesThisSecond(0), 16 | m_qpcSecondCounter(0), 17 | m_isFixedTimeStep(false), 18 | m_targetElapsedTicks(TicksPerSecond / 60) 19 | { 20 | m_qpcFrequency = GetPerformanceFrequency(); 21 | 22 | // Initialize max delta to 1/10 of a second. 23 | m_qpcMaxDelta = m_qpcFrequency / 10; 24 | } 25 | 26 | // Get elapsed time since the previous Update call. 27 | uint64 GetElapsedTicks() const { return m_elapsedTicks; } 28 | double GetElapsedSeconds() const { return TicksToSeconds(m_elapsedTicks); } 29 | 30 | // Get total time since the start of the program. 31 | uint64 GetTotalTicks() const { return m_totalTicks; } 32 | double GetTotalSeconds() const { return TicksToSeconds(m_totalTicks); } 33 | 34 | // Get total number of updates since start of the program. 35 | uint32 GetFrameCount() const { return m_frameCount; } 36 | 37 | // Get the current framerate. 38 | uint32 GetFramesPerSecond() const { return m_framesPerSecond; } 39 | 40 | // Set whether to use fixed or variable timestep mode. 41 | void SetFixedTimeStep(bool isFixedTimestep) { m_isFixedTimeStep = isFixedTimestep; } 42 | 43 | // Set how often to call Update when in fixed timestep mode. 44 | void SetTargetElapsedTicks(uint64 targetElapsed) { m_targetElapsedTicks = targetElapsed; } 45 | void SetTargetElapsedSeconds(double targetElapsed) { m_targetElapsedTicks = SecondsToTicks(targetElapsed); } 46 | 47 | // Integer format represents time using 10,000,000 ticks per second. 48 | static const uint64 TicksPerSecond = 10'000'000; 49 | 50 | static double TicksToSeconds(uint64 ticks) { return static_cast(ticks) / TicksPerSecond; } 51 | static uint64 SecondsToTicks(double seconds) { return static_cast(seconds * TicksPerSecond); } 52 | 53 | // Convenient wrapper for QueryPerformanceFrequency. Throws an exception if 54 | // the call to QueryPerformanceFrequency fails. 55 | static inline uint64 GetPerformanceFrequency() 56 | { 57 | LARGE_INTEGER freq; 58 | if (!QueryPerformanceFrequency(&freq)) 59 | { 60 | throw ref new Platform::FailureException(); 61 | } 62 | return freq.QuadPart; 63 | } 64 | 65 | // Gets the current number of ticks from QueryPerformanceCounter. Throws an 66 | // exception if the call to QueryPerformanceCounter fails. 67 | static inline int64 GetTicks() 68 | { 69 | LARGE_INTEGER ticks; 70 | if (!QueryPerformanceCounter(&ticks)) 71 | { 72 | throw ref new Platform::FailureException(); 73 | } 74 | return ticks.QuadPart; 75 | } 76 | 77 | // After an intentional timing discontinuity (for instance a blocking IO operation) 78 | // call this to avoid having the fixed timestep logic attempt a set of catch-up 79 | // Update calls. 80 | 81 | void ResetElapsedTime() 82 | { 83 | m_qpcLastTime = GetTicks(); 84 | 85 | m_leftOverTicks = 0; 86 | m_framesPerSecond = 0; 87 | m_framesThisSecond = 0; 88 | m_qpcSecondCounter = 0; 89 | } 90 | 91 | // Update timer state, calling the specified Update function the appropriate number of times. 92 | template 93 | void Tick(const TUpdate& update) 94 | { 95 | // Query the current time. 96 | uint64 currentTime = GetTicks(); 97 | uint64 timeDelta = currentTime - m_qpcLastTime; 98 | 99 | m_qpcLastTime = currentTime; 100 | m_qpcSecondCounter += timeDelta; 101 | 102 | // Clamp excessively large time deltas (e.g. after paused in the debugger). 103 | if (timeDelta > m_qpcMaxDelta) 104 | { 105 | timeDelta = m_qpcMaxDelta; 106 | } 107 | 108 | // Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp. 109 | timeDelta *= TicksPerSecond; 110 | timeDelta /= m_qpcFrequency; 111 | 112 | uint32 lastFrameCount = m_frameCount; 113 | 114 | if (m_isFixedTimeStep) 115 | { 116 | // Fixed timestep update logic 117 | 118 | // If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp 119 | // the clock to exactly match the target value. This prevents tiny and irrelevant errors 120 | // from accumulating over time. Without this clamping, a game that requested a 60 fps 121 | // fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually 122 | // accumulate enough tiny errors that it would drop a frame. It is better to just round 123 | // small deviations down to zero to leave things running smoothly. 124 | 125 | if (abs(static_cast(timeDelta - m_targetElapsedTicks)) < TicksPerSecond / 4000) 126 | { 127 | timeDelta = m_targetElapsedTicks; 128 | } 129 | 130 | m_leftOverTicks += timeDelta; 131 | 132 | while (m_leftOverTicks >= m_targetElapsedTicks) 133 | { 134 | m_elapsedTicks = m_targetElapsedTicks; 135 | m_totalTicks += m_targetElapsedTicks; 136 | m_leftOverTicks -= m_targetElapsedTicks; 137 | m_frameCount++; 138 | 139 | update(); 140 | } 141 | } 142 | else 143 | { 144 | // Variable timestep update logic. 145 | m_elapsedTicks = timeDelta; 146 | m_totalTicks += timeDelta; 147 | m_leftOverTicks = 0; 148 | m_frameCount++; 149 | 150 | update(); 151 | } 152 | 153 | // Track the current framerate. 154 | if (m_frameCount != lastFrameCount) 155 | { 156 | m_framesThisSecond++; 157 | } 158 | 159 | if (m_qpcSecondCounter >= static_cast(m_qpcFrequency)) 160 | { 161 | m_framesPerSecond = m_framesThisSecond; 162 | m_framesThisSecond = 0; 163 | m_qpcSecondCounter %= m_qpcFrequency; 164 | } 165 | } 166 | 167 | private: 168 | 169 | // Source timing data uses QPC units. 170 | uint64 m_qpcFrequency; 171 | uint64 m_qpcLastTime; 172 | uint64 m_qpcMaxDelta; 173 | 174 | // Derived timing data uses a canonical tick format. 175 | uint64 m_elapsedTicks; 176 | uint64 m_totalTicks; 177 | uint64 m_leftOverTicks; 178 | 179 | // Members for tracking the framerate. 180 | uint32 m_frameCount; 181 | uint32 m_framesPerSecond; 182 | uint32 m_framesThisSecond; 183 | uint64 m_qpcSecondCounter; 184 | 185 | // Members for configuring fixed timestep mode. 186 | bool m_isFixedTimeStep; 187 | uint64 m_targetElapsedTicks; 188 | }; 189 | } 190 | -------------------------------------------------------------------------------- /Sample/Content/GeometryShader.hlsl: -------------------------------------------------------------------------------- 1 | // Per-vertex data from the vertex shader. 2 | struct GeometryShaderInput 3 | { 4 | min16float4 pos : SV_POSITION; 5 | min16float3 color : COLOR0; 6 | uint instId : TEXCOORD0; 7 | }; 8 | 9 | // Per-vertex data passed to the rasterizer. 10 | struct GeometryShaderOutput 11 | { 12 | min16float4 pos : SV_POSITION; 13 | min16float3 color : COLOR0; 14 | uint rtvId : SV_RenderTargetArrayIndex; 15 | }; 16 | 17 | // This geometry shader is a pass-through that leaves the geometry unmodified 18 | // and sets the render target array index. 19 | [maxvertexcount(3)] 20 | void main(triangle GeometryShaderInput input[3], inout TriangleStream outStream) 21 | { 22 | GeometryShaderOutput output; 23 | [unroll(3)] 24 | for (int i = 0; i < 3; ++i) 25 | { 26 | output.pos = input[i].pos; 27 | output.color = input[i].color; 28 | output.rtvId = input[i].instId; 29 | outStream.Append(output); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sample/Content/PixelShader.hlsl: -------------------------------------------------------------------------------- 1 | // Per-pixel color data passed through the pixel shader. 2 | struct PixelShaderInput 3 | { 4 | min16float4 pos : SV_POSITION; 5 | min16float3 color : COLOR0; 6 | }; 7 | 8 | // The pixel shader passes through the color data. The color data from 9 | // is interpolated and assigned to a pixel at the rasterization step. 10 | min16float4 main(PixelShaderInput input) : SV_TARGET 11 | { 12 | return min16float4(input.color, 1.0f); 13 | } 14 | -------------------------------------------------------------------------------- /Sample/Content/ShaderStructures.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace HololensCppModules 4 | { 5 | // Constant buffer used to send hologram position transform to the shader pipeline. 6 | struct ModelConstantBuffer 7 | { 8 | DirectX::XMFLOAT4X4 model; 9 | }; 10 | 11 | // Assert that the constant buffer remains 16-byte aligned (best practice). 12 | static_assert((sizeof(ModelConstantBuffer) % (sizeof(float) * 4)) == 0, "Model constant buffer size must be 16-byte aligned (16 bytes is the length of four floats)."); 13 | 14 | 15 | // Used to send per-vertex data to the vertex shader. 16 | struct VertexPositionColor 17 | { 18 | DirectX::XMFLOAT3 pos; 19 | DirectX::XMFLOAT3 color; 20 | }; 21 | } -------------------------------------------------------------------------------- /Sample/Content/VPRTVertexShader.hlsl: -------------------------------------------------------------------------------- 1 | // A constant buffer that stores the model transform. 2 | cbuffer ModelConstantBuffer : register(b0) 3 | { 4 | float4x4 model; 5 | }; 6 | 7 | // A constant buffer that stores each set of view and projection matrices in column-major format. 8 | cbuffer ViewProjectionConstantBuffer : register(b1) 9 | { 10 | float4x4 viewProjection[2]; 11 | }; 12 | 13 | // Per-vertex data used as input to the vertex shader. 14 | struct VertexShaderInput 15 | { 16 | min16float3 pos : POSITION; 17 | min16float3 color : COLOR0; 18 | uint instId : SV_InstanceID; 19 | }; 20 | 21 | // Per-vertex data passed to the geometry shader. 22 | // Note that the render target array index is set here in the vertex shader. 23 | struct VertexShaderOutput 24 | { 25 | min16float4 pos : SV_POSITION; 26 | min16float3 color : COLOR0; 27 | uint rtvId : SV_RenderTargetArrayIndex; // SV_InstanceID % 2 28 | }; 29 | 30 | // Simple shader to do vertex processing on the GPU. 31 | VertexShaderOutput main(VertexShaderInput input) 32 | { 33 | VertexShaderOutput output; 34 | float4 pos = float4(input.pos, 1.0f); 35 | 36 | // Note which view this vertex has been sent to. Used for matrix lookup. 37 | // Taking the modulo of the instance ID allows geometry instancing to be used 38 | // along with stereo instanced drawing; in that case, two copies of each 39 | // instance would be drawn, one for left and one for right. 40 | int idx = input.instId % 2; 41 | 42 | // Transform the vertex position into world space. 43 | pos = mul(pos, model); 44 | 45 | // Correct for perspective and project the vertex position onto the screen. 46 | pos = mul(pos, viewProjection[idx]); 47 | output.pos = (min16float4)pos; 48 | 49 | // Pass the color through without modification. 50 | output.color = input.color; 51 | 52 | // Set the render target array index. 53 | output.rtvId = idx; 54 | 55 | return output; 56 | } 57 | -------------------------------------------------------------------------------- /Sample/Content/VertexShader.hlsl: -------------------------------------------------------------------------------- 1 | // A constant buffer that stores the model transform. 2 | cbuffer ModelConstantBuffer : register(b0) 3 | { 4 | float4x4 model; 5 | }; 6 | 7 | // A constant buffer that stores each set of view and projection matrices in column-major format. 8 | cbuffer ViewProjectionConstantBuffer : register(b1) 9 | { 10 | float4x4 viewProjection[2]; 11 | }; 12 | 13 | // Per-vertex data used as input to the vertex shader. 14 | struct VertexShaderInput 15 | { 16 | min16float3 pos : POSITION; 17 | min16float3 color : COLOR0; 18 | uint instId : SV_InstanceID; 19 | }; 20 | 21 | // Per-vertex data passed to the geometry shader. 22 | // Note that the render target array index will be set by the geometry shader 23 | // using the value of viewId. 24 | struct VertexShaderOutput 25 | { 26 | min16float4 pos : SV_POSITION; 27 | min16float3 color : COLOR0; 28 | uint viewId : TEXCOORD0; // SV_InstanceID % 2 29 | }; 30 | 31 | // Simple shader to do vertex processing on the GPU. 32 | VertexShaderOutput main(VertexShaderInput input) 33 | { 34 | VertexShaderOutput output; 35 | float4 pos = float4(input.pos, 1.0f); 36 | 37 | // Note which view this vertex has been sent to. Used for matrix lookup. 38 | // Taking the modulo of the instance ID allows geometry instancing to be used 39 | // along with stereo instanced drawing; in that case, two copies of each 40 | // instance would be drawn, one for left and one for right. 41 | int idx = input.instId % 2; 42 | 43 | // Transform the vertex position into world space. 44 | pos = mul(pos, model); 45 | 46 | // Correct for perspective and project the vertex position onto the screen. 47 | pos = mul(pos, viewProjection[idx]); 48 | output.pos = (min16float4)pos; 49 | 50 | // Pass the color through without modification. 51 | output.color = input.color; 52 | 53 | // Set the instance ID. The pass-through geometry shader will set the 54 | // render target array index to whatever value is set here. 55 | output.viewId = idx; 56 | 57 | return output; 58 | } 59 | -------------------------------------------------------------------------------- /Sample/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | Sample 18 | hcil 19 | Assets\StoreLogo.png 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Sample/Sample.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {d8f6e702-734f-4264-b1cd-0d09c6564d34} 6 | HolographicApp 7 | Sample 8 | en-US 9 | 14.0 10 | true 11 | Windows Store 12 | 10.0.14393.0 13 | 10.0.10586.0 14 | 10.0 15 | true 16 | 17 | 18 | 19 | 20 | Debug 21 | Win32 22 | 23 | 24 | Release 25 | Win32 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | 33 | 34 | Application 35 | false 36 | true 37 | v140 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Sample_TemporaryKey.pfx 54 | True 55 | 56 | 57 | 58 | d2d1.lib; d3d11.lib; dxgi.lib; dwrite.lib; windowscodecs.lib; %(AdditionalDependencies); 59 | %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib 60 | mincore.lib;kernel32.lib;ole32.lib;%(IgnoreSpecificDefaultLibraries) 61 | 62 | 63 | SamplePch.h 64 | $(IntDir)pch.pch 65 | ..\Modules;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) 66 | /bigobj %(AdditionalOptions) 67 | _DEBUG;%(PreprocessorDefinitions) 68 | 69 | 70 | 71 | 72 | d2d1.lib; d3d11.lib; dxgi.lib; dwrite.lib; windowscodecs.lib; %(AdditionalDependencies); 73 | %(AdditionalLibraryDirectories); $(VCInstallDir)\lib\store; $(VCInstallDir)\lib 74 | mincore.lib;kernel32.lib;ole32.lib;%(IgnoreSpecificDefaultLibraries) 75 | 76 | 77 | SamplePch.h 78 | $(IntDir)pch.pch 79 | ..\Modules;$(ProjectDir);$(IntermediateOutputPath);%(AdditionalIncludeDirectories) 80 | /bigobj %(AdditionalOptions) 81 | NDEBUG;%(PreprocessorDefinitions) 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | Create 110 | 111 | 112 | 113 | 114 | Designer 115 | 116 | 117 | 118 | 119 | 120 | 121 | Pixel 122 | 5.0 123 | 124 | 125 | Vertex 126 | 5.0 127 | 128 | 129 | Vertex 130 | 5.0 131 | 132 | 133 | Geometry 134 | 5.0 135 | 136 | 137 | 138 | 139 | {385e63db-5879-4601-9f27-28c5089956fb} 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | true 151 | 152 | 153 | 154 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /Sample/Sample.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | d8f6e702-734f-4264-b1cd-0d09c6564d34 6 | 7 | 8 | 8a7f81a8-64de-4b24-9b87-4e253a87cea4 9 | bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png 10 | 11 | 12 | ed4edfb0-2682-4dd7-8d69-4f446abfceae 13 | 14 | 15 | ae63cd22-ec0d-4239-9c95-bae75c623a05 16 | 17 | 18 | Common 19 | 20 | 21 | Common 22 | 23 | 24 | Common 25 | 26 | 27 | Common 28 | 29 | 30 | Common 31 | 32 | 33 | Common 34 | 35 | 36 | Assets 37 | 38 | 39 | Assets 40 | 41 | 42 | Assets 43 | 44 | 45 | Assets 46 | 47 | 48 | Assets 49 | 50 | 51 | Assets 52 | 53 | 54 | Assets 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Content 66 | 67 | 68 | 69 | 70 | 71 | 72 | Content\Shaders 73 | 74 | 75 | Content\Shaders 76 | 77 | 78 | Content\Shaders 79 | 80 | 81 | Content\Shaders 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Sample/SampleMain.cpp: -------------------------------------------------------------------------------- 1 | #include "SamplePch.h" 2 | #include "SampleMain.h" 3 | #include "Common\DirectXHelper.h" 4 | #include "RayCast\RayCaster.h" 5 | 6 | #include 7 | #include 8 | 9 | namespace HoloLensCppModules 10 | { 11 | // Loads and initializes application assets when the application is loaded. 12 | SampleMain::SampleMain(const std::shared_ptr& deviceResources) : 13 | m_deviceResources(deviceResources) 14 | { 15 | // Register to be notified if the device is lost or recreated. 16 | m_deviceResources->RegisterDeviceNotify(this); 17 | } 18 | 19 | void SampleMain::SetHolographicSpace(Windows::Graphics::Holographic::HolographicSpace^ holographicSpace) 20 | { 21 | using Platform::Object; 22 | using Windows::Graphics::Holographic::HolographicSpace; 23 | using Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs; 24 | using Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs; 25 | using Windows::Perception::Spatial::SpatialLocator; 26 | using std::placeholders::_1; 27 | using std::placeholders::_2; 28 | 29 | UnregisterHolographicEventHandlers(); 30 | 31 | m_holographicSpace = holographicSpace; 32 | 33 | // 34 | // TODO: Add code here to initialize your holographic content. 35 | // 36 | 37 | // Use the default SpatialLocator to track the motion of the device. 38 | m_locator = SpatialLocator::GetDefault(); 39 | 40 | // Be able to respond to changes in the positional tracking state. 41 | m_locatabilityChangedToken = 42 | m_locator->LocatabilityChanged += 43 | ref new Windows::Foundation::TypedEventHandler( 44 | std::bind(&SampleMain::OnLocatabilityChanged, this, _1, _2) 45 | ); 46 | 47 | // Respond to camera added events by creating any resources that are specific 48 | // to that camera, such as the back buffer render target view. 49 | // When we add an event handler for CameraAdded, the API layer will avoid putting 50 | // the new camera in new HolographicFrames until we complete the deferral we created 51 | // for that handler, or return from the handler without creating a deferral. This 52 | // allows the app to take more than one frame to finish creating resources and 53 | // loading assets for the new holographic camera. 54 | // This function should be registered before the app creates any HolographicFrames. 55 | m_cameraAddedToken = 56 | m_holographicSpace->CameraAdded += 57 | ref new Windows::Foundation::TypedEventHandler( 58 | std::bind(&SampleMain::OnCameraAdded, this, _1, _2) 59 | ); 60 | 61 | // Respond to camera removed events by releasing resources that were created for that 62 | // camera. 63 | // When the app receives a CameraRemoved event, it releases all references to the back 64 | // buffer right away. This includes render target views, Direct2D target bitmaps, and so on. 65 | // The app must also ensure that the back buffer is not attached as a render target, as 66 | // shown in DeviceResources::ReleaseResourcesForBackBuffer. 67 | m_cameraRemovedToken = 68 | m_holographicSpace->CameraRemoved += 69 | ref new Windows::Foundation::TypedEventHandler( 70 | std::bind(&SampleMain::OnCameraRemoved, this, _1, _2) 71 | ); 72 | 73 | // The simplest way to render world-locked holograms is to create a stationary reference frame 74 | // when the app is launched. This is roughly analogous to creating a "world" coordinate system 75 | // with the origin placed at the device's position as the app is launched. 76 | m_referenceFrame = m_locator->CreateStationaryFrameOfReferenceAtCurrentLocation(); 77 | 78 | // Notes on spatial tracking APIs: 79 | // * Stationary reference frames are designed to provide a best-fit position relative to the 80 | // overall space. Individual positions within that reference frame are allowed to drift slightly 81 | // as the device learns more about the environment. 82 | // * When precise placement of individual holograms is required, a SpatialAnchor should be used to 83 | // anchor the individual hologram to a position in the real world - for example, a point the user 84 | // indicates to be of special interest. Anchor positions do not drift, but can be corrected; the 85 | // anchor will use the corrected position starting in the next frame after the correction has 86 | // occurred. 87 | 88 | LoadLocatableCameraModuleAsync(); 89 | } 90 | 91 | void SampleMain::UnregisterHolographicEventHandlers() 92 | { 93 | if (m_holographicSpace != nullptr) 94 | { 95 | // Clear previous event registrations. 96 | 97 | if (m_cameraAddedToken.Value != 0) 98 | { 99 | m_holographicSpace->CameraAdded -= m_cameraAddedToken; 100 | m_cameraAddedToken.Value = 0; 101 | } 102 | 103 | if (m_cameraRemovedToken.Value != 0) 104 | { 105 | m_holographicSpace->CameraRemoved -= m_cameraRemovedToken; 106 | m_cameraRemovedToken.Value = 0; 107 | } 108 | } 109 | 110 | if (m_locator != nullptr) 111 | { 112 | m_locator->LocatabilityChanged -= m_locatabilityChangedToken; 113 | } 114 | } 115 | 116 | SampleMain::~SampleMain() 117 | { 118 | // Deregister device notification. 119 | m_deviceResources->RegisterDeviceNotify(nullptr); 120 | 121 | UnregisterHolographicEventHandlers(); 122 | } 123 | 124 | // Updates the application state once per frame. 125 | Windows::Graphics::Holographic::HolographicFrame^ SampleMain::Update() 126 | { 127 | using DirectX::SimpleMath::Vector2; 128 | using Windows::Graphics::Holographic::HolographicFrame; 129 | using Windows::Graphics::Holographic::HolographicFramePrediction; 130 | using Windows::Graphics::Holographic::HolographicCameraRenderingParameters; 131 | using Windows::Perception::Spatial::SpatialCoordinateSystem; 132 | using Windows::UI::Input::Spatial::SpatialInteractionSourceState; 133 | 134 | // Before doing the timer update, there is some work to do per-frame 135 | // to maintain holographic rendering. First, we will get information 136 | // about the current frame. 137 | 138 | // The HolographicFrame has information that the app needs in order 139 | // to update and render the current frame. The app begins each new 140 | // frame by calling CreateNextFrame. 141 | HolographicFrame^ holographicFrame = m_holographicSpace->CreateNextFrame(); 142 | 143 | // Get a prediction of where holographic cameras will be when this frame 144 | // is presented. 145 | HolographicFramePrediction^ prediction = holographicFrame->CurrentPrediction; 146 | 147 | // Back buffers can change from frame to frame. Validate each buffer, and recreate 148 | // resource views and depth buffers as needed. 149 | m_deviceResources->EnsureCameraResources(holographicFrame, prediction); 150 | 151 | // Next, we get a coordinate system from the attached frame of reference that is 152 | // associated with the current frame. Later, this coordinate system is used for 153 | // for creating the stereo view matrices when rendering the sample content. 154 | SpatialCoordinateSystem^ currentCoordinateSystem = m_referenceFrame->CoordinateSystem; 155 | 156 | m_timer.Tick([&]() 157 | { 158 | // 159 | // TODO: Update scene objects. 160 | // 161 | // Put time-based updates here. By default this code will run once per frame, 162 | // but if you change the StepTimer to use a fixed time step this code will 163 | // run as many times as needed to get to the current step. 164 | // 165 | }); 166 | 167 | // We complete the frame update by using information about our content positioning 168 | // to set the focus point. 169 | 170 | for (auto cameraPose : prediction->CameraPoses) 171 | { 172 | } 173 | 174 | if (m_locatableCameraModule != nullptr) 175 | { 176 | // Access to the current locatable camera frame. 177 | auto locatableCameraFrame = m_locatableCameraModule->GetFrame(); 178 | 179 | if (locatableCameraFrame != nullptr) 180 | { 181 | int id = locatableCameraFrame->GetId(); 182 | if (id % 100 == 0 && id != m_locatableCameraFrame->GetId()) 183 | { 184 | Logger::Log(L"Found a locatable camera frame with ID " + id + L"!"); 185 | } 186 | } 187 | else 188 | { 189 | Logger::Log(L"Locatable camera frame is not available yet."); 190 | } 191 | 192 | m_locatableCameraFrame = locatableCameraFrame; 193 | } 194 | 195 | if (m_spatialMappingModule != nullptr) 196 | { 197 | // Update the bounding volume of the spatial mapping module with the application's starting point. 198 | m_spatialMappingModule->UpdateBoundingVolume(currentCoordinateSystem); 199 | 200 | // Access to the current spatial mapping frame. 201 | auto spatialMappingFrame = m_spatialMappingModule->GetFrame(); 202 | if (spatialMappingFrame != nullptr) 203 | { 204 | int id = spatialMappingFrame->GetId(); 205 | if (id % 5 == 0 && id != m_spatialMappingFrame->GetId()) 206 | { 207 | Logger::Log(L"Found a spatial mapping frame with ID " + id + L"!"); 208 | int surfaceCount = spatialMappingFrame->GetEntries().size(); 209 | Logger::Log(L"It contains " + surfaceCount + L" surfaces."); 210 | } 211 | } 212 | else 213 | { 214 | Logger::Log(L"SpatialMappingFrame is not available yet."); 215 | } 216 | 217 | m_spatialMappingFrame = spatialMappingFrame; 218 | } 219 | 220 | if (m_locatableCameraFrame != nullptr && m_spatialMappingFrame != nullptr) 221 | { 222 | if (m_locatableCameraFrame->GetId() % 100 == 0) 223 | { 224 | auto result = RayCaster::RayCast(Vector2::Zero, m_locatableCameraFrame, m_spatialMappingFrame, currentCoordinateSystem); 225 | float distance = result->GetDistance(); 226 | Logger::Log(L"The distance of the RayCaster's result is " + distance + "."); 227 | } 228 | } 229 | 230 | // The holographic frame will be used to get up-to-date view and projection matrices and 231 | // to present the swap chain. 232 | return holographicFrame; 233 | } 234 | 235 | // Renders the current frame to each holographic camera, according to the 236 | // current application and spatial positioning state. Returns true if the 237 | // frame was rendered to at least one camera. 238 | bool SampleMain::Render(Windows::Graphics::Holographic::HolographicFrame^ holographicFrame) 239 | { 240 | using Windows::Graphics::Holographic::HolographicFramePrediction; 241 | 242 | // Don't try to render anything before the first Update. 243 | if (m_timer.GetFrameCount() == 0) 244 | { 245 | return false; 246 | } 247 | 248 | // 249 | // TODO: Add code for pre-pass rendering here. 250 | // 251 | // Take care of any tasks that are not specific to an individual holographic 252 | // camera. This includes anything that doesn't need the final view or projection 253 | // matrix, such as lighting maps. 254 | // 255 | 256 | // Lock the set of holographic camera resources, then draw to each camera 257 | // in this frame. 258 | return m_deviceResources->UseHolographicCameraResources( 259 | [this, holographicFrame](std::map>& cameraResourceMap) 260 | { 261 | // Up-to-date frame predictions enhance the effectiveness of image stablization and 262 | // allow more accurate positioning of holograms. 263 | holographicFrame->UpdateCurrentPrediction(); 264 | HolographicFramePrediction^ prediction = holographicFrame->CurrentPrediction; 265 | 266 | bool atLeastOneCameraRendered = false; 267 | for (auto cameraPose : prediction->CameraPoses) 268 | { 269 | // This represents the device-based resources for a HolographicCamera. 270 | DX::CameraResources* pCameraResources = cameraResourceMap[cameraPose->HolographicCamera->Id].get(); 271 | 272 | // Get the device context. 273 | const auto context = m_deviceResources->GetD3DDeviceContext(); 274 | const auto depthStencilView = pCameraResources->GetDepthStencilView(); 275 | 276 | // Set render targets to the current holographic camera. 277 | ID3D11RenderTargetView *const targets[1] = { pCameraResources->GetBackBufferRenderTargetView() }; 278 | context->OMSetRenderTargets(1, targets, depthStencilView); 279 | 280 | // Clear the back buffer and depth stencil view. 281 | context->ClearRenderTargetView(targets[0], DirectX::Colors::Transparent); 282 | context->ClearDepthStencilView(depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); 283 | 284 | // 285 | // TODO: Replace the sample content with your own content. 286 | // 287 | // Notes regarding holographic content: 288 | // * For drawing, remember that you have the potential to fill twice as many pixels 289 | // in a stereoscopic render target as compared to a non-stereoscopic render target 290 | // of the same resolution. Avoid unnecessary or repeated writes to the same pixel, 291 | // and only draw holograms that the user can see. 292 | // * To help occlude hologram geometry, you can create a depth map using geometry 293 | // data obtained via the surface mapping APIs. You can use this depth map to avoid 294 | // rendering holograms that are intended to be hidden behind tables, walls, 295 | // monitors, and so on. 296 | // * Black pixels will appear transparent to the user wearing the device, but you 297 | // should still use alpha blending to draw semitransparent holograms. You should 298 | // also clear the screen to Transparent as shown above. 299 | // 300 | 301 | 302 | // The view and projection matrices for each holographic camera will change 303 | // every frame. This function refreshes the data in the constant buffer for 304 | // the holographic camera indicated by cameraPose. 305 | pCameraResources->UpdateViewProjectionBuffer(m_deviceResources, cameraPose, m_referenceFrame->CoordinateSystem); 306 | 307 | // Attach the view/projection constant buffer for this camera to the graphics pipeline. 308 | bool cameraActive = pCameraResources->AttachViewProjectionBuffer(m_deviceResources); 309 | 310 | atLeastOneCameraRendered = true; 311 | } 312 | 313 | return atLeastOneCameraRendered; 314 | }); 315 | } 316 | 317 | void SampleMain::SaveAppState() 318 | { 319 | // 320 | // TODO: Insert code here to save your app state. 321 | // This method is called when the app is about to suspend. 322 | // 323 | // For example, store information in the SpatialAnchorStore. 324 | // 325 | } 326 | 327 | void SampleMain::LoadAppState() 328 | { 329 | // 330 | // TODO: Insert code here to load your app state. 331 | // This method is called when the app resumes. 332 | // 333 | // For example, load information from the SpatialAnchorStore. 334 | // 335 | } 336 | 337 | // Notifies classes that use Direct3D device resources that the device resources 338 | // need to be released before this method returns. 339 | void SampleMain::OnDeviceLost() 340 | { 341 | m_locatableCameraModule = nullptr; 342 | m_spatialMappingModule = nullptr; 343 | } 344 | 345 | // Notifies classes that use Direct3D device resources that the device resources 346 | // may now be recreated. 347 | void SampleMain::OnDeviceRestored() 348 | { 349 | LoadLocatableCameraModuleAsync(); 350 | } 351 | 352 | void SampleMain::OnLocatabilityChanged(Windows::Perception::Spatial::SpatialLocator^ sender, Platform::Object^ args) 353 | { 354 | using Platform::String; 355 | using Windows::Perception::Spatial::SpatialLocatability; 356 | 357 | switch (sender->Locatability) 358 | { 359 | case SpatialLocatability::Unavailable: 360 | // Holograms cannot be rendered. 361 | { 362 | String^ message = L"Warning! Positional tracking is " + 363 | sender->Locatability.ToString() + L".\n"; 364 | OutputDebugStringW(message->Data()); 365 | } 366 | break; 367 | 368 | // In the following three cases, it is still possible to place holograms using a 369 | // SpatialLocatorAttachedFrameOfReference. 370 | case SpatialLocatability::PositionalTrackingActivating: 371 | // The system is preparing to use positional tracking. 372 | 373 | case SpatialLocatability::OrientationOnly: 374 | // Positional tracking has not been activated. 375 | 376 | case SpatialLocatability::PositionalTrackingInhibited: 377 | // Positional tracking is temporarily inhibited. User action may be required 378 | // in order to restore positional tracking. 379 | break; 380 | 381 | case SpatialLocatability::PositionalTrackingActive: 382 | // Positional tracking is active. World-locked content can be rendered. 383 | break; 384 | } 385 | } 386 | 387 | void SampleMain::OnCameraAdded( 388 | Windows::Graphics::Holographic::HolographicSpace^ sender, 389 | Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs^ args 390 | ) 391 | { 392 | using Windows::Foundation::Deferral; 393 | using Windows::Graphics::Holographic::HolographicCamera; 394 | 395 | Deferral^ deferral = args->GetDeferral(); 396 | HolographicCamera^ holographicCamera = args->Camera; 397 | Concurrency::create_task([this, deferral, holographicCamera]() 398 | { 399 | // 400 | // TODO: Allocate resources for the new camera and load any content specific to 401 | // that camera. Note that the render target size (in pixels) is a property 402 | // of the HolographicCamera object, and can be used to create off-screen 403 | // render targets that match the resolution of the HolographicCamera. 404 | // 405 | 406 | // Create device-based resources for the holographic camera and add it to the list of 407 | // cameras used for updates and rendering. Notes: 408 | // * Since this function may be called at any time, the AddHolographicCamera function 409 | // waits until it can get a lock on the set of holographic camera resources before 410 | // adding the new camera. At 60 frames per second this wait should not take long. 411 | // * A subsequent Update will take the back buffer from the RenderingParameters of this 412 | // camera's CameraPose and use it to create the ID3D11RenderTargetView for this camera. 413 | // Content can then be rendered for the HolographicCamera. 414 | m_deviceResources->AddHolographicCamera(holographicCamera); 415 | 416 | // Holographic frame predictions will not include any information about this camera until 417 | // the deferral is completed. 418 | deferral->Complete(); 419 | }); 420 | } 421 | 422 | void SampleMain::OnCameraRemoved( 423 | Windows::Graphics::Holographic::HolographicSpace^ sender, 424 | Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs^ args 425 | ) 426 | { 427 | Concurrency::create_task([this]() 428 | { 429 | // 430 | // TODO: Asynchronously unload or deactivate content resources (not back buffer 431 | // resources) that are specific only to the camera that was removed. 432 | // 433 | }); 434 | 435 | // Before letting this callback return, ensure that all references to the back buffer 436 | // are released. 437 | // Since this function may be called at any time, the RemoveHolographicCamera function 438 | // waits until it can get a lock on the set of holographic camera resources before 439 | // deallocating resources for this camera. At 60 frames per second this wait should 440 | // not take long. 441 | m_deviceResources->RemoveHolographicCamera(args->Camera); 442 | } 443 | 444 | void SampleMain::LoadLocatableCameraModuleAsync() 445 | { 446 | using Windows::Perception::Spatial::SpatialPerceptionAccessStatus; 447 | using Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver; 448 | 449 | LocatableCameraModule::CreateAsync().then([this](std::shared_ptr module) 450 | { 451 | m_locatableCameraModule = std::move(module); 452 | }); 453 | 454 | // The spatial mapping API reads information about the user's environment. The user must 455 | // grant permission to the app to use this capability of the Windows Holographic device. 456 | auto requestSpatialMappingAccessTask = concurrency::create_task(SpatialSurfaceObserver::RequestAccessAsync()); 457 | requestSpatialMappingAccessTask.then([this](SpatialPerceptionAccessStatus status) 458 | { 459 | // For info on what else can cause this, see: http://msdn.microsoft.com/library/windows/apps/mt621422.aspx 460 | if (status == SpatialPerceptionAccessStatus::Allowed) 461 | { 462 | // Create the spatial mapping module. 463 | m_spatialMappingModule = std::move(std::make_shared()); 464 | } 465 | // Access was denied. This usually happens because your AppX manifest file does not declare the 466 | // spatialPerception capability. 467 | else 468 | { 469 | Logger::Log(L"Access denied."); 470 | } 471 | }); 472 | } 473 | } -------------------------------------------------------------------------------- /Sample/SampleMain.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Common\DeviceResources.h" 4 | #include "Common\StepTimer.h" 5 | #include "LocatableCamera\LocatableCameraModule.h" 6 | #include "SpatialMapping\SpatialMappingModule.h" 7 | 8 | // Updates, renders, and presents holographic content using Direct3D. 9 | namespace HoloLensCppModules 10 | { 11 | class SampleMain : public DX::IDeviceNotify 12 | { 13 | public: 14 | SampleMain(const std::shared_ptr& deviceResources); 15 | ~SampleMain(); 16 | 17 | // Sets the holographic space. This is our closest analogue to setting a new window 18 | // for the app. 19 | void SetHolographicSpace(Windows::Graphics::Holographic::HolographicSpace^ holographicSpace); 20 | 21 | // Starts the holographic frame and updates the content. 22 | Windows::Graphics::Holographic::HolographicFrame^ Update(); 23 | 24 | // Renders holograms, including world-locked content. 25 | bool Render(Windows::Graphics::Holographic::HolographicFrame^ holographicFrame); 26 | 27 | // Handle saving and loading of app state owned by AppMain. 28 | void SaveAppState(); 29 | void LoadAppState(); 30 | 31 | // IDeviceNotify 32 | virtual void OnDeviceLost(); 33 | virtual void OnDeviceRestored(); 34 | 35 | private: 36 | // Asynchronously creates resources for new holographic cameras. 37 | void OnCameraAdded( 38 | Windows::Graphics::Holographic::HolographicSpace^ sender, 39 | Windows::Graphics::Holographic::HolographicSpaceCameraAddedEventArgs^ args); 40 | 41 | // Synchronously releases resources for holographic cameras that are no longer 42 | // attached to the system. 43 | void OnCameraRemoved( 44 | Windows::Graphics::Holographic::HolographicSpace^ sender, 45 | Windows::Graphics::Holographic::HolographicSpaceCameraRemovedEventArgs^ args); 46 | 47 | // Used to notify the app when the positional tracking state changes. 48 | void OnLocatabilityChanged( 49 | Windows::Perception::Spatial::SpatialLocator^ sender, 50 | Platform::Object^ args); 51 | 52 | // Clears event registration state. Used when changing to a new HolographicSpace 53 | // and when tearing down AppMain. 54 | void UnregisterHolographicEventHandlers(); 55 | 56 | // Creates and moves a locatable camera module asynchronouslly. 57 | void LoadLocatableCameraModuleAsync(); 58 | 59 | // Cached pointer to device resources. 60 | std::shared_ptr m_deviceResources; 61 | 62 | // Render loop timer. 63 | DX::StepTimer m_timer; 64 | 65 | // Represents the holographic space around the user. 66 | Windows::Graphics::Holographic::HolographicSpace^ m_holographicSpace; 67 | 68 | // SpatialLocator that is attached to the primary camera. 69 | Windows::Perception::Spatial::SpatialLocator^ m_locator; 70 | 71 | // A reference frame attached to the holographic camera. 72 | Windows::Perception::Spatial::SpatialStationaryFrameOfReference^ m_referenceFrame; 73 | 74 | // Event registration tokens. 75 | Windows::Foundation::EventRegistrationToken m_cameraAddedToken; 76 | Windows::Foundation::EventRegistrationToken m_cameraRemovedToken; 77 | Windows::Foundation::EventRegistrationToken m_locatabilityChangedToken; 78 | 79 | // Modules from HoloLensCppModules. 80 | std::shared_ptr m_locatableCameraModule; 81 | std::shared_ptr m_spatialMappingModule; 82 | 83 | // Frames saved to make the log pretty. 84 | std::shared_ptr m_locatableCameraFrame; 85 | std::shared_ptr m_spatialMappingFrame; 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /Sample/SamplePch.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // pch.cpp 3 | // Include the standard header and generate the precompiled header. 4 | // 5 | 6 | #include "SamplePch.h" 7 | -------------------------------------------------------------------------------- /Sample/SamplePch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "Logger.h" -------------------------------------------------------------------------------- /Sample/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------