Add xrapplication project wizard

Added a template wizard with the ability to enable hands,
passthrough, and spatial anchors.

Change-Id: I5f9864f955af3941d283fcfbbbf2949d0385c648
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Nicholas Bennett
2025-02-11 15:36:08 +02:00
parent 1333189adb
commit 5c9d886510
9 changed files with 400 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.qtproject.example.%{ProjectName}" android:installLocation="auto" android:versionCode="1" android:versionName="1.0">
@if %{Hands}
<uses-permission android:name="com.oculus.permission.HAND_TRACKING" />
<uses-feature android:name="oculus.software.handtracking" android:required="false" />
@endif
@if %{Anchors}
<uses-permission android:name="com.oculus.permission.USE_ANCHOR_API" />
<uses-permission android:name="com.oculus.permission.USE_SCENE" />
@endif
<uses-feature android:name="android.hardware.vr.headtracking" android:required="true" android:version="1"/>
@if %{Passthrough}
<uses-feature android:name="com.oculus.feature.PASSTHROUGH" android:required="false"/>
@endif
<!-- %%INSERT_PERMISSIONS -->
<!-- %%INSERT_FEATURES -->
<application android:name="org.qtproject.qt.android.bindings.QtApplication" android:hardwareAccelerated="true" android:label="-- %%INSERT_APP_NAME%% --" android:requestLegacyExternalStorage="true" android:allowBackup="true" android:fullBackupOnly="false">
<meta-data android:name="com.oculus.intent.category.VR" android:value="vr_only"/>
<meta-data android:name="com.oculus.supportedDevices" android:value="quest2|questpro|quest3|quest3s"/>
<activity android:name="org.qtproject.qt.android.bindings.QtActivity" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:launchMode="singleTop" android:screenOrientation="unspecified" android:exported="true" android:label="">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="com.oculus.intent.category.VR"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
<meta-data android:name="android.app.arguments" android:value="-- %%INSERT_APP_ARGUMENTS%% --"/>
</activity>
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.qtprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/qtprovider_paths"/>
</provider>
</application>
</manifest>

View File

@@ -0,0 +1,56 @@
cmake_minimum_required(VERSION 3.16)
project(%{ProjectName} VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
find_package(Qt6 COMPONENTS Core Gui Quick Quick3D Quick3DXr)
qt_standard_project_setup(REQUIRES 6.8)
qt6_policy(SET QTP0002 NEW)
qt_add_executable(${CMAKE_PROJECT_NAME}
MANUAL_FINALIZATION
main.cpp
android/AndroidManifest.xml
)
qt_add_qml_module(${CMAKE_PROJECT_NAME}
URI ${CMAKE_PROJECT_NAME}
VERSION 1.0
QML_FILES
Main.qml
)
if (APPLE AND CMAKE_SYSTEM_NAME STREQUAL "visionOS")
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER io.qt.${CMAKE_PROJECT_NAME}
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/visionos/MacOSXBundleInfo.plist.in
)
endif()
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
Qt::Core
Qt::Gui
Qt::Quick
Qt::Quick3D
Qt::Quick3DXr
)
if(ANDROID)
set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES
QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android"
QT_ANDROID_PACKAGE_NAME "org.qtproject.example.${CMAKE_PROJECT_NAME}"
QT_ANDROID_APP_NAME "${CMAKE_PROJECT_NAME}"
QT_ANDROID_TARGET_SDK_VERSION 32
QT_ANDROID_MIN_SDK_VERSION 32
QT_ANDROID_VERSION_NAME "1.0")
endif()
qt_finalize_executable(${CMAKE_PROJECT_NAME})
install(TARGETS ${CMAKE_PROJECT_NAME}
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>NSHandsTrackingUsageDescription</key>
<string>Hand tracking needed for user input</string>
<key>NSWorldSensingUsageDescription</key>
<string>World sensing needed for anchoring and scene mapping</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<!-- // Uncomment to start in immersive space -->
<key>UIApplicationPreferredDefaultSceneSessionRole</key>
<string>CPSceneSessionRoleImmersiveSpaceApplication</string>
<key>UISceneConfigurations</key>
<dict>
<key>CPSceneSessionRoleImmersiveSpaceApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>ImmersiveApp</string>
</dict>
</array>
</dict>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,100 @@
import QtQuick
import QtQuick3D.Helpers
import QtQuick3D
import QtQuick3D.Xr
XrView {
id: xrView
@if %{Passthrough}
property bool preferPassthrough: true
passthroughEnabled: passthroughSupported && preferPassthrough
@endif
environment: SceneEnvironment {
clearColor: "skyblue"
@if %{Passthrough}
backgroundMode: xrView.passthroughEnabled ? SceneEnvironment.Transparent : SceneEnvironment.Color
@else
backgroundMode: SceneEnvironment.Color
@endif
}
xrOrigin: theOrigin
XrOrigin {
id: theOrigin
XrController {
controller: XrController.ControllerLeft
poseSpace: XrController.AimPose
Model {
source: "#Cube"
scale: Qt.vector3d(0.1, 0.1, 0.1)
materials: PrincipledMaterial {
lighting: DefaultMaterial.NoLighting
baseColor: "red"
}
}
}
XrController {
controller: XrController.ControllerRight
poseSpace: XrController.AimPose
Model {
source: "#Cube"
scale: Qt.vector3d(0.1, 0.1, 0.1)
materials: PrincipledMaterial {
lighting: DefaultMaterial.NoLighting
baseColor: "green"
}
}
}
}
DirectionalLight {
eulerRotation.x: -30
eulerRotation.y: -70
}
// The scene:
Model {
y: 100
z: -50
source: "#Cube"
scale: Qt.vector3d(0.2, 0.2, 0.2)
materials: PrincipledMaterial {
baseColor: "green"
}
eulerRotation.x: 30
PropertyAnimation on eulerRotation {
from: "30, 0, 0"
to: "30, 360, 0"
loops: -1
duration: 20000
}
}
@if %{Anchors}
// Anchors:
Repeater3D {
id: spatialAnchors
model: XrSpatialAnchorListModel {
}
delegate: Node {
id: anchorNode
required property XrSpatialAnchor anchor
required property int index
position: anchor.position
rotation: anchor.rotation
Model {
// Visualize anchor orientation
materials: PrincipledMaterial { baseColor: "white" }
source: "#Cone"
scale: Qt.vector3d(0.2, 0.2, 0.2)
eulerRotation.x: 90
}
visible: anchor.has2DBounds || anchor.has3DBounds
}
}
@endif
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -0,0 +1,15 @@
%{Cpp:LicenseTemplate}\
%{JS: QtSupport.qtIncludes([], ["QtGui/QGuiApplication", "QtQml/QQmlApplicationEngine"])}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
&app, []() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
engine.loadFromModule("%{JS: value('ProjectName')}", "Main");
return app.exec();
}

View File

@@ -0,0 +1,25 @@
; This file can be edited to change the style of the application
; Read "Qt Quick Controls 2 Configuration File" for details:
; https://doc.qt.io/qt/qtquickcontrols2-configuration.html
@if '%{QtQuickControlsStyle}' != 'Default'
[Controls]
Style=%{QtQuickControlsStyle}
@if '%{QtQuickControlsStyle}' == 'Universal'
[Universal]
Theme=%{QtQuickControlsStyleTheme}
;Accent=Steel
;Foreground=Brown
;Background=Steel
@endif
@if '%{QtQuickControlsStyle}' == 'Material'
[Material]
Theme=%{QtQuickControlsStyleTheme}
;Accent=BlueGrey
;Primary=BlueGray
;Foreground=Brown
;Background=Grey
@endif
@endif

View File

@@ -0,0 +1,113 @@
{
"version": 1,
"supportedProjectTypes": [ "CMakeProjectManager.CMakeProject" ],
"id": "U.QtQuickXRApplicationEmpty",
"category": "H.Project",
"trDescription": "Creates a Qt Quick 3D XR application with QML and C++ code. You can build and deploy the application to desktop VR and standalone XR platforms. For the Apple Vision Pro, you can develop in Qt Creator but must deploy the CMake project with XCode.",
"trDisplayName": "XR Application",
"trDisplayCategory": "Application (Qt)",
"icon": "icon.png",
"iconKind": "Themed",
"featuresRequired": [ "QtSupport.Wizards.FeatureQt.6.8" ],
"enabled": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0 }",
"options":
[
{ "key": "ProjectFile", "value": "%{ProjectDirectory}/CMakeLists.txt" },
{ "key": "MainCppFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src') }" },
{ "key": "TargetName", "value": "%{JS: 'app' + value('ProjectName') }" }
],
"pages":
[
{
"trDisplayName": "Project Location",
"trShortTitle": "Location",
"typeId": "Project"
},
{
"trDisplayName": "XR Features",
"trShortTitle": "Features",
"typeId": "Fields",
"data":
[
{
"name": "Passthrough",
"trDisplayName": "Request passthrough",
"type": "CheckBox",
"trToolTip": "Request permissions for passthrough mode.",
"data": {
"checked": true
}
},
{
"name": "Hands",
"trDisplayName": "Request hand tracking",
"type": "CheckBox",
"trToolTip": "Request permissions for hand tracking.",
"data": {
"checked": true
}
},
{
"name": "Anchors",
"trDisplayName": "Request spatial anchors",
"type": "CheckBox",
"trToolTip": "Request permissions for anchors API.",
"data": {
"checked": true
}
}
]
},
{
"trDisplayName": "Kit Selection: For Apple Vision Pro, select any kit.",
"trShortTitle": "Kits",
"typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": {
"projectFilePath": "%{ProjectFile}"
}
},
{
"trDisplayName": "Project Management",
"trShortTitle": "Summary",
"typeId": "Summary"
}
],
"generators":
[
{
"typeId": "File",
"data":
[
{
"source": "CMakeLists.txt",
"openAsProject": true
},
{
"source": "main.cpp",
"target": "%{MainCppFileName}"
},
{
"source": "Main.qml.tpl",
"target": "Main.qml",
"openInEditor": true
},
{
"source": "../git.ignore",
"target": ".gitignore",
"condition": "%{JS: !value('IsSubproject') && value('VersionControl') === 'G.Git' }"
},
{
"source": "AndroidManifest.xml.tpl",
"target": "android/AndroidManifest.xml"
},
{
"source": "MacOSXBundleInfo.plist.in",
"target": "visionos/MacOSXBundleInfo.plist.in"
}
]
}
]
}