I can't see an obvious way to change the blending function (glBlendFunc) for a scene kit node or geometry - it doesn't seem to be part of the material, and it isn't very obvious from the scene kit documentation how it organises render passes. Do I need to make a Render delegate for the node which just changes the GLblending mode, or do I need to somehow set up different render passes etc. (It's not obvious from the documentation how I even control things like render passes)?
-
1What are you trying to do? Alpha blend a node or do something more advanced? If you explain what you are trying to accomplish, it will be easier for us to help you. – David Rönnqvist Dec 05 '14 at 16:37
-
1I'm trying to do additive blending - to render something as glowing light with a blend function like glBlendFunc(GL_SRC_ALPHA, GL_ONE).I would have assumed that the bland function used to composite the results of the fragment shader would be specified as part of the material, and I'm baffled why it doesn't seem to be possible - it's such a common requirement. I guess I can force the SceneKit to do it by writing a node render delegate, but I have thousands of these objects in my scene and it will be incredibly inefficient - I might as well not be using sceneKit at that point. – jportway Dec 05 '14 at 17:15
-
Almost sounds like you are doing a particle system (in which case additive blending would be one of the possible `blendMode`s)? Or maybe there is more to it? – David Rönnqvist Dec 05 '14 at 17:35
-
It's the kind of thing you might use if you were doing a particle system for fire or something like that. In this case it's not actually particles, but it's the same idea. I've never known any kind of scene graph that didn't allow you to specify it - if you want to render any kind of glow - for instance a glowing halo around a light or something like that - you need to specify a blend function. It's really weird (and incredibly frustrating) that SceneKit seems to have such an odd blind spot. – jportway Dec 05 '14 at 17:53
-
SCNTechnique looked like exactly what I was after, since it has a "blendState" parameter. However creating a technique with blending enabled doesn't seem to have any effect - I've got a horrible feeling that rather than enabling blending while rendering the pass, instead this might be to control how the finished render pass i combined with other passes. – jportway Dec 05 '14 at 19:55
-
OK - as far as I can tell, SCNTechnique isn't the answer. Setting the blending mode in the Technique doesn't seem to have an effect on the blending mode used when geometry is rendered because although the technique seems to set the blending mode at the start of rendering as requested, SceneKit resets the blending mode before rendering geometry. I'm not sure if this is a bug, or whether the SCNTechnique blendState is intended only to control how the results of the technique are composited with other render passes. – jportway Dec 07 '14 at 11:38
2 Answers
Will It Blend? - SceneKit
Yes! In iOS 9 and OS X 10.11 (currently in beta), blendMode
is an attribute on materials, so you can render any SceneKit content with additive, multiplicative, or other kinds of blending.
But for while you're still supporting earlier OS versions... SceneKit in iOS 8.x and OS X 10.8 through 10.10 doesn't offer API for blend modes.
There are a couple of options you can look at for working around this.
1. Set the GL state yourself
If you call glBlendFunc
and friends before SceneKit draws, SceneKit will render using the blend state you've selected. The trick is setting the state at an appropriate time for drawing your blended content and leaving the state as SceneKit expects for un-blended content.
If you set your GL state in renderer:willRenderScene:atTime:
and unset it in renderer:didRenderScene:atTime:
, you'll apply blending to the entire scene. Probably not what you want. And you can't use a node renderer delegate for only the node you want blended because then SceneKit won't render your node content.
If you can find a good way to wedge those calls in, though, they should work. Try rendering related nodes with a custom program and set your state in handleBindingOfSymbol:usingBlock:
, maybe?
2. Use Programmable Blending (iOS only)
The graphics hardware in iOS devices supports reading the color value of a destination fragment in the shader. You can combine this value with the color you intend to write in any number of ways — for example, you can create Photoshop-style blend modes.
In SceneKit, you can use this with a fragment shader modifier — read from gl_LastFragData
and write to _output
. The example here uses that to do a simple additive blend.
#pragma transparent
#extension GL_EXT_shader_framebuffer_fetch : require
#pragma body
_output.color = gl_LastFragData[0] + _output.color;

- 124,678
- 26
- 272
- 326
-
The problem I found with setting the blend state myself is that, in effect, you end up having to set up the blend mode for every bit of geometry because you can't predict the order in which they'll be rendered so you can't just set the blend mode before all the elements that need additive blending and then change it back afterwards. If you've got lots of blended geometry then this gets really inefficient really quickly. It's very odd that scene kit doesn't have support for blend modes - traditionally one of the main points of using a scene graph is managing rendering state like this – jportway Apr 07 '15 at 23:05
-
Option 2) sounds truly awesome! Just one question: Is it any slower than being able to just set the blend mode? I completely agree with jportway that it's really odd that one can't control the blend mode without having to fiddle with all these things. – Max Apr 08 '15 at 10:19
-
@Max: I am not a hardware guy. But I gather the way blending works on the kind of mobile GPUs found in iOS devices is that it uses programmable hardware regardless — when you set GL blend state, the driver is writing a shader for you. If that's the case, there shouldn't be any difference in per fragment performance. If you have an A7 or better device, try profiling it in Xcode to see for yourself. – rickster Apr 13 '15 at 07:53
-
From what I can tell after several hours of experimenting, there is no way to actually set the blend mode used to render a piece of geometry, or to control the overall blend mode used to render a pass using SCNTechnique.
SceneKit appears to only have two different blending modes - one where blending is off - if it considers the material opaque, and a "transparent" blending mode (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) when it considers a material transparent. This is bad news if you want to render things like glows, because it doesn't seem possible to get anything like a (GL_ONE, GL_ONE) blend mode you'd want for rendering light beams or glows.
However, I've found a hack to get around this which doesn't give you proper control over blending, but which works if you're wanting to render glowing things like light beams:
Because SceneKit uses GL_ONE, GL_ONE_MINUS_SRC_ALPHA blending mode all you should have to do is render your geometry with an alpha channel of 0. Unfortunately, it's not that simple because the default SceneKit shader discards fragments with an alpha channel of 0, so nothing will actually get rendered. A quick-and-dirty workaround is to use a diffuse colour map which has an alpha channel of 1 (assuming an 8 bit per channel map with values from 1-255). Because the alpha channel is nearly 0, pretty much all of the background image will show through. This mostly works, but because the alpha isn't quite zero it will still produce noticeable artefacts in bright areas.
So to work around this problem you can just use a standard texture map with a solid alpha chanel, but attach a shader modifier to "SCNShaderModifierEntryPointFragment" which simply sets the alpha channel of the output colour to zero. This works because fragment shader modifiers come after the zero-alpha culling.
here's that shader modifier in its entirety :
#pragma transparent
#pragma body
_output.color.a = 0;
note the "#pragma transparent" declaration in the first line - this is necessary to force SceneKit to use its transparent blending mode even when it otherwise wouldn't.
This is not a complete solution, because it's not real control over blending - it's only a useful hack for producing light beam glows etc - and the shading process certainly isn't as optimal as it could be, but it works well for this case.

- 917
- 8
- 17
-
This doesn't work for me, I'm trying with a SCNShape with a solid color. I want to additive blend between two of these shapes. Do you have an idea what to do? – Max Apr 06 '15 at 13:19
-
-
Hey! Wow that was fast. Have a look here, there's an image: http://stackoverflow.com/questions/29458247/scenekit-how-to-use-different-blend-modes-e-g-additive-blending I think it's not perfect, but I might be confused. – Max Apr 06 '15 at 18:28
-
Hi Max - I've commented in your other thread - basically this technique throws away the alpha value you've set for the geometry. It's not a proper solution, but it works for most cases. If you need to fade something then rather than using the alpha channel you can change the colour of the geometry to make it darker which should have the same effect. – jportway Apr 06 '15 at 19:40
-
Oh - your other thread seems to have disappeared now. Looking at the image you posted there I suggest you try setting the alpha value of your geometry to 1 and see how that goes (at the moment it's 0.5 - if you want the same visual look make your colours half as bright) – jportway Apr 07 '15 at 22:52
-
Another question to the shader modifier approach: What if I want to do normal alpha blending with the shader? I'm just trying to draw circles and I want to anti-alias the edges by making them semi-transparent but I can't get normal blending to work now. All I try is always blending additive. – Max Apr 08 '15 at 11:01