You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让SceneKit的SCNTechnique与includeCategoryBitmask配合生效?

用SCNTechnique实现多指定categoryBitmask节点置顶绘制

我需要用SCNTechnique让多个带有指定categoryBitmask(值为2)的SCNNode(角度关节Gizmo)始终绘制在其他节点上方。之前用StackOverflow上Simeon的方法(基于Gizmo.metal)实现了单个节点的效果,但扩展到多节点时,修改plist配置后没有生效。

我尝试在pass_gizmo阶段添加了以下配置:

<key>includesCategoryMask</key>
<integer>2</integer>
<key>excludesCategoryMask</key>
<integer>0</integer>
<key>inputs</key>

已知同一时间场景只能用一个SCNTechnique,所以按节点名称区分的方案不适用。项目基于Xcode游戏模板,已添加Gizmo.metal和名为scntec的plist文件,GameViewController实现了SCNSceneRendererDelegate协议,加载plist的代码如下:

// retrieve the SCNView
let scnView = self.view as! SCNView
    
scnView.delegate = self
    
// set the scene to the view
scnView.scene = scene

if let path = Bundle.main.path(forResource: "scntec", ofType: "plist"), let dict = NSDictionary(contentsOfFile: path)
{
   let technique = SCNTechnique(dictionary: dict as! [String : AnyObject])
   scnView.technique = technique
}

解决方法

正确的SCNTechnique plist配置

要实现多节点按category过滤并置顶,需要构建包含两个核心渲染通道的技术配置:

  1. 先渲染所有非Gizmo节点(排除categoryBitmask=2的节点)
  2. 再渲染所有Gizmo节点(仅包含categoryBitmask=2的节点),并依赖第一个通道的输出作为底层画面,保证Gizmo叠加在最上层。

完整的scntec.plist配置示例:

<?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>passes</key>
    <dict>
        <!-- 通道1:渲染所有非Gizmo节点 -->
        <key>pass_scene</key>
        <dict>
            <key>draw</key>
            <string>DRAW_SCENE</string>
            <key>excludesCategoryMask</key>
            <integer>2</integer>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>COLOR_TEXTURE</string>
            </dict>
        </dict>
        
        <!-- 通道2:渲染Gizmo节点,叠加在通道1的结果上 -->
        <key>pass_gizmo</key>
        <dict>
            <key>draw</key>
            <string>DRAW_SCENE</string>
            <key>includesCategoryMask</key>
            <integer>2</integer>
            <key>inputs</key>
            <dict>
                <key>colorSampler</key>
                <string>COLOR_TEXTURE</string>
            </dict>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>COLOR</string>
            </dict>
            <key>program</key>
            <string>Gizmo</string> <!-- 对应你的Gizmo.metal程序 -->
        </dict>
    </dict>
    
    <key>sequence</key>
    <array>
        <string>pass_scene</string>
        <string>pass_gizmo</string>
    </array>
    
    <key>targets</key>
    <dict>
        <key>COLOR_TEXTURE</key>
        <dict>
            <key>type</key>
            <string>texture</string>
            <key>size</key>
            <string>framebuffer</string>
            <key>format</key>
            <string>RGBA8</string>
        </dict>
    </dict>
    
    <key>symbols</key>
    <dict>
        <key>Gizmo</key>
        <dict>
            <key>type</key>
            <string>program</string>
            <key>metalLibrary</key>
            <string>Gizmo</string>
            <key>vertexFunction</key>
            <string>vertex_gizmo</string>
            <key>fragmentFunction</key>
            <string>fragment_gizmo</string>
        </dict>
    </dict>
</dict>
</plist>

关键细节调整

  • 通道顺序:必须先渲染普通场景,再渲染Gizmo,确保层级叠加逻辑正确
  • Gizmo.metal适配:片元函数需要接收上一通道的场景纹理输入,实现透明叠加效果,示例代码:
#include <metal_stdlib>
#include <SceneKit/scn_metal>

using namespace metal;

struct NodeBuffer {
    float4x4 modelViewProjectionTransform;
};

struct FragmentInput {
    float4 position [[position]];
    float4 color [[color(0)]];
};

fragment float4 fragment_gizmo(FragmentInput in [[stage_in]],
                               texture2d<float, access::sample> colorSampler [[texture(0)]],
                               sampler sampler [[sampler(0)]]) {
    // 获取上一通道的场景颜色
    float2 uv = in.position.xy / scn_framebuffer_size();
    float4 sceneColor = colorSampler.sample(sampler, uv);
    
    // 叠加Gizmo颜色(保留Gizmo自身透明度)
    return sceneColor * (1.0 - in.color.a) + in.color * in.color.a;
}

节点配置验证

确保所有需要置顶的Gizmo节点的categoryBitmask设置为2:

gizmoNode.categoryBitmask = 2

内容的提问来源于stack exchange,提问作者bhartsb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 23:47:46