【问题标题】:3D-Globe sizing and scaling issues with SceneKit and SwiftSceneKit 和 Swift 的 3D-Globe 大小和缩放问题
【发布时间】:2014-10-30 12:36:46
【问题描述】:

我有一个关于如何使用场景工具包设置 3d 地球动画轴的问题...我希望地球的中心在固定轴上旋转,就像桌子上旋转的地球一样。我将如何实施?

完整的源代码可以在 Github 上找到...https://github.com/schwa/iOS-8-SceneKit-Globe-Test ...但我也会在下面粘贴代码。

非常感谢您的帮助和反馈!

//  AppDelegate.swift

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    func applicationWillResignActive(application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(application: UIApplication) {
        // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }


}




//  CGlobeScene.m

#import "CGlobeScene.h"

#import <GLKit/GLKit.h>
#import <QuartzCore/QuartzCore.h>
#import <CoreLocation/CoreLocation.h>

@interface CGlobeScene ()
@property (readwrite, nonatomic, strong) SCNCamera *camera;
@property (readwrite, nonatomic, strong) SCNNode *cameraNode;
@property (readwrite, nonatomic, strong) SCNNode *ambientLightNode;
@property (readwrite, nonatomic, strong) SCNNode *lightNode;
@property (readwrite, nonatomic, strong) SCNNode *globeNode;
@end

#pragma mark -

@implementation CGlobeScene

- (id)init
    {
    if ((self = [super init]) != NULL)
        {
        self.camera = [SCNCamera camera];
        self.camera.zNear = 0.01;
        self.cameraNode = [SCNNode node];
        self.cameraNode.position = (SCNVector3){ 0, 0, 1.5 };
        self.cameraNode.camera = self.camera;

        self.camera.focalBlurRadius = 0;
        CABasicAnimation *theFocusAnimation = [CABasicAnimation animationWithKeyPath:@"focalBlurRadius"];
        theFocusAnimation.fromValue = @(100);
        theFocusAnimation.toValue = @(0);
        theFocusAnimation.duration = 2.0;
        theFocusAnimation.removedOnCompletion = YES;
        [self.camera addAnimation:theFocusAnimation forKey:@"focus"];

        [self.rootNode addChildNode:self.cameraNode];

        SCNLight *theAmbientLight = [SCNLight light];
        theAmbientLight.type = SCNLightTypeAmbient;
        theAmbientLight.color = [UIColor colorWithWhite:0.5 alpha:1.0];
        self.ambientLightNode = [SCNNode node];
        self.ambientLightNode.light = theAmbientLight;
        [self.rootNode addChildNode:self.ambientLightNode];

        self.globeNode = [SCNNode node];
        [self.rootNode addChildNode:self.globeNode];

        SCNSphere *theGlobeGeometry = [SCNSphere sphereWithRadius:0.5];
        theGlobeGeometry.firstMaterial.diffuse.contents = [UIImage imageNamed:@"earth_diffuse.jpg"];
        theGlobeGeometry.firstMaterial.ambient.contents = [UIImage imageNamed:@"earth_ambient2.jpeg"];
//      theGlobeGeometry.firstMaterial.ambient.contents = [UIImage imageNamed:@"earth_ambient.jpg"];
        theGlobeGeometry.firstMaterial.specular.contents = [UIImage imageNamed:@"earth_specular.jpg"];
        theGlobeGeometry.firstMaterial.emission.contents = NULL;
        theGlobeGeometry.firstMaterial.transparent.contents = NULL;
        theGlobeGeometry.firstMaterial.reflective.contents = NULL;
        theGlobeGeometry.firstMaterial.multiply.contents = NULL;
        theGlobeGeometry.firstMaterial.normal.contents = [UIImage imageNamed:@"earth_normal.jpg"];

        SCNNode *theGlobeModelNode = [SCNNode nodeWithGeometry:theGlobeGeometry];
        [self.globeNode addChildNode:theGlobeModelNode];

        SCNSphere *theCloudGeometry = [SCNSphere sphereWithRadius:0.501];
        theCloudGeometry.firstMaterial.diffuse.contents = NULL;
        theCloudGeometry.firstMaterial.ambient.contents = NULL;
        theCloudGeometry.firstMaterial.specular.contents = NULL;
        theCloudGeometry.firstMaterial.emission.contents = NULL;
        theCloudGeometry.firstMaterial.transparent.contents = [UIImage imageNamed:@"earth_clouds.png"];
        theCloudGeometry.firstMaterial.reflective.contents = NULL;
        theCloudGeometry.firstMaterial.multiply.contents = NULL;
        theCloudGeometry.firstMaterial.normal.contents = NULL;

        SCNNode *theCloudModelNode = [SCNNode nodeWithGeometry:theCloudGeometry];
        [self.globeNode addChildNode:theCloudModelNode];
        }
    return self;
    }

@end




//  GameViewController.swift
//  SceneKitTest

import UIKit
import QuartzCore
import SceneKit

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // create a new scene
        let scene = GlobeScene()

        // create and add a light to the scene
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light.type = SCNLightTypeOmni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        scene.rootNode.addChildNode(lightNode)

        // create and add an ambient light to the scene
//        let ambientLightNode = SCNNode()
//        ambientLightNode.light = SCNLight()
//        ambientLightNode.light.type = SCNLightTypeAmbient
//        ambientLightNode.light.color = UIColor.darkGrayColor()
//        scene.rootNode.addChildNode(ambientLightNode)

        // retrieve the SCNView
        let scnView = self.view as SCNView

        // set the scene to the view
        scnView.scene = scene

        // allows the user to manipulate the camera
        scnView.allowsCameraControl = true

        // show statistics such as fps and timing information
        scnView.showsStatistics = true

        // configure the view
        scnView.backgroundColor = UIColor.blackColor()

        // add a tap gesture recognizer
        let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
        let gestureRecognizers = NSMutableArray()
        gestureRecognizers.addObject(tapGesture)
        gestureRecognizers.addObjectsFromArray(scnView.gestureRecognizers)
        scnView.gestureRecognizers = gestureRecognizers
    }

    func handleTap(gestureRecognize: UIGestureRecognizer) {
        // retrieve the SCNView
        let scnView = self.view as SCNView

        // check what nodes are tapped
        let p = gestureRecognize.locationInView(scnView)
        let hitResults = scnView.hitTest(p, options: nil)

        // check that we clicked on at least one object
        if hitResults.count > 0 {
            // retrieved the first clicked object
            let result: AnyObject! = hitResults[0]

            // get its material
            let material = result.node!.geometry.firstMaterial

            // highlight it
            SCNTransaction.begin()
            SCNTransaction.setAnimationDuration(0.5)

            // on completion - unhighlight
            SCNTransaction.setCompletionBlock {
                SCNTransaction.begin()
                SCNTransaction.setAnimationDuration(0.5)

                material.emission.contents = UIColor.blackColor()

                SCNTransaction.commit()
            }

            material.emission.contents = UIColor.redColor()

            SCNTransaction.commit()
        }
    }

    override func shouldAutorotate() -> Bool {
        return true
    }

    override func supportedInterfaceOrientations() -> Int {
        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
            return Int(UIInterfaceOrientationMask.AllButUpsideDown.toRaw())
        } else {
            return Int(UIInterfaceOrientationMask.All.toRaw())
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }

}



//  GlobeScene.swift
//  SceneKitTest

import SceneKit
import QuartzCore

class GlobeScene: SCNScene {

    var camera: SCNCamera
    var cameraNode: SCNNode
    var ambientLightNode: SCNNode
    var globeNode: SCNNode

    init() {

        self.camera = SCNCamera()
        self.camera.zNear = 0.01
        self.cameraNode = SCNNode()
        self.cameraNode.position = SCNVector3(x: 0.0, y: 0.0, z: 1.5)
        self.cameraNode.camera = self.camera

        self.camera.focalBlurRadius = 0;
//        CABasicAnimation *theFocusAnimation = [CABasicAnimation animationWithKeyPath:"focalBlurRadius"];
//        theFocusAnimation.fromValue = @(100);
//        theFocusAnimation.toValue = @(0);
//        theFocusAnimation.duration = 2.0;
//        theFocusAnimation.removedOnCompletion = YES;
//        [self.camera addAnimation:theFocusAnimation forKey:@"focus"];

        let theAmbientLight = SCNLight()
        theAmbientLight.type = SCNLightTypeAmbient
        theAmbientLight.color = UIColor(white: 0.5, alpha: 1.0)
        self.ambientLightNode = SCNNode()
        self.ambientLightNode.light = theAmbientLight

        self.globeNode = SCNNode()
        let theGlobeGeometry = SCNSphere(radius: 0.5)
        theGlobeGeometry.firstMaterial.diffuse.contents = UIImage(named:"earth_diffuse.jpg")
        theGlobeGeometry.firstMaterial.ambient.contents = UIImage(named:"earth_ambient2.jpeg")
//      theGlobeGeometry.firstMaterial.ambient.contents = UIImage(named:"earth_ambient.jpg")
        theGlobeGeometry.firstMaterial.specular.contents = UIImage(named:"earth_specular.jpg")
        theGlobeGeometry.firstMaterial.emission.contents = nil
        theGlobeGeometry.firstMaterial.transparent.contents = nil
        theGlobeGeometry.firstMaterial.reflective.contents = nil
        theGlobeGeometry.firstMaterial.multiply.contents = nil
        theGlobeGeometry.firstMaterial.normal.contents = UIImage(named:"earth_normal.jpg")

        let theGlobeModelNode = SCNNode(geometry: theGlobeGeometry)
        self.globeNode.addChildNode(theGlobeModelNode)

        let theCloudGeometry = SCNSphere(radius:0.501)
        theCloudGeometry.firstMaterial.diffuse.contents = nil
        theCloudGeometry.firstMaterial.ambient.contents = nil
        theCloudGeometry.firstMaterial.specular.contents = nil
        theCloudGeometry.firstMaterial.emission.contents = nil
        theCloudGeometry.firstMaterial.transparent.contents = UIImage(named:"earth_clouds.png")
        theCloudGeometry.firstMaterial.reflective.contents = nil
        theCloudGeometry.firstMaterial.multiply.contents = nil
        theCloudGeometry.firstMaterial.normal.contents = nil

        let theCloudModelNode = SCNNode(geometry: theCloudGeometry)
        self.globeNode.addChildNode(theCloudModelNode)

        // animate the 3d object
        let animation: CABasicAnimation = CABasicAnimation(keyPath: "rotation")
        animation.toValue = NSValue(SCNVector4: SCNVector4(x: 1, y: 1, z: 0, w: Float(M_PI)*2))
        animation.duration = 5
        animation.repeatCount = MAXFLOAT //repeat forever
        globeNode.addAnimation(animation, forKey: nil)

        super.init()

        self.rootNode.addChildNode(self.cameraNode)
        self.rootNode.addChildNode(self.ambientLightNode)
        self.rootNode.addChildNode(self.globeNode)
    }
}

【问题讨论】:

    标签: ios swift scenekit


    【解决方案1】:

    您必须在给定恒定视野的情况下更改相机到对象的距离,或者根据相机到对象的距离来更改相机的 FOV。

    http://en.wikipedia.org/wiki/Angle_of_viewHow to calculate the z-distance of a camera to view an image at 100% of its original scale in a 3D space

    【讨论】:

    • 好的,感谢您的参考,我会检查该信息。所以更具体到这个应用程序中的这个代码示例,我将编辑 self.camera 值坐标,基本上......?
    猜你喜欢
    • 2014-02-03
    • 2015-06-15
    • 2015-05-01
    • 1970-01-01
    • 2018-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多