【问题标题】:How to use SCNAvoidOccluderConstraint (any example)如何使用 SCNAvoidOccluderConstraint(任何示例)
【发布时间】:2017-08-15 20:44:22
【问题描述】:

有人有使用SCNAvoidOccluderConstraint的例子吗?

我找到的唯一描述是:

@abstract 一个 SCNAvoidOccluderConstraint 约束放置接收器 在阻止具有指定类别的节点的位置 遮挡目标。

@discussion 目标节点及其子节点是 作为潜在的遮挡物被忽略。

更新:Xcode 9 正式发布,但文档中仍然没有一行。

【问题讨论】:

  • 嘿 Vasilii,你对这个感到高兴吗?
  • @JohnM 不,仍然没有运气:(

标签: swift scenekit xcode9


【解决方案1】:

来晚了,但这是一个工作示例(在 Python 中,但可以很容易地在 Swift 或 ObjC 中重现)。带有 SCNAvoidOccluderConstraint 的球会在中间的块挡住另一个球的视线时跳回其轨迹。

"""
avoid occluder demo
"""

from objc_util import *
import sceneKit as scn
import ui
import math

def dot(v1, v2):
  return sum(x*y for x,y in zip(list(v1),list(v2)))

def det2(v1, v2):
  return v1[0]*v2[1] - v1[1]*v2[0]

class Demo:

  @classmethod
  def run(cls):
    cls().main()

  @on_main_thread
  def main(self):
    main_view = ui.View()
    w, h = ui.get_screen_size()
    main_view.frame = (0,0,w,h)
    main_view.name = 'avoid occluder demo'

    scene_view = scn.View(main_view.frame, superView=main_view)
    scene_view.autoresizingMask = scn.ViewAutoresizing.FlexibleHeight | scn.ViewAutoresizing.FlexibleWidth
    scene_view.allowsCameraControl = True
    scene_view.delegate = self
    scene_view.backgroundColor = 'white'
    scene_view.rendersContinuously = True
    scene_view.scene = scn.Scene()

    root_node = scene_view.scene.rootNode

    floor_geometry = scn.Floor()
    floor_node = scn.Node.nodeWithGeometry(floor_geometry)
    root_node.addChildNode(floor_node)

    ball_radius = 0.2
    ball_geometry = scn.Sphere(radius=ball_radius)
    ball_geometry.firstMaterial.diffuse.contents = (.48, .48, .48)
    ball_geometry.firstMaterial.specular.contents = (.88, .88, .88)
    self.ball_node_1 = scn.Node.nodeWithGeometry(ball_geometry)
    self.ball_node_2 = scn.Node.nodeWithGeometry(ball_geometry)

    root_node.addChildNode(self.ball_node_1)
    root_node.addChildNode(self.ball_node_2)

    occluder_geometry = scn.Box(0.3, 2., 15., 0.2)
    occluder_geometry.firstMaterial.diffuse.contents = (.91, .91, .91)
    occluder_node = scn.Node.nodeWithGeometry(occluder_geometry)
    occluder_node.position = (0., 0.8, 0.)
    root_node.addChildNode(occluder_node)

    self.orbit_r = 10
    self.omega_speed_1 = math.pi/1500
    self.omega_speed_2 = 1.5*self.omega_speed_1
    self.ball_node_1.position = (self.orbit_r, 0.5, 0.)
    self.ball_node_2.position = (0., 0.5, self.orbit_r)

    constraint = scn.AvoidOccluderConstraint.avoidOccluderConstraintWithTarget(self.ball_node_1)
    self.ball_node_2.constraints = [constraint]

    camera_node = scn.Node()
    camera_node.camera = scn.Camera()
    camera_node.position = (0.5*self.orbit_r , 0.5*self.orbit_r, 1.5*self.orbit_r)
    camera_node.lookAt(root_node.position)
    root_node.addChildNode(camera_node)

    light_node = scn.Node()
    light_node.position = (self.orbit_r, self.orbit_r, self.orbit_r)
    light = scn.Light()
    light.type = scn.LightTypeDirectional
    light.castsShadow = True
    light.shadowSampleCount = 32
    light.color = (.99, 1.0, .86)
    light_node.light = light
    light_node.lookAt(root_node.position)
    root_node.addChildNode(light_node)

    main_view.present(hide_title_bar=False)

  def update(self, view, atTime):
    pos_1 = self.ball_node_1.presentationNode.position
    pos_2 = self.ball_node_2.presentationNode.position
    self.omega_1 = -math.atan2(det2((pos_1.x, pos_1.z), (1., 0.)), dot((pos_1.x, pos_1.z), (1., 0.)))
    self.omega_2 = -math.atan2(det2((pos_2.x, pos_2.z), (1., 0.)), dot((pos_2.x, pos_2.z), (1., 0.)))
    self.omega_1 += self.omega_speed_1
    self.omega_2 += self.omega_speed_2
    self.ball_node_1.position = (self.orbit_r*math.cos(self.omega_1), 0.5, self.orbit_r*math.sin(self.omega_1))
    self.ball_node_2.position = (self.orbit_r*math.cos(self.omega_2), 0.5, self.orbit_r*math.sin(self.omega_2))

Demo.run()

【讨论】:

  • 为了详细说明这个答案,对于那些像我一样看过Python并且喜欢wth的人来说,这个例子来自@pulbrich的Pythonista模块here。您可以使用它在您的 iOS 设备上直接(或多或少地)为 SceneKit 编码。很不错。
【解决方案2】:

我最近遇到了这个老家伙,希望能更深入地了解这个约束是否可以用于解决特定问题。不幸的是,Apple 的文档仍然很糟糕,所以我在这里留下更多的笔记供后人参考。

SCNAvoidOccluderConstraint 将 SCNNode 作为目标。如果一个物体挡住了目标节点和您添加此约束的节点之间的视线,具有约束的节点将跳转到其原始位置和目标之间最近的点,以重新建立其视线。目标节点。

在大多数情况下,该点将立即位于阻碍对象的另一侧,因此您的受约束对象不会一直移动到阻碍对象的另一侧;其中心点将与遮挡物相对于目标的可见边缘对齐。

此外,您可以使用 SCNNode 的 categoryBitMask 和约束的 occluderCategoryBitMask 将某些节点排除在遮挡物之外。

这是对@pulbrich 在 Swift 中的原始答案的松散改编,它说明了用法。您可以将其粘贴到默认 XCode SceneKit 游戏项目的 GameViewController.swift 文件中:

import SceneKit
import QuartzCore

class GameViewController: NSViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let scene = SCNScene()
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
        cameraNode.look(at: SCNVector3(0,0,0))
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 0)
        scene.rootNode.addChildNode(lightNode)
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.color = NSColor.darkGray
        scene.rootNode.addChildNode(ambientLightNode)
        let scnView = self.view as! SCNView
        scnView.scene = scene
        scnView.allowsCameraControl = true
        scnView.showsStatistics = true
        scnView.backgroundColor = NSColor.black
        
        //--------------------------

        let ball_radius = 0.2
        let ball_geometry = SCNSphere(radius: ball_radius)
        let ball_node_1 = SCNNode.init(geometry: ball_geometry)
        ball_node_1.name = "b1"
        let ball_node_2 = SCNNode.init(geometry:ball_geometry)
        ball_node_2.name = "b2"
        
        scene.rootNode.addChildNode(ball_node_1)
        scene.rootNode.addChildNode(ball_node_2)
        
        ball_node_1.worldPosition = SCNVector3(5, 5, 0)
        ball_node_2.worldPosition = SCNVector3(5, -5, 0)
        
        let occluder_geometry = SCNBox(width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0)
        let occluder_node = SCNNode.init(geometry: occluder_geometry)
        scene.rootNode.addChildNode(occluder_node)

        let constraint = SCNAvoidOccluderConstraint(target: ball_node_1)
        ball_node_2.constraints = [constraint]
        
        let a1 = CABasicAnimation(keyPath: "position")
        a1.toValue = SCNVector3(-5,5,0)
        a1.duration = 5
        a1.autoreverses = true
        a1.repeatCount = .infinity
        ball_node_1.addAnimation(a1, forKey: "move1")
        
        //IMPORTANT NOTE: this constraint will hose CABasicAnimation,
        //but the presense of the animation will snap it back to the toValue
        //vector when the target is no longer occluded
        let a2 = CABasicAnimation(keyPath: "position")
        a2.toValue = SCNVector3(5,-5,0)
        //a2.toValue = SCNVector3(-5,-5,0)
        a2.duration = 5
        a2.autoreverses = true
        a2.repeatCount = .infinity
        ball_node_2.addAnimation(a2, forKey: "move2")
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多