无法在SK3DNode上方显示精灵

时间:2020-05-03 05:13:00

标签: ios sprite-kit scenekit

我正在使用SK3DNode实例显示SpriteKit场景中的一些基本3D几何图形,以显示SceneKit场景的内容,如Apple's article here中所述。

我已经可以使用SceneKit节点变换和SK3DNode的位置/视口大小来随意定位节点和3D内容。

接下来,我想在我的SpriteKit场景中显示其他一些精灵,叠加在3D内容之上,但是我不能这样做:SK3DNode的内容总是绘制在顶端。

我尝试指定SK3DNode和SKSpriteNode的zPosition属性,但无济于事。

摘自Apple关于SK3DNode的文档:

使用SK3DNode对象将3D SceneKit内容合并到 基于SpriteKit的游戏。当SpriteKit渲染节点时, SceneKit 首先对场景进行动画处理和渲染。然后这个渲染的图像是 合成到SpriteKit场景中。使用scnScene属性来 指定要渲染的SceneKit场景。

(重点是我的)

关于z顺序,这有点模棱两可(似乎只提到进行渲染的时间顺序)。

我整理了minimal demo project on GitHub;相关代码为:

1。 SceneKit场景

import SceneKit
class SceneKitScene: SCNScene {

    override init() {
        super.init()

        let box = SCNBox(width: 10, height: 10, length: 10, chamferRadius: 0)
        let material = SCNMaterial()
        material.diffuse.contents = UIColor.green
        box.materials = [material]

        let boxNode = SCNNode(geometry: box)
        boxNode.transform = SCNMatrix4MakeRotation(.pi/2, 1, 1, 1)

        self.rootNode.addChildNode(boxNode)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

2。 SpriteKit场景

import SpriteKit
class SpriteKitScene: SKScene {

    override init(size: CGSize) {
        super.init(size: size)

        // Scene Background
        self.backgroundColor = .red

        // 3D Node
        let objectNode = SK3DNode(viewportSize: size)
        objectNode.scnScene = SceneKitScene()
        addChild(objectNode)
        objectNode.position = CGPoint(x: size.width/2, y: size.height/2)

        let camera = SCNCamera()
        let cameraNode = SCNNode()
        cameraNode.camera = camera
        objectNode.pointOfView = cameraNode
        objectNode.pointOfView?.position = SCNVector3(x: 0, y: 0, z: 60)
        objectNode.zPosition = -100

        // 2D Sprite
        let sprite = SKSpriteNode(color: .yellow, size: CGSize(width: 250, height: 60))
        sprite.position = objectNode.position
        sprite.zPosition = +100
        addChild(sprite)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

... 渲染结果为:

enter image description here

(我想要黄色矩形上方绿色框)

2 个答案:

答案 0 :(得分:3)

我与此事发生了与Apple的技术支持事件,他们才回到我身边。解决方案实际上非常简单。

如果要在b[0] = ne; int i = 0; 上渲染2D精灵,则需要停止b[0] = ne; // do something with b[0] if you want. int i = 1; 的内容写入深度缓冲区。


为此,您只需要在SK3DNodes上将SK3DNodes设置为writesToDepthBuffer

false

景气。有效。

答案 1 :(得分:1)

请注意,这只是我偶然发现的内容。我不知道它为什么起作用,并且如果不进一步了解,我可能会不信任它,但也许会有所帮助解释或实际解决方案。


似乎在SK3DNode旁边有SKShapeNode(带有填充)(作为同级,同级树的一部分或子级),可以按正确的顺序绘制它。 SK3DNode似乎也不需要与SKShapeNode相交。

填充很重要,因为透明填充会使此功能不起作用。中风似乎没有任何作用。

尺寸很小且alpha填充几乎为零的import PlaygroundSupport import SceneKit import SpriteKit let viewSize = CGSize(width: 300, height: 150) let viewportSize: CGFloat = viewSize.height * 0.75 func skview(color: UIColor, index: Int) -> SKView { let scene = SKScene(size: viewSize) scene.backgroundColor = color let view = SKView( frame: CGRect( origin: CGPoint(x: 0, y: CGFloat(index) * viewSize.height), size: viewSize ) ) view.presentScene(scene) view.showsDrawCount = true // Draw the box of the 3d node view port let viewport = SKSpriteNode(color: .orange, size: CGSize(width: viewportSize, height: viewportSize)) viewport.position = CGPoint(x: viewSize.width / 2, y: viewSize.height / 2) scene.addChild(viewport) return view } func cube() -> SK3DNode { let mat = SCNMaterial() mat.diffuse.contents = UIColor.green let box = SCNBox(width: viewportSize, height: viewportSize, length: viewportSize, chamferRadius: 0) box.firstMaterial = mat let boxNode3d = SCNNode(geometry: box) boxNode3d.runAction(.repeatForever(.rotateBy(x: 10, y: 10, z: 10, duration: 10))) let scene = SCNScene() scene.rootNode.addChildNode(boxNode3d) let boxNode2d = SK3DNode(viewportSize: CGSize(width: viewportSize, height: viewportSize)) boxNode2d.position = CGPoint(x: viewSize.width / 2, y: viewSize.height / 2) boxNode2d.scnScene = scene return boxNode2d } func shape() -> SKShapeNode { let shape = SKShapeNode(rectOf: CGSize(width: viewSize.height / 4, height: viewSize.height / 4)) shape.strokeColor = .clear shape.fillColor = .purple return shape } func rect(_ color: UIColor) -> SKSpriteNode { let sp = SKSpriteNode(texture: nil, color: color, size: CGSize(width: 200, height: viewSize.height / 4)) sp.position = CGPoint(x: viewSize.width / 2, y: viewSize.height / 2) return sp } // The original issue, untouched. func v1() -> SKView { let v = skview(color: .red, index: 0) v.scene?.addChild(cube()) v.scene?.addChild(rect(.yellow)) return v } // Shape added as sibling after the 3d node. Notice that it doesn't overlap the SK3DNode. func v2() -> SKView { let v = skview(color: .blue, index: 1) v.scene?.addChild(cube()) v.scene?.addChild(shape()) v.scene?.addChild(rect(.yellow)) return v } // Shape added to the 3d node. func v3() -> SKView { let v = skview(color: .magenta, index: 2) let box = cube() box.addChild(shape()) v.scene?.addChild(box) v.scene?.addChild(rect(.yellow)) return v } // 3d node added after, but zPos set to -1. func v4() -> SKView { let v = skview(color: .cyan, index: 3) v.scene?.addChild(shape()) v.scene?.addChild(rect(.yellow)) let box = cube() box.zPosition = -1 v.scene?.addChild(box) return v } // Shape added after the 3d node, but not as a sibling. func v5() -> SKView { let v = skview(color: .green, index: 4) let parent = SKNode() parent.addChild(cube()) parent.addChild(rect(.yellow)) v.scene?.addChild(parent) v.scene?.addChild(shape()) return v } let container = UIView(frame: CGRect(origin: .zero, size: CGSize(width: viewSize.width, height: viewSize.height * 5))) container.addSubview(v1()) container.addSubview(v2()) container.addSubview(v3()) container.addSubview(v4()) container.addSubview(v5()) PlaygroundPage.current.liveView = container 也适用。

这是我的游乐场:

...

let shape = SKShapeNode(rectOf: CGSize(width: 0.01, height: 0.01))
shape.strokeColor = .clear
shape.fillColor = UIColor.black.withAlphaComponent(0.01)

// 3D Node
let objectNode = SK3DNode(viewportSize: size)
objectNode.addChild(shape)

...


TL; DR

在您的代码中,尝试:

{{1}}