如何在SceneKit中创建盘状光源

问题描述 投票:4回答:1

我正在寻找一种类似于Sun使用SceneKit照亮地球的光源。这是一门天文学课程。由于太阳比地球大,因此全向SCNLight不会起作用,因为它发出的光是从单个点发出的。太阳发出的光实质上是从很大的球体发出的,而不是单个点。

此图像是使用全向光源创建的,但并未真实显示地球的阴影区域。具体来说,北极不亮,但应该亮(在这种情况下,我们在夏天。picture

第二张图片更逼真,您可以看到北极照亮了,就像夏天一样。

enter image description here

问题是,要获取第二张图像,我必须非常繁琐地放置定向光以使图像正确(这是我手动完成的。对于第一张图像,我只是将全向光放置在与太阳球)。由于整个物体都是要动画的,因此使用定向光并必须随着地球沿其轨道前进不断对其进行重新定位,这将需要一些相当复杂的数学运算。

因此,我正在考虑创建一个SCNLight,该SCNLight使用通过程序创建的模型I / O光源对象进行初始化。根据苹果公司的“文档”,在Swift中,可以使用initializer from a specified model I/O light object创建一个SCNLight,据我理解,它允许创建"light source [that] illuminates a scene in all directions from an area in the shape of a disc"

“文档”指出以下“创建光”:

init(mdlLight: MDLLight)

它被定义为便利初始化程序:

convenience init(mdlLight: MDLLight)

我期望能够执行以下操作:

let lightModelObject = MDLLight()
lightModelObject.lightType = .discArea

let discShapedSceneLight = SCNLight(lightModelObject) //cannot convert value ... error.

但是最后一条语句使我得到:“无法将类型'MDLLight'的值转换为预期的参数类型'NSCoder'”。我也尝试过:

let discShapedSceneLight = SCNLight.init(lightModelObject)

但那里也没有运气。

我完全被卡住了!感觉到我在Swift中使用初始值设定项有些根本不了解的地方。

任何评论将不胜感激。

EDIT:根据相同的文档,我还在objective-C中尝试了以下操作:

#import <ModelIO/MDLLight.h>
...
SCNLight *discLight = [SCNLight light];
MDLPhysicallcPlausibleLight *ppl = [MDLPhysicallyPlausibleLight lightWithSCNLight:discLight];

但出现此错误:“选择器'lightWithSCNLight:'的未知类方法']

编辑:感谢@EmilioPelaez解决了这个问题。

我将完整的代码和所需的照明放在下面,也许会帮助其他人。

import UIKit
import QuartzCore
import SceneKit
import SceneKit.ModelIO

class GameViewController: UIViewController {

    var scnView:SCNView!
    var scnScene:SCNScene!
    var cameraNode:SCNNode!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupView()
        setupScene()
        setupCamera()
        drawSolarSystem()
    }

    func setupView() {
        scnView = self.view as! SCNView
        scnView.showsStatistics = true
        scnView.allowsCameraControl = true
        scnView.autoenablesDefaultLighting = false
    }

    func setupScene() {
        scnScene = SCNScene()
        scnView.scene = scnScene
        scnScene.background.contents = UIColor.systemBlue
    }

    func setupCamera() {
        cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 10)
        scnScene.rootNode.addChildNode(cameraNode)
    }

    func drawSolarSystem() {
      var geometryObject:SCNGeometry

//SUN object and light source
        let sunX:Float = -3.5   ///position a little off to the left of center

        //create the material for the Sun's surface
        let sunMaterial = SCNMaterial()
        sunMaterial.emission.contents = UIColor.yellow          ///the color the material emits.
//        sunMaterial.transparency = 0.3
//        sunMaterial.diffuse.contents = UIColor.systemYellow ///the color the material reflects when lit.

        //create the Sphere and assign it the material
        geometryObject = SCNSphere(radius: 1.0)
        geometryObject.firstMaterial=sunMaterial

        //create the node and assign it the geometry (object) previously created.
        let sunNode = SCNNode(geometry: geometryObject)
        sunNode.position = SCNVector3(x:sunX, y:0, z:0)
        scnScene.rootNode.addChildNode(sunNode)

        //create the light source and position it same place as the sun
        //create an MDLAreaLight, since the "normal" SCNLight types - such as omni - are not suitable.
        //The .omni type emanates from a point, and so doesn't correctly represent the sun lighting the earth
         let lightModelObject = MDLAreaLight()
         lightModelObject.lightType = .discArea
//         lightModelObject.areaRadius = 5.01 ///This doesn't appear to affect the light.

        //create the node and assign it the MDLAreaLight
         let sunLightNode = SCNNode()
         sunLightNode.light = SCNLight(mdlLight:lightModelObject)
         sunLightNode.light?.color = UIColor .white
         sunLightNode.position = SCNVector3(x:sunX, y:0, z:0)
         scnScene.rootNode.addChildNode(sunLightNode)


        //EARTH EQUATORIAL PLANE but centered on the Sun
        let floorObject = SCNFloor()
        floorObject.reflectivity = 0
        floorObject.width = 2
        floorObject.length = 3
        let earthEquatorialPlaneNode = SCNNode(geometry: floorObject)
        earthEquatorialPlaneNode.position = SCNVector3(x:sunX, y:0, z:0)
        scnScene.rootNode.addChildNode(earthEquatorialPlaneNode)


//EARTH main node - node with 2 subnodes, one sphere and one axis
        ///a node can only have a single geometry object attached. In order to attach multiple geometries, create a (parent) node without any geometry, and then attach subnodes with one geometry each.

        //The parent node
        let earthNode = SCNNode()
        earthNode.position = SCNVector3(x: 0, y:-1.2, z:0)
        scnScene.rootNode.addChildNode(earthNode)

        //the child node for the earth axis of rotation object
        geometryObject = SCNCylinder(radius: 0.01, height: 1.2)
        let earthAxisNode = SCNNode(geometry: geometryObject)
        earthNode.addChildNode(earthAxisNode)

        //the child node for the earth sphere object
        geometryObject = SCNSphere(radius: 0.5)
        let earthSphereNode = SCNNode(geometry: geometryObject)
        earthNode.addChildNode(earthSphereNode)

        //put some meridians and an equator onto the sphere.
        let earthSphereMaterial = SCNMaterial()
        geometryObject.firstMaterial = earthSphereMaterial
        earthSphereMaterial.diffuse.contents = "coordinateGrid.png"
        earthSphereMaterial.lightingModel = .lambert

    }

    override var shouldAutorotate: Bool {
        return true
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }

}
ios swift scenekit scnlight
1个回答
1
投票

如果添加import SceneKit.ModelIO,则应该能够使用当前不起作用的初始化程序。

© www.soinside.com 2019 - 2024. All rights reserved.