ARKit, SceneKit ve Dünyayı Kontrol Etmek

Bu serinin 1. bölümünde, bir 3B modeli işlediğimiz, Xcode'da bir AR projesi oluşturduğumuz, bir AR oturumu başladığımız ve modelimizi genişletilmiş sahnemize koyduğumuz bir iş akışından geçtik.

Bu yayında, çeşitli SceneKit yöntemlerini kullanarak modelimizi eyleme sokmaya başlayacağız ve dünyamızdaki nesnelerle etkileşime girmeye başlayacağız.

Bu yazının projesi https://github.com/AbovegroundDan/ARTutorial_Part2 adresinde bulunabilir.

SceneKit İşlemleri

SceneKit, bir düğüme uygulanabilecek bir dizi eylem sağlar. Bu eylemler hareket, döndürme, ölçeklendirme ve diğer düğüm özelliklerini canlandırmak için kullanılabilir. Aynı anda çalışacak şekilde gruplandırılabilir, birbiri ardına çalıştırmak için sıralanır ve tekrarlanır veya tersine çevrilebilir. Tam liste https://developer.apple.com/documentation/scenekit/scnaction adresinde bulunabilir.

Mevcut projeyi değiştirmeye devam edeceğiz ve hedefimize bazı işlemler eklemeye başlayacağız. Alanımıza bir dönüş ekleyerek başlayalım.

HoverScene'deki addSphere yönteminden sonra, aşağıdaki yöntemi ekleyin:

Bu kodda, Y ekseni etrafında 180 derecelik bir dönüş tanımlayan bir eylem yaratıyoruz. Bu rotasyonun tamamlanması 5 saniye sürmelidir. Sonra bu eylemi gerçekleştiririz ve onu iletilen düğüme ekleriz. Şimdi, bu yöntemi addSphere yöntemimizden çağırmamız gerekir. Yöntemin sonunda, alt düğümü eklediğimiz satırdan sonra aşağıdaki satırı ekleyin:

Şimdi, bu kodu çalıştırırsak, küremizin diğer yöne bakacak şekilde döndüğünü ve sonra durduğunu göreceğiz. Şimdi yapmak istediğimiz şey, bu animasyonu tekrar ettirmek, böylece sürekli devam ediyor.

AddAnimation kodumuzu şu şekilde değiştirelim:

Burada, döndürme eylemini girdi olarak alan sonsuza dek tekrarlanan bir eylem ekledik. Sonra döndürme eylemi yerine, repeatForever eylemini düğüme ekleriz. Kodu tekrar çalıştırın, kürenin artık sürekli döndüğünü göreceğiz.

Hadi küreye biraz pizzazz ekleyelim. Ayrıca biraz aşağı yukarı yuvarlanmasına izin verelim. Bir yukarı kaydırma eylemi, aşağı kaydırma eylemi ekleyeceğiz, bu iki işlemi sıralayacağız ve bunları mevcut döndürme eylemimizle gruplayacağız. AddAnimation yönteminin şöyle görünmesi gerekir:

Şimdi dünyamızın herhangi bir yerine yerleştirebileceğimiz dönen ve asılı bir küremiz var.

HitTestler ve Soyutlamalar

Sahneye biraz etkileşim ekleyelim. Kullanıcının küreleri dünyaya yerleştirmesini sağlayarak sahneyi başlatmak için bir hedef belirleyelim ve ardından etkinleştirmek için öğesine dokunun. Kurallarımızla biraz daha karmaşıklaştığımızdan, sahne nesnelerimizle ilgilenme yöntemimizi soyutlamanın zamanı geldi. Projemizde Nesneler adlı yeni bir grup oluşturun. Bu klasörde SceneObject.swift adlı yeni bir Swift dosyası oluşturacağız.

SCNNode'dan türetilen bir temel sınıf SceneObject oluşturacağız.

Nesnenin yüklenmesini kodun geri kalanından soyutlamak istiyoruz, bu nedenle dosya adını alan bir init () yöntemi oluşturalım. Bu başlatıcıda, yüklemek için kullandığımız kodu dosyadan taşıyacağız.

Şimdi SceneObject'den türeyen bir Sphere sınıfı oluşturabiliriz:

Artık kendisini yükleyebilen bir Sphere nesne sınıfımız var. Onlara dokunduğumuzda küreleri canlandıracağımızdan, HoverScene'deki addAnimation çağrısını addSphere yönteminden kaldıralım. Ayrıca, şimdi tüm yükleme kodlarını Sphere sınıfına taşıdığımız için, Sphere'i başlatabilir ve doğrudan sahnenin kök düğümüne ekleyebiliriz. Son derece basitleştirilmiş yöntemimiz şuna benziyor:

Çok daha temiz!

Şimdi, bir vuruş testini nasıl yapabileceğimize bir göz atacağız. Görüntü denetleyicimizde halihazırda bir dokunma hareketi algılayıcımız var, o yüzden buna bağlanabiliriz, ancak musluklarımızın bir Küreye, başka bir nesneye mi, yoksa hiçbir şeye mi çarptığını nasıl bilebiliriz?

Neyse ki, ARSCNView bize bu konuda yardımcı olabilir. Aşağıdaki yönteme sahiptir:

Onu görünümde bir konumla besleyebiliriz ve bize z noktası ya da derinliği ne olursa olsun, bu noktanın altındaki bir dizi düğümü geri verecektir.

Sadece Sphere nesnelerini almak istediğimiz için hitTest'te döndürülen her düğümün bir Sphere olup olmadığını kontrol eden hızlı bir filtre oluşturalım. Bunu yapmak için, kontrol etmek istediğimiz her düğüm için en üstteki ana düğümü tutmamız gerekir. Node + Extensions.swift dosyamıza geri dönelim ve aşağıdaki yöntemi ekleyelim:

Sahnemizdeki tüm nesneler sahnedeki kök düğümün bir çocuğu olduğundan, o düğüme ulaştığımızda durup, daha fazla kontrol etmemeyi istiyoruz. Özyinelemeli bir yöntem olduğundan, kök düğümün düğümümüzün ebeveyni olduğunu bulduğumuzda durup geri döneriz.

Arkamızda, ViewController'imize geri dönelim ve dokunma hareketi tanıyıcı temsilcimizi değiştirelim. Boş bir alana dokunursak yeni küreler eklemeye devam etmek istiyoruz, ancak mevcut bir alana dokunursak, animasyonunu başlatmak istiyoruz.

Bir dokunuş elde ettiğimizde, sahne görünümümüzde noktayı yakalamak, bunu sahne görünümünün hitTest yöntemine aktarmak ve geri döndüğümüzü görmek istiyoruz. Bir seferde yalnızca bir nesneyle ilgilenmek istediğimiz için, birincisini alırız (isabet varsa), sonra en üstteki ebeveyni kapmak için en üstteki () uzantımızı kullanırız ve bir küre olup olmadığını kontrol ederiz. Öyleyse, animasyonumuzu buna ekleriz. Testimizden herhangi bir sonuç alamadıysak, daha önce yaptığımız gibi kamera önünde yeni bir Küre ekliyoruz.

Devam et ve uygulamayı tekrar çalıştır. Bir küre eklemek için üzerine dokunabiliriz ve sonra hareket etmeye başlamak için herhangi bir küreye dokunabiliriz. Ancak tanıttığımız bir hata var. Bir küreye dokunmaya devam edebiliriz ve animasyonlar nesneye her seferinde eklenmeye devam eder. Test edebilir ve kürenin daha hızlı döndüğünü ve her dokunduğunuzda daha hızlı yukarı ve aşağı hareket ettiğini görebilirsiniz.

Animasyon küreye özgü olduğundan, addAnimation kodunu Sphere'in kendisine taşıyalım ve yeniden canlandırmak için () yeniden adlandıralım. Node.addAnimation yerine, sadece addAnimation öğesini çağırabiliriz. Ayrıca Sphere sınıfına, animasyonu eklemeden önce kontrol edeceğimiz bir bayrak ekleyeceğiz ve ilk eklendiğinde doğrulayacağız:

Geriye kalan tek şey, bu yeni aramayı kürenin kendisinde çalıştırmak için jest geri aramamızdaki kodu değiştirmek.

Artık hepimiz bu bölüme hazırız. Dünyaya yerleştirebileceğimiz, animasyonu başlatabilmemiz için bazı etkileşimler eklediğimiz ve kodu biraz temizlediğimiz bir alanımız var.

Ekstra kredi

Dünyaya bir küre yerleştirme şeklimiz oldukça ani. Biz dokunun ve aniden orada. Bu işleve biraz pizzazz ekleyelim ve yerleştirdiğimizde küreyi canlandıralım.

HoverScene'deki addSphere yöntemimizde, bir ölçek efekti ekleyelim. Küreyi eklediğimiz zaman ölçeğini harekete geçireceğiz ve standart bir doğrusal ölçek kullanmak yerine hemen çıkma ya da etki bırakma etkisine gireceğiz.

AddSphere yöntemimizi aşağıdakine değiştirelim ve bize bu sıçramayı sağlayacak olan easeOutElastic zamanlama işlevini ekleyelim:

Şimdi bir küre yerleştirmek için dokunduğumuzda, oldukça havalı bir animasyon efekti elde ediyoruz.

Ekstra kredi, kısmen deux

SceneKit ile pek çok şey yaptık, ancak ARKit'in yapabileceği bazı şeylerin yüzeyini aldık. Daha fazla ARKit işlevine geçmeden önce hızlı bir tanıtım olarak, küreyi kameraya "bakarak" yaparak sahneye biraz eğlence ekleyelim. Oluşturucunun updateAtTime yöntemine zaten kancaları takıldık ve oradaki kameraya da bir referansımız var. Sphere sınıfına belirli bir yöne bakması için bir yöntem ekleyerek başlayalım. Kürenin “gözü” zaten nesnenin ileri yönü olan negatif Z ile karşı karşıya. Yapacağımız şey, “gözümüzün” karşı karşıya kalacağı bir noktayı işaretleyen bir vektör alan bir yöntem oluşturmak.

Bu kodda, küre ve hedef (kamera) konumu arasındaki mesafeye bakarız. Bir miktardan azsa, hedefi görmesi için gözü canlandırırız. Göz kameraya bakıyorsa ve kullanıcı bu mesafeden daha uzağa giderse, “devriye” animasyonumuza gireceğiz. Bu kodda dikkat edilmesi gereken bir husus, “LookAt” animasyonu uygulamak için kullanışlı bir SCNAction olmadığı için, görünümümüzü (at :) çağrısını hareketi hareketlendirmemize izin veren bir SCNTransaction içine sarmamızdır. Unity veya Unreal gibi özel 3D oyun motorları bu şeyler için kolaylık işlevlerine sahiptir, ancak SceneKit henüz bu düzeyde değildir.

TargetPos SCNVector3'te iletilen bir mesafe araması olduğunu fark edebilirsiniz, ancak bu yöntem SCNVector3 için mevcut değildir. Yapacağımız şey bu mesafe araması için yeni bir uzantı eklemek.

Bu kodu yeni bir UtilityExtensions.swift dosyasına koydum, ancak istediğiniz yere koymaktan çekinmeyin.

Ardından, bayrak kontrolünü kaldırmak ve sahne denetleyicimizdeki her karede bir yöntem çağırmak için updateAtTime yöntemimizi değiştirmemiz gerekecek. Sahne denetleyicimiz, mesajı sahnedeki tüm Sphere nesnelerine göndermekten sorumlu olacak.

HoverScene'de, yalnızca Sphere nesnelerine filtre uygulayacak ve devriye yöntemini çağıracak makeUpdateCameraPos yöntemini oluşturacağız.

Küreleri biraz daha uzağa yerleştirmek için yerleştirme yöntemimizi de değiştirelim. DidTapScreen yöntemini, küremizi 1 yerine 5 metre uzağa yerleştirelim:

Sphere sınıfımızda, göz bakışını 4.85 metreye çıkarmak için eşiğimizi yapalım:

Ayrıca Sphere animasyonumuzu, etrafa bakmayacak şekilde biraz etrafa bakacak şekilde değiştirelim.

Float.random basitçe olan bir başka uzantıdır:

Bir deneme yap ve bazı küreler koy. Kendilerine, dokunmalarına gerek kalmadan kendi başlarına canlandırmalılar. Her birine yaklaştırın ve gözlerini size çevirdiklerini görmelisiniz. Daha ileri yürüyün ve bölgelerini devriye gezmeye geri dönmeliler. Şimdi, distopik bir geleceğin doğusundaki bir sahnemiz var, gözlerimizi her hareketimizi izliyor.

ARKit eğlencesi için bizi izlemeye devam edin!