How to add transparency with a shader in SceneKit?
Asked Answered
A

3

5

I would like to have a transparency effect from an image, for now I just test with a torus, but the shader does not seem to work with alpha. From what I understood from this thread (Using Blending Functions in Scenekit) and this wiki link about transparency : (http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Transparency), GLBlendFunc is replaced by pragma transparency in SceneKit.

Would you know what is wrong with this code?

I created a new project with SceneKit, and I changed the ship mesh for a torus.


EDIT :
I am trying with a plane, but the image below does not appear inside the plane, instead I get the image with the red and brownish boxes below.

My image with alpha :

enter image description here

The result (the image with alpha should replace the brownish color) :

enter image description here

let plane = SCNPlane(width: 2, height: 2)
var texture = SKTexture(imageNamed:"small")
texture.filteringMode = SKTextureFilteringMode.Nearest
plane.firstMaterial?.diffuse.contents = texture
let ship = SCNNode(geometry: plane) //SCNTorus(ringRadius: 1, pipeRadius: 0.5)
ship.position = SCNVector3(x: 0, y: 0, z: 15)
scene.rootNode.addChildNode(ship)

let myscale : CGFloat = 10
let box = SCNBox(width: myscale, height: myscale, length: myscale, chamferRadius: 0)
box.firstMaterial?.diffuse.contents = UIColor.redColor()
let theBox = SCNNode(geometry: box)
theBox.position = SCNVector3(x: 0, y: 0, z: 5)
scene.rootNode.addChildNode(theBox)


let scnView = self.view as SCNView
scnView.scene = scene
scnView.backgroundColor = UIColor.blackColor()


var shaders = NSMutableDictionary()
shaders[SCNShaderModifierEntryPointFragment] = String(contentsOfFile: NSBundle.mainBundle().pathForResource("test", ofType: "shader")!, encoding: NSUTF8StringEncoding, error: nil)
var material = SCNMaterial()
material.shaderModifiers = shaders
ship.geometry?.materials = [material]

The shader :

#pragma transparent
#pragma body
_output.color.rgba = vec4(0.0, 0.2, 0.0, 0.2);
Anglocatholic answered 10/5, 2015 at 23:12 Comment(0)
B
4

SceneKit uses premultiplied alpha (r, g and b fields should be multiplied by the desired a) :

vec4(0.0, 0.2, 0.0, 0.2); // `vec4(0.0, 1.0, 0.0, 1.0) * alpha` with alpha = 0.2
Bereft answered 12/5, 2015 at 15:38 Comment(4)
Thanks, I edited my post, could you have a look? I am trying to do the same with an image and a texture with alpha. The image does not appear, instead there is a color that fills the plane.Anglocatholic
could you also post the shader?Bereft
I edited my post, I haven't really changed the shader, since the image did not appear well, I thought the problem might be something else than the color (0.2).Anglocatholic
Thank you! this really saved my bacon!Lay
P
3

I was struggling with this problem too. Finally I found out that to make '#pragma transparent' work, I had to add it to another shader other than the one executing my transparency code.

For example, I added transparency code to the surface shader, and added '#pragma transparent' to the geometry shader. The Apple API document also added '#pragma transparent' to the geometry shader, don't know if they were intended to do so.

NSString *geometryScript = @""
"#pragma transparent";

NSString *surfaceScript = @""
//"#pragma transparent" // You must not put it together with the transparency code
"float a = 0.1;"
"_surface.diffuse = vec4(_surface.diffuse.rgb * a, a);";

// This works for the transparency code in surface shader too.
//NSString *fragmentScript = @""
//"#pragma transparent";

yourMaterial.shaderModifiers = @{SCNShaderModifierEntryPointGeometry:geometryScript,
SCNShaderModifierEntryPointSurface:surfaceScript};

This code works in iOS 11.2, Xcode 9.2.

This rule applies to SCNShaderModifierEntryPointFragment shader as well. Likewise, if you want to change transparency there, you can add '#pragma transparent' to the geometry shader or the surface shader. I haven't tested SCNShaderModifierEntryPointLightingModel shader.

If you don't add any '#pragma transparent' to a shader, a black background may be blended with the transparent pixels.

Patrick answered 18/1, 2018 at 8:23 Comment(0)
G
2

Adding transparency can be quite easily done in the SCNShadable Surface or Fragment entry point

The SCNShaderModifierEntryPointSurface entry point version

#pragma transparent
#pragma body

_surface.diffuse.a = 0.5;

The SCNShaderModifierEntryPointFragment entry point version

#pragma transparent
#pragma body

_output.color.a = 0.5;
Greathouse answered 31/5, 2016 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.