使用 ``clip_distance`` 的 SceneKit Metal 着色器

SceneKit Metal shader using ``clip_distance``

我正在修改 https://medium.com/@MalikAlayli/metal-with-scenekit-create-your-first-shader-2c4e4e983300 中给出的 SceneKit Metal 着色器。它显示一个带有图像纹理的立方体,由 SceneKit 使用金属着色器渲染。

我使用 SCNSphere(radius: 3) 将立方体更改为半径为 3、以 (0,0,0) 为中心的球体。然后,我用clip_distance把满足in.position.z > 1.5的球体“切”掉了一部分。结果如下图所示。下面也给出了我使用的Metal shader。

如你所见,边界并不平滑。它显示多边形的边界,而不是插值表面。那么,有没有可能让它变得平滑呢?如果是,如何?谢谢。

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

struct NodeBuffer {
    float4x4 modelTransform;
    float4x4 modelViewProjectionTransform;
    float4x4 modelViewTransform;
    float4x4 normalTransform;
    float2x3 boundingBox;
};

struct VertexInput {
    float3 position  [[attribute(SCNVertexSemanticPosition)]];
    float2 uv [[attribute(SCNVertexSemanticTexcoord0)]];
};


struct VertexOut {
    float4 position [[position]];
    float2 uv;
    float clip_distance [[clip_distance]];
};

vertex VertexOut textureSamplerVertex(VertexInput in [[ stage_in ]], constant NodeBuffer& scn_node [[buffer(1)]]) {
    VertexOut out;
    out.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0);
    out.uv = in.uv;
    if ((in.position.z > 1.5)) {
        out.clip_distance = -1;
    }
    else {
        out.clip_distance = 1;
    }
    return out;
}

fragment float4 textureSamplerFragment(VertexOut out [[ stage_in ]], texture2d<float, access::sample> customTexture [[texture(0)]]) {
    constexpr sampler textureSampler(coord::normalized, filter::linear, address::repeat);
    return customTexture.sample(textureSampler, out.uv );
}

The clip distances will be linearly interpolated across the primitive and the portion of the primitive with interpolated distances less than 0.0 will be clipped. (gl_ClipDistance)

为了使剪辑片段的边界恰好位于 z = 1.5,您需要确保当 z = 1.5 时插值剪辑距离恰好位于 0.0,然后在每个片段上为正或负边.

out.clip_distance = (1.5 - in.position.z);