有没有办法在其他人面前绘制SCNNode?

时间:2015-05-23 06:56:47

标签: swift scenekit scnnode

我一直试图用场景工具包创建一个场景,其中指定的对象总是在其他人面前,尽管事实上它实际上在其他对象的后面。与blender中使用的效果相似。

显然,blender使用GUI和大量数学来转换2D对象,但我需要在带有SCNGeometry的SCNNode中使用此效果,换句话说,当前位于场景中的3D对象。

我考虑使用类别面具,但在阅读了Apple的文档后,我意识到这对我正在寻找的效果并不起作用。

有没有人知道在SceneKit中做这个的方法?或者更好的是,甚至可以这样做吗?

非常感谢大家,现在以及我从StackExchange获得的所有其他帮助!

6 个答案:

答案 0 :(得分:6)

所以,事实证明我找到了问题的答案(在mnuages的帮助下)。我只是想发一个完整的答案。

Final result
与mnuages建议一样,我尝试将readsFromDepthBufferwritesToDepthBuffer设置为false,并将节点的renderingOrder设置为较大的数字。它的工作方式不对。它总是落后于每个物体,而不是总是在前面。获取图片中显示的结果的方法是仅将readsFromDepthBuffer设置为false,并将多维数据集的renderingOrder设置为-1,否则将无法绘制它。

由于多维数据集和其他节点的素材的readsFromDepthBufferwritesToDepthBuffer设置为默认值true,因此它仍然位于其后面的对象前面,并且在它前面的物体,换句话说,它将是正常的,只有箭头将表现我们想要的方式。

从图像中可以看出,立方体前面的线条部分是可见的。对于背后的部分,不能说同样的事情。

答案 1 :(得分:2)

正如我之前的回答中所解释的那样,接受的答案并不是最优的,只适用于广告牌,huds和其他大致扁平的物体(不一定完全是2D)。当使用3D对象并禁用从深度缓冲区和上面图像中的对象读取时,它无法从各个角度正确渲染。即,3D对象需要从深度缓冲区读取以检测其自身的像素和深度。总而言之,我提出了正确答案:

SCNTechnique

简而言之,再渲染2次。一个用于控件Gizmo(DRAW_NODE),另一个用于通过另一个传递将其与场景混合在一起(DRAW_QUAD,使用以前传递的着色器作为输入)。

以下是techique的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>
        <key>gizmoonly</key>
        <dict>
            <key>colorStates</key>
            <dict>
                <key>clear</key>
                <true/>
                <key>clearColor</key>
                <string>0.5 0.5 0.5 0.0</string>
            </dict>
            <key>depthStates</key>
            <dict>
                <key>clear</key>
                <true/>
            </dict>
            <key>inputs</key>
            <dict>
                <key>colorSampler</key>
                <string>COLOR</string>
            </dict>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>gizmonode</string>
            </dict>
            <key>draw</key>
            <string>DRAW_NODE</string>
            <key>node</key>
            <string>movegizmo</string>
        </dict>
        <key>quadscene</key>
        <dict>
            <key>colorStates</key>
            <dict>
                <key>clear</key>
                <true/>
                <key>clearColor</key>
                <string>sceneBackground</string>
            </dict>
            <key>depthStates</key>
            <dict>
                <key>clear</key>
                <true/>
            </dict>
            <key>inputs</key>
            <dict>
                <key>totalSceneO</key>
                <string>COLOR</string>
                <key>a_texcoord</key>
                <string>a_texcoord-symbol</string>
                <key>gizmoNodeO</key>
                <string>gizmonode</string>
            </dict>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>COLOR</string>
            </dict>
            <key>draw</key>
            <string>DRAW_QUAD</string>
            <key>program</key>
            <string>gizmo</string>
        </dict>
    </dict>
    <key>sequence</key>
    <array>
        <string>gizmoonly</string>
        <string>quadscene</string>
    </array>
    <key>targets</key>
    <dict>
        <key>totalscene</key>
        <dict>
            <key>type</key>
            <string>color</string>
        </dict>
        <key>gizmonode</key>
        <dict>
            <key>type</key>
            <string>color</string>
        </dict>
    </dict>
    <key>symbols</key>
    <dict>
        <key>a_texcoord-symbol</key>
        <dict>
            <key>semantic</key>
            <string>texcoord</string>
        </dict>
        <key>vertexSymbol</key>
        <dict>
            <key>semantic</key>
            <string>vertex</string>
        </dict>
    </dict>
</dict>
</plist>

以下是第二遍的顶点着色器:

attribute vec4 a_position;
varying vec2 uv;

void main() {
    gl_Position = a_position;
    uv = (a_position.xy + 1.0) * 0.5;
}

第二遍的片段着色器:

uniform sampler2D totalSceneO;
uniform sampler2D gizmoNodeO;

varying vec2 uv;

void main() {
    vec4 t0 = texture2D(totalSceneO, uv);
    vec4 t1 = texture2D(gizmoNodeO, uv);
    gl_FragColor = (1.0 - t1.a) * t0 + t1.a * t1;
}

Swift代码:

if let path = NSBundle.mainBundle().pathForResource("scntec", ofType: "plist") {
            if let dico1 = NSDictionary(contentsOfFile: path)  {
                let dico = dico1 as! [String : AnyObject]

                let technique = SCNTechnique(dictionary:dico)
                scnView.technique = technique
            }
}

Objective-C代码:

NSURL *url = [[NSBundle mainBundle] URLForResource:@"scntec" withExtension:@"plist"];
SCNTechnique *technique = [SCNTechnique techniqueWithDictionary:[NSDictionary dictionaryWithContentsOfURL:url]];
    self.myView.technique = technique;

设置Gizmo节点的名称:

theGizmo.name = @"movegizmo";

答案 2 :(得分:1)

SCNMaterial公开writesToDepthBufferreadsFromDepthBuffer可以让您这样做(如果需要,可以与SCNNode renderingOrder结合使用)

答案 3 :(得分:1)

readsFromDepthBuffer答案可能适用于所示图像中的角度,但如果您要旋转并查看不同角度,您将看到Gizmo的轴从某些角度不正确地重叠。换句话说,一些轴应该位于另一个轴的前面,取决于面的呈现顺序。这显然是因为对象(材质)不会读取深度缓冲区,包括已经渲染自身的部分。

通常,在主场景前渲染SCNNode的简单方法是在场景的overlaySKScene中使用SK3DNode(具有自己的场景和深度缓冲区)。对于答案中图片中显示的场景,这将需要额外的代码来旋转和准确定位SK3DNode,因此它可能不是OP正在寻找的东西,但这对于发现此问题的其他人可能有所帮助。

答案 4 :(得分:1)

我不确定这是否有帮助,但我很高兴地发现,Apple在其文档中描述的方法实际上效果很好。 我有一个对象,应该永久显示在所有其他对象的前面。将其渲染顺序(节点检查器)设置为更高的值(但对于所述节点而言都是相同的),并取消选中所有使用过的材料的“读取深度”复选框(材料检查器),即可得到所需的结果。 所有其他对象的渲染顺序保持为零,不应用任何负序。 我知道您在代码中需要此功能,但是也许您可以从中获得一些好处?

答案 5 :(得分:0)

@Xartec的答案是正确的方法。您基本上是在透明背景上单独渲染Gizmo,然后使用简单的着色器将其与场景混合。这是与Metal相同的设置

Gizmo.metal

#include <metal_stdlib>
using namespace metal;

#include <SceneKit/scn_metal>

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

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

vertex out_vertex_t gizmo_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);

    return out;
};

constexpr sampler s = sampler(coord::normalized,
                              r_address::clamp_to_edge,
                              t_address::repeat,
                              filter::linear);

fragment half4 gizmo_fragment(out_vertex_t vert [[stage_in]],
                              texture2d<float, access::sample> totalSampler [[texture(0)]],
                              texture2d<float, access::sample> gizmoSampler [[texture(1)]])
{

    float4 t0 = totalSampler.sample(s, vert.uv);
    float4 t1 = gizmoSampler.sample(s, vert.uv);

    return half4((1.0 - t1.a) * t0 + t1.a * t1);
}

GizmoTechnique.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>
        <key>pass_scene</key>
        <dict>
            <key>draw</key>
            <string>DRAW_SCENE</string>
            <key>inputs</key>
            <dict/>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>color_scene</string>
            </dict>
            <key>colorStates</key>
            <dict>
                <key>clear</key>
                <true/>
                <key>clearColor</key>
                <string>sceneBackground</string>
            </dict>
        </dict>
        <key>pass_gizmo</key>
        <dict>
            <key>colorStates</key>
            <dict>
                <key>clear</key>
                <true/>
                <key>clearColor</key>
                <string>0 0 0 0</string>
            </dict>
            <key>depthStates</key>
            <dict>
                <key>clear</key>
                <true/>
            </dict>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>color_gizmo</string>
            </dict>
            <key>inputs</key>
            <dict/>
            <key>draw</key>
            <string>DRAW_NODE</string>
            <key>node</key>
            <string>transformGizmo</string>
        </dict>
        <key>mix</key>
        <dict>
            <key>colorStates</key>
            <dict>
                <key>clear</key>
                <true/>
            </dict>
            <key>depthStates</key>
            <dict>
                <key>clear</key>
                <true/>
            </dict>
            <key>inputs</key>
            <dict>
                <key>totalSampler</key>
                <string>COLOR</string>
                <key>gizmoSampler</key>
                <string>color_gizmo</string>
            </dict>
            <key>outputs</key>
            <dict>
                <key>color</key>
                <string>COLOR</string>
            </dict>
            <key>draw</key>
            <string>DRAW_QUAD</string>
            <key>program</key>
            <string>doesntexist</string>
            <key>metalFragmentShader</key>
            <string>gizmo_fragment</string>
            <key>metalVertexShader</key>
            <string>gizmo_vertex</string>
        </dict>
    </dict>
    <key>sequence</key>
    <array>
        <string>pass_gizmo</string>
        <string>mix</string>
    </array>
    <key>targets</key>
    <dict>
        <key>color_gizmo</key>
        <dict>
            <key>type</key>
            <string>color</string>
        </dict>
    </dict>
    <key>symbols</key>
    <dict>
        <key>vertexSymbol</key>
        <dict>
            <key>semantic</key>
            <string>vertex</string>
        </dict>
    </dict>
</dict>
</plist>