iOS SceneKit SCNTechnique Metal vertex and fragment methods not work in iOS12

383 views Asked by At

I have a dictionary file for the SCNSceneView.technique as below:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>targets</key>
    <dict>
        <key>rt_0</key>
        <dict>
            <key>size</key>
            <string>128x256</string>
            <key>type</key>
            <string>color</string>
        </dict>
        <key>rt_1</key>
        <dict>
            <key>size</key>
            <string>128x256</string>
            <key>type</key>
            <string>color</string>
        </dict>
    </dict>
    <key>passes</key>
    <dict>
        <key>pass_final</key>
        <dict>
            <key>draw</key>
            <string>DRAW_QUAD</string>
            <key>program</key>
            <string>doesntexist</string>
            <key>metalVertexShader</key>
            <string>pass_through_vertex</string>
            <key>metalFragmentShader</key>
            <string>pass_through_fragment_final</string>
            <key>inputs</key>
            <dict>
                <key>colorSampler</key>
                <string>COLOR</string>
                <key>blurSampler</key>
                <string>rt_1</string>
                <key>aPos</key>
                <string>vertexSymbol</string>
            </dict>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>COLOR</string>
            </dict>
        </dict>
        <key>pass_vert</key>
        <dict>
            <key>draw</key>
            <string>DRAW_QUAD</string>
            <key>program</key>
            <string>doesntexist</string>
            <key>metalVertexShader</key>
            <string>pass_through_vertex</string>
            <key>metalFragmentShader</key>
            <string>pass_through_fragment_vert</string>
            <key>inputs</key>
            <dict>
                <key>colorSampler</key>
                <string>COLOR</string>
                <key>aPos</key>
                <string>vertexSymbol</string>
            </dict>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>rt_0</string>
            </dict>
        </dict>
        <key>pass_hori</key>
        <dict>
            <key>draw</key>
            <string>DRAW_QUAD</string>
            <key>program</key>
            <string>doesntexist</string>
            <key>metalVertexShader</key>
            <string>pass_through_vertex</string>
            <key>metalFragmentShader</key>
            <string>pass_through_fragment_hori</string>
            <key>inputs</key>
            <dict>
                <key>colorSampler</key>
                <string>rt_0</string>
                <key>aPos</key>
                <string>vertexSymbol</string>
            </dict>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>rt_1</string>
            </dict>
        </dict>
    </dict>
    <key>sequence</key>
    <array>
        <string>pass_vert</string>
        <string>pass_hori</string>
        <string>pass_vert</string>
        <string>pass_hori</string>
        <string>pass_final</string>
    </array>
    <key>symbols</key>
    <dict>
        <key>vertexSymbol</key>
        <dict>
            <key>semantic</key>
            <string>vertex</string>
        </dict>
    </dict>
    <key>reflectionResolutionScaleFactor</key>
    <string>0.5</string>
</dict>
</plist>

The metal file for passes in the technique file is as below:

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

struct custom_vertex_t
{
    float4 position [[attribute(SCNVertexSemanticPosition)]];
};

constexpr sampler s = sampler(coord::normalized,
                              address::repeat,
                              filter::linear);

constexpr sampler sClamp = sampler(coord::normalized,
                              filter::linear);

struct out_vertex_t
{
    float4 position [[position]];
    float2 uv;
};

vertex out_vertex_t pass_through_vertex(custom_vertex_t in [[stage_in]])
{
    out_vertex_t out;
    out.position = in.position;
    out.uv = float2((in.position.x + 1.0) * 0.5 , (in.position.y + 1.0) * -0.5 + 1.0);
    return out;
};

// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/
constant float offset[] = { 0.0, 1.0, 2.0, 3.0, 4.0 };
constant float weight[] = { 0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162 };

fragment half4 pass_through_fragment_hori(out_vertex_t vert [[stage_in]],
                                          texture2d<float, access::sample> colorSampler [[texture(0)]])
{

    float4 FragmentColor = colorSampler.sample( s, vert.uv) * weight[0];
    for (int i=1; i<5; i++) {
        FragmentColor += colorSampler.sample( sClamp, ( vert.uv + float2(offset[i], 0.0)/224.0 ) ) * weight[i];
        FragmentColor += colorSampler.sample( sClamp, ( vert.uv - float2(offset[i], 0.0)/224.0 ) ) * weight[i];
    }

    return half4(FragmentColor);
}

fragment half4 pass_through_fragment_vert(out_vertex_t vert [[stage_in]],
                                     texture2d<float, access::sample> colorSampler [[texture(0)]])
{

    float4 FragmentColor = colorSampler.sample( s, vert.uv) * weight[0];
    for (int i=1; i<5; i++) {
        FragmentColor += colorSampler.sample( sClamp, ( vert.uv + float2(0.0, offset[i])/224.0 ) ) * weight[i];
        FragmentColor += colorSampler.sample( sClamp, ( vert.uv - float2(0.0, offset[i])/224.0 ) ) * weight[i];
    }


    return half4(FragmentColor);

};
fragment half4 pass_through_fragment_final(out_vertex_t vert [[stage_in]],
                                          texture2d<float, access::sample> colorSampler [[texture(0)]],
                                           texture2d<float, access::sample> blurSampler [[texture(1)]])
{

    float4 FragmentColor = colorSampler.sample( s, vert.uv);
    float4 BlurColor = blurSampler.sample( s, vert.uv) * 0.5;
    FragmentColor.xyz += BlurColor.xyz;
    return half4(FragmentColor);
}

Basically the technique is a post process blur filter with chained passes for a sceneView, it worked fine under iOS11 and Xcode9 before. But after iOS12, I am receiving these error codes:

[SceneKit] Error: Pass XXX(all passes included) is not linked to the rendering graph and will be ignored check it's input/output

It seems that the vertex and fragment metal methods are not linked yet. But I don't know what has changed under iOS 12 and Xcode10.

Does anyone know how to fix the code?

0

There are 0 answers