命中检测过程是指在视图上去一点,找出3D中的哪个对象位于视图上这个点的下方。实际上就是要回答:我点了谁?
在对一个SceneKit视图进行命中检测时,会得到一个SCNHitTestResult对象的数组,其中描述了找到的对象,以及该对象的相关信息。
下面这段代码可以让你点击的地方短暂的发亮一下:
import UIKit
import SceneKit
import SpriteKit
class SceneKitViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let sceneView = self.view as! SCNView
sceneView.backgroundColor = UIColor.grayColor()
//sceneView.allowsCameraControl = true
// 添加场景
let sceneOne = SCNScene()
sceneView.scene = sceneOne
// 添加照相机 并指明水平和垂直视角都是45度
let cameraOne = SCNCamera()
cameraOne.xFov = 45
cameraOne.yFov = 45
// 将照相机附加到节点
let cameraNode = SCNNode()
cameraNode.camera = cameraOne
cameraNode.position = SCNVector3(0,0,20)
sceneOne.rootNode.addChildNode(cameraNode)
// 添加3D对象
let capsuleOne = SCNCapsule(capRadius: 2.5,height: 10)
let capsuleNodeOne = SCNNode(geometry: capsuleOne)
capsuleNodeOne.position = SCNVector3(0,0)
sceneOne.rootNode.addChildNode(capsuleNodeOne)
// 添加环境光源
let ambientLight = SCNLight()
ambientLight.type = SCNLightTypeAmbient
ambientLight.color = UIColor(white: 0.25,alpha: 1.0)
let ambientNodeOne = SCNNode()
ambientNodeOne.light = ambientLight
sceneOne.rootNode.addChildNode(ambientNodeOne)
// 添加泛光源
let omniLight = SCNLight()
omniLight.type = SCNLightTypeOmni
omniLight.color = UIColor(white:1.0,alpha: 1.0)
let omniNodeOne = SCNNode()
omniNodeOne.light = omniLight
omniNodeOne.position = SCNVector3(-5,8,5)
sceneOne.rootNode.addChildNode(omniNodeOne)
// 为场景中的内容实现动画
let moveUpAndDownAnimation = CABasicAnimation(keyPath: "position")
moveUpAndDownAnimation.byValue = NSValue(SCNVector3:SCNVector3(0,5,0))
// 在最后加速和减速,而不是机械弹跳
moveUpAndDownAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaSEOut)
// 在末端自动返回
moveUpAndDownAnimation.autoreverses = true
// 动画无限次循环
moveUpAndDownAnimation.repeatCount = Float.infinity
moveUpAndDownAnimation.duration = 2
// 添加到一个节点
capsuleNodeOne.addAnimation(moveUpAndDownAnimation,forKey: "upAndDown")
// 创建文本几何体
let text3D = SCNText(string: "BlaBlaBla",extrusionDepth: 0.3)
text3D.font = UIFont.systemFontOfSize(2)
let textNode = SCNNode(geometry: text3D)
textNode.position = SCNVector3(-5,6,0)
capsuleNodeOne.addChildNode(textNode)
// 合并动画
let rotateAnimation = CABasicAnimation(keyPath: "eulerAngles")
rotateAnimation.byValue = NSValue(SCNVector3: SCNVector3(x: Float(0),y: Float(M_PI*2),z: Float(0)))
rotateAnimation.repeatCount = Float.infinity
rotateAnimation.duration = 4
textNode.addAnimation(rotateAnimation,forKey: "rotation")
// 质感和纹理
let redMetallicMaterial = SCNMaterial()
redMetallicMaterial.diffuse.contents = UIColor.grayColor()
redMetallicMaterial.specular.contents = UIColor.whiteColor()
redMetallicMaterial.shininess = 1
capsuleOne.materials = [redMetallicMaterial]
// 文字纹理
let noiseTexture = SKTexture(noiseWithSmoothness:0.25,size:CGSize(width: 512,height: 512),grayscale:true)
let noiseMaterial = SCNMaterial()
noiseMaterial.diffuse.contents = noiseTexture
text3D.materials = [noiseMaterial]
// 法向贴图
let noiseNormalMapTexture = noiseTexture.textureByGeneratingNormalMapWithSmoothness(0.1,contrast: 1)
redMetallicMaterial.normal.contents = noiseNormalMapTexture
// 命中检测
let tapRecognizerOne = UITapGestureRecognizer(target: self,action: "tapped:")
sceneView.addGestureRecognizer(tapRecognizerOne)
// 启动用户交互
sceneView.userInteractionEnabled = true
}
func tapped(tapRecognizer:UITapGestureRecognizer){
if tapRecognizer.state == UIGestureRecognizerState.Ended{
let sceneView = self.view as! SCNView
let hits = sceneView.hitTest(tapRecognizer.locationInView(tapRecognizer.view),options: nil) as [SCNHitTestResult]
for hit in hits {
if let theMaterial = (hit.node.geometry?.materials[0]) as SCNMaterial? {
let highLightAnimation = CABasicAnimation(keyPath: "contents")
highLightAnimation.fromValue = UIColor.blackColor()
highLightAnimation.toValue = UIColor.yellowColor()
highLightAnimation.autoreverses = true
highLightAnimation.repeatCount = 0
highLightAnimation.duration = 0.3
theMaterial.emission.addAnimation(highLightAnimation,forKey: "highLight")
}
}
}
}
}