SCNTechnique stencil buffer - how to read from it?

Desired outcome:

Draw a silhouette / outline / edge of constant width around meshes of different shapes in SceneKit. I'm only going for the outer silhouette, and not interested in the inside edges. Eventually, I would like to have the outline only so that and have the inside area of the mesh be either discarded or transparent. I figured that using the stencil buffer may achieve the right look.


What I tried:

  1. I had success making an SCNTechnique where the first pass scales up the mesh and makes every fragment and constant color, then the second renders it at regular size.
  2. Then tried writing to a stencil at regular size, then reading from the stencil buffer in the second (scaled up) pass, so that ONLY the outline would be visible. I can't seem to get this to work. I may not have the right "stencilStates" dictionary, though it is hard to know what is wrong, as I can't generate any different visual feedback or errors when trying differnent keys + values. I thought that by clearing the stencil buffer (all 0's), then replacing with 1's ones during the first pass, then reading anything is "notEqual" to 1 would give me just the outline. However I can't seem to stencil out any part of the second pass.


Here is a playground where I've replicated what I tried: https://github.com/mackhowell/scenekit-outline-shader-scntechnique/tree/stencil-test. (The linked branch "stencil-test" is where I've documented this issue.)


And here is my SCNTechnique dictionary:


let stencilPass: [String: Any] = [
    "program": "outline",
    "inputs": [
        "a_vertex": "position-symbol",
        "modelViewProjection": "mvpt-symbol",
    ],
    "outputs": [
        "stencil": "COLOR"
    ],
    "draw": "DRAW_NODE",
    "stencilStates": [
        "enable": true,
        "clear": true,
        "behavior": [
            "depthFail": "keep",
            "fail": "keep",
            "pass": "replace",
            "function": "always",
            "referenceValue": 1
        ]
    ]
]

let embiggenPass: [String: Any] = [
    "program": "embiggen",
    "inputs": [
        "a_vertex": "position-symbol",
        "modelTransform": "mt-symbol",
        "viewTransform": "vt-symbol",
        "projectionTransform": "pt-symbol",
    ],
    "outputs": [
        "color": "COLOR"
    ],
    "draw": "DRAW_NODE",
    "stencilStates": [
        "behavior": [
            "depthFail": "keep",
            "fail": "keep",
            "pass": "keep",
            "function": "notEqual",
            "referenceValue": 1
        ]
    ]
]

let technique: [String: Any] = [
    "passes": [
        "embiggen": embiggenPass,
        "stencil": stencilPass
    ],
    "sequence": [
        "stencil",
        "embiggen"
    ],
    "symbols": [
        "position-symbol": ["semantic": "vertex"],
        "mvpt-symbol": ["semantic": "modelViewProjectionTransform"],
        "mt-symbol": ["semantic": "modelTransform"],
        "vt-symbol": ["semantic": "viewTransform"],
        "pt-symbol": ["semantic": "projectionTransform"],
    ]
]


Thanks!

Replies

Hi,

I have same requirement. Please share if you have got the solution for this, it will be helpful. Thanks.