An Introduksjon til SceneKit: brukermedvirkning, animasjoner og fysikk
19
Del
en
Del
Dette Cyber mandag Envato Tuts + Kursene vil bli redusert til bare $ 3. Ikke gå glipp av.
Hva du skal lage
Dette er den andre delen av vår innledende serie på SceneKit. I denne opplæringen, antar jeg at du er kjent med begrepene forklart i den første delen, inkludert å sette opp en scene med lys, skygger, kameraer, noder og materialer.
I denne opplæringen, jeg kommer til å lære deg om noen av de mer kompliserte-men også mer nyttig-funksjonene SceneKit, for eksempel animasjon, brukermedvirkning, partikkel-systemer, og fysikk. Ved å implementere disse funksjonene, kan du lage interaktiv og dynamisk 3D-innhold i stedet for statiske objekter som du gjorde i forrige tutorial.
1. Sette opp Scene
Opprett en ny Xcode prosjekt basert på iOS > Application > Enkel visning Application mal.
Navn prosjektet, satt språk til Swift, og enheter til Universal.
Åpne ViewController.swift og importere SceneKit rammeverket
. Import UIKitimport SceneKit
Deretter erklærer følgende egenskaper i ViewController klassen
Var sceneView:.! SCNView Var kamera! SCNNode Var bakken! SCNNode Var lys! SCNNode Var knappen! SCNNode Var sphere1: SCNNode Var sphere2: SCNNode < p> Vi setter opp scenen i viewDidLoad metoden som vist nedenfor
styre func viewDidLoad () {super.viewDidLoad () sceneView = SCNView. (ramme: self.view.frame) sceneView.scene = SCNScene () selv. view.addSubview (sceneView) la groundGeometry = SCNFloor () groundGeometry.reflectivity = 0 la groundMaterial = SCNMaterial () groundMaterial.diffuse.contents = UIColor.blueColor () groundGeometry.materials = [groundMaterial] bakken = SCNNode (geometri: groundGeometry) la Kameraet = SCNCamera () camera.zFar = 10000 self.camera = SCNNode () self.camera.camera = kamera self.camera.position = SCNVector3 (x: -20, y: 15 z: 20) la begrensningen = SCNLookAtConstraint ( target: bakken) constraint.gimbalLockEnabled = true self.camera.constraints = [begrensning] la Ambient = SCNLight () ambientLight.color = UIColor.darkGrayColor () ambientLight.type = SCNLightTypeAmbient self.camera.light = Ambient la Spotlight = SCNLight ( ) spotLight.type = SCNLightTypeSpot spotLight.castsShadow = true spotLight.spotInnerAngle = 70,0 spotLight.spotOuterAngle = 90,0 spotLight.zFar = 500 lys = SCNNode () light.light = Spotlight light.position = SCNVector3 (x: 0, y: 25, z: 25) light.constraints = [begrensning] la sphereGeometry = SCNSphere (radius: 1,5) la sphereMaterial = SCNMaterial () sphereMaterial.diffuse.contents = UIColor.greenColor () sphereGeometry.materials = [sphereMaterial] sphere1 = SCNNode (geometri: sphereGeometry) sphere1.position = SCNVector3 (x: -15, y: 1,5, z: 0) sphere2 = SCNNode (geometri: sphereGeometry) sphere2.position = SCNVector3 (x: 15, y: 1,5, z: 0) la buttonGeometry = SCNBox (bredde: 4, høyde: 1, lengde: 4, chamferRadius: 0) la buttonMaterial = SCNMaterial () buttonMaterial.diffuse.contents = UIColor.redColor () buttonGeometry.materials = [buttonMaterial] -knappen = SCNNode (geometri: buttonGeometry) button.position = SCNVector3 (x: 0, y: 0,5, z: 15)??? sceneView.scene .rootNode.addChildNode (self.camera) sceneView.scene .rootNode.addChildNode (jord) sceneView.scene .rootNode.addChildNode (lys) sceneView.scene? .rootNode.addChildNode (knapp) sceneView.scene? .rootNode.addChildNode (sphere1) sceneView.scene? .rootNode.addChildNode (sphere2)}
Gjennomføringen av viewDidLoad bør se kjent ut hvis du ' har lest den første del av denne serien. Alt vi gjør er å sette opp scenen som vi skal bruke i denne opplæringen. De eneste nye ting inkludere SCNFloor klassen og zFar eiendommen.
Som navnet tilsier, er SCNFloor klassen brukes til å lage et gulv eller bakken for scenen. Dette er mye enklere i forhold til å skape og rotere en SCNPlane som vi gjorde i forrige tutorial.
zFar egenskapen avgjør hvor langt i det fjerne et kamera kan se eller hvor langt lyset fra en bestemt kilde kan nå. Bygge og drive din app. Scenen skal se omtrent slik ut:
2. Brukermedvirkning
Brukermedvirkning er håndtert i SceneKit ved en kombinasjon av UIGestureRecognizer klassen og traff tester. For å oppdage en kran, for eksempel, må du først legge en UITapGestureRecognizer til en SCNView, bestemme springen posisjon i visningen, og se om den er i kontakt med eller treffer noen av nodene.
For bedre å forstå hvordan dette fungerer, vil vi bruke et eksempel. Når en node er tappet, fjerner vi det fra scenen. Legg inn følgende kode til viewDidLoad metoden i ViewController klasse:
styre func viewDidLoad () {super.viewDidLoad () sceneView = SCNView (ramme: self.view.frame) sceneView.scene = SCNScene () self.view .addSubview (sceneView) la tapRecognizer = UITapGestureRecognizer () tapRecognizer.numberOfTapsRequired = 1 tapRecognizer.numberOfTouchesRequired = 1 tapRecognizer.addTarget (selv, handling: "sceneTapped:") sceneView.gestureRecognizers = [tapRecognizer] ...}
Neste, legge følgende metode til ViewController Klasse:
func sceneTapped (kjenneren: UITapGestureRecognizer) {la location = recognizer.locationInView (sceneView) la hitResults = sceneView.hitTest? (plassering, opsjoner: null) hvis hitResults .count > 0 {la resultat = hitResults! [0] as! SCNHitTestResult la node = result.node node.removeFromParentNode ()}}
I denne metoden, må du først få plasseringen av springen som en CGPoint. Deretter bruker du dette punktet for å utføre en hit test på sceneView objekt og lagre SCNHitTestResult objektene i en matrise kalles hitResults. Alternativ parameter av denne metoden kan inneholde en ordbok av nøkler og verdier, som du kan lese om i Apples dokumentasjon. Vi sjekker deretter å se om treffet test returnert minst ett resultat, og hvis det gjorde, fjerner vi det første elementet i matrisen fra den overordnede noden.
Hvis treffet test returnerte flere resultater, objektene er sortert etter deres z posisjon, det vil si i hvilken rekkefølge de vises fra dagens kameraets ståsted. For eksempel, i dagens scene, hvis du trykker på en av de to kuler eller på knappen noden du tappet vil danne det første elementet i den returnerte matrisen. Fordi bakken vises direkte bak disse objektene fra kameraets synsvinkel, vil imidlertid den første noden være et annet element i rekken av resultatene, den andre i dette tilfellet. Dette skjer fordi en kran på samme sted ville treffe bakken node hvis kulene og knappen var ikke der.
Bygg og kjøre applikasjonen, og klikk objektene i scenen. De skal forsvinne når du trykker hver enkelt.
Nå som vi kan bestemme når en node er tappet, kan vi begynne å legge animasjoner til mix.
3. Animasjon
Det er to klasser som kan brukes til å utføre animasjoner i SceneKit:
SCNAction
SCNTransaction
SCNAction objekter er meget nyttig for enkle og gjenbrukbare variasjoner, for eksempel bevegelse, rotasjon og skalering. Du kan kombinere en rekke handlinger sammen til en egendefinert handling objekt.
SCNTransaction klassen kan utføre de samme animasjonene, men det er mer allsidig på noen måter, for eksempel animere materialer. Dette økt allsidighet, men kommer på bekostning av SCNTransaction animasjoner bare har samme gjenbruk som en funksjon og oppsettet blir gjort via klassemetoder.
For første animasjon, jeg kommer til å vise deg koden ved hjelp av både SCNAction og SCNTransaction klasser. Eksempelet vil flytte knappen nede og slå den hvite når den er tappet. Oppdater gjennomføringen av sceneTapped (_ :) metode som vist nedenfor
func sceneTapped (kjenneren. UITapGestureRecognizer) {la plassering = recognizer.locationInView (sceneView) la hitResults = sceneView.hitTest (plassering, alternativer: nil ) hvis hitResults .count > 0 {la resultat = hitResults! [0] as! SCNHitTestResult la node = result.node hvis node == knappen {SCNTransaction.begin () SCNTransaction.setAnimationDuration (0,5) la materiale = node.geometry? Materialer, såsom for eksempel! [SCNMaterial] la materielle = materialer [0] material.diffuse.contents = UIColor.whiteColor () SCNTransaction.commit () la action = SCNAction.moveByX (0, y: -0,8, z: 0, varighet: 0,5) node. runAction (handling)}}}
I sceneTapped (_ :) metoden, får vi en referanse til noden brukeren har tappet og sjekke om dette er knappen i scenen. Hvis det er, animere vi materialet sitt fra rød til hvit, bruker SCNTransaction klasse, og flytte den langs y-aksen i negativ retning ved hjelp av en SCNAction eksempel. Varigheten av animasjonen er satt til 0,5 sekunder.
Bygg og kjøre appen på nytt, og trykk på knappen. Det bør gå ned og endre farge til hvit som vist i skjermbildet under.
4. Fysikk
Sette opp realistiske fysikksimuleringer er enkelt med SceneKit rammeverket. Funksjonaliteten som SceneKit sin fysikk simuleringer tilby, er omfattende, alt fra grunnleggende hastigheter, akselerasjoner og krefter, til gravitasjons og elektriske felt, og selv dueller.
Hva du skal gjøre i den aktuelle scenen, påfør et gravitasjonsfelt til en av kulene, slik at den andre kulen er trukket mot den første kulen som følge av tyngdekraften. Dette tyngdekraften vil bli aktiv når du trykker på knappen.
Oppsettet for denne simuleringen er veldig enkel. Bruk en SCNPhysicsBody objekt for hver node som du ønsker å bli påvirket av fysikksimulering og et SCNPhysicsField objekt for hver node som du ønsker å være kilden til et felt. Oppdatere viewDidLoad metoden som vist nedenfor
styre func viewDidLoad () {... buttonGeometry.materials = [buttonMaterial] -knappen = SCNNode (geometri: buttonGeometry). Button.position = SCNVector3 (x: 0, y: 0,5, z 15) //fysikk la groundShape = SCNPhysicsShape (geometri: groundGeometry, alternativer: null) la groundBody = SCNPhysicsBody (type: .Kinematic, form: groundShape) ground.physicsBody = groundBody la gravityField = SCNPhysicsField.radialGravityField () gravityField.strength = 0 sphere1.physicsField = gravityField la formen = SCNPhysicsShape (geometri: sphereGeometry, alternativer: null) la sphere1Body = SCNPhysicsBody (type: .Kinematic, form: form) sphere1.physicsBody = sphere1Body la sphere2Body = SCNPhysicsBody (type: .Dynamic, form: form) sphere2.physicsBody = sphere2Body sceneView.scene? .rootNode.addChildNode (self.camera) sceneView.scene? .rootNode.addChildNode (jord) sceneView.scene? .rootNode.addChildNode (lys) ...}
begynne med å lage en SCNPhysicsShape eksempel som angir den faktiske formen på objektet som tar del i fysikk simulering. For grunnformene du bruker i denne scenen, de geometriske objekter er helt greit å bruke. For kompliserte 3D-modeller, men det er bedre å kombinere flere primitive figurer sammen for å skape en tilnærmet formen på objektet for fysikk simulering.
Fra denne formen, du deretter opprette en SCNPhysicsBody forekomst og legge den i bakken av scenen. Dette er nødvendig, fordi hver SceneKit scene har som standard en eksisterende tyngdefelt som trekker hvert objekt nedover. Den kinematiske typen du gi til dette SCNPhysicsBody betyr at objektet vil ta del i kollisjoner, men er upåvirket av krefter (og vil ikke falle på grunn av tyngdekraften).
Deretter oppretter du gravitasjonsfeltet og tildele denne til den første noden sfære. Ved å følge den samme fremgangsmåte som for bakken, deretter lage en fysikk organ for hver av de to kuler. Du angir andre sfæren som en dynamisk fysikk kroppen skjønt, fordi du vil at det skal bli berørt og beveget av gravitasjonsfeltet du opprettet.
Til slutt, må du stille inn styrken på dette feltet for å aktivere det når knappen er avlyttet. Legg til følgende linje til sceneTapped (_ :) metode:
func sceneTapped (kjenneren: UITapGestureRecognizer) {? ... Hvis node == knappen {... sphere1.physicsField .strength = 750}}}
bygge og drive din app, trykk på knappen, og se på som den andre kula akselererer sakte mot den første. Merk at det kan ta noen sekunder før den andre kula begynner å bevege seg.
Det er bare én ting igjen å gjøre, men gjør kulene eksploderer når de kolliderer.
5. Kollisjon Detection og partikkel Systems
For å skape effekten av en eksplosjon vi skal utnytte SCNParticleSystem klassen. En partikkel system kan lages av en ekstern 3D-program, kildekode, eller, som jeg er i ferd med å vise deg, Xcode partikkelsystem redaktør. Opprett en ny fil ved å trykke Command + N og velg SceneKit Particle System fra iOS > Resource delen.
Sett partikkel system malen til Reactor.
Klikk Neste navn på filen Explosion, og lagre det i prosjektmappen.
I prosjekt Navigator, du vil nå se to nye filer, Explosion.scnp og spark.png. Den spark.png bildet er en ressurs som brukes av partikkel system, automatisk lagt til i prosjektet. Hvis du åpner Explosion.scnp, vil du se det blir animert og rendret i sanntid i Xcode. Partikkel system editor er et svært kraftig verktøy i Xcode og lar deg tilpasse en partikkel system uten å måtte gjøre det programmatisk.
Med partikkel system åpen, gå til attributter Inspektør på høyre og endre følgende attributter i Emitter seksjonen:
Fødsel hastighet til 300
Direction modus til Random
Endre følgende attributter i Simulering seksjonen:
Levetid til tre
Speed faktor til 2
Og til slutt, må du endre følgende attributter i livssyklusen seksjonen:
Emission dur. til 1
Looping å Plays gang
Din partikkel system skal nå skyter ut i alle retninger, og ligne på følgende skjermbilde:
Åpne ViewController.swift og gjøre ViewController klasse i samsvar med SCNPhysicsContactDelegate protokollen. Vedta denne protokollen er nødvendig for å oppdage en kollisjon mellom to noder
klasse ViewController. UIViewController, SCNPhysicsContactDelegate
Neste, tildele den aktuelle ViewController eksempel som contactDelegate av physicsWorld objekt i viewDidLoad metoden
styre func viewDidLoad. () {super.viewDidLoad () sceneView = SCNView? (ramme: self.view.frame) sceneView.scene = SCNScene () sceneView.scene .physicsWorld.contactDelegate = selv self.view.addSubview (sceneView) ...} < p> Til slutt implementere physicsWorld (_: didUpdateContact :) metoden i ViewController Klasse:
func physicsWorld (verden: SCNPhysicsWorld, didUpdateContact kontakt: SCNPhysicsContact) {if (contact.nodeA == sphere1 || contact.nodeA == sphere2) & & (contact.nodeB == sphere1 || contact.nodeB == sphere2) {la particleSystem = SCNParticleSystem (kalt: "Explosion", inDirectory: null) la systemNode = SCNNode () systemNode.addParticleSystem (particleSystem) systemNode.position = kontakt. nodeA.position sceneView.scene? .rootNode.addChildNode (systemNode) contact.nodeA.removeFromParentNode () contact.nodeB.removeFromParentNode ()}}
Vi sjekker først for å se om de to noder involvert i kollisjonen er de to sfærene . Hvis det er tilfelle, så laster vi partikkelsystem fra filen vi laget et øyeblikk siden, og legge den til en ny node. Til slutt fjerner vi begge sfærer involvert i kollisjonen fra åstedet.
Bygg og kjøre appen på nytt, og trykk på knappen. Når kulene ta kontakt, bør de begge forsvinner og din partikkel system skal se ut og animere.
Konklusjon
I denne opplæringen, viste jeg deg hvordan du kan implementere brukermedvirkning, animasjon, fysikk simulering, og partikkel-systemer bruker SceneKit rammeverket. Teknikkene du har lært i denne serien kan brukes på ethvert prosjekt med en rekke animasjoner, fysikk simuleringer osv
Du skal nå være komfortabel å lage en enkel scene og legge dynamiske elementer til den, for eksempel animasjon og partikler systemer. Begrepene du har lært i denne serien er gjeldende for den minste scenen med et enkelt objekt hele veien opp til en stor skala spill.