5

Basically, I would like to render an outline around a cube. To do this, I think I can use an SCNTechnique which has the following render passes:

  1. Render the cubes normally, and also write their occupied pixels to a stencil buffer.
  2. Render slightly larger cubes if they don't intersect with the stencil in the first pass.

The problem is, the documentation for stencils in SCNTechnique is very sparse, and I can't work out exactly how to use it.

I have already successfully drawn outlines by drawing the larger 'outline cubes' first with depth testing disabled and then drawing the normal cubes afterwards, and this works fairly well, however I'd like to use stencils instead due to other complications with this method.

In an attempt to get it to work using stencil buffers, my first pass's stencilStates looks like (along with why I think I need the properties):

clear = YES  // To clear the buffer from last 
enable = YES // To write to the buffer
behavior:
    writeMask = 1     // Use bit 1
    function = always // Always write to stencil regardless?

The second pass's stencilStates looks like:

clear = NO   // Keep the buffer from last step
enable = NO  // Don't write to the buffer (only read?)
behavior:
    readMask = 1      // Use bit 1
    fail     = keep   // Not sure if these...
    pass     = zero   // ...should be the other way round

There are quite a few other properties for stencil buffer behaviours, but I'm not sure which I need and how to use them. I'm also not certain if the stencil buffer needs to be listed as an input or output for each pass?

Edit 1: Here's exactly what I'm looking to implement, rendered by drawing the blue, larger outline cube first without writing to the depth buffer:

Cube with blue outline

If it wasn't for some side-effects with drawing in this manor, I'd leave the implementation like this, but instead I think the stencil approach would avoid these side effects and I think it would be useful to know how to use them anyway!

Edit 2: I've been playing around, trying to produce a similar effect using OpenGL (in C) directly. I don't pretend to fully understand how stencils work (and I basically borrowed the code from a tutorial), but these commands produce what I'm trying to achieve.

Before drawing the main cube, writing to the stencil buffer:

glStencilFunc(GL_ALWAYS, 1, 0xFF); // Set any stencil to 1
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilMask(0xFF); // Write to stencil buffer
glClear(GL_STENCIL_BUFFER_BIT); // Clear stencil buffer (0 by default)

After drawing the main cube, and before drawing the larger outline cube, testing the current stencil buffer:

glStencilFunc(GL_EQUAL, 0, 0xFF); // Pass test if stencil value is 0
glStencilMask(0x00); // Don't write anything to stencil buffer

The question, therefore, is how to achieve the above using an SCNTechnique.

Robert
  • 5,735
  • 3
  • 40
  • 53
  • Sorry to ask a visual question, but can you show an image/shot of the type of outline effect you're looking for? Hit up google images with keywords about cubes and outlines and cartoon effects until you find something you prefer/want/desire. – Confused Jan 02 '17 at 07:06
  • @Confused Sure, I've edited in a render of what I'm trying to achieve (but with stencils). Thanks for taking a look! – Robert Jan 02 '17 at 14:08
  • I have just looked at stencil buffers in the loosest of readings of how OpenGL discusses them. I'm not sure they're the right tool for this. They could be used because they do have masking, but the same is true of inversion masking, that the white dice could do of the blue box around it. My gut feeling (and a naive gut, at that) is that a pixel shader that somehow knows where the edges of the dice are could draw a better, smoother outline of this type around the dice. But I have no idea how to do that, or if it's even possible in SceneKit. – Confused Jan 02 '17 at 14:37
  • Yes, I think that's possible; `SCNTechnique`s seem to be fairly configurable. It will let you write your own GLSL shaders to perform the edge detection (and that method would probably produce an edge with a more consistent width, as the perspective will cause it to vary slightly otherwise). On the other hand, I would have expected stencils to have better performance, and the fact that they're primitive shapes makes it even easier. I would like to understand how stencils work in SceneKit too, and since they're based on OpenGL ones I think I'll try making a prototype in that first. – Robert Jan 02 '17 at 14:50
  • If you could figure out how to draw your outline with a Core Image filter sequence, you could attach that filter to the node. Bullet 3 of @rickster's' answer to http://stackoverflow.com/questions/27507530/ios-scenekit-neon-glow outlines (heh) some approaches that might work for your project too. – Hal Mueller Jan 03 '17 at 07:37
  • @Robert Have you figured it out? I am trying to do the exact same thing. Unfortunately I do not even have your first solution figured out yet... – reggian Apr 17 '18 at 20:09
  • @Reggian Unfortunately I never did, in the end I just stuck with modifying the depth states which worked well enough. There might be more articles about stencils now, I might come back to it at some point and give it another shot! – Robert Apr 19 '18 at 07:53

1 Answers1

0

You can use SCNTechnique to draw an outline. The idea is to draw the object masks to a buffer, blur one channel of the mask, then combine it with the original rendered frame. That combination shader checks the blurred channel, and the non-blurred one and only renders the outline outside of the object.

There is an example that draws a glow around nodes here: https://github.com/laanlabs/SCNTechniqueGlow You should be able to modify it to get the effect you want.

Morty
  • 1,436
  • 14
  • 12