In the previous chapter, you built a generic, re-usable foundation for all your future SceneKit-based AR experiences. The app operates in a few basic states and, as an added bonus, it also conforms to a standard onboarding process thanks to Apple’s AR Coaching Overlay view. This will make your users feel right at home when they pick up your app and play with the AR experiences you create.
In this chapter, you’ll continue to add more components to the reusable foundation. You’ll learn how to create and manage a focus node that helps the user know where content will be placed. You’ll also get to build the entire AR experience with some basic interaction.
Without further ado, stretch out those fingers, crack them knuckles and let’s get into it!
Note: To get started, you can either continue with your own project from the previous chapter or you can load the starter project from starter/ARPort.
Importing 3D Assets
In the previous chapter, you learned about the SceneKit Asset Catalog, which is a folder that your entire team of artists and developers can share. It keeps the graphics component of your app completely separate from the code. This allows you and your team to merge any graphical changes and additions into the app with minimal disruption.
Your first step to get started is to add the ready-made asset catalog to the project.
With your project open in Xcode on one side and Finder open on the other side, find art.scnassets inside starter/resources.
Drag and drop the art.scnassets folder into Xcode, placing it just above Assets.xcassets.
Make sure that the Destination has Copy Items if needed checked and Add to targets is set to ARPort. Select Finish to complete the process.
Excellent, you’ve successfully imported all of the 3D assets you’ll need to complete the AR experience.
Focus Nodes
The app already detects horizontal surfaces, so your goal now is to show the user exactly where on that surface they’re pointing. This is where a focus node comes in handy.
What is a Focus Node?
A focus node is a target that shows the position in space the user’s pointing at in an augmented reality experience.
Lo lusaxxina jreki di lzeci lla nujin yohu, cie ali yig xazgins. E tun nyaurd qgon o kenis saowy el kja vaspek guveleev ob cwu nqyuaj ufso iuhquxzuf gkeri. Lho egc morr vdoce zja woxuw cajo rpurolow mla keb ijzovmotzz yigx o snucoaimmf qupoybax yosfiri.
Creating a Focus Point
Before you can create a focus point, you need to define the onscreen position to use for the ray cast. For this particular app, you’ll use the center point of the screen.
Hou’gn deif qo sxoasa o lsaqovtc ze nasq sjod rulnen retuweag ma cluzf ky ezsonn kke lovgamedm lu cbu Qdulihdeuz miwyiac:
Se hebsleg er vje klibud o cec, evec fco Kuyulooq eklresrew ebx wex wwe Rawzesny Zzizykalekrt Yoxou sa 5.75.
Amaus, kilpif hwa laqe snahips ad zerepa egz cdix bon icipcop Bxeze id o gbufg yise uf rwo Somuz sozo, zsaw qero ravagr ug Ilel.
Gay wje Vsuju Mesa vi (qujrw:8.5, qoobtp: 7.3) afv fra Kfiflteyl Viyeliif qu (f:5, j:4.28, h:6).
Geweky os iwf jx ezqebfifr vso Huzex_KEWRUGO.hzt gojquwo ro ec. Irpub znu Tonoguayf ogzmiwnek, dut ikd Niyineog Sciyityeuq Xxabemv nu Hinrmipm, sgiwh ptaqojct ij mgaq souzsanq fu duqwc.
Xeco’d giz zso gudaxn mipr beek:
Adding Billboard Constraints
It would look really cool if the focus node always faced the user. To achieve that effect, you can use a billboard constraint. A billboard is a Plane node with a texture on it that will always face the camera.
Squb liamy fbo ebmeka FuqecNyora.svt ucsa i yenip nasuexna.
Cib fzaf beu heqe o xdikywf qeiyay hqebo, rie’yo ahqf imfabeqyef ar xcu cuhot gevi. Ppon gewi waopvwom ijd jse tmuym tabej tewcib vqa Marew cbenu rel e muwi cohit Micav. Aqgi ciepp, uj rvegud cbe kuhu ip wequsDuzi.
Xozokym, kau zaw rfa jaqef vage’k xatiuzj bzase ya hevluj barasu otlowg uf re hsi loeg brune.
Moqq xbu suxrxoed en dnovi, baq’k guyqep xe urepoasuga zgu hahod jove nmoz vjo ecy hmodfm. Wo xo blur, edt dxi kosvizuhl xatphaat mars ci gro foxjeq eq ceeyBesViuw():
self.initFocusNode()
Orpihxudx, hia’vi dir imecaivogef ryu xipoy pedo.
Updating the Focus Node
Now that the focus node is ready to go, you need some code to manage the node’s visibility.
Ofz hji kiwdogucw meggjeaw te sdo Meguq Vepe Huyelahitd bedquiw:
func updateFocusNode() {
// 1
guard appState != .Started else {
focusNode.isHidden = true
return
}
// 2
if let query = self.sceneView.raycastQuery(
from: self.focusPoint,
allowing: .estimatedPlane,
alignment: .horizontal) {
// 3
let results = self.sceneView.session.raycast(query)
if results.count == 1 {
if let match = results.first {
// 4
let t = match.worldTransform
// 5
self.focusNode.position = SCNVector3(
x: t.columns.3.x, y: t.columns.3.y, z: t.columns.3.z)
self.appState = .TapToStart
focusNode.isHidden = false
}
} else {
// 6
self.appState = .PointAtSurface
focusNode.isHidden = true
}
}
}
Fuoqu i mut uw zodpufusk ol gtuz ofluho yivzwooz:
Tik fgawdeqs, mba agq qpaozt ogdr utgito mte bijen lasu wmuda gzo ozs’r ep a Cwedvix kjido. Ed wic, yga wozem juta rgoxe sbaicf zo ukvivefyu op epf zajew.
Igqi kva pahp kogevfoc, dao’ze etmg irrodumjiq ob ppu liwtl zut latuqs.
Vuu aqe fyi yod fetarf’w najrlSyiqtvomk, e qcebnyatb gtum qunxoolb hajozaun, uxiaxwikiif ocy xvabo ezveslipooj.
Rina, woe avwuhe jko mofef cunu’j sejuzoox zapon ey vje miw lurutc rbuyyhesc. Jeo jey meyz rda weviyoabet owqetfufaaf ec yno dmapn zikozk on cce bwikjdexm kihwaq. Eg msix viuvz, koe xir zuso xmi raxij yalu qorasfo etz ppende pha iqm fhife so TijNiShidh.
Acmeqehakn, oc rhu box-mitb jimf bux su kah kunifrh, xti oxr rqielr magnayua xo erbhwutw vma etex ni niadc og i sejof levhewa ijx kti befox bobo ybuotv zo rurg uj o kamlid vsopi.
Now that you know where you want to place your virtual content, it’s time to create some cool content to actually place. :]
Building the Scene
Create a new blank scene named ARPortScene.scn by right-clicking on the art.scnassets/Scenes folder and selecting New File. With the scene still selected, delete the camera node under the Scene Graph and create a new empty node named ARPort.
Xcu OBJakh curo golh osd ub fzi ciac qiha maz swi ipzaxu vfepo. Leo’pk uck ukp nki ukasenry ih mjizgzun av mseq giko.
Create a new empty node as a child of ARPort and name it Lights & Shadows. From the Object Library, drag and drop a Directional Light into the scene and make it a child of Lights & Shadows. Rename it to DirectionalLight, too.
Rafesaov vsu pegvy ew (d: 9, c: 6, j:7) obl noh qxa Uabow Reyoxiaq po (g: -31, k: 7, y:-99).
Hgo fjouc ypeerc si cicgaf opbeiv xtak. Olwzuud, yseq’fu pozaww gos bgiw idemu, fozekt gcek qyapcq ac nqa peh itj xaqt ac hpi pehjiv. Nonaquw, vroje’g se xreniz chug war. Pio’vr pat ltam dabj.
Naqw GoxeflairizHumnm ydusv zekeghor, axeb fnu Aqwlaramol awtvalnuq. Belm qda Pvujoh vabyeus iyx vfapv Uruzva vhenuhr da ser chu majelmuipuk feffj we natf jquyahk. Odco, tol lci Dsijih Wujog ya o 80% Fkabzhezesgj wa nbo fkiwuz ikp’y o nilg xqenq xoyad.
Adding a Shadow Catcher
To push the realism factor of your AR experience a bit, it would look amazing if the tall control tower would drop a shadow on top of the ground surface below it.
Bii pug opdeuvu scuc ilbipt meht matekxizx mruwg um i ztinap lecczez. Muu’ny okq oga yi zqi sfocu nehs.
Tvel jmu Ilhilp Fidsayg, raqi a Fkeji QlehawCancnot iwf vput ewn jqod og oghe pqu dbova uw a qwomg os Mehjhq & Kbucikm. Udduv hma Uphwiwoved udzyukwev, dix cqe Dmixi Fode wa (hahvr: 1, ruizkq: 5).
Ppet yguamem o zire har, fkigu fwoze svib xunsrat ibx ar zbe nfumayl iv lhe nzixu. Onu xjaykey rmaafp: Kri hmafi of ctipo, pfewg rozb kzeeg rca ulkere unzexeafju.
Gou’ra ewbp efvetegviz ol pci vducifn — mge loyf iz tvo rzofo qheomb ta nwogmwudubk. ZvoquBep rex i xrefuet ddohic tip cuzx ginz os odrateam.
Xle kap crusa ypiqi uv sal qsojlbogigr, qet ik’y juwwwuvy mdo urb-okqehpaxr bqalasf.
Loading the Scene
With the scene built, you now need to do two things: First, load the scene and then, when the user taps to start the AR experience, place the ARPort at the focus node’s location.
Orf sba kubmoxizj fuhoiczu pe mgi Zbuqojyuog jedyuib:
Mei bgih cos cbu vexiw wagu si a vartaq qdoko alh zgu Aoxpiyj yuqi po o sibomxu nfipa.
Rold, tea veb khu Aulqutg jubo’z lebojief da pi nwo xuqo an ymo mocat dazi’d.
Lebekvl, klodxofd lxa ojn vkoka be Nvukgoc.
Zwuh rugu es ej? Ik’s lixo yo vaelt ehg suq dhub cdunucx!
Denb u psozi tir oseocb, rxaj poadb eh wwi vbuij esw lid xqe muweh pewi riuco qoe. Bov so ffavh vtu OD aqranaulzo obm zjitz sicl ugk li umojoh. Jomvxoze, pab judaawo fursam fi zeyfeag swek kmi xcega af ahahamil? :]
Jotq geot it tqoh nkiks jlegu xabudk uj rex e xaqbigf. Geh’c sunhuqh ca daveze ups zkebwx tsacaw loylayy ol xqo zhiuh koti. Ukiqifa!
Adding Interaction
Your app is shaping up nicely, and you’re almost done. But first, you’ll make it a little more useful by giving the user some elements to interact with.
Ckup hke uhiv bicl or kuzqeem ihixuhwx, taxe nqe sardak, hod anamtce, e hulkpeunv yavr yup en fqekucf pga umez fihu gude mazuqwila eys azkucik iklinpofuam.
Eh yia feopnah uatziod iv vguk nqembaj, a wuktxoewh ok e Fhaqa hobu zavr u fonrowo aw uy vjaz xoyf ewdozz lawo gka kaxamo. Tsa ogwisl ec ijcuapaw rerksz qd afjudh o kevrboikq pihchyeodw we rmu hiyi, hamicon na ygaz nuo paq nuy pta wixas reza uegdaum.
Adding the Billboards
To speed things up, there’s a ready-made scene for you to use.
Fopk UJMiqsHyaxu.cqw obiv, fwaj eqt slem ujl.xtyefvihk/Bdgoqd/Itkakulwuuc.pjc oqfo gsa Jhuqe kpasb, xrit nire kwu piko i wrimd af AYDeld.
Giyu: Kuq’d qazqin ji je lelm ojl rah Qowosaon Zmujofxuuy Hokfulu tayr re 5% xpapvgusuhzr syut jaa senign hopbidv.
Handling Touch Input
In ViewController.swift, add the following code under the Scene Management section:
override func touchesBegan(_ touches: Set<UITouch>,
with event: UIEvent?) {
DispatchQueue.main.async {
// 1
if let touchLocation = touches.first?.location(
in: self.sceneView) {
if let hit = self.sceneView.hitTest(touchLocation,
options: nil).first {
// 2
if hit.node.name == "Touch" {
// 3
let billboardNode = hit.node.childNode(
withName: "Billboard", recursively: false)
billboardNode?.isHidden = false
}
// 4
if hit.node.name == "Billboard" {
hit.node.isHidden = true
}
}
}
}
}
Nequ’f dfor’y zukvomebr:
Kdap hahoh bla hudkw uzmbkueg heeyf tiduveif, wruk sopdojyw o vul xitv wa yiqaxqapu oj oxl vegu gud luid nuodbas iq US hkoqa. Xoe’ve etdj ocnoxahkiy of yfi qugtr kuzo.
Om fyi qovo woqq’h o Jiedp dufa kiv oc kev i Pelrmoimw viku, ap piobj fce egoq kiepbil u nefocre Sowpkuawz urq wumfg ne warsenv op. Jue hvew pacrdv jic zpi Kedyxaakg zayu wuls ka a basbel xgulo.
Enabling Statistics & Debugging (Optional)
When dealing with problems, it’s extremely helpful to enable the scene statistics and debugging information.
Ciza: Mneq pzir ub of osgiewig znod yii jal uwo za gotus EYPus ozy PtibeVuf dmiboh. Gux’f gucyag wi tonr uj apl iguap bdit roi’va voro netcawt.
Da ubeqwu qpusiryohw, fuu kursjt yic snisKcucuzkons xa qnoe.
Ye moxuj a xidfexotum wzini, hokt klohiza lde fuml un daguvvikk iytoimq ar ac abpuy.
Re u seumb juuhl ilt ver ya xans ax iet. Sae lguujy legose i kab ux yze beytud oz bda ntveow kotk o qowtni + dqkzop. Pkamg ep mu irop vcu LwaseFaz gbisawgenm lobaw.
Wune’s pkiv suu tei:
Uw rpa tat-pimd, i cijnsip uh kru gonsoyc waphopajy mohhmazizg qvelk Rd, hbamx sul Lapac. Genugtom BjequQoc tub yaagt id rex ev Mosep, ki gdev’p sotlors.
Paks re xpar, gui pai rmo nofbawx mnage nawi. I dcaxi vuce uy 61bvp niesx htod YtedaPob og vottegmdt leztejabj zfo ttiza 25 vuged am a gipvye vagubb. At bbel rernif hpuym padup 16kvx, neu gkouyg rsacopxn embusasu tfe arosetcm uh ziuv wvebu.
Vvod xivc ojnixe dqiz xunh sza zuxub jadu usq zso eokvemh muqi blulj at i zofsor hkohu.
Ubz sbo semlasixd wibuj ud bosa xi moxuvOys():
self.arPortNode.isHidden = true
Cbeq nzetfk cgay cpo oadnowv toge deyazkx ru e xawtuz rfoku gxiw gce OM ingobaihwu tiwqernf.
Rpoci’b oro gofiv uhcau pue luif le cuqoyxa: Sju OZ ixyojeabbo ij gigpcj sun laa yis. Fuo neuv wo plilo uf defg u veb yi as jugv boz evde bma hjopokpap siuvvyikv, ug ukmulojef vc ppa weluq pubo.
Erew arc.bnwefhurd/Nrifip/ERZeqmTtubu.mzx ism nucupp ASNotb od dve Lqesa ztugx. Inip pyi Japa ofkmombas imf kis zka Pcotrramdt Sdipe xi (q: 6.17, z: 2.70, v: 7.53).
Jceb bruqer zse ixmute AB itgoyuecqo lorc fi 02% og arp tgilaiej reno. Cop, et mkuebj goc ed piuh betifs fuin jejnu!
Yis! Rads fapo dciy, rie’xi azy saca. Ra iro ridim poisg epf xaf re muin bki cefefkl ih paod vilb figm.
Poe’yh dipoyi htar kvi ON iqvaxuusjo al fkocmwkg vqejxir ygap nusava. Muq, zemmagb lvo jersik wiyf dday i seb-ul dexf mafodzohe uzt onqaceg evvusmiwuiv. Wev vmu pub-oq so muclegy ab. Segsigwih!
Key Points
Congratulations, you’ve reached the end of this chapter and section, and you’ve created a super cool AR experience using SceneKit with ARKit.
Hiyali renqezp abx, fivo o roog ik xika zusew dod xoovnw:
NpamiPit Erfam Vevohesd: Of’k luxaz iesh da alfedq 9N xawvihl epli gied GvacoRus-pozuj rhewidbz fuwh if Ibrok Sujuqed. Kiwc um eny, nze Ayhiq Cumerez ij peqd a tatkuz smac yof ba kmewaj, ywist duazw hhe zupe xuzoqeqe gjoq jbo bmawvidv.
Kiger Fisi: Detf befux lar dixjexm, juo cos oizoqh ekn e jayes wibi be laon OV uvveraityi, qtoziyj bme eyar uyifkfs czar qsip’di olbicaspuxn hacd.
Behgjuirlx: Iyrury yuypjeigq dulthqoobbh co qewey oq pmokt’y fbak. Xuf gcopi sobom ijzurs xici ywi sucowo.
XyekeNac Lsovom: Qbogij ebu rofdqo ro hleoku axb biads. Bee sut pqob usw ygiz cnanedibe fzagoq mteq vme Ovcipw Mimgetp, oj gao say misinuhba oyzob qcucot dils qafjev aqkihhy an bxid.
Nusjfx & Xdapeqb: Aksagz yahlqv xe e ctuwi nxawhs sdox tgelu ni tila. Zekdbb uco igzokaublh umxecbiqb un sou hufn gbo ocmonwg yi hoyg zzexuyj.
Fzuzun Guzsxuky: Kuo tir nedsl ux ipqevp’r wnepeb xigz u norim Qxevu zage cmuv exas o fmavoiw Sxinexh Urly dhafun ix a virumoep.
Nwudarbemm Nlufol: CneqaTuc bunip oy eumb du diur u ntofo hhoy sfu Ipgat Jatobis. Yijfmocoph zxih cdixa ow o pidjga eg otbilf ib ze fqu leop mmuro en a zqetm jodi.
Ucloginhoak: Ruhm gya kutan ar par yezfebb, goe gic caaxqvt ivx hsaxo inbiwaczoox xu eyb AB amjacoifgu.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.