- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在尝试将触摸从 SpriteKit 转换为 SceneKit,但遇到了一些困难。我的目的是移动一个 3D“怪物”,使其看起来就像在同一位置(虽然在后面)是一个 2D Crystal 。 2D Crystal 被添加到 SpriteKit 提供的 overlaySKScene
并定位。我们的“怪物”是一个全 3D SCNNode
,它位于 SCNScene
中,如下所示。
我已经尝试了多种方法,其中最接近的是我在下面的 makeMonsterEatCrystalAtLocation
方法中,尽管我知道这是错误的,因为它只在 SpriteKit 世界中起作用 -它不会从 SpriteKit 转换为 SceneKit。我还查看了 SCNSceneRenderer
协议(protocol)中的 unprojectPoint
,但该方法仅适用于 SceneKit 本身。任何帮助将不胜感激!我不偏爱 Objective-C 或 Swift,即使下面是 Obj-C。
- (void)setupSceneKit {
_sceneView = [[SCNView alloc] initWithFrame:[[UIScreen mainScreen] bounds] options:@{@"SCNPreferredRenderingAPIKey": @(SCNRenderingAPIOpenGLES2)}];
[self.view insertSubview:_sceneView aboveSubview:backgroundView];
_sceneView.scene = [SCNScene scene];
_sceneView.allowsCameraControl = YES;
_sceneView.autoenablesDefaultLighting = NO;
_sceneView.backgroundColor = [UIColor clearColor];
camera = [SCNCamera camera];
[camera setXFov:20];
[camera setYFov:20];
camera.zFar = 10000.0f;
cameraNode = [SCNNode node];
cameraNode.camera = camera;
cameraNode.position = SCNVector3Make(0, 3, 700);
[_sceneView.scene.rootNode addChildNode:cameraNode];
}
- (void)createMonster {
_monsterNode = [SCNNode node];
[self.sceneView.scene.rootNode addChildNode:_monsterNode];
[SCNTransaction begin];
[SCNTransaction setAnimationDuration:0.5f];
_monsterNode.position = SCNVector3Zero;
[SCNTransaction commit];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
CGPoint crystalLocation = [[touches anyObject] locationInNode:self.sceneView.overlaySKScene];
SKNode *touchedCrystalNode = [self.sceneView.overlaySKScene nodeAtPoint:crystalLocation];
// determine that this is the SKNode touchedCrystalNode we're looking for...
[self makeMonsterEatCrystalAtLocation:crystalLocation];
}
- (void)makeMonsterEatCrystalAtLocation:(CGPoint)location {
// Attempt to move the "monster" (SCNNode in SceneKit) to appear as if its in the same
// location as the "crystal" (which is presented in the SpriteKit overlay: self.sceneView.overlaySKScene) and eventually
// play an animation of the monster eating the crystal.
CGPoint scnPoint = [self.sceneView.overlaySKScene convertPointToView:location];
[SCNTransaction begin];
[SCNTransaction setAnimationDuration:0.5f];
self.monsterNode.position = SCNVector3Make(scnPoint.x, scnPoint.y, 0);
[SCNTransaction commit];
// ...
}
最佳答案
一种方法是将您的怪物放在 SK3DNode
中。然后,您可以在 SpriteKit 中度过大部分时间,而无需在坐标系之间进行转换。
投影时,你必须处理几个不同的坐标系:SpriteKit 场景(原点在左下角)、SceneKit View 的屏幕坐标(原点在左上角或左下角,取决于操作系统)、 View 的相机局部坐标系统,以及 SceneKit 场景的世界坐标系。
让我们从 SceneKit 方面开始。您的相机有自己的 3D 坐标系,表示 view frustum 的内容.屏幕上的单个点对应于平截头体内从近平面到远平面的一条线段;相机空间中的 Z 轴对应于点在近平面和远平面之间的相对位置。您的 SCNView
,由于遵守 SCNSceneRenderer
协议(protocol),可以在屏幕坐标和 3D 世界空间之间进行转换。
要移动您的怪物,您将使用 projectPoint
获取其当前相机 x/y/z 坐标,找出您要移动到的屏幕位置,然后使用 unprojectPoint
来计算该屏幕位置的世界位置。像这样:
let screenDestinationX = 100.0
let screenDestinationY = 200.0
let monsterCoordinates = sceneView.projectPoint(MonsterNode.position)
let monsterDestinationCoordinates = SCNVector3D(x: screenDestinationX,
y: screenDestinationY,
z: monsterCoordinates.z)
let monsterDestinationPosition = sceneView.unprojectPoint(monsterDestinationCoordinates)
通过为怪物的开始和结束保持相同的相机 Z 坐标,您将使怪物与相机保持相同的距离。
现在是 SpriteKit 方面。如果您的 sceneView.overlaySKScene
将其 scaleMode
设置为 SKSceneScaleMode.ResizeFill
,则您的 SKScene
的大小将与你的屏幕。当然,Y 轴的方向可能不同。所以向你的 Crystal 询问它的 SpriteKit 坐标,必要时翻转 Y(高度减去 Y,而不仅仅是 Y),并且你有目的地 X 和 Y,你可以传递给 SceneKit 进行投影。
我有一个示例项目,它显示了 SceneKit 和覆盖 SpriteKit 坐标之间的转换,位于 https://github.com/halmueller/ImmersiveInterfaces/tree/master/Tracking%20Overlay。 .它并不完全符合您的要求,但它确实显示了交互。
最后,下面是一个显示世界坐标和相机坐标之间转换的 Playground:
import SceneKit
import SpriteKit
import XCPlayground
let sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 800, height: 600))
XCPlaygroundPage.currentPage.liveView = sceneView
var scene = SCNScene()
sceneView.scene = scene
sceneView.backgroundColor = SKColor.greenColor()
sceneView.debugOptions = .ShowWireframe
// default lighting
sceneView.autoenablesDefaultLighting = true
// a camera
var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
print (cameraNode.camera?.zFar, cameraNode.camera?.zNear)
cameraNode.camera?.automaticallyAdjustsZRange = false
cameraNode.position = SCNVector3(x: 5, y: 5, z: 50)
scene.rootNode.addChildNode(cameraNode)
let center = SCNNode()
center.position = SCNVector3(x:0, y:0, z:0)
scene.rootNode.addChildNode(center)
let centerConstraint = SCNLookAtConstraint(target: center)
cameraNode.constraints = [centerConstraint]
let sphere = SCNSphere(radius: 2)
sphere.geodesic = true
let sphereNode1 = SCNNode(geometry: sphere)
sphereNode1.position = SCNVector3(x:-8, y:5, z:10)
scene.rootNode.addChildNode(sphereNode1)
let sphereNode2 = SCNNode(geometry: sphere)
sphereNode2.position = SCNVector3(x:8, y:-5, z:-30)
scene.rootNode.addChildNode(sphereNode2)
let sphere1Coordinates = sceneView.projectPoint(sphereNode1.position)
print ("sphere1 position", sphereNode1.position, "screen coordinates",sphere1Coordinates)
let sphere2Coordinates = sceneView.projectPoint(sphereNode2.position)
print ("sphere2 position", sphereNode2.position, "screen coordinates",sphere2Coordinates)
let sphere2NearCoordinates = SCNVector3(x: sphere2Coordinates.x, y: sphere2Coordinates.y, z: sphere1Coordinates.z)
let sphere2FarPosition = sphereNode2.position
let sphere2NearPosition = sceneView.unprojectPoint(sphere2NearCoordinates)
let sphere1FarCoordinates = SCNVector3(x: sphere1Coordinates.x, y: sphere1Coordinates.y, z: sphere2Coordinates.z)
let sphere1NearPosition = sphereNode1.position
let sphere1FarPosition = sceneView.unprojectPoint(sphere1FarCoordinates)
let sphere1LowerCoordinates = SCNVector3(x: sphere1Coordinates.x, y: sphere1Coordinates.y - 100, z: sphere2Coordinates.z)
let sphere1LowerPosition = sceneView.unprojectPoint(sphere1LowerCoordinates)
let forwardAction = SCNAction.moveTo(sphere2NearPosition, duration: 3)
let backAction = SCNAction.moveTo(sphere2FarPosition, duration: 3)
let shiftAction = SCNAction.moveTo(sphere1LowerPosition, duration: 3)
let forwardBackShift = SCNAction.sequence([forwardAction, backAction, forwardAction, shiftAction])
sphereNode2.runAction(forwardBackShift) {
print ("sphere1 position", sphereNode1.position, "screen coordinates",sceneView.projectPoint(sphereNode1.position))
print ("sphere2 position", sphereNode2.position, "screen coordinates",sceneView.projectPoint(sphereNode2.position))
}
关于objective-c - 将 SpriteKit SKScene overlaySKScene 的 2D 点映射到 SceneKit SCNScene 中的 3D 点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34443727/
我正在尝试创建一个允许放置 3d 对象的应用程序。我能够编写一些有效的代码,但仅限于几何对象。我需要在一个场景中添加多个 SCNScenes。我该如何实现? 我是如何尝试的: let sceneVie
我正在使用一个共享项目,并花了很多时间将它更新为 Swift 2,所以我想让它正常工作,但不幸的是我有一个运行时错误需要处理。 Storyboard 上没有任何内容,因此一切都是以编程方式完成的。看到
我一直在尝试将 SCNScene 子类化,因为这似乎是保持场景相关逻辑的最佳位置。现在我不确定是否推荐这样做,所以我的第一个问题是——我是否应该将 SCNScene 子类化,如果不是,为什么不呢? 文
我有一个使用 SpriteKit 和发射器粒子 (sks) 的应用程序,我发现它不如 Scene kit 的粒子 (scnp) 真实。所以我希望将它合并到 SKScene 中,但我不确定这是否可能。所
目前,我正在制作有关ARKit的演示。我正在使用两个 3D 对象 .dae 文件。还实现了该对象的旋转,但在这里我遇到了问题,因为对象连续旋转,我们如何只旋转一次? 如何替换屏幕上的这些对象? 我还提
import UIKit import SceneKit class Scene: SCNScene { var cameraPosition = SCNVector3Make(0, 0, 1
我正在尝试创建包含带有纹理的 SCNScene 的 pod,但出现错误: SceneKit Error: Failed loading : C3DImage src:file:///Users/...
我正在尝试用代码更改当前的 sceneNamed,但我的方法似乎有一些问题。首先,新场景将发生变化,但我必须触摸或评价对象才能发生变化。其次,childNodeWithName 似乎根本没有变化!这是
我正在构建一个 ARKit + SceneKit 应用程序,它需要在现实世界中显示模型。每次用户选择一个按钮时,模型都会改变。 我尝试在按下按钮时将新模型加载到节点中,然后将其添加到场景的根节点,但这
感谢这里提供的答案 -- Programmatically create a UIView with color gradient --我可以为我的应用程序的主屏幕背景设置颜色渐变。 在使用 CAGr
我正在使用 ARKit,我无法从 SCNScene url 获取下载进度。这是我的代码: func downloadModel(hitTestResult: ARHitTestResult) {
我正在为我的 IT 任务做一个 ARKit 应用程序,我遵循了位掩码和碰撞指南,我让它工作,但它只适用于一个简单的盒子,而不是我的 3D 模型,所以有没有办法转换将此代码添加到底部的代码还是我做错了什
我想知道我应该如何从实例化的 SceneKit 场景中提取 SCNRenderer。我正在尝试获取位于 SCNRenderer 中的 AVAudioEngine,以便我可以将音频过滤器应用于我的节点。
如何将 off-screen SCNScene 渲染到 UIImage 中? 我知道 SCNView 提供了一个 -snapshot 方法,但不幸的是,它不适用于离屏 View 。 similar q
我正在使用一种非常简单的方法来设置 SKVideoNode 并通过几何体的漫反射内容将其放置在 SCNNode 中。当我这样做时,唯一纹理更新和正确显示视频的时间是相机或节点移动时。当两者都静止时,纹
我正在尝试找到将 SCNScene 与物理表对齐的最佳策略。就像 ARKit 应用程序 WWWFreeRivers . 目前我只是在测试一个简单的平面模型,其尺寸与表格相同。如果我画出 ARKit 检
我正在 SceneKit 中开发一个项目,用户可以更改场景中的对象,并希望能够在用户点击提交按钮时保存场景的状态。在SceneKit的文档中,有一个函数调用write:https://develope
我正在使用 SceneKit 和 ARKit。我用一系列表情符号制作了一个collectionView。现在,我希望用户能够从 collectionView 中选择表情符号,并且当他/她触摸屏幕时,所
我有一个带有相机设置的 SCNScene 子类,我想在所有子类中使用它。 let scene01 = TheSubclassScene() let scene02 = TheSubclassScene
我正在尝试加载目前只有 3 面墙、天花板和地板的场景。我正在加载我在 blender 中创建的场景并正常加载它。但是,具有 SCNBox 几何形状的 SCNNode 会直接掉落。该盒子附有一个动态物理
我是一名优秀的程序员,十分优秀!