这里可能不是最终解决方案,但它可以给你一个指导,如何实现深度渲染技术。
注意:这里的一切都取决于相机与几何体之间的距离。非常简化的实现。它使用了一个
SCNProgram()
来处理材质。
下面是
GameViewController.swift
的代码:
class GameViewController: UIViewController {
@IBOutlet weak var sceneView : SCNView!
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene()
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.camera?.automaticallyAdjustsZRange = true
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 0, z: 100)
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = UIColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
sceneView.scene = scene
sceneView.allowsCameraControl = true
sceneView.showsStatistics = true
sceneView.backgroundColor = UIColor.black
sceneView.scene?.lightingEnvironment.contents = UIColor.black
sceneView.scene?.background.contents = UIColor.black
self.setupRing()
self.setupStick()
}
func setupCube() {
let cube = SCNBox(width: 20.0, height: 20.0, length: 20.0, chamferRadius: 2.5)
let cubeNode = SCNNode(geometry: cube)
cubeNode.geometry?.firstMaterial = depthMaterial()
sceneView.scene?.rootNode.addChildNode(cubeNode)
}
func setupRing() {
let ring = SCNTorus(ringRadius: 20.0, pipeRadius: 4.0)
let ringNode = SCNNode(geometry: ring)
ringNode.position = SCNVector3(0.0, +10.0, 20.0)
ringNode.geometry?.firstMaterial = depthMaterial()
sceneView.scene?.rootNode.addChildNode(ringNode)
let ring2 = SCNTorus(ringRadius: 20.0, pipeRadius: 4.0)
let ringNode2 = SCNNode(geometry: ring2)
ringNode2.position = SCNVector3(0.0, -10.0, 20.0)
ringNode2.geometry?.firstMaterial = depthMaterial()
sceneView.scene?.rootNode.addChildNode(ringNode2)
}
func setupStick() {
let stick = SCNCylinder(radius: 5.0, height: 70.0)
let stickNode = SCNNode(geometry: stick)
stickNode.position = SCNVector3(0.0, 0.0, 20.0)
stickNode.geometry?.firstMaterial = depthMaterial()
sceneView.scene?.rootNode.addChildNode(stickNode)
}
override var prefersStatusBarHidden: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
func depthMaterial() -> SCNMaterial {
let sceneProgramDepth = SCNProgram()
sceneProgramDepth.vertexFunctionName = "myVertexDepth"
sceneProgramDepth.fragmentFunctionName = "myFragmentDepth"
let material = SCNMaterial()
material.name = "metal"
material.program = sceneProgramDepth
return material
}
}
这里是深度着色器(以及一些变体)
shaders.metal
。
#include <metal_stdlib>
using namespace metal;
#include <SceneKit/scn_metal>
struct MyNodeBuffer {
float4x4 modelViewTransform;
float4x4 normalTransform;
};
typedef struct {
float3 position [[attribute(SCNVertexSemanticPosition)]];
} MyDepthInput;
struct SimpleVertexDepth {
float4 position [[position]];
float depth;
};
vertex SimpleVertexDepth myVertexDepth(MyDepthInput in [[stage_in]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant MyNodeBuffer& scn_node [[buffer(1)]])
{
float4 modelSpacePosition(in.position, 1.0f);
float4 eyeSpacePosition = scn_node.modelViewTransform * modelSpacePosition;
float depth = length(eyeSpacePosition.xyz);
SimpleVertexDepth out;
out.position = scn_frame.projectionTransform * eyeSpacePosition;
out.depth = depth;
return out;
}
fragment half4 myFragmentDepth(SimpleVertexDepth in [[stage_in]])
{
float contrastFactor = 3.0;
float gray = 1.0 - pow(saturate(in.depth / 100), contrastFactor);
return half4(gray, gray, gray, 1.0);
}
我目前偏爱的一个名字叫做“另一种变体(更好)”。结果看起来是这样的:
![SceneKit Depth Render Shader](https://istack.dev59.com/XCsSu.webp)
随意尝试那些东西吧。希望我能以某种方式帮到你。
(如果你找到更好的解决方案,我会非常感兴趣看到它。)
附注:作为一个草稿项目,使用SceneKit默认模板和太空飞船,然后删除太空飞船 :)