In deze zelfstudie leert u hoe u een eenvoudige 3D-scène in SceneKit kunt maken zonder de complexiteit van OpenGL. Dit omvat basisgeometrie, camera's, lichten, materialen en schaduwen.
Het SceneKit-framework werd voor het eerst gelanceerd door Apple naast OS X 10.8 Mountain Lion en werd later beschikbaar gesteld op iOS met de release van iOS 8. Het doel van dit framework is om ontwikkelaars in staat te stellen eenvoudig 3D-graphics te integreren in games en applicaties zonder de complexiteit van grafische API's, zoals OpenGL en Metal.
Met SceneKit kunt u eenvoudig een beschrijving van de gewenste items in uw scène opgeven, waarbij het framework zelf alle OpenGL-renderingcode voor u verwerkt. In deze eerste zelfstudie leer ik je enkele basisprincipes van het werken met 3D-middelen en de basis van het SceneKit-framework..
Voor deze zelfstudie moet je Xcode 6 of hoger gebruiken. Hoewel dit niet nodig is, raad ik aan een fysiek apparaat met iOS 8 te gebruiken om je SceneKit-code te testen. Je kunt de iOS-simulator gebruiken, maar de prestaties zijn niet geweldig als je scène complexer wordt. Houd er rekening mee dat voor het testen op een fysiek iOS-apparaat een geregistreerd iOS-ontwikkelaarsaccount vereist is.
Het eerste dat u moet weten over SceneKit is dat activa, vertegenwoordigd door knooppunten, gerangschikt zijn in een hiërarchische structuur genaamd scènemetekening. Als je bekend bent met iOS-ontwikkeling, werkt deze boom net als een gewone bekijk de hiërarchiein UIKit. Elke scène die u maakt, heeft één wortelknooppunt waaraan u opeenvolgende knooppunten toevoegt en die ook een basis biedt voor het 3D-coördinatensysteem van die scène.
Wanneer u een knooppunt aan een scène toevoegt, wordt de positie ervan bepaald door een reeks van drie getallen, een driecomponentvector die wordt weergegeven door de SCNVector3
structuur in uw code. Elk van deze drie componenten definieert de positie van het knooppunt op de x-, y- en z-assen zoals weergegeven in de onderstaande afbeelding.
De positie van het knooppunt van uw scène is gedefinieerd als (0, 0, 0). In de bovenstaande afbeelding is dit de positie waar de drie assen elkaar kruisen. De meegeleverde camera in de afbeelding vertegenwoordigt de standaardrichting waarin een camera wijst wanneer deze aan uw scène wordt toegevoegd.
Nu u enkele basisprincipes kent van hoe objecten worden voorgesteld door SceneKit, bent u klaar om te beginnen met het schrijven van een code.
Open Xcode en maak een nieuwe iOS-applicatie gebaseerd op de Toepassing enkele weergave sjabloon. Hoewel u gemakkelijk een toepassing kunt maken vanuit de Spel sjabloon met SceneKit, voor deze tutorial zal ik je laten zien hoe je vanaf het begin met SceneKit kunt werken.
Voer een in productnaam, reeks Taal naar Snel, en apparaten naar universeel. Klik volgende doorgaan.
Nadat u uw project hebt gemaakt, navigeert u naar ViewController.swift en voeg bovenaan de volgende importinstructie toe om het SceneKit-framework te importeren:
importeer SceneKit
Voeg vervolgens de volgende implementatie van de viewDidLoad
methode in de ViewController
klasse:
override func viewDidLoad () super.viewDidLoad () laat sceneView = SCNView (frame: self.view.frame) self.view.addSubview (sceneView)
In de viewDidLoad
methode, we creëren een SCNView
object, passerend in het kader van de weergave van de view controller. We wijzen de SCNView
bijvoorbeeld naar een constante, sceneView
, en voeg het toe als een subweergave van de weergave van de view controller.
De SCNView
class is een subklasse van UIView
en biedt een uitlaatklep voor je SceneKit-inhoud. Afgezien van het hebben van de functionaliteit van een normale weergave, een SCNView
heeft ook verschillende eigenschappen en methoden met betrekking tot de inhoud van SceneKit.
Om te controleren of alles naar behoren functioneert, bouw en run je je app. Je zult zien dat je gewoon een blanco witte weergave hebt.
Content in een SCNView
, je moet eerst een maken SCNScene
en wijs het toe aan de weergave. In deze scène moet u vervolgens een camera en ten minste één licht. Voor dit voorbeeld gaat u ook een kubus toevoegen om SceneKit te renderen. Voeg de volgende code toe aan de viewDidLoad
methode:
override func viewDidLoad () super.viewDidLoad () laat sceneView = SCNView (frame: self.view.frame) self.view.addSubview (sceneView) let scene = SCNScene () sceneView.scene = scene let camera = SCNCamera () laat cameraNode = SCNNode () cameraNode.camera = camera cameraNode.position = SCNVector3 (x: 0.0, y: 0.0, z: 3.0) laat licht = SCNLight () light.type = SCNLightTypeOmni laat lightNode = SCNNode () lightNode.light = light lightNode.position = SCNVector3 (x: 1.5, y: 1.5, z: 1.5) let cubeGeometry = SCNBox (width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0.0) laat cubeNode = SCNNode (geometry: cubeGeometry) scène. rootNode.addChildNode (lightNode) scene.rootNode.addChildNode (cameraNode) scene.rootNode.addChildNode (cubeNode)
Laten we door de viewDidLoad
methode stap voor stap:
in het
methode. Tenzij u een voorbereide scène uit een extern bestand laadt, is dit de initialisatie die u altijd zult gebruiken.SCNCamera
object en een SCNNode
bijvoorbeeld voor de camera. U wijst vervolgens de SCNCamera
bezwaar tegen de camera
eigendom van cameraNode
en verplaats dit knooppunt langs de z-as om de kubus te zien die je een beetje later zult maken.SCNLight
object en een SCNNode
genaamd lightNode
. De SCNLight
instantie is toegewezen aan de licht
eigendom van het lichtknooppunt. De type
eigendom van de SCNLight
ingesteld op SCNLightTypeOmni
. Dit lichttype verdeelt het licht gelijkmatig in alle richtingen vanaf een punt in de 3D-ruimte. Je kunt dit lichttype zien als een gewone gloeilamp.SCNBox
klasse, waarbij de breedte, hoogte en lengte allemaal even groot zijn. De SCNBox
class is een subklasse van SCNGeometry
en is een van de primitieve vormen die je kunt maken. Andere vormen omvatten bollen, piramides en torussen. U maakt ook een knooppunt doorgeven in de kubus voor de geometrie
parameter.SCNScene
object detecteert automatisch wanneer een knooppunt een camera of lichtobject bevat, waardoor de scène overeenkomstig wordt weergegeven.Bouw en voer je app uit en je ziet dat je nu een zwarte kubus hebt die wordt verlicht door je licht vanuit de rechterbovenhoek.
Helaas ziet de kubus er op dit moment niet driedimensionaal uit. Dit komt omdat de camera er recht voor staat. Wat je nu gaat doen, is de positie van de camera veranderen, zodat deze een beter zicht op de kubus heeft.
Om de camera echter direct op de kubus te richten, voegt u er ook een toe SCNLookAtConstraint
naar de camera. Begin met het bijwerken van de positie van de camera zoals hieronder weergegeven.
cameraNode.position = SCNVector3 (x: -3.0, y: 3.0, z: 3.0)
Voeg vervolgens het volgende codefragment toe aan de methode viewDidLoad, na het instantiëren van het knooppunt voor de kubus:
let constraint = SCNLookAtConstraint (target: cubeNode) constraint.gimbalLockEnabled = true cameraNode.constraints = [constraint]
De positiewijziging verplaatst de camera naar links en omhoog. Door een beperking toe te voegen, met de kubus als doel en gimbalLockEnabled
ingesteld op waar
, je zorgt ervoor dat de camera in dit geval parallel blijft met de horizon en het kijkvenster, het scherm van je apparaat. Dit gebeurt door de rotatie uit te schakelen langs de rolas, de as die van de camera naar het doel van de beperking wijst.
Bouw en voer je app opnieuw uit en je zult je kubus in al zijn 3D-glorie zien.
Het is tijd om meer realisme aan de scène toe te voegen met materialen en schaduwen. Je zult eerst een ander object nodig hebben om een schaduw op te werpen. Gebruik het volgende codefragment om een vlak te maken, een platte rechthoek en plaats deze onder de kubus. Vergeet niet om het nieuwe knooppunt als een kindknooppunt toe te voegen aan het hoofdknooppunt van de scène.
override func viewDidLoad () ... let cubeGeometry = SCNBox (width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0.0) let cubeNode = SCNNode (geometry: cubeGeometry) let planeGeometry = SCNPlane (width: 50.0, height: 50.0) let planeNode = SCNNode (geometry: planeGeometry) planeNode.eulerAngles = SCNVector3 (x: GLKMathDegreesToRadians (-90), y: 0, z: 0) planeNode.position = SCNVector3 (x: 0, y: -0.5, z: 0) ... scene.rootNode.addChildNode (lightNode) scene.rootNode.addChildNode (cameraNode) scene.rootNode.addChildNode (cubeNode) scene.rootNode.addChildNode (planeNode)
Door het veranderen van de vliegtuigknopen eulerAngles
eigenschap, draait u het vlak 90 graden achteruit langs de x-as. We moeten dit doen, omdat vlakken standaard verticaal worden gemaakt. In SceneKit worden rotatiehoeken berekend in radialen in plaats van graden, maar deze waarden kunnen eenvoudig worden geconverteerd met behulp van de GLKMathDegreesToRadians (_ :)
en GLKMathsRadiansToDegrees (_ :)
functies. GLK staat voor GLKit, het OpenGL-framework van Apple.
Voeg vervolgens een materiaal toe aan de kubus en het vlak. Voor dit voorbeeld geef je de kubus en het vlak een vaste kleur, respectievelijk rood en groen. Voeg de volgende regels toe aan de viewDidLoad
methode om deze materialen te maken.
override func viewDidLoad () ... planeNode.position = SCNVector3 (x: 0, y: -0.5, z: 0) laat redMaterial = SCNMaterial () redMaterial.diffuse.contents = UIColor.redColor () cubeGeometry.materials = [redMaterial] let greenMaterial = SCNMaterial () greenMaterial.diffuse.contents = UIColor.greenColor () planeGeometry.materials = [greenMaterial] laat constraint = SCNLookAtConstraint (target: cubeNode) ...
Voor elk SCNMaterial
object, kent u de diffuse inhoud toe a UIColor
waarde. De diffuse eigenschap van een materiaal bepaalt hoe het wordt weergegeven bij direct licht. Merk op dat de toegewezen waarde niet a hoeft te zijn UIColor
voorwerp. Er zijn veel andere acceptabele objecttypen die aan deze eigenschap kunnen worden toegewezen, zoals UIImage
, CALayer
, en zelfs een SpriteKit-textuur (SKTexture
).
Bouw en voer je app opnieuw uit om niet alleen het vliegtuig voor de eerste keer te zien, maar ook de materialen die je hebt gemaakt.
Nu is het tijd om wat schaduw toe te voegen aan je scène. Van de vier lichtsoorten die beschikbaar zijn in SceneKit, kunnen alleen spotlichten schaduwen maken. Voor dit voorbeeld, zal je je bestaande omni-licht veranderen in een spotlicht, gericht op de kubus. Voeg de volgende code toe aan de viewDidLoad
methode:
override func viewDidLoad () ... let light = SCNLight () light.type = SCNLightTypeSpot light.spotInnerAngle = 30.0 light.spotOuterAngle = 80.0 light.castsShadow = true let lightNode = SCNNode () lightNode.light = light lightNode.position = SCNVector3 ( x: 1.5, y: 1.5, z: 1.5) ... let constraint = SCNLookAtConstraint (target: cubeNode) constraint.gimbalLockEnabled = true cameraNode.constraints = [constraint] lightNode.constraints = [constraint] ...
Als u het spotlicht wilt maken, stelt u eerst het type licht in op SCNLightTypeSpot
. Vervolgens geeft u de binnen- en buitenhoeken van het spotlicht in graden op. De standaardwaarden zijn 0 en 45 respectievelijk. De binnenhoek bepaalt hoeveel gebied het licht in direct licht bedekt, terwijl de buitenhoek bepaalt hoeveel gebied gedeeltelijk wordt verlicht. Het verschil tussen deze hoeken wordt duidelijk zodra je de resulterende scène ziet. Je vertelt dan expliciet het licht om schaduwen te werpen en hetzelfde toe te voegen SCNLookAtConstraint
die je eerder voor je camera hebt gemaakt.
Bouw en voer je app uit om de resulterende scène te bekijken. De binnenhoek die je hebt opgegeven in je code wordt weergegeven waar het vlak een ononderbroken groen vlak onder de kubus is. De buitenhoek wordt weergegeven door de lichtgradiënt die vervaagt naar zwart wanneer deze zich verwijdert van het doelwit van het licht.
U zult zien dat uw kubus nu een schaduw werpt op de juiste manier. Het spotlicht verlicht echter slechts een deel van het vlak. Dit komt omdat er geen omgevingslicht in uw scène is.
Een omgevingslicht is een lichtbron die alles verlicht met een gelijke lichtverdeling. Omdat een omgevingslicht de hele scène verlicht, doet de positie er niet toe en kunt u deze aan elk gewenst knooppunt toevoegen, zelfs hetzelfde knooppunt als uw camera. Gebruik het volgende codefragment om een omgevingslicht voor uw scène te maken.
override func viewDidLoad () ... let camera = SCNCamera () laat cameraNode = SCNNode () cameraNode.camera = camera cameraNode.position = SCNVector3 (x: -3.0, y: 3.0, z: 3.0) laat ambientLight = SCNLight () ambientLight .type = SCNLightTypeAmbient ambientLight.color = UIColor (rood: 0.2, groen: 0.2, blauw: 0.2, alpha: 1.0) cameraNode.light = ambientLight ...
Het codefragment maakt een SCNLight
, net zoals je eerder deed. Het grootste verschil is het licht type
eigenschap, die is ingesteld op SCNLightTypeAmbient
. U stelt de kleur ervan ook in op een donkergrijs zodat deze uw scène niet overbelast. De standaardkleur voor een lamp is puur wit (RGB-waarde van 1, 1, 1) en als deze kleur op een omgevingslicht staat, wordt de hele scène volledig verlicht, zoals in de onderstaande schermafbeelding wordt getoond.
Bouw en voer uw app nog een laatste keer uit om het uiteindelijke resultaat te bekijken.
Als je het einde van deze zelfstudie hebt gehaald, zou je je nu vertrouwd moeten maken met de volgende onderwerpen:
SCNView
Met een SCNScene
In de volgende tutorial van deze serie, leer je over enkele meer geavanceerde concepten van het SceneKit-framework, inclusief animatie, gebruikersinteractie, deeltjessystemen en het simuleren van fysica..