111
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9c0884dab4c8bbc4d8a979f9838b8cbe
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d9779e2a208874279abf2acd33869873
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d4e1b058addf948b589443857632c8e7
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f192b64343523994e999fa8a5c964120
|
||||||
|
folderAsset: yes
|
||||||
|
timeCreated: 1466076008
|
||||||
|
licenseType: Free
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e3f6095e1f6cb45b399b9c5a3def17f9
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
Binary file not shown.
+80
@@ -0,0 +1,80 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9571c8196841b422bb87ee1f1f937e39
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
: Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 0
|
||||||
|
Exclude Editor: 1
|
||||||
|
Exclude Linux64: 1
|
||||||
|
Exclude OSXUniversal: 1
|
||||||
|
Exclude Win: 1
|
||||||
|
Exclude Win64: 1
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: ARM64
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: AnyOS
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CPU: AnyCPU
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Binary file not shown.
+80
@@ -0,0 +1,80 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ec9137557106b48d8995616414845b71
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
: Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 0
|
||||||
|
Exclude Editor: 1
|
||||||
|
Exclude Linux64: 1
|
||||||
|
Exclude OSXUniversal: 1
|
||||||
|
Exclude Win: 1
|
||||||
|
Exclude Win64: 1
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: ARM64
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: AnyOS
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CPU: AnyCPU
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,32 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c0353ebb74a494fc38f3854047d3a2cd
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
#if (UNITY_IOS || PLATFORM_ANDROID) && !UNITY_EDITOR
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Immersal
|
||||||
|
{
|
||||||
|
public class NativeBindings
|
||||||
|
{
|
||||||
|
#if UNITY_IOS
|
||||||
|
[DllImport("__Internal")]
|
||||||
|
public static extern void startLocation();
|
||||||
|
|
||||||
|
[DllImport("__Internal")]
|
||||||
|
public static extern void stopLocation();
|
||||||
|
|
||||||
|
[DllImport("__Internal")]
|
||||||
|
public static extern double getLatitude();
|
||||||
|
|
||||||
|
[DllImport("__Internal")]
|
||||||
|
public static extern double getLongitude();
|
||||||
|
|
||||||
|
[DllImport("__Internal")]
|
||||||
|
public static extern double getAltitude();
|
||||||
|
|
||||||
|
[DllImport("__Internal")]
|
||||||
|
public static extern double getHorizontalAccuracy();
|
||||||
|
|
||||||
|
[DllImport("__Internal")]
|
||||||
|
public static extern double getVerticalAccuracy();
|
||||||
|
|
||||||
|
[DllImport("__Internal")]
|
||||||
|
public static extern bool locationServicesEnabled();
|
||||||
|
|
||||||
|
#elif PLATFORM_ANDROID
|
||||||
|
static AndroidJavaClass obj = new AndroidJavaClass("com.immersal.nativebindings.Main");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public static bool StartLocation()
|
||||||
|
{
|
||||||
|
if (!Input.location.isEnabledByUser)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_IOS
|
||||||
|
startLocation();
|
||||||
|
#elif PLATFORM_ANDROID
|
||||||
|
obj.CallStatic("startLocation");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void StopLocation()
|
||||||
|
{
|
||||||
|
#if UNITY_IOS
|
||||||
|
stopLocation();
|
||||||
|
#elif PLATFORM_ANDROID
|
||||||
|
obj.CallStatic("stopLocation");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetLatitude()
|
||||||
|
{
|
||||||
|
#if UNITY_IOS
|
||||||
|
return getLatitude();
|
||||||
|
#elif PLATFORM_ANDROID
|
||||||
|
return obj.CallStatic<double>("getLatitude");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetLongitude()
|
||||||
|
{
|
||||||
|
#if UNITY_IOS
|
||||||
|
return getLongitude();
|
||||||
|
#elif PLATFORM_ANDROID
|
||||||
|
return obj.CallStatic<double>("getLongitude");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetAltitude()
|
||||||
|
{
|
||||||
|
#if UNITY_IOS
|
||||||
|
return getAltitude();
|
||||||
|
#elif PLATFORM_ANDROID
|
||||||
|
return obj.CallStatic<double>("getAltitude");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetHorizontalAccuracy()
|
||||||
|
{
|
||||||
|
#if UNITY_IOS
|
||||||
|
return getHorizontalAccuracy();
|
||||||
|
#elif PLATFORM_ANDROID
|
||||||
|
return obj.CallStatic<double>("getHorizontalAccuracy");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double GetVerticalAccuracy()
|
||||||
|
{
|
||||||
|
#if UNITY_IOS
|
||||||
|
return getVerticalAccuracy();
|
||||||
|
#elif PLATFORM_ANDROID
|
||||||
|
return obj.CallStatic<double>("getVerticalAccuracy");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool LocationServicesEnabled()
|
||||||
|
{
|
||||||
|
#if UNITY_IOS
|
||||||
|
return locationServicesEnabled();
|
||||||
|
#elif PLATFORM_ANDROID
|
||||||
|
return obj.CallStatic<bool>("locationServicesEnabled");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1f141c749ad8c4a4dbdd7b392e91a9c3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 867bc362f511875419b00825c35adb62
|
||||||
|
folderAsset: yes
|
||||||
|
timeCreated: 1469455304
|
||||||
|
licenseType: Free
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0a60313de0e704fd682e181e56ca94a7
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 1
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
: Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 1
|
||||||
|
Exclude Editor: 0
|
||||||
|
Exclude Linux: 1
|
||||||
|
Exclude Linux64: 0
|
||||||
|
Exclude LinuxUniversal: 0
|
||||||
|
Exclude Lumin: 1
|
||||||
|
Exclude OSXIntel: 1
|
||||||
|
Exclude OSXIntel64: 0
|
||||||
|
Exclude OSXUniversal: 0
|
||||||
|
Exclude Win: 1
|
||||||
|
Exclude Win64: 0
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: x86_64
|
||||||
|
OS: OSX
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: ARMv7
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: OSX
|
||||||
|
- first:
|
||||||
|
Facebook: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Facebook: Win64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Linux
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: LinuxUniversal
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: x86_64
|
||||||
|
- first:
|
||||||
|
Standalone: OSXIntel
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: OSXIntel64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CPU: AnyCPU
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>22D68</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>PosePlugin</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.immersal.PosePlugin</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>PosePlugin</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>BNDL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string></string>
|
||||||
|
<key>DTPlatformName</key>
|
||||||
|
<string>macosx</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>13.3</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>22E245</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx13.3</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>1430</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>14E222b</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>12.0</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2022 Immersal - Part of Hexagon. All rights reserved.</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
Binary file not shown.
+115
@@ -0,0 +1,115 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>files</key>
|
||||||
|
<dict/>
|
||||||
|
<key>files2</key>
|
||||||
|
<dict/>
|
||||||
|
<key>rules</key>
|
||||||
|
<dict>
|
||||||
|
<key>^Resources/</key>
|
||||||
|
<true/>
|
||||||
|
<key>^Resources/.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version.plist$</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>rules2</key>
|
||||||
|
<dict>
|
||||||
|
<key>.*\.dSYM($|/)</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>11</real>
|
||||||
|
</dict>
|
||||||
|
<key>^(.*/)?\.DS_Store$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>2000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
||||||
|
<dict>
|
||||||
|
<key>nested</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>10</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^Info\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^PkgInfo$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^[^/]+$</key>
|
||||||
|
<dict>
|
||||||
|
<key>nested</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>10</real>
|
||||||
|
</dict>
|
||||||
|
<key>^embedded\.provisionprofile$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
Binary file not shown.
@@ -0,0 +1,116 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b3ad48f0b80387d47808cea0b43f73fb
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 1
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
: Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 1
|
||||||
|
Exclude Editor: 0
|
||||||
|
Exclude Linux64: 0
|
||||||
|
Exclude OSXUniversal: 1
|
||||||
|
Exclude Win: 1
|
||||||
|
Exclude Win64: 0
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
: Linux
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
: LinuxUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: x86_64
|
||||||
|
- first:
|
||||||
|
: OSXIntel
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
: OSXIntel64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: ARMv7
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: x86_64
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: Windows
|
||||||
|
- first:
|
||||||
|
Facebook: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Facebook: Win64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: x86_64
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CPU: AnyCPU
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,81 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9af32ce34e3c09740a2296f38904f864
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
: Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 1
|
||||||
|
Exclude Editor: 0
|
||||||
|
Exclude Linux64: 0
|
||||||
|
Exclude Lumin: 1
|
||||||
|
Exclude OSXUniversal: 0
|
||||||
|
Exclude Win: 0
|
||||||
|
Exclude Win64: 0
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: ARMv7
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: x86_64
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: Windows
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: x86_64
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CPU: AnyCPU
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bba6e78353c194c489388f40a4f2bd6c
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!1 &1434895627878410
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 4682760393691964}
|
||||||
|
- component: {fileID: 8869940821398010349}
|
||||||
|
- component: {fileID: 7715055325084305990}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: ImmersalSDK
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!4 &4682760393691964
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1434895627878410}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
--- !u!114 &8869940821398010349
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1434895627878410}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: bc609bf82f8e346d593bc1a41c2b7cb8, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_AndroidResolution: 2
|
||||||
|
m_Downsample: 1
|
||||||
|
onPoseLost:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
onPoseFound:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
secondsToDecayPose: 10
|
||||||
|
--- !u!114 &7715055325084305990
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 1434895627878410}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: da24111645ab24d549a37ea7da86304b, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_AutoStart: 1
|
||||||
|
localizationInterval: 2
|
||||||
|
m_UseFiltering: 1
|
||||||
|
m_ResetOnMapChange: 0
|
||||||
|
m_BurstMode: 1
|
||||||
|
m_EnableLogging: 0
|
||||||
|
MultipleLocalizationsCount: 20
|
||||||
|
OnMultipleLocalizations:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 181e478384bef4862b94db5a060df1b6
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 100100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9e40124e0b172426ba7c8c93d75c788b
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 30df7aac5e0027a46a0a8d0a3afc1f6a
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
Shader "Immersal/Point Cloud"
|
||||||
|
{
|
||||||
|
Properties
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SubShader
|
||||||
|
{
|
||||||
|
Cull Off
|
||||||
|
Tags{ "RenderType" = "Opaque" }
|
||||||
|
LOD 100
|
||||||
|
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
CGPROGRAM
|
||||||
|
#pragma vertex vert
|
||||||
|
#pragma fragment frag
|
||||||
|
#pragma target 3.0
|
||||||
|
|
||||||
|
#include "UnityCG.cginc"
|
||||||
|
|
||||||
|
float _PointSize;
|
||||||
|
fixed _PerspectiveEnabled;
|
||||||
|
fixed4 _PointColor;
|
||||||
|
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
float3 vertex : POSITION;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexOut
|
||||||
|
{
|
||||||
|
float psize : PSIZE;
|
||||||
|
float4 center : TEXCOORD0;
|
||||||
|
half size : TEXCOORD1;
|
||||||
|
UNITY_FOG_COORDS(0)
|
||||||
|
};
|
||||||
|
|
||||||
|
VertexOut vert(Vertex vertex, out float4 outpos : SV_POSITION)
|
||||||
|
{
|
||||||
|
VertexOut o;
|
||||||
|
outpos = UnityObjectToClipPos(vertex.vertex);
|
||||||
|
|
||||||
|
o.psize = lerp(_PointSize, _PointSize / outpos.w * _ScreenParams.y, step(0.5, _PerspectiveEnabled));
|
||||||
|
o.size = o.psize;
|
||||||
|
|
||||||
|
o.center = ComputeScreenPos(outpos);
|
||||||
|
UNITY_TRANSFER_FOG(o, o.position);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed4 frag(VertexOut i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target
|
||||||
|
{
|
||||||
|
fixed4 c = _PointColor;
|
||||||
|
float4 center = i.center;
|
||||||
|
center.xy /= center.w;
|
||||||
|
center.xy *= _ScreenParams.xy;
|
||||||
|
float d = distance(vpos.xy, center.xy);
|
||||||
|
|
||||||
|
if (d > i.size * 0.5) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNITY_APPLY_FOG(input.fogCoord, c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
ENDCG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 80bb3c180be837f4daba8ccfbd06b6eb
|
||||||
|
ShaderImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
defaultTextures: []
|
||||||
|
nonModifiableTextures: []
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: eee6937ee2c707d42a0b601979052c50
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 09263de2dbfc4a743bdd4c5ff73574ef
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.XR.ARFoundation;
|
||||||
|
using UnityEngine.XR.ARSubsystems;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Unity.Collections.LowLevel.Unsafe;
|
||||||
|
|
||||||
|
namespace Immersal.AR
|
||||||
|
{
|
||||||
|
public class ARHelper {
|
||||||
|
public static Matrix4x4 SwitchHandedness(Matrix4x4 b)
|
||||||
|
{
|
||||||
|
Matrix4x4 D = Matrix4x4.identity;
|
||||||
|
D.m00 = -1;
|
||||||
|
return D * b * D;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion SwitchHandedness(Quaternion b)
|
||||||
|
{
|
||||||
|
Matrix4x4 m = SwitchHandedness(Matrix4x4.Rotate(b));
|
||||||
|
return m.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 SwitchHandedness(Vector3 b)
|
||||||
|
{
|
||||||
|
Matrix4x4 m = SwitchHandedness(Matrix4x4.TRS(b, Quaternion.identity, Vector3.one));
|
||||||
|
return m.GetColumn(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DoubleQuaternionToDoubleMatrix3x3(out double[] m, double[] q)
|
||||||
|
{
|
||||||
|
m = new double [] {1, 0, 0, 0, 1, 0, 0, 0, 1}; //identity matrix
|
||||||
|
|
||||||
|
// input quaternion should be in WXYZ order
|
||||||
|
double w = q[0];
|
||||||
|
double x = q[1];
|
||||||
|
double y = q[2];
|
||||||
|
double z = q[3];
|
||||||
|
|
||||||
|
double ww = w * w;
|
||||||
|
double xx = x * x;
|
||||||
|
double yy = y * y;
|
||||||
|
double zz = z * z;
|
||||||
|
|
||||||
|
double xy = x * y;
|
||||||
|
double zw = z * w;
|
||||||
|
double xz = x * z;
|
||||||
|
double yw = y * w;
|
||||||
|
double yz = y * z;
|
||||||
|
double xw = x * w;
|
||||||
|
|
||||||
|
double inv = 1.0 / (xx + yy + zz + ww);
|
||||||
|
|
||||||
|
m[0] = ( xx - yy - zz + ww) * inv;
|
||||||
|
m[1] = 2.0 * (xy - zw) * inv;
|
||||||
|
m[2] = 2.0 * (xz + yw) * inv;
|
||||||
|
m[3] = 2.0 * (xy + zw) * inv;
|
||||||
|
m[4] = (-xx + yy - zz + ww) * inv;
|
||||||
|
m[5] = 2.0 * (yz - xw) * inv;
|
||||||
|
m[6] = 2.0 * (xz - yw) * inv;
|
||||||
|
m[7] = 2.0 * (yz + xw) * inv;
|
||||||
|
m[8] = (-xx - yy + zz + ww) * inv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetIntrinsics(out Vector4 intrinsics)
|
||||||
|
{
|
||||||
|
intrinsics = Vector4.zero;
|
||||||
|
XRCameraIntrinsics intr;
|
||||||
|
ARCameraManager manager = ImmersalSDK.Instance?.cameraManager;
|
||||||
|
|
||||||
|
if (manager != null && manager.TryGetIntrinsics(out intr))
|
||||||
|
{
|
||||||
|
intrinsics.x = intr.focalLength.x;
|
||||||
|
intrinsics.y = intr.focalLength.y;
|
||||||
|
intrinsics.z = intr.principalPoint.x;
|
||||||
|
intrinsics.w = intr.principalPoint.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetRotation(ref Quaternion rot)
|
||||||
|
{
|
||||||
|
float angle = 0f;
|
||||||
|
switch (Screen.orientation)
|
||||||
|
{
|
||||||
|
case ScreenOrientation.Portrait:
|
||||||
|
angle = 90f;
|
||||||
|
break;
|
||||||
|
case ScreenOrientation.LandscapeLeft:
|
||||||
|
angle = 180f;
|
||||||
|
break;
|
||||||
|
case ScreenOrientation.LandscapeRight:
|
||||||
|
angle = 0f;
|
||||||
|
break;
|
||||||
|
case ScreenOrientation.PortraitUpsideDown:
|
||||||
|
angle = -90f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
angle = 0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rot *= Quaternion.Euler(0f, 0f, angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetPlaneDataFast(ref IntPtr pixels, XRCpuImage image)
|
||||||
|
{
|
||||||
|
XRCpuImage.Plane plane = image.GetPlane(0); // use the Y plane
|
||||||
|
int width = image.width, height = image.height;
|
||||||
|
|
||||||
|
if (width == plane.rowStride)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
pixels = (IntPtr)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(plane.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte[] data = new byte[width * height];
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* dstPtr = data)
|
||||||
|
{
|
||||||
|
byte* srcPtr = (byte*)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(plane.data);
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
|
UnsafeUtility.MemCpyStride(dstPtr, width, srcPtr, plane.rowStride, width, height);
|
||||||
|
}
|
||||||
|
pixels = (IntPtr)dstPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetPlaneData(out byte[] pixels, XRCpuImage image)
|
||||||
|
{
|
||||||
|
XRCpuImage.Plane plane = image.GetPlane(0); // use the Y plane
|
||||||
|
int width = image.width, height = image.height;
|
||||||
|
pixels = new byte[width * height];
|
||||||
|
|
||||||
|
if (width == plane.rowStride)
|
||||||
|
{
|
||||||
|
plane.data.CopyTo(pixels);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* dstPtr = pixels)
|
||||||
|
{
|
||||||
|
byte* srcPtr = (byte*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(plane.data);
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
|
UnsafeUtility.MemCpyStride(dstPtr, width, srcPtr, plane.rowStride, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetPlaneDataRGB(out byte[] pixels, XRCpuImage image)
|
||||||
|
{
|
||||||
|
var conversionParams = new XRCpuImage.ConversionParams
|
||||||
|
{
|
||||||
|
inputRect = new RectInt(0, 0, image.width, image.height),
|
||||||
|
outputDimensions = new Vector2Int(image.width, image.height),
|
||||||
|
outputFormat = TextureFormat.RGB24,
|
||||||
|
transformation = XRCpuImage.Transformation.None
|
||||||
|
};
|
||||||
|
|
||||||
|
int size = image.GetConvertedDataSize(conversionParams);
|
||||||
|
pixels = new byte[size];
|
||||||
|
GCHandle bufferHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
|
||||||
|
image.Convert(conversionParams, bufferHandle.AddrOfPinnedObject(), pixels.Length);
|
||||||
|
bufferHandle.Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetTrackingQuality(out int quality)
|
||||||
|
{
|
||||||
|
quality = default;
|
||||||
|
|
||||||
|
if (ImmersalSDK.Instance?.arSession == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var arSubsystem = ImmersalSDK.Instance?.arSession.subsystem;
|
||||||
|
|
||||||
|
if (arSubsystem != null && arSubsystem.running)
|
||||||
|
{
|
||||||
|
switch (arSubsystem.trackingState)
|
||||||
|
{
|
||||||
|
case TrackingState.Tracking:
|
||||||
|
quality = 4;
|
||||||
|
break;
|
||||||
|
case TrackingState.Limited:
|
||||||
|
quality = 1;
|
||||||
|
break;
|
||||||
|
case TrackingState.None:
|
||||||
|
quality = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f78d5a866c99746cdb1556667e77111c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,613 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Immersal.AR
|
||||||
|
{
|
||||||
|
[System.Serializable]
|
||||||
|
public class MapLocalizedEvent : UnityEvent<int>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[ExecuteAlways]
|
||||||
|
public class ARMap : MonoBehaviour
|
||||||
|
{
|
||||||
|
public static readonly Color[] pointCloudColors = new Color[] { new Color(0.22f, 1f, 0.46f),
|
||||||
|
new Color(0.96f, 0.14f, 0.14f),
|
||||||
|
new Color(0.16f, 0.69f, 0.95f),
|
||||||
|
new Color(0.93f, 0.84f, 0.12f),
|
||||||
|
new Color(0.57f, 0.93f, 0.12f),
|
||||||
|
new Color(1f, 0.38f, 0.78f),
|
||||||
|
new Color(0.4f, 0f, 0.9f),
|
||||||
|
new Color(0.89f, 0.4f, 0f)
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum RenderMode { DoNotRender, EditorOnly, EditorAndRuntime }
|
||||||
|
|
||||||
|
public static Dictionary<int, ARMap> mapHandleToMap = new Dictionary<int, ARMap>();
|
||||||
|
public static bool pointCloudVisible = true;
|
||||||
|
|
||||||
|
public RenderMode renderMode = RenderMode.EditorOnly;
|
||||||
|
public TextAsset mapFile;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private Color m_PointColor = new Color(0.57f, 0.93f, 0.12f);
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
public string mapLicense;
|
||||||
|
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[Space(10)]
|
||||||
|
[Header("Map License Detail")]
|
||||||
|
[SerializeField][ReadOnly]
|
||||||
|
private string m_LicenceId = "0";
|
||||||
|
[SerializeField][ReadOnly]
|
||||||
|
private string m_ExpireTime = "0";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[Space(10)]
|
||||||
|
[Header("Map Metadata")]
|
||||||
|
|
||||||
|
[SerializeField][ReadOnly]
|
||||||
|
private int m_MapId = -1;
|
||||||
|
[SerializeField][ReadOnly]
|
||||||
|
private string m_MapName = null;
|
||||||
|
[ReadOnly]
|
||||||
|
public int privacy;
|
||||||
|
[ReadOnly]
|
||||||
|
public MapAlignment mapAlignment;
|
||||||
|
[ReadOnly]
|
||||||
|
public WGS84 wgs84;
|
||||||
|
|
||||||
|
[Space(10)]
|
||||||
|
[Header("Events")]
|
||||||
|
|
||||||
|
public MapLocalizedEvent OnFirstLocalization = null;
|
||||||
|
protected ARSpace m_ARSpace = null;
|
||||||
|
private bool m_LocalizedOnce = false;
|
||||||
|
|
||||||
|
public Color pointColor
|
||||||
|
{
|
||||||
|
get { return m_PointColor; }
|
||||||
|
set { m_PointColor = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float pointSize = 0.33f;
|
||||||
|
// public static bool isRenderable = true;
|
||||||
|
public static bool renderAs3dPoints = true;
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public struct MapAlignment
|
||||||
|
{
|
||||||
|
public double tx;
|
||||||
|
public double ty;
|
||||||
|
public double tz;
|
||||||
|
public double qx;
|
||||||
|
public double qy;
|
||||||
|
public double qz;
|
||||||
|
public double qw;
|
||||||
|
public double scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public struct WGS84
|
||||||
|
{
|
||||||
|
public double latitude;
|
||||||
|
public double longitude;
|
||||||
|
public double altitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Shader m_Shader;
|
||||||
|
private Material m_Material;
|
||||||
|
private Mesh m_Mesh;
|
||||||
|
private MeshFilter m_MeshFilter;
|
||||||
|
private MeshRenderer m_MeshRenderer;
|
||||||
|
|
||||||
|
public Transform root { get; protected set; }
|
||||||
|
public int mapHandle { get; private set; } = -1;
|
||||||
|
|
||||||
|
public int mapId
|
||||||
|
{
|
||||||
|
get => m_MapId;
|
||||||
|
private set => m_MapId = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string mapName
|
||||||
|
{
|
||||||
|
get => m_MapName;
|
||||||
|
set => m_MapName = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int MapHandleToId(int handle)
|
||||||
|
{
|
||||||
|
if (mapHandleToMap.ContainsKey(handle))
|
||||||
|
{
|
||||||
|
return mapHandleToMap[handle].mapId;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int MapIdToHandle(int id)
|
||||||
|
{
|
||||||
|
if (ARSpace.mapIdToMap.ContainsKey(id))
|
||||||
|
{
|
||||||
|
return ARSpace.mapIdToMap[id].mapHandle;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double[] MapToEcefGet()
|
||||||
|
{
|
||||||
|
double[] q = new double[] {this.mapAlignment.qw, this.mapAlignment.qx, this.mapAlignment.qy, this.mapAlignment.qz};
|
||||||
|
double[] m = new double[9];
|
||||||
|
ARHelper.DoubleQuaternionToDoubleMatrix3x3(out m, q);
|
||||||
|
|
||||||
|
double[] mapToEcef = new double[] {this.mapAlignment.tx, this.mapAlignment.ty, this.mapAlignment.tz, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], this.mapAlignment.scale};
|
||||||
|
|
||||||
|
return mapToEcef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void FreeMap(bool destroy = false)
|
||||||
|
{
|
||||||
|
if (mapHandle >= 0)
|
||||||
|
{
|
||||||
|
Immersal.Core.FreeMap(mapHandle);
|
||||||
|
|
||||||
|
if (mapHandleToMap.ContainsKey(mapHandle))
|
||||||
|
{
|
||||||
|
mapHandleToMap.Remove(mapHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mapHandle = -1;
|
||||||
|
ClearMesh();
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
if (this.mapId > 0)
|
||||||
|
{
|
||||||
|
ARSpace.UnregisterSpace(root, this.mapId);
|
||||||
|
this.mapId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destroy)
|
||||||
|
{
|
||||||
|
GameObject.Destroy(gameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Reset()
|
||||||
|
{
|
||||||
|
m_LocalizedOnce = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<int> LoadMap(byte[] mapBytes = null, int mapId = -1)
|
||||||
|
{
|
||||||
|
if (mapBytes == null)
|
||||||
|
{
|
||||||
|
mapBytes = (mapFile != null) ? mapFile.bytes : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapBytes != null)
|
||||||
|
{
|
||||||
|
Task<int> t = Task.Run(() =>
|
||||||
|
{
|
||||||
|
var bytes = System.Convert.FromBase64String(mapLicense);
|
||||||
|
var str = System.Text.Encoding.UTF8.GetString(bytes);
|
||||||
|
return Immersal.Core.LoadMap(mapBytes, str);
|
||||||
|
});
|
||||||
|
|
||||||
|
await t;
|
||||||
|
if (mapHandle != -1)
|
||||||
|
{
|
||||||
|
FreeMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
mapHandle = t.Result;
|
||||||
|
|
||||||
|
if (this == null)
|
||||||
|
{
|
||||||
|
FreeMap();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapId > 0)
|
||||||
|
{
|
||||||
|
this.mapId = mapId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ParseMapIdAndName();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapHandle >= 0)
|
||||||
|
{
|
||||||
|
int pointCloudSize = Immersal.Core.GetPointCloudSize(mapHandle);
|
||||||
|
Vector3[] points = new Vector3[pointCloudSize];
|
||||||
|
Immersal.Core.GetPointCloud(mapHandle, points);
|
||||||
|
for (int i = 0; i < pointCloudSize; i++)
|
||||||
|
{
|
||||||
|
points[i] = ARHelper.SwitchHandedness(points[i]);
|
||||||
|
}
|
||||||
|
mapHandleToMap[mapHandle] = this;
|
||||||
|
InitializeMesh(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mapId > 0 && m_ARSpace != null)
|
||||||
|
{
|
||||||
|
root = m_ARSpace.transform;
|
||||||
|
ARSpace.RegisterSpace(root, this, transform.localPosition, transform.localRotation, transform.localScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeMesh(Vector3[] pointPositions)
|
||||||
|
{
|
||||||
|
if (this == null) return;
|
||||||
|
|
||||||
|
if (m_Shader == null)
|
||||||
|
{
|
||||||
|
m_Shader = Shader.Find("Immersal/Point Cloud");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Material == null)
|
||||||
|
{
|
||||||
|
m_Material = new Material(m_Shader);
|
||||||
|
m_Material.hideFlags = HideFlags.DontSave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Mesh == null)
|
||||||
|
{
|
||||||
|
m_Mesh = new Mesh();
|
||||||
|
m_Mesh.indexFormat = IndexFormat.UInt32;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numPoints = pointPositions.Length;
|
||||||
|
|
||||||
|
int[] indices = new int[numPoints];
|
||||||
|
Vector3[] pts = new Vector3[numPoints];
|
||||||
|
Color32[] col = new Color32[numPoints];
|
||||||
|
|
||||||
|
for (int i = 0; i < numPoints; ++i)
|
||||||
|
{
|
||||||
|
indices[i] = i;
|
||||||
|
pts[i] = pointPositions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Mesh.Clear();
|
||||||
|
m_Mesh.vertices = pts;
|
||||||
|
m_Mesh.colors32 = col;
|
||||||
|
m_Mesh.SetIndices(indices, MeshTopology.Points, 0);
|
||||||
|
m_Mesh.RecalculateBounds();
|
||||||
|
|
||||||
|
if (m_MeshFilter == null)
|
||||||
|
{
|
||||||
|
m_MeshFilter = gameObject.GetComponent<MeshFilter>();
|
||||||
|
if (m_MeshFilter == null)
|
||||||
|
{
|
||||||
|
m_MeshFilter = gameObject.AddComponent<MeshFilter>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_MeshRenderer == null)
|
||||||
|
{
|
||||||
|
m_MeshRenderer = gameObject.GetComponent<MeshRenderer>();
|
||||||
|
if (m_MeshRenderer == null)
|
||||||
|
{
|
||||||
|
m_MeshRenderer = gameObject.AddComponent<MeshRenderer>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_MeshFilter.mesh = m_Mesh;
|
||||||
|
m_MeshRenderer.material = m_Material;
|
||||||
|
|
||||||
|
m_MeshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||||||
|
m_MeshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
|
||||||
|
m_MeshRenderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeMesh()
|
||||||
|
{
|
||||||
|
InitializeMesh(new Vector3[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearMesh()
|
||||||
|
{
|
||||||
|
if (m_Mesh != null)
|
||||||
|
{
|
||||||
|
m_Mesh.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifySuccessfulLocalization(int mapId)
|
||||||
|
{
|
||||||
|
if (m_LocalizedOnce)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OnFirstLocalization?.Invoke(mapId);
|
||||||
|
m_LocalizedOnce = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
m_ARSpace = gameObject.GetComponentInParent<ARSpace>();
|
||||||
|
if (!m_ARSpace)
|
||||||
|
{
|
||||||
|
GameObject go = new GameObject("AR Space");
|
||||||
|
m_ARSpace = go.AddComponent<ARSpace>();
|
||||||
|
transform.SetParent(go.transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseMapIdAndName();
|
||||||
|
InitializeMesh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseMapIdAndName()
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
if (GetMapId(out id))
|
||||||
|
{
|
||||||
|
this.mapId = id;
|
||||||
|
this.mapName = mapFile.name.Substring(id.ToString().Length + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Application.isEditor)
|
||||||
|
{
|
||||||
|
if (mapFile != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string destinationFolder = Path.Combine("Assets", "Map Data");
|
||||||
|
string jsonFilePath = Path.Combine(destinationFolder, string.Format("{0}-metadata.json", mapFile.name));
|
||||||
|
|
||||||
|
MetadataFile metadataFile = JsonUtility.FromJson<MetadataFile>(File.ReadAllText(jsonFilePath));
|
||||||
|
|
||||||
|
this.mapAlignment.tx = metadataFile.tx;
|
||||||
|
this.mapAlignment.ty = metadataFile.ty;
|
||||||
|
this.mapAlignment.tz = metadataFile.tz;
|
||||||
|
|
||||||
|
this.mapAlignment.qx = metadataFile.qx;
|
||||||
|
this.mapAlignment.qy = metadataFile.qy;
|
||||||
|
this.mapAlignment.qz = metadataFile.qz;
|
||||||
|
this.mapAlignment.qw = metadataFile.qw;
|
||||||
|
|
||||||
|
this.mapAlignment.scale = metadataFile.scale;
|
||||||
|
|
||||||
|
this.wgs84.latitude = metadataFile.latitude;
|
||||||
|
this.wgs84.longitude = metadataFile.longitude;
|
||||||
|
this.wgs84.altitude = metadataFile.altitude;
|
||||||
|
|
||||||
|
this.privacy = metadataFile.privacy;
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException e)
|
||||||
|
{
|
||||||
|
Debug.LogWarningFormat("{0}\nCould not find {1}-metadata.json", e.Message, mapFile.name);
|
||||||
|
// set default values in case metadata is not available
|
||||||
|
|
||||||
|
this.mapAlignment.tx = 0.0;
|
||||||
|
this.mapAlignment.ty = 0.0;
|
||||||
|
this.mapAlignment.tz = 0.0;
|
||||||
|
|
||||||
|
this.mapAlignment.qx = 0.0;
|
||||||
|
this.mapAlignment.qy = 0.0;
|
||||||
|
this.mapAlignment.qz = 0.0;
|
||||||
|
this.mapAlignment.qw = 1.0;
|
||||||
|
|
||||||
|
this.mapAlignment.scale = 1.0;
|
||||||
|
|
||||||
|
this.wgs84.latitude = 0.0;
|
||||||
|
this.wgs84.longitude = 0.0;
|
||||||
|
this.wgs84.altitude = 0.0;
|
||||||
|
|
||||||
|
this.privacy = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
public struct MetadataFile
|
||||||
|
{
|
||||||
|
public string error;
|
||||||
|
public int id;
|
||||||
|
public int type;
|
||||||
|
public string created;
|
||||||
|
public string version;
|
||||||
|
public int user;
|
||||||
|
public int creator;
|
||||||
|
public string name;
|
||||||
|
public int size;
|
||||||
|
public string status;
|
||||||
|
public int privacy;
|
||||||
|
public double latitude;
|
||||||
|
public double longitude;
|
||||||
|
public double altitude;
|
||||||
|
public double tx;
|
||||||
|
public double ty;
|
||||||
|
public double tz;
|
||||||
|
public double qw;
|
||||||
|
public double qx;
|
||||||
|
public double qy;
|
||||||
|
public double qz;
|
||||||
|
public double scale;
|
||||||
|
public string sha256_al;
|
||||||
|
public string sha256_sparse;
|
||||||
|
public string sha256_dense;
|
||||||
|
public string sha256_tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool GetMapId(out int mapId)
|
||||||
|
{
|
||||||
|
if (mapFile == null)
|
||||||
|
{
|
||||||
|
mapId = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string mapFileName = mapFile.name;
|
||||||
|
Regex rx = new Regex(@"^\d+");
|
||||||
|
Match match = rx.Match(mapFileName);
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
mapId = Int32.Parse(match.Value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mapId = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnEnable()
|
||||||
|
{
|
||||||
|
if (mapFile != null)
|
||||||
|
{
|
||||||
|
await LoadMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
FreeMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
FreeMap();
|
||||||
|
|
||||||
|
if (m_Material != null)
|
||||||
|
{
|
||||||
|
if (Application.isPlaying)
|
||||||
|
{
|
||||||
|
Destroy(m_Mesh);
|
||||||
|
Destroy(m_Material);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DestroyImmediate(m_Mesh);
|
||||||
|
DestroyImmediate(m_Material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsRenderable()
|
||||||
|
{
|
||||||
|
if (pointCloudVisible)
|
||||||
|
{
|
||||||
|
switch (renderMode)
|
||||||
|
{
|
||||||
|
case RenderMode.DoNotRender:
|
||||||
|
return false;
|
||||||
|
case RenderMode.EditorOnly:
|
||||||
|
if (Application.isEditor)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case RenderMode.EditorAndRuntime:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnRenderObject()
|
||||||
|
{
|
||||||
|
if (IsRenderable() && m_Material != null)
|
||||||
|
{
|
||||||
|
m_MeshRenderer.enabled = true;
|
||||||
|
|
||||||
|
if (renderAs3dPoints)
|
||||||
|
{
|
||||||
|
m_Material.SetFloat("_PerspectiveEnabled", 1f);
|
||||||
|
m_Material.SetFloat("_PointSize", Mathf.Lerp(0.002f, 0.14f, Mathf.Max(0, Mathf.Pow(pointSize, 3f))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_Material.SetFloat("_PerspectiveEnabled", 0f);
|
||||||
|
m_Material.SetFloat("_PointSize", Mathf.Lerp(1.5f, 40f, Mathf.Max(0, pointSize)));
|
||||||
|
}
|
||||||
|
m_Material.SetColor("_PointColor", m_PointColor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_MeshRenderer.enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
|
||||||
|
private string _prevMapLicense = null;
|
||||||
|
private TextAsset _prevMapFile = null;
|
||||||
|
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
if (mapLicense != _prevMapLicense)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bytes = System.Convert.FromBase64String(mapLicense);
|
||||||
|
var str = System.Text.Encoding.UTF8.GetString(bytes);
|
||||||
|
|
||||||
|
MapLicense obj = JsonUtility.FromJson<MapLicense>(str);
|
||||||
|
|
||||||
|
m_LicenceId = obj.certificateID;
|
||||||
|
m_ExpireTime = obj.expireTime;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
Debug.LogWarningFormat("Incorrect map license!\n{0}", e.Message);
|
||||||
|
|
||||||
|
m_LicenceId = "0";
|
||||||
|
m_ExpireTime = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
_prevMapLicense = mapLicense;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapFile != null)
|
||||||
|
{
|
||||||
|
if (mapFile != _prevMapFile)
|
||||||
|
{
|
||||||
|
ParseMapIdAndName();
|
||||||
|
}
|
||||||
|
|
||||||
|
_prevMapFile = mapFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class MapLicense
|
||||||
|
{
|
||||||
|
public string certificateID;
|
||||||
|
public string applyTime;
|
||||||
|
public string expireTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6a7ab799a64cb7941b7b41a8e1211b12
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences:
|
||||||
|
- mapFile: {instanceID: 0}
|
||||||
|
- m_Shader: {fileID: 4800000, guid: 9cee2ca6ff2bbdc458a11fe108bb2e5b, type: 3}
|
||||||
|
- m_Sorter: {fileID: 7200000, guid: 333809191cc59694fb5772e17740acfe, type: 3}
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Immersal.AR
|
||||||
|
{
|
||||||
|
public class SpaceContainer
|
||||||
|
{
|
||||||
|
public int mapCount = 0;
|
||||||
|
public Vector3 targetPosition = Vector3.zero;
|
||||||
|
public Quaternion targetRotation = Quaternion.identity;
|
||||||
|
public PoseFilter filter = new PoseFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MapOffset
|
||||||
|
{
|
||||||
|
public Vector3 position;
|
||||||
|
public Quaternion rotation;
|
||||||
|
public Vector3 scale;
|
||||||
|
public SpaceContainer space;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ARSpace : MonoBehaviour
|
||||||
|
{
|
||||||
|
public static bool _inited = false;
|
||||||
|
|
||||||
|
public static Dictionary<Transform, SpaceContainer> transformToSpace = new Dictionary<Transform, SpaceContainer>();
|
||||||
|
public static Dictionary<SpaceContainer, Transform> spaceToTransform = new Dictionary<SpaceContainer, Transform>();
|
||||||
|
public static Dictionary<int, MapOffset> mapIdToOffset = new Dictionary<int, MapOffset>();
|
||||||
|
public static Dictionary<int, ARMap> mapIdToMap = new Dictionary<int, ARMap>();
|
||||||
|
|
||||||
|
private Matrix4x4 m_InitialOffset = Matrix4x4.identity;
|
||||||
|
|
||||||
|
public Matrix4x4 initialOffset
|
||||||
|
{
|
||||||
|
get { return m_InitialOffset; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void Awake()
|
||||||
|
{
|
||||||
|
if (!_inited)
|
||||||
|
{
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
init();
|
||||||
|
#endif
|
||||||
|
_inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 pos = transform.position;
|
||||||
|
Quaternion rot = transform.rotation;
|
||||||
|
Matrix4x4 offset = Matrix4x4.TRS(pos, rot, Vector3.one);
|
||||||
|
|
||||||
|
m_InitialOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDestroy()
|
||||||
|
{
|
||||||
|
transformToSpace.Clear();
|
||||||
|
spaceToTransform.Clear();
|
||||||
|
mapIdToOffset.Clear();
|
||||||
|
mapIdToMap.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pose ToCloudSpace(Vector3 camPos, Quaternion camRot)
|
||||||
|
{
|
||||||
|
Matrix4x4 trackerSpace = Matrix4x4.TRS(camPos, camRot, Vector3.one);
|
||||||
|
Matrix4x4 trackerToCloudSpace = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
||||||
|
Matrix4x4 cloudSpace = trackerToCloudSpace.inverse * trackerSpace;
|
||||||
|
|
||||||
|
return new Pose(cloudSpace.GetColumn(3), cloudSpace.rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pose FromCloudSpace(Vector3 camPos, Quaternion camRot)
|
||||||
|
{
|
||||||
|
Matrix4x4 cloudSpace = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
||||||
|
Matrix4x4 trackerSpace = Matrix4x4.TRS(camPos, camRot, Vector3.one);
|
||||||
|
Matrix4x4 m = trackerSpace * (cloudSpace.inverse);
|
||||||
|
|
||||||
|
return new Pose(m.GetColumn(3), m.rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterSpace(Transform tr, ARMap map, Vector3 offsetPosition, Quaternion offsetRotation, Vector3 offsetScale)
|
||||||
|
{
|
||||||
|
if (tr == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SpaceContainer sc;
|
||||||
|
|
||||||
|
if (!transformToSpace.ContainsKey(tr))
|
||||||
|
{
|
||||||
|
sc = new SpaceContainer();
|
||||||
|
transformToSpace[tr] = sc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sc = transformToSpace[tr];
|
||||||
|
}
|
||||||
|
|
||||||
|
spaceToTransform[sc] = tr;
|
||||||
|
|
||||||
|
sc.mapCount++;
|
||||||
|
|
||||||
|
MapOffset mo = new MapOffset();
|
||||||
|
mo.position = offsetPosition;
|
||||||
|
mo.rotation = offsetRotation;
|
||||||
|
mo.scale = offsetScale;
|
||||||
|
mo.space = sc;
|
||||||
|
|
||||||
|
mapIdToOffset[map.mapId] = mo;
|
||||||
|
mapIdToMap[map.mapId] = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterSpace(Transform tr, ARMap map)
|
||||||
|
{
|
||||||
|
RegisterSpace(tr, map, Vector3.zero, Quaternion.identity, Vector3.one);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnregisterSpace(Transform tr, int mapId)
|
||||||
|
{
|
||||||
|
if (tr == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (transformToSpace.ContainsKey(tr))
|
||||||
|
{
|
||||||
|
SpaceContainer sc = transformToSpace[tr];
|
||||||
|
if (--sc.mapCount == 0)
|
||||||
|
{
|
||||||
|
transformToSpace.Remove(tr);
|
||||||
|
spaceToTransform.Remove(sc);
|
||||||
|
}
|
||||||
|
if (mapIdToOffset.ContainsKey(mapId))
|
||||||
|
mapIdToOffset.Remove(mapId);
|
||||||
|
if (mapIdToMap.ContainsKey(mapId))
|
||||||
|
mapIdToMap.Remove(mapId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateSpace(SpaceContainer space, Vector3 pos, Quaternion rot)
|
||||||
|
{
|
||||||
|
if (space == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (spaceToTransform.ContainsKey(space))
|
||||||
|
{
|
||||||
|
Transform tr = spaceToTransform[space];
|
||||||
|
tr.SetPositionAndRotation(pos, rot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("RokidLocalizer", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern void init();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 53a086897bd294848aa39db1a6b2e6ed
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Immersal.AR
|
||||||
|
{
|
||||||
|
public class LocalizerStats
|
||||||
|
{
|
||||||
|
public int localizationAttemptCount = 0;
|
||||||
|
public int localizationSuccessCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct LocalizerPose
|
||||||
|
{
|
||||||
|
public bool valid;
|
||||||
|
public double[] mapToEcef;
|
||||||
|
public Matrix4x4 matrix;
|
||||||
|
public Pose lastUpdatedPose;
|
||||||
|
public double vLatitude;
|
||||||
|
public double vLongitude;
|
||||||
|
public double vAltitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class LocalizerBase : MonoBehaviour
|
||||||
|
{
|
||||||
|
[Tooltip("Start localizing at app startup")]
|
||||||
|
[SerializeField]
|
||||||
|
protected bool m_AutoStart = true;
|
||||||
|
[Tooltip("Time between localization requests in seconds")]
|
||||||
|
public float localizationInterval = 2.0f;
|
||||||
|
[Tooltip("Filter localizer poses for smoother results")]
|
||||||
|
[SerializeField]
|
||||||
|
protected bool m_UseFiltering = true;
|
||||||
|
[Tooltip("Reset localizer filtering when relocalized against a different map than the previous time")]
|
||||||
|
[SerializeField]
|
||||||
|
protected bool m_ResetOnMapChange = false;
|
||||||
|
[Tooltip("Try to localize at maximum speed at app startup / resume")]
|
||||||
|
[SerializeField]
|
||||||
|
protected bool m_BurstMode = true;
|
||||||
|
[SerializeField]
|
||||||
|
protected bool m_EnableLogging;
|
||||||
|
|
||||||
|
public LocalizerStats stats { get; protected set; } = new LocalizerStats();
|
||||||
|
public int lastLocalizedMapId { get; protected set; }
|
||||||
|
public LocalizerPose lastLocalizedPose = default;
|
||||||
|
public bool isTracking { get; protected set; }
|
||||||
|
public bool isLocalizing { get; protected set; }
|
||||||
|
|
||||||
|
public Action<LocalizerPose> OnPoseFound;
|
||||||
|
public Action<int> OnMapChanged;
|
||||||
|
public Action OnReset;
|
||||||
|
|
||||||
|
protected ImmersalSDK m_Sdk = null;
|
||||||
|
protected IntPtr m_PixelBuffer = IntPtr.Zero;
|
||||||
|
protected float m_LastLocalizeTime = 0.0f;
|
||||||
|
protected float m_BurstStartTime = 0.0f;
|
||||||
|
protected bool m_BurstModeActive = false;
|
||||||
|
protected bool m_LocalizeContinuously = false;
|
||||||
|
protected Camera m_Cam = null;
|
||||||
|
protected float m_WarpThresholdDistSq = 5.0f * 5.0f;
|
||||||
|
protected float m_WarpThresholdCosAngle = Mathf.Cos(20.0f * Mathf.PI / 180.0f);
|
||||||
|
|
||||||
|
public bool burstMode
|
||||||
|
{
|
||||||
|
get { return m_BurstMode; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetBurstMode(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool useFiltering
|
||||||
|
{
|
||||||
|
get { return m_UseFiltering; }
|
||||||
|
set { m_UseFiltering = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool resetOnMapChange
|
||||||
|
{
|
||||||
|
get { return m_ResetOnMapChange; }
|
||||||
|
set { m_ResetOnMapChange = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool autoStart
|
||||||
|
{
|
||||||
|
get { return m_AutoStart; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_AutoStart = value;
|
||||||
|
SetContinuousLocalization(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Virtual methods
|
||||||
|
|
||||||
|
public virtual void Start()
|
||||||
|
{
|
||||||
|
m_Sdk = ImmersalSDK.Instance;
|
||||||
|
lastLocalizedMapId = -1;
|
||||||
|
SetBurstMode(burstMode);
|
||||||
|
SetContinuousLocalization(autoStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnEnable()
|
||||||
|
{
|
||||||
|
m_Cam = Camera.main;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnDisable()
|
||||||
|
{
|
||||||
|
isTracking = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnDestroy()
|
||||||
|
{
|
||||||
|
m_PixelBuffer = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnApplicationPause(bool pauseStatus)
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
if (!pauseStatus)
|
||||||
|
SetBurstMode(burstMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Localize()
|
||||||
|
{
|
||||||
|
LocalizerDebugLog(string.Format("Successful localizations: {0}/{1}", stats.localizationSuccessCount, stats.localizationAttemptCount));
|
||||||
|
isLocalizing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Reset()
|
||||||
|
{
|
||||||
|
lastLocalizedMapId = -1;
|
||||||
|
|
||||||
|
stats.localizationAttemptCount = stats.localizationSuccessCount = 0;
|
||||||
|
SetBurstMode(burstMode);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<Transform, SpaceContainer> item in ARSpace.transformToSpace)
|
||||||
|
item.Value.filter.ResetFiltering();
|
||||||
|
|
||||||
|
OnReset?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void StartLocalizing()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
SetContinuousLocalization(autoStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void StopLocalizing()
|
||||||
|
{
|
||||||
|
SetContinuousLocalization(false);
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Pause()
|
||||||
|
{
|
||||||
|
SetContinuousLocalization(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Resume()
|
||||||
|
{
|
||||||
|
SetContinuousLocalization(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void LocalizerDebugLog(string message)
|
||||||
|
{
|
||||||
|
if (m_EnableLogging)
|
||||||
|
{
|
||||||
|
Debug.LogFormat("[{0}]: {1}", this.GetType().Name, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Update()
|
||||||
|
{
|
||||||
|
if (!m_LocalizeContinuously)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ARSpace.transformToSpace.Count == 0)
|
||||||
|
{
|
||||||
|
m_BurstStartTime = Time.unscaledTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useFiltering)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<Transform, SpaceContainer> item in ARSpace.transformToSpace)
|
||||||
|
{
|
||||||
|
float distSq = (item.Value.filter.position - item.Value.targetPosition).sqrMagnitude;
|
||||||
|
float cosAngle = Quaternion.Dot(item.Value.filter.rotation, item.Value.targetRotation);
|
||||||
|
if (item.Value.filter.SampleCount() == 1 || distSq > m_WarpThresholdDistSq || cosAngle < m_WarpThresholdCosAngle)
|
||||||
|
{
|
||||||
|
item.Value.targetPosition = item.Value.filter.position;
|
||||||
|
item.Value.targetRotation = item.Value.filter.rotation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float smoothing = 0.025f;
|
||||||
|
float steps = Time.deltaTime / (1.0f / 60.0f);
|
||||||
|
if (steps < 1.0f)
|
||||||
|
steps = 1.0f;
|
||||||
|
else if (steps > 6.0f)
|
||||||
|
steps = 6.0f;
|
||||||
|
float alpha = 1.0f - Mathf.Pow(1.0f - smoothing, steps);
|
||||||
|
|
||||||
|
item.Value.targetRotation = Quaternion.Slerp(item.Value.targetRotation, item.Value.filter.rotation, alpha);
|
||||||
|
item.Value.targetPosition = Vector3.Lerp(item.Value.targetPosition, item.Value.filter.position, alpha);
|
||||||
|
}
|
||||||
|
ARSpace.UpdateSpace(item.Value, item.Value.targetPosition, item.Value.targetRotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float curTime = Time.unscaledTime;
|
||||||
|
if (m_BurstModeActive) // try to localize at max speed during app start/resume
|
||||||
|
{
|
||||||
|
if (!isLocalizing && isTracking)
|
||||||
|
{
|
||||||
|
float elapsedTime = curTime - m_BurstStartTime;
|
||||||
|
isLocalizing = true;
|
||||||
|
|
||||||
|
Localize();
|
||||||
|
|
||||||
|
if (stats.localizationSuccessCount == 10 || elapsedTime >= 15f)
|
||||||
|
{
|
||||||
|
m_BurstModeActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLocalizing && isTracking && (curTime - m_LastLocalizeTime) >= localizationInterval)
|
||||||
|
{
|
||||||
|
m_LastLocalizeTime = curTime;
|
||||||
|
isLocalizing = true;
|
||||||
|
|
||||||
|
Localize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void SetBurstMode(bool on)
|
||||||
|
{
|
||||||
|
m_BurstStartTime = Time.unscaledTime;
|
||||||
|
m_BurstModeActive = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetContinuousLocalization(bool on)
|
||||||
|
{
|
||||||
|
m_LocalizeContinuously = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void GetLocalizerPose(out LocalizerPose localizerPose, int mapId, Vector3 pos, Quaternion rot, Matrix4x4 m, double[] mapToEcef = null)
|
||||||
|
{
|
||||||
|
localizerPose = default;
|
||||||
|
|
||||||
|
if (mapToEcef == null)
|
||||||
|
{
|
||||||
|
mapToEcef = ARSpace.mapIdToMap[mapId].MapToEcefGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
double[] wgs84 = new double[3];
|
||||||
|
int r = Immersal.Core.PosMapToWgs84(wgs84, ARHelper.SwitchHandedness(pos), mapToEcef);
|
||||||
|
|
||||||
|
if (r == 0)
|
||||||
|
{
|
||||||
|
localizerPose.valid = true;
|
||||||
|
localizerPose.mapToEcef = mapToEcef;
|
||||||
|
localizerPose.matrix = m;
|
||||||
|
localizerPose.lastUpdatedPose = new Pose(pos, rot);
|
||||||
|
localizerPose.vLatitude = wgs84[0];
|
||||||
|
localizerPose.vLongitude = wgs84[1];
|
||||||
|
localizerPose.vAltitude = wgs84[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 06ec00cf50a16443a92eafce8161c1a1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Immersal.AR
|
||||||
|
{
|
||||||
|
public class PoseFilter
|
||||||
|
{
|
||||||
|
public Vector3 position = Vector3.zero;
|
||||||
|
public Quaternion rotation = Quaternion.identity;
|
||||||
|
|
||||||
|
private static uint m_HistorySize = 8;
|
||||||
|
private Vector3[] m_P = new Vector3[m_HistorySize];
|
||||||
|
private Vector3[] m_X = new Vector3[m_HistorySize];
|
||||||
|
private Vector3[] m_Z = new Vector3[m_HistorySize];
|
||||||
|
private uint m_Samples = 0;
|
||||||
|
|
||||||
|
public uint SampleCount()
|
||||||
|
{
|
||||||
|
return m_Samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InvalidateHistory()
|
||||||
|
{
|
||||||
|
m_Samples = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetFiltering()
|
||||||
|
{
|
||||||
|
position = Vector3.zero;
|
||||||
|
rotation = Quaternion.identity;
|
||||||
|
InvalidateHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefinePose(Matrix4x4 r)
|
||||||
|
{
|
||||||
|
uint idx = m_Samples% m_HistorySize;
|
||||||
|
m_P[idx] = r.GetColumn(3);
|
||||||
|
m_X[idx] = r.GetColumn(0);
|
||||||
|
m_Z[idx] = r.GetColumn(2);
|
||||||
|
m_Samples++;
|
||||||
|
uint n = m_Samples > m_HistorySize ? m_HistorySize : m_Samples;
|
||||||
|
position = FilterAVT(m_P, n);
|
||||||
|
Vector3 x = Vector3.Normalize(FilterAVT(m_X, n));
|
||||||
|
Vector3 z = Vector3.Normalize(FilterAVT(m_Z, n));
|
||||||
|
Vector3 up = Vector3.Normalize(Vector3.Cross(z, x));
|
||||||
|
rotation = Quaternion.LookRotation(z, up);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3 FilterAVT(Vector3[] buf, uint n)
|
||||||
|
{
|
||||||
|
Vector3 mean = Vector3.zero;
|
||||||
|
for (uint i = 0; i < n; i++)
|
||||||
|
mean += buf[i];
|
||||||
|
mean /= (float)n;
|
||||||
|
if (n <= 2)
|
||||||
|
return mean;
|
||||||
|
float s = 0;
|
||||||
|
for (uint i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
s += Vector3.SqrMagnitude(buf[i] - mean);
|
||||||
|
}
|
||||||
|
s /= (float)n;
|
||||||
|
Vector3 avg = Vector3.zero;
|
||||||
|
int ib = 0;
|
||||||
|
for (uint i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
float d = Vector3.SqrMagnitude(buf[i] - mean);
|
||||||
|
if (d <= s)
|
||||||
|
{
|
||||||
|
avg += buf[i];
|
||||||
|
ib++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ib > 0)
|
||||||
|
{
|
||||||
|
avg /= (float)ib;
|
||||||
|
return avg;
|
||||||
|
}
|
||||||
|
return mean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3081ca6de5f736847b8e96b9683e38d7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||||
|
using System.Diagnostics;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Immersal
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct LocalizeInfo
|
||||||
|
{
|
||||||
|
public int handle;
|
||||||
|
public float px, py, pz;
|
||||||
|
public float r00, r01, r02, r10, r11, r12, r20, r21, r22;
|
||||||
|
public int confidence;
|
||||||
|
};
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void LogCallback(IntPtr msg);
|
||||||
|
|
||||||
|
public static class Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get a Vector3 point cloud representation of the map data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mapHandle">An integer map handle</param>
|
||||||
|
/// <param name="points">A preallocated Vector3 array for the points</param>
|
||||||
|
/// <returns>Returns the number of points if succeeded, 0 otherwise.</returns>
|
||||||
|
public static int GetPointCloud(int mapHandle, Vector3[] points)
|
||||||
|
{
|
||||||
|
GCHandle vector3ArrayHandle = GCHandle.Alloc(points, GCHandleType.Pinned);
|
||||||
|
int n = Native.icvPointsGet(mapHandle, vector3ArrayHandle.AddrOfPinnedObject(), points.Length);
|
||||||
|
vector3ArrayHandle.Free();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get point count of the map's point cloud.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mapHandle">An integer map handle</param>
|
||||||
|
/// <returns>Returns the number of points.</returns>
|
||||||
|
public static int GetPointCloudSize(int mapHandle) => Native.icvPointsGetCount(mapHandle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load map data from a .bytes file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Map data as a byte array</param>
|
||||||
|
/// <returns>An integer map handle.</returns>
|
||||||
|
public static int LoadMap(byte[] buffer, string license) => Native.icvLoadMap(buffer, license);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Free the map data from memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mapHandle">An integer map handle</param>
|
||||||
|
/// <returns>Returns 1 if succeeded, 0 otherwise.</returns>
|
||||||
|
public static int FreeMap(int mapHandle) => Native.icvFreeMap(mapHandle);
|
||||||
|
|
||||||
|
public static int UndistortFishEyeImage(byte[] result, int byteSizeMax, byte[] pixels, int width,
|
||||||
|
int height, int channels, ref Vector4 intrinsics, ref Vector4 distCoeffs, float alpha)
|
||||||
|
{
|
||||||
|
GCHandle resultHandle = GCHandle.Alloc(result, GCHandleType.Pinned);
|
||||||
|
GCHandle pixelsHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
|
||||||
|
int r = Native.icvUndistortFishEye(resultHandle.AddrOfPinnedObject(), byteSizeMax,
|
||||||
|
pixelsHandle.AddrOfPinnedObject(), width, height, channels, ref intrinsics, ref distCoeffs, alpha);
|
||||||
|
resultHandle.Free();
|
||||||
|
pixelsHandle.Free();
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the position and orientation of the image within the map.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="width">Image width</param>
|
||||||
|
/// <param name="height">Image height</param>
|
||||||
|
/// <param name="intrinsics">Camera intrinsics</param>
|
||||||
|
/// <param name="pixels">Raw pixel buffer data from the camera</param>
|
||||||
|
/// <param name="rot">Camera rotation as float array</param>
|
||||||
|
/// <returns>An integer map ID if succeeded, -1 otherwise</returns>
|
||||||
|
public static LocalizeInfo LocalizeImage(int n, int[] handles, int width,
|
||||||
|
int height, ref Vector4 intrinsics, IntPtr pixels, int solverType, float[] rot)
|
||||||
|
{
|
||||||
|
GCHandle intHandle = GCHandle.Alloc(handles, GCHandleType.Pinned);
|
||||||
|
LocalizeInfo result = Native.icvLocalize(n, intHandle.AddrOfPinnedObject(), width, height,
|
||||||
|
ref intrinsics, pixels, solverType, rot);
|
||||||
|
intHandle.Free();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalizeInfo LocalizeImage(int n, int[] handles, int width,
|
||||||
|
int height, ref Vector4 intrinsics, IntPtr pixels)
|
||||||
|
{
|
||||||
|
int sFlag = 0;
|
||||||
|
float[] rot = new float[1];
|
||||||
|
return LocalizeImage(n, handles, width, height, ref intrinsics, pixels, sFlag, rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the position and orientation of the image within the map.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="width">Image width</param>
|
||||||
|
/// <param name="height">Image height</param>
|
||||||
|
/// <param name="intrinsics">Camera intrinsics</param>
|
||||||
|
/// <param name="pixels">Raw pixel buffer data from the camera</param>
|
||||||
|
/// <returns>An integer map ID if succeeded, -1 otherwise</returns>
|
||||||
|
public static LocalizeInfo LocalizeImage(int width, int height,
|
||||||
|
ref Vector4 intrinsics, IntPtr pixels)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
int[] handles = new int[1];
|
||||||
|
return LocalizeImage(n, handles, width, height, ref intrinsics, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the position and orientation of the image within the map.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="width">Image width</param>
|
||||||
|
/// <param name="height">Image height</param>
|
||||||
|
/// <param name="intrinsics">Camera intrinsics</param>
|
||||||
|
/// <param name="pixels">Raw pixel buffer data from the camera</param>
|
||||||
|
/// <param name="rot">Camera rotation as float array</param>
|
||||||
|
/// <returns>An integer map ID if succeeded, -1 otherwise</returns>
|
||||||
|
public static LocalizeInfo LocalizeImage(int width, int height,
|
||||||
|
ref Vector4 intrinsics, IntPtr pixels, float[] rot)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
int[] handles = new int[1];
|
||||||
|
return LocalizeImage(n, handles, width, height, ref intrinsics, pixels, 1, rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ecef"></param>
|
||||||
|
/// <param name="map"></param>
|
||||||
|
/// <param name="mapToEcef"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int PosMapToEcef(double[] ecef, Vector3 map, double[] mapToEcef)
|
||||||
|
{
|
||||||
|
GCHandle ecefHandle = GCHandle.Alloc(ecef, GCHandleType.Pinned);
|
||||||
|
GCHandle mapToEcefHandle = GCHandle.Alloc(mapToEcef, GCHandleType.Pinned);
|
||||||
|
int r = Native.icvPosMapToEcef(ecefHandle.AddrOfPinnedObject(), ref map,
|
||||||
|
mapToEcefHandle.AddrOfPinnedObject());
|
||||||
|
mapToEcefHandle.Free();
|
||||||
|
ecefHandle.Free();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="wgs84"></param>
|
||||||
|
/// <param name="ecef"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int PosEcefToWgs84(double[] wgs84, double[] ecef)
|
||||||
|
{
|
||||||
|
GCHandle wgs84Handle = GCHandle.Alloc(wgs84, GCHandleType.Pinned);
|
||||||
|
GCHandle ecefHandle = GCHandle.Alloc(ecef, GCHandleType.Pinned);
|
||||||
|
int r = Native.icvPosEcefToWgs84(wgs84Handle.AddrOfPinnedObject(), ecefHandle.AddrOfPinnedObject());
|
||||||
|
ecefHandle.Free();
|
||||||
|
wgs84Handle.Free();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ecef"></param>
|
||||||
|
/// <param name="wgs84"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int PosWgs84ToEcef(double[] ecef, double[] wgs84)
|
||||||
|
{
|
||||||
|
GCHandle ecefHandle = GCHandle.Alloc(ecef, GCHandleType.Pinned);
|
||||||
|
GCHandle wgs84Handle = GCHandle.Alloc(wgs84, GCHandleType.Pinned);
|
||||||
|
int r = Native.icvPosWgs84ToEcef(ecefHandle.AddrOfPinnedObject(), wgs84Handle.AddrOfPinnedObject());
|
||||||
|
wgs84Handle.Free();
|
||||||
|
ecefHandle.Free();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="map"></param>
|
||||||
|
/// <param name="ecef"></param>
|
||||||
|
/// <param name="mapToEcef"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int PosEcefToMap(out Vector3 map, double[] ecef, double[] mapToEcef)
|
||||||
|
{
|
||||||
|
GCHandle ecefHandle = GCHandle.Alloc(ecef, GCHandleType.Pinned);
|
||||||
|
GCHandle mapToEcefHandle = GCHandle.Alloc(mapToEcef, GCHandleType.Pinned);
|
||||||
|
int r = Native.icvPosEcefToMap(out map, ecefHandle.AddrOfPinnedObject(),
|
||||||
|
mapToEcefHandle.AddrOfPinnedObject());
|
||||||
|
mapToEcefHandle.Free();
|
||||||
|
ecefHandle.Free();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="wgs84"></param>
|
||||||
|
/// <param name="map"></param>
|
||||||
|
/// <param name="mapToEcef"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int PosMapToWgs84(double[] wgs84, Vector3 map, double[] mapToEcef)
|
||||||
|
{
|
||||||
|
double[] ecef = new double[3];
|
||||||
|
int err = PosMapToEcef(ecef, map, mapToEcef);
|
||||||
|
if (err != 0)
|
||||||
|
return err;
|
||||||
|
return PosEcefToWgs84(wgs84, ecef);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ecef"></param>
|
||||||
|
/// <param name="map"></param>
|
||||||
|
/// <param name="mapToEcef"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int RotMapToEcef(out Quaternion ecef, Quaternion map, double[] mapToEcef)
|
||||||
|
{
|
||||||
|
GCHandle mapToEcefHandle = GCHandle.Alloc(mapToEcef, GCHandleType.Pinned);
|
||||||
|
int r = Native.icvRotMapToEcef(out ecef, ref map, mapToEcefHandle.AddrOfPinnedObject());
|
||||||
|
mapToEcefHandle.Free();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="map"></param>
|
||||||
|
/// <param name="ecef"></param>
|
||||||
|
/// <param name="mapToEcef"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int RotEcefToMap(out Quaternion map, Quaternion ecef, double[] mapToEcef)
|
||||||
|
{
|
||||||
|
GCHandle mapToEcefHandle = GCHandle.Alloc(mapToEcef, GCHandleType.Pinned);
|
||||||
|
int r = Native.icvRotEcefToMap(out map, ref ecef, mapToEcefHandle.AddrOfPinnedObject());
|
||||||
|
mapToEcefHandle.Free();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set internal plugin parameters.
|
||||||
|
///
|
||||||
|
/// Available parameters:
|
||||||
|
/// "LocalizationMaxPixels" - 0 is no limit (the default), 960*720 or higher.
|
||||||
|
/// "NumThreads" - how many CPU cores to use; -1 (system default) or a positive integer.
|
||||||
|
/// "ImageCompressionLevel" - 0 (no compression, fastest) to 9 (slowest). Defaults to 4.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter">Parameter name</param>
|
||||||
|
/// <param name="value">An integer parameter value</param>
|
||||||
|
/// <returns>Returns 1 if succeeded, -1 otherwise.</returns>
|
||||||
|
public static int SetInteger(string parameter, int value) => Native.icvSetInteger(parameter, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Native
|
||||||
|
{
|
||||||
|
private const string Assembly =
|
||||||
|
#if UNITY_IOS && !UNITY_EDITOR
|
||||||
|
"__Internal";
|
||||||
|
#else
|
||||||
|
"PosePlugin";
|
||||||
|
#endif
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void PP_RegisterLogCallback(IntPtr callbackDelegate);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvPointsGet(int mapHandle, IntPtr array, int maxCount);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvPointsGetCount(int mapHandle);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvLoadMap(byte[] buffer, string license);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvFreeMap(int mapHandle);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvUndistortFishEye(IntPtr capture, int captureSizeMax, IntPtr pixels,
|
||||||
|
int width, int height, int channels, ref Vector4 intrinsics, ref Vector4 distCoeffs, float alpha);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern LocalizeInfo icvLocalize(int n, IntPtr handles, int width,
|
||||||
|
int height, ref Vector4 intrinsics, IntPtr pixels, int sFlag, float[] rot);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvPosMapToEcef(IntPtr ecef, ref Vector3 map, IntPtr mapToEcef);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvPosEcefToWgs84(IntPtr wgs84, IntPtr ecef);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvPosWgs84ToEcef(IntPtr ecef, IntPtr wgs84);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvPosEcefToMap(out Vector3 map, IntPtr ecef, IntPtr mapToEcef);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvRotMapToEcef(out Quaternion ecef, ref Quaternion map, IntPtr mapToEcef);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvRotEcefToMap(out Quaternion map, ref Quaternion ecef, IntPtr mapToEcef);
|
||||||
|
|
||||||
|
[DllImport(Assembly, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int icvSetInteger([MarshalAs(UnmanagedType.LPStr)] string parameter, int value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2a0cde8ffdea2d24bb36590dbe44cb53
|
||||||
|
timeCreated: 1464961012
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 068ff142a326946a4921c7907dd3368c
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
|
||||||
|
public class ReadOnlyDrawer : PropertyDrawer
|
||||||
|
{
|
||||||
|
public override float GetPropertyHeight(SerializedProperty property,
|
||||||
|
GUIContent label)
|
||||||
|
{
|
||||||
|
return EditorGUI.GetPropertyHeight(property, label, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnGUI(Rect position,
|
||||||
|
SerializedProperty property,
|
||||||
|
GUIContent label)
|
||||||
|
{
|
||||||
|
GUI.enabled = false;
|
||||||
|
EditorGUI.PropertyField(position, property, label, true);
|
||||||
|
GUI.enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6a04c0995666dab4988bf70980c9d391
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,336 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using Unity.Collections;
|
||||||
|
using UnityEngine.XR.ARFoundation;
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Immersal.AR;
|
||||||
|
using UnityEngine.XR.ARSubsystems;
|
||||||
|
using AOT;
|
||||||
|
|
||||||
|
namespace Immersal
|
||||||
|
{
|
||||||
|
public class ImmersalSDK : MonoBehaviour
|
||||||
|
{
|
||||||
|
public static string sdkVersion = "1.20.0";
|
||||||
|
public static bool isHWAR = false;
|
||||||
|
// private static readonly string[] ServerList = new[] {"https://api.immersal.com", "https://immersal.hexagon.com.cn"};
|
||||||
|
|
||||||
|
public enum CameraResolution { Default, HD, FullHD, Max }; // With Huawei AR Engine SDK, only Default (640x480) and Max (1440x1080) are supported.
|
||||||
|
|
||||||
|
private static ImmersalSDK instance = null;
|
||||||
|
|
||||||
|
[Tooltip("Application target frame rate")]
|
||||||
|
private int m_TargetFrameRate = 60;
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("Android resolution")]
|
||||||
|
private CameraResolution m_AndroidResolution = CameraResolution.FullHD;
|
||||||
|
[Tooltip("Downsample image to HD resolution")]
|
||||||
|
[SerializeField]
|
||||||
|
private bool m_Downsample = true;
|
||||||
|
|
||||||
|
public UnityEvent onPoseLost = null;
|
||||||
|
public UnityEvent onPoseFound = null;
|
||||||
|
|
||||||
|
public int secondsToDecayPose = 10;
|
||||||
|
|
||||||
|
public LocalizerBase Localizer { get; private set; }
|
||||||
|
public int TrackingQuality { get; private set; }
|
||||||
|
|
||||||
|
private ARCameraManager m_CameraManager;
|
||||||
|
private ARSession m_ARSession;
|
||||||
|
private bool m_bCamConfigDone = false;
|
||||||
|
private string m_LocalizationServer;
|
||||||
|
private int m_PreviousResults = 0;
|
||||||
|
private int m_CurrentResults = 0;
|
||||||
|
private int q = 0;
|
||||||
|
private float m_LatestPoseUpdated = 0f;
|
||||||
|
private bool m_HasPose = false;
|
||||||
|
private XRCameraConfiguration? m_InitialConfig;
|
||||||
|
|
||||||
|
public static HttpClient client;
|
||||||
|
|
||||||
|
public int targetFrameRate
|
||||||
|
{
|
||||||
|
get { return m_TargetFrameRate; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_TargetFrameRate = value;
|
||||||
|
SetFrameRate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CameraResolution androidResolution
|
||||||
|
{
|
||||||
|
get { return m_AndroidResolution; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_AndroidResolution = value;
|
||||||
|
ConfigureCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool downsample
|
||||||
|
{
|
||||||
|
get { return m_Downsample; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_Downsample = value;
|
||||||
|
SetDownsample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ARCameraManager cameraManager
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (m_CameraManager == null)
|
||||||
|
{
|
||||||
|
m_CameraManager = UnityEngine.Object.FindObjectOfType<ARCameraManager>();
|
||||||
|
}
|
||||||
|
return m_CameraManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ARSession arSession
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (m_ARSession == null)
|
||||||
|
{
|
||||||
|
m_ARSession = UnityEngine.Object.FindObjectOfType<ARSession>();
|
||||||
|
}
|
||||||
|
return m_ARSession;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ImmersalSDK Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (instance == null && !Application.isPlaying)
|
||||||
|
{
|
||||||
|
instance = UnityEngine.Object.FindObjectOfType<ImmersalSDK>();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("No ImmersalSDK instance found. Ensure one exists in the scene.");
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Awake()
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
if (instance != this)
|
||||||
|
{
|
||||||
|
Debug.LogError("There must be only one ImmersalSDK object in a scene.");
|
||||||
|
UnityEngine.Object.DestroyImmediate(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogCallback callback_delegate = new LogCallback(Log);
|
||||||
|
IntPtr intptr_delegate = Marshal.GetFunctionPointerForDelegate(callback_delegate);
|
||||||
|
Native.PP_RegisterLogCallback(intptr_delegate);
|
||||||
|
|
||||||
|
HttpClientHandler handler = new HttpClientHandler();
|
||||||
|
handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
|
||||||
|
client = new HttpClient(handler);
|
||||||
|
client.DefaultRequestHeaders.ExpectContinue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
SetFrameRate();
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
SetDownsample();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
onPoseLost?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
[MonoPInvokeCallback(typeof(LogCallback))]
|
||||||
|
public static void Log(IntPtr ansiString)
|
||||||
|
{
|
||||||
|
string msg = Marshal.PtrToStringAnsi(ansiString);
|
||||||
|
Debug.LogFormat("Plugin: {0}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetFrameRate()
|
||||||
|
{
|
||||||
|
Application.targetFrameRate = targetFrameRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetDownsample()
|
||||||
|
{
|
||||||
|
if (downsample)
|
||||||
|
{
|
||||||
|
Core.SetInteger("LocalizationMaxPixels", 960*720);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Core.SetInteger("LocalizationMaxPixels", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (Localizer != null)
|
||||||
|
{
|
||||||
|
LocalizerStats stats = Localizer.stats;
|
||||||
|
if (stats.localizationAttemptCount > 0)
|
||||||
|
{
|
||||||
|
q = CurrentResults(stats.localizationSuccessCount);
|
||||||
|
|
||||||
|
if (!m_HasPose && q > 1)
|
||||||
|
{
|
||||||
|
m_HasPose = true;
|
||||||
|
onPoseFound?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_HasPose && (q < 1 || !Localizer.isTracking))
|
||||||
|
{
|
||||||
|
m_HasPose = false;
|
||||||
|
Localizer.Reset();
|
||||||
|
m_PreviousResults = 0;
|
||||||
|
m_CurrentResults = 0;
|
||||||
|
onPoseLost?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackingQuality = q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isHWAR)
|
||||||
|
{
|
||||||
|
if (!m_bCamConfigDone && cameraManager != null)
|
||||||
|
ConfigureCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigureCamera()
|
||||||
|
{
|
||||||
|
#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS)
|
||||||
|
var cameraSubsystem = cameraManager.subsystem;
|
||||||
|
if (cameraSubsystem == null || !cameraSubsystem.running)
|
||||||
|
return;
|
||||||
|
var configurations = cameraSubsystem.GetConfigurations(Allocator.Temp);
|
||||||
|
if (!configurations.IsCreated || (configurations.Length <= 0))
|
||||||
|
return;
|
||||||
|
int bestError = int.MaxValue;
|
||||||
|
var currentConfig = cameraSubsystem.currentConfiguration;
|
||||||
|
int dw = (int)currentConfig?.width;
|
||||||
|
int dh = (int)currentConfig?.height;
|
||||||
|
if (dw == 0 && dh == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CameraResolution reso = androidResolution;
|
||||||
|
|
||||||
|
if (!m_bCamConfigDone)
|
||||||
|
{
|
||||||
|
m_InitialConfig = currentConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (reso)
|
||||||
|
{
|
||||||
|
case CameraResolution.Default:
|
||||||
|
dw = (int)currentConfig?.width;
|
||||||
|
dh = (int)currentConfig?.height;
|
||||||
|
break;
|
||||||
|
case CameraResolution.HD:
|
||||||
|
dw = 1280;
|
||||||
|
dh = 720;
|
||||||
|
break;
|
||||||
|
case CameraResolution.FullHD:
|
||||||
|
dw = 1920;
|
||||||
|
dh = 1080;
|
||||||
|
break;
|
||||||
|
case CameraResolution.Max:
|
||||||
|
dw = 80000;
|
||||||
|
dh = 80000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var config in configurations)
|
||||||
|
{
|
||||||
|
int perror = config.width * config.height - dw * dh;
|
||||||
|
if (Math.Abs(perror) < bestError)
|
||||||
|
{
|
||||||
|
bestError = Math.Abs(perror);
|
||||||
|
currentConfig = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reso != CameraResolution.Default) {
|
||||||
|
Debug.LogFormat("resolution = {0}x{1}", (int)currentConfig?.width, (int)currentConfig?.height);
|
||||||
|
cameraSubsystem.currentConfiguration = currentConfig;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cameraSubsystem.currentConfiguration = m_InitialConfig;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
m_bCamConfigDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CurrentResults(int localizationResults) {
|
||||||
|
int diffResults = localizationResults - m_PreviousResults;
|
||||||
|
m_PreviousResults = localizationResults;
|
||||||
|
if (diffResults > 0)
|
||||||
|
{
|
||||||
|
m_LatestPoseUpdated = Time.time;
|
||||||
|
m_CurrentResults += diffResults;
|
||||||
|
if (m_CurrentResults > 3)
|
||||||
|
{
|
||||||
|
m_CurrentResults = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Time.time - m_LatestPoseUpdated > secondsToDecayPose)
|
||||||
|
{
|
||||||
|
m_LatestPoseUpdated = Time.time;
|
||||||
|
if (m_CurrentResults > 0)
|
||||||
|
{
|
||||||
|
m_CurrentResults--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_CurrentResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterLocalizer(LocalizerBase localizer)
|
||||||
|
{
|
||||||
|
Localizer = localizer;
|
||||||
|
Localizer.OnReset += OnLocalizerReset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnRegisterLocalizer()
|
||||||
|
{
|
||||||
|
Localizer.OnReset -= OnLocalizerReset;
|
||||||
|
Localizer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLocalizerReset()
|
||||||
|
{
|
||||||
|
m_CurrentResults = m_PreviousResults = 0;
|
||||||
|
m_HasPose = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bc609bf82f8e346d593bc1a41c2b7cb8
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class ReadOnlyAttribute : PropertyAttribute
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2058786f596e5a34bae16afef4229107
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fbaad84308ffb477989e6e185c52e381
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
/*===============================================================================
|
||||||
|
Copyright (C) 2023 Immersal - Part of Hexagon. All Rights Reserved.
|
||||||
|
|
||||||
|
This file is part of the Immersal SDK.
|
||||||
|
|
||||||
|
The Immersal SDK cannot be copied, distributed, or made available to
|
||||||
|
third-parties for commercial purposes without written permission of Immersal Ltd.
|
||||||
|
|
||||||
|
Contact sales@immersal.com for licensing requests.
|
||||||
|
===============================================================================*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Immersal.AR;
|
||||||
|
using Rokid.UXR.Module;
|
||||||
|
using Rokid.UXR.Native;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace Immersal.XR.Rokid
|
||||||
|
{
|
||||||
|
public struct RokidCameraData
|
||||||
|
{
|
||||||
|
public long Timestamp;
|
||||||
|
public int Width;
|
||||||
|
public int Height;
|
||||||
|
public byte[] Bytes;
|
||||||
|
public Pose Pose;
|
||||||
|
public Vector4 Distortion;
|
||||||
|
public float Alpha;
|
||||||
|
public Vector4 Intrinsics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CameraType
|
||||||
|
{
|
||||||
|
NV21 = 2 //ARGB not supported.
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RokidLocalizer : LocalizerBase
|
||||||
|
{
|
||||||
|
private static RokidLocalizer instance = null;
|
||||||
|
|
||||||
|
public static RokidLocalizer Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (instance == null && !Application.isPlaying)
|
||||||
|
{
|
||||||
|
instance = UnityEngine.Object.FindObjectOfType<RokidLocalizer>();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("No RokidLocalizer instance found. Ensure one exists in the scene.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Channels => m_cameraType == CameraType.NV21 ? 1 : 4;
|
||||||
|
public int MultipleLocalizationsCount = 20;
|
||||||
|
public UnityEvent OnMultipleLocalizations = null;
|
||||||
|
public RokidCameraData m_LatestCameraData;
|
||||||
|
|
||||||
|
private bool m_IsInitialized = false;
|
||||||
|
private bool m_MultipleLocalizationEventInvoked = false;
|
||||||
|
private CameraType m_cameraType = CameraType.NV21;
|
||||||
|
|
||||||
|
void Awake()
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance != this)
|
||||||
|
{
|
||||||
|
Debug.LogError("There must be only one RokidLocalizer object in a scene.");
|
||||||
|
UnityEngine.Object.DestroyImmediate(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
NativeInterface.NativeAPI.StartCameraPreview();
|
||||||
|
// 1 = ARGB, 2 = NV21
|
||||||
|
NativeInterface.NativeAPI.SetCameraPreviewDataType((int) m_cameraType);
|
||||||
|
NativeInterface.NativeAPI.OnCameraDataUpdate += OnCameraDataUpdate;
|
||||||
|
m_IsInitialized = true;
|
||||||
|
isTracking = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
base.Start();
|
||||||
|
m_Sdk.RegisterLocalizer(instance);
|
||||||
|
|
||||||
|
Screen.sleepTimeout = SleepTimeout.NeverSleep;
|
||||||
|
NativeInterface.NativeAPI.Recenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Listener of Camera data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="width">preview size width</param>
|
||||||
|
/// <param name="height">preview size height</param>
|
||||||
|
/// <param name="yuvImage">camera image</param>
|
||||||
|
/// <param name="ts">timestamp</param>
|
||||||
|
public void OnCameraDataUpdate(int width, int height, byte[] data, long ts)
|
||||||
|
{
|
||||||
|
Pose pose = NativeInterface.NativeAPI.GetHistoryCameraPhysicsPose(ts);
|
||||||
|
|
||||||
|
// fisheye:alpha,k1,k2,k3,k4;
|
||||||
|
var d = new float[5];
|
||||||
|
NativeInterface.NativeAPI.GetDistortion(d);
|
||||||
|
var distortionCoefficients = new Vector4(d[1], d[2], d[3], d[4]);
|
||||||
|
var alpha = d[0];
|
||||||
|
var intrinsics = GetIntrinsics();
|
||||||
|
|
||||||
|
m_LatestCameraData = new RokidCameraData
|
||||||
|
{
|
||||||
|
Timestamp = ts,
|
||||||
|
Width = width,
|
||||||
|
Height = height,
|
||||||
|
Bytes = data,
|
||||||
|
Pose = pose,
|
||||||
|
Distortion = distortionCoefficients,
|
||||||
|
Intrinsics = intrinsics,
|
||||||
|
Alpha = alpha
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Release()
|
||||||
|
{
|
||||||
|
if (m_IsInitialized)
|
||||||
|
{
|
||||||
|
NativeInterface.NativeAPI.OnCameraDataUpdate -= OnCameraDataUpdate;
|
||||||
|
NativeInterface.NativeAPI.StopCameraPreview();
|
||||||
|
NativeInterface.NativeAPI.ClearCameraDataUpdate();
|
||||||
|
m_IsInitialized = false;
|
||||||
|
isTracking = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public void OnDestroy()
|
||||||
|
{
|
||||||
|
Release();
|
||||||
|
base.OnDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
override public void OnApplicationPause(bool pauseStatus)
|
||||||
|
{
|
||||||
|
if (pauseStatus)
|
||||||
|
{
|
||||||
|
Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnApplicationPause(pauseStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected void Update()
|
||||||
|
{
|
||||||
|
if (m_IsInitialized == false && NativeInterface.NativeAPI.IsPreviewing())
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async void Localize()
|
||||||
|
{
|
||||||
|
var data = m_LatestCameraData;
|
||||||
|
data = await UndistortImage(data);
|
||||||
|
SetPixelBuffer(data.Bytes);
|
||||||
|
|
||||||
|
if (m_PixelBuffer != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
stats.localizationAttemptCount++;
|
||||||
|
|
||||||
|
Vector3 camPos = data.Pose.position;
|
||||||
|
Quaternion camRot = data.Pose.rotation;
|
||||||
|
float startTime = Time.realtimeSinceStartup;
|
||||||
|
|
||||||
|
Task<LocalizeInfo> t = Task.Run(() =>
|
||||||
|
{
|
||||||
|
return Immersal.Core.LocalizeImage(data.Width, data.Height, ref data.Intrinsics, m_PixelBuffer);
|
||||||
|
});
|
||||||
|
|
||||||
|
await t;
|
||||||
|
|
||||||
|
LocalizeInfo locInfo = t.Result;
|
||||||
|
|
||||||
|
Matrix4x4 resultMatrix = Matrix4x4.identity;
|
||||||
|
resultMatrix.m00 = locInfo.r00;
|
||||||
|
resultMatrix.m01 = locInfo.r01;
|
||||||
|
resultMatrix.m02 = locInfo.r02;
|
||||||
|
resultMatrix.m03 = locInfo.px;
|
||||||
|
resultMatrix.m10 = locInfo.r10;
|
||||||
|
resultMatrix.m11 = locInfo.r11;
|
||||||
|
resultMatrix.m12 = locInfo.r12;
|
||||||
|
resultMatrix.m13 = locInfo.py;
|
||||||
|
resultMatrix.m20 = locInfo.r20;
|
||||||
|
resultMatrix.m21 = locInfo.r21;
|
||||||
|
resultMatrix.m22 = locInfo.r22;
|
||||||
|
resultMatrix.m23 = locInfo.pz;
|
||||||
|
|
||||||
|
Vector3 pos = resultMatrix.GetColumn(3);
|
||||||
|
Quaternion rot = resultMatrix.rotation;
|
||||||
|
|
||||||
|
int mapHandle = locInfo.handle;
|
||||||
|
int mapId = ARMap.MapHandleToId(mapHandle);
|
||||||
|
float elapsedTime = Time.realtimeSinceStartup - startTime;
|
||||||
|
|
||||||
|
if (mapId > 0 && ARSpace.mapIdToMap.ContainsKey(mapId))
|
||||||
|
{
|
||||||
|
LocalizerDebugLog(string.Format("Relocalized in {0} seconds", elapsedTime));
|
||||||
|
stats.localizationSuccessCount++;
|
||||||
|
|
||||||
|
if (stats.localizationSuccessCount >= MultipleLocalizationsCount &&
|
||||||
|
!m_MultipleLocalizationEventInvoked)
|
||||||
|
{
|
||||||
|
OnMultipleLocalizations.Invoke();
|
||||||
|
m_MultipleLocalizationEventInvoked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ARMap map = ARSpace.mapIdToMap[mapId];
|
||||||
|
|
||||||
|
if (mapId != lastLocalizedMapId)
|
||||||
|
{
|
||||||
|
if (resetOnMapChange)
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLocalizedMapId = mapId;
|
||||||
|
OnMapChanged?.Invoke(mapId);
|
||||||
|
}
|
||||||
|
|
||||||
|
rot *= Quaternion.Euler(0f, 0f, 180.0f);
|
||||||
|
pos = ARHelper.SwitchHandedness(pos);
|
||||||
|
rot = ARHelper.SwitchHandedness(rot);
|
||||||
|
|
||||||
|
MapOffset mo = ARSpace.mapIdToOffset[mapId];
|
||||||
|
|
||||||
|
Matrix4x4 offsetNoScale = Matrix4x4.TRS(mo.position, mo.rotation, Vector3.one);
|
||||||
|
Vector3 scaledPos = Vector3.Scale(pos, mo.scale);
|
||||||
|
Matrix4x4 cloudSpace = offsetNoScale * Matrix4x4.TRS(scaledPos, rot, Vector3.one);
|
||||||
|
Matrix4x4 trackerSpace = Matrix4x4.TRS(camPos, camRot, Vector3.one);
|
||||||
|
Matrix4x4 m = trackerSpace * (cloudSpace.inverse);
|
||||||
|
|
||||||
|
if (useFiltering)
|
||||||
|
mo.space.filter.RefinePose(m);
|
||||||
|
else
|
||||||
|
ARSpace.UpdateSpace(mo.space, m.GetColumn(3), m.rotation);
|
||||||
|
|
||||||
|
Vector3 p = m.GetColumn(3);
|
||||||
|
Vector3 euler = m.rotation.eulerAngles;
|
||||||
|
|
||||||
|
GetLocalizerPose(out lastLocalizedPose, mapId, pos, rot, m.inverse);
|
||||||
|
map.NotifySuccessfulLocalization(mapId);
|
||||||
|
OnPoseFound?.Invoke(lastLocalizedPose);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LocalizerDebugLog(string.Format("Localization attempt failed after {0} seconds", elapsedTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("No camera pixel buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Localize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void SetPixelBuffer(byte[] data)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (byte* pinnedData = data)
|
||||||
|
{
|
||||||
|
m_PixelBuffer = (IntPtr) pinnedData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector4 GetIntrinsics()
|
||||||
|
{
|
||||||
|
Vector4 intrinsics = Vector4.zero;
|
||||||
|
float[] focalLength = new float[2];
|
||||||
|
float[] principalPoint = new float[2];
|
||||||
|
NativeInterface.NativeAPI.GetFocalLength(focalLength);
|
||||||
|
NativeInterface.NativeAPI.GetPrincipalPoint(principalPoint);
|
||||||
|
intrinsics.x = focalLength[0];
|
||||||
|
intrinsics.y = focalLength[1];
|
||||||
|
intrinsics.z = principalPoint[0];
|
||||||
|
intrinsics.w = principalPoint[1];
|
||||||
|
return intrinsics;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<RokidCameraData> UndistortImage(RokidCameraData data)
|
||||||
|
{
|
||||||
|
Task<(byte[], int)> d = Task.Run(() =>
|
||||||
|
{
|
||||||
|
var result = new byte[Channels * data.Width * data.Height];
|
||||||
|
var r = Immersal.Core.UndistortFishEyeImage(result, result.Length, data.Bytes,
|
||||||
|
data.Width, data.Height, Channels, ref data.Intrinsics,
|
||||||
|
ref data.Distortion, data.Alpha);
|
||||||
|
return (result, r);
|
||||||
|
});
|
||||||
|
|
||||||
|
await d;
|
||||||
|
data.Bytes = d.Result.Item1;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: da24111645ab24d549a37ea7da86304b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "ImmersalSDK",
|
||||||
|
"rootNamespace": "",
|
||||||
|
"references": [
|
||||||
|
"Unity.XR.ARFoundation",
|
||||||
|
"Unity.XR.ARSubsystems",
|
||||||
|
"Unity.EditorCoroutines.Editor",
|
||||||
|
"UnityEngine.SpatialTracking",
|
||||||
|
"Unity.TextMeshPro",
|
||||||
|
"Unity.XR.CoreUtils",
|
||||||
|
"Rokid.Unity.XR"
|
||||||
|
],
|
||||||
|
"includePlatforms": [],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": true,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ff70fce64a3314305977bdf5610ed86b
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Reference in New Issue
Block a user