SceneKit - 渲染几何体的表面法线

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

在 Xcode SceneKit 编辑器中,可以可视化 SCNGeoemtry 的表面法线

编辑器似乎使用了 SCNGeometrySource.Semantic 来渲染图像: https://developer.apple.com/documentation/scenekit/scngeometrysource/semantic

如何将几何体的表面法线渲染到图像?

xcode scenekit scnnode scngeometry
1个回答
0
投票

我们来尝试一下吧。您可以通过使用

SCNProgram()
进行渲染来实现几何体的法线或类似法线的着色。这取代了 Apple 提供的整个渲染(如
constant
phong
blinn
physicallyBased

开始使用 Xcode 附带的默认 SceneKit 模板,即包含旋转宇宙飞船的模板。

首先,创建一个 Metal-File,并将其命名为

shaders.metal

将以下代码复制到此文件中。

#include <metal_stdlib>
using namespace metal;
#include <SceneKit/scn_metal>

// Nodebuffer
struct MyNodeBuffer {
    // float4x4 modelTransform;
    // float4x4 inverseModelTransform;
    float4x4 modelViewTransform; // required
    // float4x4 inverseModelViewTransform;
    float4x4 normalTransform; // required
    // float4x4 modelViewProjectionTransform;
    // float4x4 inverseModelViewProjectionTransform;
};

// as is from StackOverflow
typedef struct {
    float3 position  [[ attribute(SCNVertexSemanticPosition)  ]];
    float3 normal    [[ attribute(SCNVertexSemanticNormal)    ]];
    float4 color     [[ attribute(SCNVertexSemanticColor)     ]];
    float2 texCoords [[ attribute(SCNVertexSemanticTexcoord0) ]];
} MyVertexInput;

// MARK: - Structs filled by Vertex Shader
struct SimpleVertexNormal
{
    float4 position [[ position ]];
    float3 normal;
};

// MARK: - Normal Shader
vertex SimpleVertexNormal myVertexNormal(MyVertexInput 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);
    
    SimpleVertexNormal out;
    
    out.position                    = scn_frame.projectionTransform * eyeSpacePosition;
    out.normal                      = in.normal;
    
    return out;
}

fragment float4 myFragmentNormal(SimpleVertexNormal in [[stage_in]])

{
    // Normal Color
    float3 normal           = normalize(in.normal);
    float3 normalColor      = float3(abs(normal));
    
    // Final Color
    float4 color            = float4(normalColor, 1.0);
    return color;
}

在 GameViewController 中插入以下函数,该函数会将这个着色器附加到给定的节点(您也可以全局定义 SCNProgram 并重新使用它)。

func applyNormalShader(node: SCNNode) {
    let sceneProgramNormal = SCNProgram()      // Metal Shader Program
    sceneProgramNormal.fragmentFunctionName    = "myFragmentNormal"
    sceneProgramNormal.vertexFunctionName      = "myVertexNormal"
    
    node.geometry?.firstMaterial?.program = sceneProgramNormal
}

最后一步是将节点归档到该着色器。我将在这里使用默认的太空飞船。 (确保归档包含要使用该自定义着色器程序着色的几何体的确切节点。)

修改代码如下: (这里:在

viewDidLoad

// retrieve the ship node
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!

// animate the 3d object
ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))

// apply shader
applyNormalShader(node: ship.childNodes.first!)

注意:这可能与 Xcode 预览中的不完全相同,但它应该让您了解如何继续/扩展这些内容。希望这会对您有所帮助。

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