instructions
ARKit series of articles directory
This is Raywenderlich’s translation of the free chapter on ARKit by Tutorials, chapter 9 of the original book. The book chapter 7 ~ 9 completed a space-time door app. The website address www.raywenderlich.com/195419/buil…
This is chapter 9, “Materials and Lighting”, of our book ARKit by Tutorials. This book shows you how to build five immersive, good-looking AR apps using Apple’s augmented reality framework, ARKit. Let’s go!
In the first two of this app’s three tutorials, you learned how to add 3D objects to your scene using SceneKit. Now it’s time to put that knowledge to use and construct the entire portal. In this tutorial, you will learn:
- Create walls, ceilings and roofs and adjust their position and orientation.
- Different textures were used to make the interior of the portal more realistic.
- Add lighting to your scene.
start
Click here to download this article, and then open the Starter project in the Starter folder. Before you start, you need to know a little about SceneKit.
SceneKit coordinate system
As you saw in the previous chapter,SceneKit can be used to add virtual objects to your view. The SceneKit content view contains nodes in a tree-like hierarchy known as the Scene Graph. The scene has a root node, which defines the world coordinate space of the scene, and other nodes make up the visible content of the world. Every node or 3D object you render on the screen is an object of type SCNNode. An SCNNode object defines the transformation (position, orientation, and scaling) of its coordinate system relative to its parent node. It has no visible content of its own.
The rootNode object in the scene defines the world coordinate system rendered by SceneKit. Each child node you add to the root node creates its own coordinate system, which in turn is inherited by its own child node.
SceneKit uses a right-handed coordinate system (default); The view is oriented in the negative direction of the z axis, as shown below.
SCNNode
SCNVector3
SCNVector3
Float
The orientation of the SCNNode object (pitch, yaw, roll) is defined by the eulerAngles attribute. It is also represented by an SCNVector3 structure, where each component is an Angle in radians.
texture
The SCNNode object itself does not contain any visible content. When you need to add 2D and 3D objects to your scene, simply add the SCNGeometry object to the node. The geometry has a SCNmaterial object that determines how it should look.
A SCNMaterial has several visible properties. Each visible property is an instance object of type SCNMaterialProperty, which provides an entity color, texture, or other 2D content. Many of these visible properties are used to complete the base coloring, which makes the material look more realistic based on physical coloring and special effects.
SceneKit Asset Catalog is designed to help you manage the materials in your project without the need for code. In your Starter project, open the assets. scnAssets folder. You’ll see that there are already some pictures showing the various visible properties in ceilings, floors, and walls.
SCNLight
Create a spacetime gate
Let’s move on to creating the space-time gate floor. Open scnnodehelpers.swift and add the following code at the top of the file under the import SceneKit statement.
/ 1
let SURFACE_LENGTH: CGFloat = 3.0
let SURFACE_HEIGHT: CGFloat = 0.2
let SURFACE_WIDTH: CGFloat = 3.0
/ / 2
let SCALEX: Float = 2.0
let SCALEY: Float = 2.0
/ / 3
let WALL_WIDTH:CGFloat = 0.2
let WALL_HEIGHT:CGFloat = 3.0
let WALL_LENGTH:CGFloat = 3.0
Copy the code
Code Meaning:
- Defines constants that represent the size of the floor and ceiling in the portal. The height of the floor and ceiling is also their thickness.
- These constants represent scaling and repetition of the surface texture.
- These define the width, height, and length of the wall nodes.
Next, add the following method to SCNNodeHelpers:
func repeatTextures(geometry: SCNGeometry, scaleX: Float, scaleY: Float) {
/ / 1geometry.firstMaterial? .diffuse.wrapS =SCNWrapMode.repeatgeometry.firstMaterial? .selfIllumination.wrapS =SCNWrapMode.repeatgeometry.firstMaterial? .normal.wrapS =SCNWrapMode.repeatgeometry.firstMaterial? .specular.wrapS =SCNWrapMode.repeatgeometry.firstMaterial? .emission.wrapS =SCNWrapMode.repeatgeometry.firstMaterial? .roughness.wrapS =SCNWrapMode.repeat
/ / 2geometry.firstMaterial? .diffuse.wrapT =SCNWrapMode.repeatgeometry.firstMaterial? .selfIllumination.wrapT =SCNWrapMode.repeatgeometry.firstMaterial? .normal.wrapT =SCNWrapMode.repeatgeometry.firstMaterial? .specular.wrapT =SCNWrapMode.repeatgeometry.firstMaterial? .emission.wrapT =SCNWrapMode.repeatgeometry.firstMaterial? .roughness.wrapT =SCNWrapMode.repeat
/ / 3geometry.firstMaterial? .diffuse.contentsTransform =SCNMatrix4MakeScale(scaleX, scaleY, 0) geometry.firstMaterial? .selfIllumination.contentsTransform =SCNMatrix4MakeScale(scaleX, scaleY, 0) geometry.firstMaterial? .normal.contentsTransform =SCNMatrix4MakeScale(scaleX, scaleY, 0) geometry.firstMaterial? .specular.contentsTransform =SCNMatrix4MakeScale(scaleX, scaleY, 0) geometry.firstMaterial? .emission.contentsTransform =SCNMatrix4MakeScale(scaleX, scaleY, 0) geometry.firstMaterial? .roughness.contentsTransform =SCNMatrix4MakeScale(scaleX, scaleY, 0)}Copy the code
Here we define a method to make the texture repeat in the X and Y directions.
Code interpretation;
- This method takes an SCNGeometry object and X,Y scaling factors as input. The texture map uses the S and T coordinate system :S for X,T for Y. Here you define the S direction wrapping mode for all visible properties as scnwrapMode.repeat.
- The wrapping mode in the T direction is defined for all visible properties as scnwrapmode.repeat. In repeat mode, texture sampling uses only a small portion of the texture coordinates.
- Here, each visible property contentsTransform is set to the scale transformation matrix represented by the SCNMatrix4 structure. Set the X and Y scaling factors to scaleX and scaleY.
You only let the user enter the portal when the floor and ceiling nodes are displayed; In other cases, hide. To do this, add the following code in SCNNodeHelpers:
func makeOuterSurfaceNode(width: CGFloat, height: CGFloat, length: CGFloat) -> SCNNode {
/ / 1
let outerSurface = SCNBox(width: width,
height: height,
length: length,
chamferRadius: 0)
/ / 2outerSurface.firstMaterial? .diffuse.contents =UIColor.white outerSurface.firstMaterial? .transparency =0.000001
/ / 3
let outerSurfaceNode = SCNNode(geometry: outerSurface)
outerSurfaceNode.renderingOrder = 10
return outerSurfaceNode
}
Copy the code
Explanation of code:
- Create an outerSurface scene cube geometry object with the same dimensions as the floor and ceiling.
- Add visible content to the diffuse properties of the cube object to render it out. Set Transparency to a very low value so that the object is hidden from view.
- Create an SCNNode object from the outerSurface geometry. Set the renderingOrder of the node to 10. The larger the render order value of a node, the later it will be rendered. In order to make the floor and ceiling invisible from outside the portal, you will need to render the internal ceiling and floor nodes in a rendering order much larger than 10.
Now add the following code to SCNNodeHelpers to build the portal floor:
func makeFloorNode(a) -> SCNNode {
/ / 1
let outerFloorNode = makeOuterSurfaceNode(
width: SURFACE_WIDTH,
height: SURFACE_HEIGHT,
length: SURFACE_LENGTH)
/ / 2
outerFloorNode.position = SCNVector3(SURFACE_HEIGHT * 0.5,
-SURFACE_HEIGHT.0)
let floorNode = SCNNode()
floorNode.addChildNode(outerFloorNode)
/ / 3
let innerFloor = SCNBox(width: SURFACE_WIDTH,
height: SURFACE_HEIGHT,
length: SURFACE_LENGTH,
chamferRadius: 0)
/ / 4innerFloor.firstMaterial? .lightingModel = .physicallyBased innerFloor.firstMaterial? .diffuse.contents =UIImage(named:
"Assets.scnassets/floor/textures/Floor_Diffuse.png") innerFloor.firstMaterial? .normal.contents =UIImage(named:
"Assets.scnassets/floor/textures/Floor_Normal.png") innerFloor.firstMaterial? .roughness.contents =UIImage(named:
"Assets.scnassets/floor/textures/Floor_Roughness.png") innerFloor.firstMaterial? .specular.contents =UIImage(named:
"Assets.scnassets/floor/textures/Floor_Specular.png") innerFloor.firstMaterial? .selfIllumination.contents =UIImage(named:
"Assets.scnassets/floor/textures/Floor_Gloss.png")
/ / 5
repeatTextures(geometry: innerFloor,
scaleX: SCALEX, scaleY: SCALEY)
/ / 6
let innerFloorNode = SCNNode(geometry: innerFloor)
innerFloorNode.renderingOrder = 100
/ / 7
innerFloorNode.position = SCNVector3(SURFACE_HEIGHT * 0.5.0.0)
floorNode.addChildNode(innerFloorNode)
return floorNode
}
Copy the code
Explanation of code:
- Create an outer floor node using the dimensions of the floor defined.
- Place the outerFloorNode so that it lies below the underside of the floor node. Add this to a floorNode, which will hold both the inner and outer surfaces of the floor.
- Use the SCNBox object to create floor geometry with pre-defined dimensions.
- The lightingModel for the floor material is set to physicallyBased. This type of shadow contains an abstraction of the actual lighting and material physics. The visible property of the material is set to the texture image in the scnAssets collection.
- The texture of the material is repeated in the X and Y directions using the previously defined repeatTextures().
- Create a node for the floor using the innerFloor geometry object and set the render order higher than the outerFloorNode. This ensures that the floor nodes are not visible when the user is outside the portal.
- Finally, position the innerFloorNode so it is above the outerFloorNode and add it to the floorNode as a child node. Returns the floor node object to the function caller.
Open the PortalViewController. Swift and add the following constants:
let POSITION_Y: CGFloat = -WALL_HEIGHT*0.5
let POSITION_Z: CGFloat = -SURFACE_LENGTH*0.5
Copy the code
These constants represent the position offset of the node in the Y and Z directions.
Add the floor node to the time empty gate by replacing makePortal().
func makePortal(a) -> SCNNode {
/ / 1
let portal = SCNNode(a)/ / 2
let floorNode = makeFloorNode()
floorNode.position = SCNVector3(0.POSITION_Y.POSITION_Z)
/ / 3
portal.addChildNode(floorNode)
return portal
}
Copy the code
The code is simple:
- Create an SCNNode object to hold the portal.
- Use the makeFloorNode() method defined in SCNNodeHelpers to create floor nodes. Use the previous constant offset value to set the floorNode’s position. The center of the SCNGeometry will align with the coordinates of the parent node.< for example, if set to (1,1,1), the geometry center will align with (1,1,1)>
- Add the floorNode to the empty gate node and return the spacetime gate node. Note that the space-time gate node is at the anchor point added to renderer(_ :, didAdd:, for) when the user clicks on the view.
Run the app. You will see that the floor node is a little dark because you haven’t added light yet!
Now add the ceiling node. Open scnnodehelpers.swift and add the following methods:
func makeCeilingNode(a) -> SCNNode {
/ / 1
let outerCeilingNode = makeOuterSurfaceNode(
width: SURFACE_WIDTH,
height: SURFACE_HEIGHT,
length: SURFACE_LENGTH)
/ / 2
outerCeilingNode.position = SCNVector3(SURFACE_HEIGHT * 0.5.SURFACE_HEIGHT.0)
let ceilingNode = SCNNode()
ceilingNode.addChildNode(outerCeilingNode)
/ / 3
let innerCeiling = SCNBox(width: SURFACE_WIDTH,
height: SURFACE_HEIGHT,
length: SURFACE_LENGTH,
chamferRadius: 0)
/ / 4innerCeiling.firstMaterial? .lightingModel = .physicallyBased innerCeiling.firstMaterial? .diffuse.contents =UIImage(named:
"Assets.scnassets/ceiling/textures/Ceiling_Diffuse.png") innerCeiling.firstMaterial? .emission.contents =UIImage(named:
"Assets.scnassets/ceiling/textures/Ceiling_Emis.png") innerCeiling.firstMaterial? .normal.contents =UIImage(named:
"Assets.scnassets/ceiling/textures/Ceiling_Normal.png") innerCeiling.firstMaterial? .specular.contents =UIImage(named:
"Assets.scnassets/ceiling/textures/Ceiling_Specular.png") innerCeiling.firstMaterial? .selfIllumination.contents =UIImage(named:
"Assets.scnassets/ceiling/textures/Ceiling_Gloss.png")
/ / 5
repeatTextures(geometry: innerCeiling, scaleX:
SCALEX, scaleY: SCALEY)
/ / 6
let innerCeilingNode = SCNNode(geometry: innerCeiling)
innerCeilingNode.renderingOrder = 100
/ / 7
innerCeilingNode.position = SCNVector3(SURFACE_HEIGHT * 0.5.0.0)
ceilingNode.addChildNode(innerCeilingNode)
return ceilingNode
}
Copy the code
Explanation of code:
- Similar to the floor, create an outerCeilingNode.
- Position the outer ceiling node so it is above the ceiling. Create a node to hold the inner and outer ceilings. Add the outerCeilingNode as a child node of the ceilingNode.
- Create an SCNBox object of appropriate size for innerCeiling.
- Set the lightModel to physicallyBased and the visible property of the material to the texture image in the scnAssets material set.
- The texture of the material is repeated in the X and Y directions using the previously defined repeatTextures().
- Create a node for the innerCeilingNode, using the innerCeiling object and setting the render order higher than the outerCeilingNode, so that it is rendered after the outer layer.
- Finally, set the location of the innerCeilingNode and add it to the ceilingNode as a child node. Returns ceilingNode to the function caller.
Now you need to call this method somewhere else. Open the PortalViewController. The swift, add the following code to makePortal (), in front of the return statement.
/ 1
let ceilingNode = makeCeilingNode()
ceilingNode.position = SCNVector3(0.POSITION_Y+WALL_HEIGHT.POSITION_Z)
/ / 2
portal.addChildNode(ceilingNode)
Copy the code
- Create the ceiling node using the makeCeilingNode() method just defined. Set the location of ceilingNode to the SCNVector3 structure. The Y coordinate of the center point is offset by the floor thickness plus the wall height. You can also subtract SURFACE_HEIGHT to get the thickness of the ceiling. Similar to the floor, the Z offset is also set to position_z. This is the distance from the center of the ceiling to the camera on the Z axis.
- Add ceilingNode as a child node of the portal.
Run the app and you’ll see:
Time to add walls!
Open scnnodehelpers.swift and add the following methods.
func makeWallNode(length: CGFloat = WALL_LENGTH,
height: CGFloat = WALL_HEIGHT,
maskLowerSide:Bool = false) -> SCNNode {
/ / 1
let outerWall = SCNBox(width: WALL_WIDTH,
height: height,
length: length,
chamferRadius: 0)
/ / 2outerWall.firstMaterial? .diffuse.contents =UIColor.white outerWall.firstMaterial? .transparency =0.000001
/ / 3
let outerWallNode = SCNNode(geometry: outerWall)
let multiplier: CGFloat = maskLowerSide ? -1 : 1
outerWallNode.position = SCNVector3(WALL_WIDTH*multiplier,0.0)
outerWallNode.renderingOrder = 10
/ / 4
let wallNode = SCNNode()
wallNode.addChildNode(outerWallNode)
/ / 5
let innerWall = SCNBox(width: WALL_WIDTH,
height: height,
length: length,
chamferRadius: 0)
/ / 6innerWall.firstMaterial? .lightingModel = .physicallyBased innerWall.firstMaterial? .diffuse.contents =UIImage(named:
"Assets.scnassets/wall/textures/Walls_Diffuse.png") innerWall.firstMaterial? .metalness.contents =UIImage(named:
"Assets.scnassets/wall/textures/Walls_Metalness.png") innerWall.firstMaterial? .roughness.contents =UIImage(named:
"Assets.scnassets/wall/textures/Walls_Roughness.png") innerWall.firstMaterial? .normal.contents =UIImage(named:
"Assets.scnassets/wall/textures/Walls_Normal.png") innerWall.firstMaterial? .specular.contents =UIImage(named:
"Assets.scnassets/wall/textures/Walls_Spec.png") innerWall.firstMaterial? .selfIllumination.contents =UIImage(named:
"Assets.scnassets/wall/textures/Walls_Gloss.png")
/ / 7
let innerWallNode = SCNNode(geometry: innerWall)
wallNode.addChildNode(innerWallNode)
return wallNode
}
Copy the code
Explanation of code:
- Create an outerWall node and place it on the outside of the wall, making sure it is transparent from the outside. Create SCNBox objects to match the size of the wall.
- Set the material’s diffuse content to pure white and the transparency value to a very low value. This helps us achieve the effect of external perspective.
- Create a node for outerWall geometry. Multiplier is set based on which side of the outerWall needs to be rendered. If maskLowerSide is set to true, the outer wall will be placed below the inner wall in the wall node’s coordinate system; Otherwise, it is placed on top of the inner layer. Position the nodes so that the outer wall is offset by the width of the wall in the X direction. Set the render order of the outer wall to a low value so that it will be rendered first. This will make the walls invisible from the outside.
- Create a node to hold the wall and add outerWallNode as its child.
- Create an SCNBox object for innerWall with the same size as the wall.
- Set lightingModel to physicallyBased. Similar to the ceiling and floor nodes, set the contents of the visible properties to various wall texture images.
- Finally, use the innerWall geometry to create an innerWallNode object. Add this node to the parent wallNode object. By default,innerWallNode is placed at the origin of wallNode. Returns the node to the function caller.
Now add the wall beyond the portal. Open PortalViewController. Swift and add the following ways, in makePortal () at the end of the return statement before:
/ / 1
let farWallNode = makeWallNode()
/ / 2
farWallNode.eulerAngles = SCNVector3(0.90.0.degreesToRadians, 0)
/ / 3
farWallNode.position = SCNVector3(0.POSITION_Y+WALL_HEIGHT*0.5.POSITION_Z-SURFACE_LENGTH*0.5)
portal.addChildNode(farWallNode)
Copy the code
The code is straightforward:
- Create a node for the far wall. FarWallNode needs to cover the lower side. So use the default maskLowerSide value of false.
- Set eulerAngles for the nodes. Since the wall is rotated along the Y-axis and perpendicular to the camera, the second component is rotated by 90 degrees. It doesn’t rotate in the X and Z directions.
- Set the center of farWallNode to POSITION_Y. Its depth is calculated as the depth of the center point of the ceiling plus the distance from the center point of the ceiling to the far end.
Create and run the app, and you’ll see that the top of the wall is connected to the ceiling in the distance, and the bottom is connected to the floor.
Next you will add the left and right walls. In makePortal(), add the following code before the return statement:
/ / 1
let rightSideWallNode = makeWallNode(maskLowerSide: true)
/ / 2
rightSideWallNode.eulerAngles = SCNVector3(0.180.0.degreesToRadians, 0)
/ / 3
rightSideWallNode.position = SCNVector3(WALL_LENGTH*0.5.POSITION_Y+WALL_HEIGHT*0.5.POSITION_Z)
portal.addChildNode(rightSideWallNode)
/ / 4
let leftSideWallNode = makeWallNode(maskLowerSide: true)
/ / 5
leftSideWallNode.position = SCNVector3(-WALL_LENGTH*0.5.POSITION_Y+WALL_HEIGHT*0.5.POSITION_Z)
portal.addChildNode(leftSideWallNode)
Copy the code
Explanation of code:
- Creates nodes for the right wall. You want the outer wall to be one level lower in the node, so you set maskLowerSide to true.
- Set the wall to rotate 180 degrees along the Y-axis. This ensures that the inside of the wall faces to the right.
- Position the wall so that it is level with the right side of the far wall, ceiling, and floor. Add rightSideWallNode as a child node of protal.
- Similar to the right wall node, create a node to represent the left wall and set maskLowerSide to true.
- The left wall doesn’t need to rotate anymore, but you still need to align it with the left side of the far wall, ceiling, and floor joints. Adds a child node of the empty gate node to the left wall.
Compile and run the app. Your portal now has three walls. If you walk out of the portal, all the walls are invisible.
Add a door frame channel
One more thing to finish: an entrance! Currently, the portal does not have a fourth wall. What we really need is not a fourth wall, but a doorway to enter and exit.
Open the PortalViewController. Swift and add the following constants:
let DOOR_WIDTH:CGFloat = 1.0
let DOOR_HEIGHT:CGFloat = 2.4
Copy the code
As their name suggests, they define the width and height of the doorframe.
Add the following code to the PortalViewController:
func addDoorway(node: SCNNode) {
/ / 1
let halfWallLength: CGFloat = WALL_LENGTH * 0.5
let frontHalfWallLength: CGFloat =
(WALL_LENGTH - DOOR_WIDTH) * 0.5
/ / 2
let rightDoorSideNode = makeWallNode(length: frontHalfWallLength)
rightDoorSideNode.eulerAngles = SCNVector3(0.270.0.degreesToRadians, 0)
rightDoorSideNode.position = SCNVector3(halfWallLength - 0.5 * DOOR_WIDTH.POSITION_Y+WALL_HEIGHT*0.5.POSITION_Z+SURFACE_LENGTH*0.5)
node.addChildNode(rightDoorSideNode)
/ / 3
let leftDoorSideNode = makeWallNode(length: frontHalfWallLength)
leftDoorSideNode.eulerAngles = SCNVector3(0.270.0.degreesToRadians, 0)
leftDoorSideNode.position = SCNVector3(-halfWallLength + 0.5 * frontHalfWallLength,
POSITION_Y+WALL_HEIGHT*0.5.POSITION_Z+SURFACE_LENGTH*0.5)
node.addChildNode(leftDoorSideNode)
}
Copy the code
AddDoorway (node:) this method adds a wall to the specified node doorway. Explanation of code:
- Define constants to store half the length of the wall, and the length of the walls on either side of the door.
- From the constants declared in the previous step, create a node to represent the wall to the right of the entry. You also need to adjust the position and rotation of the node so that it is aligned with the right side wall, ceiling and floor joints. RightDoorSideNode is then added to the specified node to become its child node.
- As in step 2, create the left node of the doorframe channel and set the leftDoorSideNode position and rotation. Finally, add it to node as a child node with addChildNode().
In the makePortalNode() method, add the following statement before return portal:
addDoorway(node: portal)
Copy the code
Here add the doorframe channel to the empty gate node.
Run the app. You will see the frame on the space-time door, but currently the top of the door goes straight to the ceiling. We need to add another wall to make the doorframe reach DOOR_HEIGHT as defined in the trailer.
addDoorway(node:)
/ / 1
let aboveDoorNode = makeWallNode(length: DOOR_WIDTH,
height: WALL_HEIGHT - DOOR_HEIGHT)
/ / 2
aboveDoorNode.eulerAngles = SCNVector3(0.270.0.degreesToRadians, 0)
/ / 3
aboveDoorNode.position =
SCNVector3(0.POSITION_Y+ (WALL_HEIGHT-DOOR_HEIGHT) *0.5+DOOR_HEIGHT.POSITION_Z+SURFACE_LENGTH*0.5)
node.addChildNode(aboveDoorNode)
Copy the code
- Create a wall node with the dimensions of the entrance above.
- Adjust the rotation of the aboveDoorNode so that it is in front of the space-time gate. The masked side faces outward.
- Set the position of the node so that it is just above the doorway. Add it as a child node of node.
Run the app. This time you will see that the doorway frame now has proper walls.
Place the light
This portal doesn’t look very attractive. In fact, it’s rather dark and gloomy. You can add a light source to illuminate them! Add the following methods to the PortalViewController:
func placeLightSource(rootNode: SCNNode) {
/ / 1
let light = SCNLight()
light.intensity = 10
/ / 2
light.type = .omni
/ / 3
let lightNode = SCNNode()
lightNode.light = light
/ / 4
lightNode.position = SCNVector3(0.POSITION_Y+WALL_HEIGHT.POSITION_Z)
rootNode.addChildNode(lightNode)
}
Copy the code
Explanation of code:
- Create an SCNLight object and set its intensity. Because we are using a physically-based light model, this value is the light flux of the source. The default is 1000 lumens, but you want a lower intensity to make it look slightly darker.
- The type of light determines the shape and direction of the light, as well as a series of properties that modify the behavior of the light. Here, you set the light type to Omnidirectional, which is point light. The intensity and direction of the light in one direction are fixed. The light’s position relative to other objects in the scene determines its direction.
- Create a node to hold the light and attach a Light object to the node’s light property.
- Place the light in the center of the ceiling with Y and Z offsets, then add the lightNode as a child of the rootNode. In makePortal(), add the following code before return portal.
placeLightSource(rootNode: portal)
Copy the code
This places a light source inside the portal. Run the app and you’ll see a brighter, more attractive channel into your virtual world!
What’s the next step?
At this point our portal app is complete! You’ve learned a lot by creating this science-fiction portal. Let’s review what the app involves.
- You already have a basic understanding of SceneKit’s coordinate system and textures.
- You’ve learned how to create SCNNode objects with different geometries and attach textures to them.
- You also put light sources in the scene to make the portal look more realistic.
If you want to take it to the next level, there’s a lot you can do:
- Make a door that opens or closes when the user clicks on the screen.
- Explore using more different geometries to create a room that has unlimited access.
- Try changing the channel to a different shape. Don’t stop there. Let your sci-fi imagination run wild!
If you enjoyed this tutorial series, buy the full version of this book,ARKit by Tutorials, Available on our Online Store.
This chapter materials download