OK - I've figured it out.
The EmissionDuration needs to be set low - I had it at 10 seconds, which means I could be waiting between 0...10 for it to start.
Post
Replies
Boosts
Views
Activity
I have worked out that you need to take the channel values from the underlying cgColor to make this work:
extension UIColor {
var float4: Float4 {
if
cgColor.numberOfComponents == 4,
let c = cgColor.components
{
Float4(Float(c[0]), Float(c[1]), Float(c[2]), Float(c[3]))
} else {
Float4()
}
}
}
Hello,
I've tested this and am still unable to get it to work, with the following focused test:
import GameController
import SwiftUI
struct ContentView: View {
@State private var gamepadNotification: NSObjectProtocol? = nil
@State private var keyboardNotification: NSObjectProtocol? = nil
@FocusState var focused
var body: some View {
VStack {
Text("Hello, world!")
}
.focused($focused, equals: true)
.handlesGameControllerEvents(matching: .gamepad)
.task {
try? await Task.sleep(for: .seconds(1))
focused = true
print("Setting up notification for controller connections")
gamepadNotification = NotificationCenter.default.addObserver(
forName: NSNotification.Name.GCControllerDidConnect,
object: nil, queue: nil) { note in
print("Handling GCControllerDidConnect notification RV")
}
keyboardNotification = NotificationCenter.default.addObserver(
forName: NSNotification.Name.GCKeyboardDidConnect,
object: nil, queue: nil) { note in
print("Handling GCKeyboardDidConnect notification RV")
}
GCController.startWirelessControllerDiscovery{}
}
}
}
I have set up the following in info.plist
<?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>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationPreferredDefaultSceneSessionRole</key>
<string>UIWindowSceneSessionRoleApplication</string>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict/>
</dict>
<key>GCSupportsControllerUserInteraction</key>
<true/>
<key>GCSupportedGameControllers</key>
<array>
<dict>
<key>ProfileName</key>
<string>MicroGamepad</string>
</dict>
<dict>
<key>ProfileName</key>
<string>ExtendedGamepad</string>
</dict>
<dict>
<key>ProfileName</key>
<string>DirectionalGamepad</string>
</dict>
</array>
</dict>
</plist>
On vision OS 2.1 I am seeing the following on the console:
Setting up notification for controller connections
Handling GCKeyboardDidConnect notification RV
i.e. I can setup the keyboard connection handler, but not the gamepad connection handler
————————————————————————————————————————
On vision OS 2.2 I am seeing the following on the console:
Setting up notification for controller connections
i.e. now the keyboard connection notification is not working.
Even though I am not able to setup either a keyboard nor gamepad connection event handler I am however able to control the simulator with the controller. i.e. the controller is connected and can pan and move the simulator with the controllers joysticks.
————————————————————————————————————————
Here’s the version numbers of the dev tools:
Simulator: Version 16.0 (1038), SimulatorKit 942, CoreSimulator 993.7
XCode: Version 16.2 (16C5031c)
visionOS on simulator: visionOS 2.2 (22N840)
I am running into the same issue now with Xcode 16.1 and MacOS 15.2
I think the full solution would require this to be wrapped in a TimelineView to work? Something such as:
TimelineView(.periodic(from: .now, by: 1)) { context in
VStack {
Model3D(named: "quantumComputer") { phase in
switch phase {
case .empty:
ProgressView()
case let .failure(error):
Text(error.localizedDescription)
case let .success(model):
model
.resizable()
.scaledToFit()
.offset(x: -100, y: 0)
.rotation3DEffect(
Rotation3D(angle: Angle2D(degrees: 1 * context.date.timeIntervalSinceReferenceDate),
axis: .y
)
)
/// Other code in here
}
}
Thank you for your reply. I've replicated these steps and have the effect working as described.
Could I ask a clarification though...
This approach requires each model to have its shader graph updated in Reality Composer Pro to give it this capability. I understand that I could create a re-usable node graph if I wanted to have a more complex effect (the colouring was just a simple effect for sake of the question) - yet still each entity would need updating in Reality Composer Pro to wire it in.
Thus, just to be sure, there is no way to create a shader that can be applied to any model entity. I see RealityKit provides CustomMaterial, which can be setup with a shader, but this is not available in VisionOS at present?
CustomMaterial
I am seeing exactly the same. I have a 'LazyVStack' enclosed in a 'ScrollView', in which I can be displaying thousands of elements. Definite slow down. I've pulled my code apart and still can't get an improvement.
Hey, Thank you! Phil
Thank you! I have a few clarifying questions:
When in kinematic mode is the ModelEntity ignored for collision detection?
When I add an entity to RealityView's content, via .add() what Anchor does this attach it to? If I have an anchor with multiple ModelEntities attached, they each have to be added to the content to be picked up by the physics engine? But when I do this, they ignore the anchor's translation and default to the world view.
And finally, when simulating something like a bullet/arrow, is it better to use a TriggerVolume component for efficiency?
I have worked out the issue. On iOS one needs to set up an NSMetadataQuery in addition to using a NSFilePresenter. Something like:
let metadataQuery = NSMetadataQuery()
metadataQuery.notificationBatchingInterval = 1
metadataQuery.searchScopes = [NSMetadataQueryUbiquitousDocumentsScope]
metadataQuery.predicate = NSPredicate(format: "%K LIKE %@", NSMetadataItemFSNameKey, "*.txt")
metadataQuery.start()
And then establish a process to listen for changes. For example using Combine:
NotificationCenter.default.publisher(for: .NSMetadataQueryDidUpdate)
.receive(on: DispatchQueue.main)
.sink { [weak self] notification in
guard let self = self else { return }
self.metadataQuery.stop()
for resultSets in 0..<self.metadataQuery.resultCount {
if let resultSet = self.metadataQuery.result(at: resultSets) as? NSMetadataItem {
/// DO YOUR MAGIC HERE...
}
}
self.metadataQuery.start()
}
.store(in: &backgroundProcesses)
OK - my bad! I set-up a separate project, away from my main code base that test running multiple FileManager enumerations in parallel (using Tasks) and it all worked...couldn't provoke it no matter how hard I prodded it. And then my eyes flicked back to my main code and a small dim light bulb in my head went on....four hours later I've tracked down a somewhat subtle bug in my code.
thank you for your responses!
Is this the same problem that's impacting the following code snippet:
let urls: [URL] = [url1, url2, url3, ... ] // Image we have 1,000s of URLs here
await withTaskGroup(of: CGImageSource.self) { taskGroup in
for url in urls {
taskGroup.addTask { return CGImageSourceCreateWithURL(url as CFURL, nil) }
}
var results = [CGImageSource]()
for await result in taskGroup {
results.append(result)
}
return results
}
I don't have a way to await the call to CGImageSourceCreateWithURL - this code blocks up.
I've resorted to prefixing any console output with a unique string, say peggers then filtering this in the console window. The issue is though that I might miss an important output from somewhere not in my code, drawing my eye to an issue. But such output is swamped anyway at the moment.
Having looked and thought carefully about this, I have found that adding Task.yield() solves the issue, as I proactively await:
final class NewFileCounter: ObservableObject {
@Published var fileCount = 0
func findImagesInFolder(_ folderURL: URL) {
let fileManager = FileManager.default
Task.detached {
var foundFileCount = 0
let options = FileManager.DirectoryEnumerationOptions(arrayLiteral: [.skipsHiddenFiles, .skipsPackageDescendants])
if let enumerator = fileManager.enumerator(at: folderURL, includingPropertiesForKeys: [], options: options) {
while let _ = enumerator.nextObject() as? URL {
foundFileCount += 1
await Task.yield()
if foundFileCount % 10_000 == 0 {
let fileCount = foundFileCount
await MainActor.run { self.fileCount = fileCount }
}
}
let fileCount = foundFileCount
await MainActor.run { self.fileCount = fileCount }
}
}
}
}
Quinn - that's super helpful. Thank you!