如何定位 SCNCamera 以便可以看到对象 "just fits"?
How do I position an SCNCamera such that an object "just fits" in view?
我正在使用 SceneKit 制作 3D 棋盘游戏。棋盘本身是平的,但上面的棋子是 3D 的。我想定位相机,使其以这样的角度俯视板子:
camera
/
/
/
/
/
board /
___________
我想定位相机,使整个板都在视野中,而且不小。我在运行时知道棋盘的尺寸,但在编译时不知道,因为用户可以从许多不同的棋盘中选择来玩游戏。
我试着计算相机至少需要多远才能看到电路板的全宽。我画了这样的图:
并计算出距离是板的宽度除以 tan(FOV/2) 的一半。
将其翻译成代码:
private func setupCamera(boardWidth: CGFloat, maxBoardZ: CGFloat, boardCenterX: CGFloat) {
cameraNode = SCNNode()
let camera = SCNCamera()
cameraNode.camera = camera
let boardRadius = boardWidth / 2
let cameraDistance = boardRadius / tan(degreesToRadians(camera.fieldOfView) / 2)
let cameraHeight: Float = 10
cameraNode.position = SCNVector3(x: Float(boardCenterX), y: cameraHeight, z: Float(maxBoardZ + cameraDistance))
cameraNode.eulerAngles.x = -0.5
}
cameraNode
是场景的 属性,我后来将场景视图的 pointOfView
设置为。
这在纵向模式下看起来不错(这只是整个 phone 屏幕的一部分):
如果不切断电路板的一部分,相机就不可能靠近电路板。
但是在横向模式下,与它所在的 SCNView
相比,棋盘非常小:
镜头可以移近一点!我本以为会是这样的:
注意白色背景区域 - 那是 SCNView
。
我认为 FOV 可能在横向上发生了变化,但当我在调试器中检查时,无论方向如何,FOV 始终为 60 度。看起来即使 SCNCamera
有一个 fieldOfView
属性,SCNView
也有它自己的、独立的、取决于它的宽度和高度的 FOV,我不知道如何访问它。
如何定位相机,使整个板 刚好 适合 SCNView
?
好的 - 在这里发布 - 希望没问题。
我只对几张大地图使用了 strafe,但最终将它们删除了。我希望所有地图都适合 - 它看起来与您的非常相似。所以是的,我倒退了。我把相机放在我想要的地方,然后摆弄地图和面板大小,所以我一次只处理一件事。
我有三角形、四边形和六边形的面板。这是一个塔防游戏,所以攻击者可以根据面板的类型以不同的方式移动。
class Camera
{
var data = Data.sharedInstance
var util = Util.sharedInstance
var gameDefaults = Defaults()
var cameraEye = SCNNode()
var cameraFocus = SCNNode()
var centerX: Int = 100
var strafeDelta: Float = 0.8
var zoomLevel: Int = 35
var zoomLevelMax: Int = 35 // Max number of zoom levels
//********************************************************************
init()
{
cameraEye.name = "Camera Eye"
cameraFocus.name = "Camera Focus"
cameraFocus.isHidden = true
cameraFocus.position = SCNVector3(x: 0, y: 0, z: 0)
cameraEye.camera = SCNCamera()
cameraEye.constraints = []
cameraEye.position = SCNVector3(x: 0, y: 15, z: 0.1)
let vConstraint = SCNLookAtConstraint(target: cameraFocus)
vConstraint.isGimbalLockEnabled = true
cameraEye.constraints = [vConstraint]
}
//********************************************************************
func reset()
{
centerX = 100
cameraFocus.position = SCNVector3(x: 0, y: 0, z: 0)
cameraEye.constraints = []
cameraEye.position = SCNVector3(x: 0, y: 32, z: 0.1)
cameraFocus.position = SCNVector3Make(0, 0, 0)
let vConstraint = SCNLookAtConstraint(target: cameraFocus)
vConstraint.isGimbalLockEnabled = true
cameraEye.constraints = [vConstraint]
}
//********************************************************************
func strafeRight()
{
if(centerX + 1 < 112)
{
centerX += 1
cameraEye.position.x += strafeDelta
cameraFocus.position.x += strafeDelta
}
}
//********************************************************************
func strafeLeft()
{
if(centerX - 1 > 90)
{
centerX -= 1
cameraEye.position.x -= strafeDelta
cameraFocus.position.x -= strafeDelta
}
}
//********************************************************************
}
我是这样使用 GKGraph 的:
var graphNodes: [GKPanelNode] = [] // All active graph nodes with connections
var myGraph = GKGraph() // declaring the Graph
然后是典型的面板负载,可能与您的相似
func getQuadPanelNode(vPanelType: panelTypes) -> SCNNode
{
let plane = SCNBox(width: 1.4, height: 0.001, length: 1.4, chamferRadius: 0)
plane.materials = []
plane.materials = setQuadPanelTextures(vPanelType: vPanelType)
plane.firstMaterial?.isDoubleSided = false
return SCNNode(geometry: plane)
}
然后从我创建的地图加载面板。
func loadPanels()
{
removePanelNodes()
for vPanel in mapsDetail.getDetail(vMap: data.mapSelected)
{
let vPanel = Panel.init(vName: "Panel:" + vPanel.name, vPanelType: vPanel.type, vPosition: vPanel.pos, vRotation: vPanel.up)
gridPanels[vPanel.panelName] = vPanel
if(vPanel.type == .entry) { entryPanelName = vPanel.panelName }
if(vPanel.type == .exit) { exitPanelName = vPanel.panelName }
}
}
我正在使用 SceneKit 制作 3D 棋盘游戏。棋盘本身是平的,但上面的棋子是 3D 的。我想定位相机,使其以这样的角度俯视板子:
camera
/
/
/
/
/
board /
___________
我想定位相机,使整个板都在视野中,而且不小。我在运行时知道棋盘的尺寸,但在编译时不知道,因为用户可以从许多不同的棋盘中选择来玩游戏。
我试着计算相机至少需要多远才能看到电路板的全宽。我画了这样的图:
并计算出距离是板的宽度除以 tan(FOV/2) 的一半。
将其翻译成代码:
private func setupCamera(boardWidth: CGFloat, maxBoardZ: CGFloat, boardCenterX: CGFloat) {
cameraNode = SCNNode()
let camera = SCNCamera()
cameraNode.camera = camera
let boardRadius = boardWidth / 2
let cameraDistance = boardRadius / tan(degreesToRadians(camera.fieldOfView) / 2)
let cameraHeight: Float = 10
cameraNode.position = SCNVector3(x: Float(boardCenterX), y: cameraHeight, z: Float(maxBoardZ + cameraDistance))
cameraNode.eulerAngles.x = -0.5
}
cameraNode
是场景的 属性,我后来将场景视图的 pointOfView
设置为。
这在纵向模式下看起来不错(这只是整个 phone 屏幕的一部分):
如果不切断电路板的一部分,相机就不可能靠近电路板。
但是在横向模式下,与它所在的 SCNView
相比,棋盘非常小:
镜头可以移近一点!我本以为会是这样的:
注意白色背景区域 - 那是 SCNView
。
我认为 FOV 可能在横向上发生了变化,但当我在调试器中检查时,无论方向如何,FOV 始终为 60 度。看起来即使 SCNCamera
有一个 fieldOfView
属性,SCNView
也有它自己的、独立的、取决于它的宽度和高度的 FOV,我不知道如何访问它。
如何定位相机,使整个板 刚好 适合 SCNView
?
好的 - 在这里发布 - 希望没问题。
我只对几张大地图使用了 strafe,但最终将它们删除了。我希望所有地图都适合 - 它看起来与您的非常相似。所以是的,我倒退了。我把相机放在我想要的地方,然后摆弄地图和面板大小,所以我一次只处理一件事。
我有三角形、四边形和六边形的面板。这是一个塔防游戏,所以攻击者可以根据面板的类型以不同的方式移动。
class Camera
{
var data = Data.sharedInstance
var util = Util.sharedInstance
var gameDefaults = Defaults()
var cameraEye = SCNNode()
var cameraFocus = SCNNode()
var centerX: Int = 100
var strafeDelta: Float = 0.8
var zoomLevel: Int = 35
var zoomLevelMax: Int = 35 // Max number of zoom levels
//********************************************************************
init()
{
cameraEye.name = "Camera Eye"
cameraFocus.name = "Camera Focus"
cameraFocus.isHidden = true
cameraFocus.position = SCNVector3(x: 0, y: 0, z: 0)
cameraEye.camera = SCNCamera()
cameraEye.constraints = []
cameraEye.position = SCNVector3(x: 0, y: 15, z: 0.1)
let vConstraint = SCNLookAtConstraint(target: cameraFocus)
vConstraint.isGimbalLockEnabled = true
cameraEye.constraints = [vConstraint]
}
//********************************************************************
func reset()
{
centerX = 100
cameraFocus.position = SCNVector3(x: 0, y: 0, z: 0)
cameraEye.constraints = []
cameraEye.position = SCNVector3(x: 0, y: 32, z: 0.1)
cameraFocus.position = SCNVector3Make(0, 0, 0)
let vConstraint = SCNLookAtConstraint(target: cameraFocus)
vConstraint.isGimbalLockEnabled = true
cameraEye.constraints = [vConstraint]
}
//********************************************************************
func strafeRight()
{
if(centerX + 1 < 112)
{
centerX += 1
cameraEye.position.x += strafeDelta
cameraFocus.position.x += strafeDelta
}
}
//********************************************************************
func strafeLeft()
{
if(centerX - 1 > 90)
{
centerX -= 1
cameraEye.position.x -= strafeDelta
cameraFocus.position.x -= strafeDelta
}
}
//********************************************************************
}
我是这样使用 GKGraph 的:
var graphNodes: [GKPanelNode] = [] // All active graph nodes with connections
var myGraph = GKGraph() // declaring the Graph
然后是典型的面板负载,可能与您的相似
func getQuadPanelNode(vPanelType: panelTypes) -> SCNNode
{
let plane = SCNBox(width: 1.4, height: 0.001, length: 1.4, chamferRadius: 0)
plane.materials = []
plane.materials = setQuadPanelTextures(vPanelType: vPanelType)
plane.firstMaterial?.isDoubleSided = false
return SCNNode(geometry: plane)
}
然后从我创建的地图加载面板。
func loadPanels()
{
removePanelNodes()
for vPanel in mapsDetail.getDetail(vMap: data.mapSelected)
{
let vPanel = Panel.init(vName: "Panel:" + vPanel.name, vPanelType: vPanel.type, vPosition: vPanel.pos, vRotation: vPanel.up)
gridPanels[vPanel.panelName] = vPanel
if(vPanel.type == .entry) { entryPanelName = vPanel.panelName }
if(vPanel.type == .exit) { exitPanelName = vPanel.panelName }
}
}