Я пытаюсь отобразить базовый c 3D-контент в моем приложении, основанном в основном на SpriteKit. Я действительно не могу сделать это наоборот (т.е. добавить оверлеи SpriteKit в приложение на основе SceneKit).
Одна из моих сцен имеет SK3DNode с некоторой базовой c геометрией и Я не могу заставить тестирование сработать .
Этот код создает сцену SceneKit для визуализации в 3D-узле:
class ObjectScene: SCNScene {
override init() {
super.init()
let box = createSolidBox(side: 1, radius: 0.05, color: .red)
let boxNode = SCNNode(geometry: box)
self.rootNode.addChildNode(boxNode)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
func createSolidBox(side: CGFloat, radius: CGFloat, color: SKColor) -> SCNBox {
let box = SCNBox(width: side, height: side, length: side, chamferRadius: radius)
let material = SCNMaterial()
material.diffuse.contents = color
material.locksAmbientWithDiffuse = true
box.materials = [SCNMaterial](repeating: material, count: 6)
return box
}
Сцена SpriteKit , с другой стороны, выглядит следующим образом:
class GameScene: SKScene {
let objectNode: SK3DNode
override init(size: CGSize) {
self.objectNode = SK3DNode(viewportSize: size)
super.init(size: size)
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
objectNode.scnScene = ObjectScene()
self.addChild(objectNode)
let camera = SCNCamera()
let cameraNode = SCNNode()
cameraNode.camera = camera
objectNode.pointOfView = cameraNode
objectNode.pointOfView?.position = SCNVector3(x: 0, y: 0, z: 10)
/*
Based on Apple's sample code at:
https://developer.apple.com/documentation/spritekit/sk3dnode/displaying_3d_content_in_a_spritekit_scene
*/
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let location = touches.first!.location(in: objectNode)
let results = objectNode.hitTest(location, options: nil)
print("Results: \(results.count)")
}
}
(поскольку сцена создается экземпляром программно (не из файла sks), она создается / представлен на viewDidAppear ( :) вместо viewDidLoad (), так что размер представления известен и может быть правильно задан.) _
Я поместил приведенный выше код в MRE на Github .
Прямо сейчас, , где бы я ни нажимал, попаданий не обнаружено . Если я добавлю все больше и больше объектов, до такой степени, что они заполняют весь видовой экран, некоторые местоположения экрана вызовут попадание, но это выглядит совершенно не связанным с объектами, отображаемыми на экране.
Я думаю, что возможно, я не используя системы координат правильно, однако документация Apple не предоставляет конкретный код и, по-видимому, предполагает, что SK3DNode автоматически преобразует координаты SpriteKit в SceneKit для выполнения теста.
Я не нашел ни одного примера кода, который пытается выполнить точно это, так что я понятия не имею.
- Должен ли я выполнить какое-то дополнительное преобразование на касании даже перед тем, как вызвать
hitTest(_:options:)
? - Имеет ли свойство
scaleMode
свойства SKScene влияет на это каким-либо образом? если да, то как? - Имеет ли значение свойство
anchorPoint
?
Я играл с количеством объектов (давая каждому узлу имя для целей отладки) и свойствами выше, но не могу сделать ничего значимого из результатов, которые я получаю.
ОБНОВЛЕНИЕ
Я попытался оставить привязку SKScene по умолчанию (0, 0)
и вместо этого поместите SK3DNode в центр (ширина / 2, высота / 2).
Затем я добавил код для проверки всех целых координат сетки SKView, как показано ниже:
for x in 0 ..< Int(size.width) {
for y in 0 ..< Int(size.height) {
let x0 = CGFloat(x)
let y0 = CGFloat(y)
let point = CGPoint(x: x0, y: y0)
let results = objectNode.hitTest(point, options: nil)
if results.count > 0 {
print("Results at (\(x), \(y)): \(results.count)")
}
}
}
... и сравнил выходной журнал с ручными измерениями отрисованного окна на снимке экрана, который я сделал в имитаторе, используя инструмент редактирования изображений (Pixelmator) , Я изменил размер скриншота до 50%, так что я мог измерить точек вместо пикселей .
Я понял, что сообщенные координаты отклоняются с коэффициентом тео; То есть код ниже:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let location = touches.first!.location(in: self)
let point = CGPoint(x: 2*location.x, y: 2*location.y)
let results = objectNode.hitTest(point, options: nil)
print("Results: \(results.count)")
}
... дает ожидаемые результаты , но я до сих пор не понимаю, почему. Я даже попытался изменить размер окна и расстояние до камеры, а также постукивать со всех сторон как внутри, так и снаружи рендеринга. Работает отлично.
Возможно, UITouch дает мне координаты в точках, но каким-то образом SK3DNode ожидает пиксели ?? Я определенно не хочу жестко закодировать эти маги c 2x в мой код ...