The documentation suggests that it should be possible to use a single shader with multiple instances of an SKNode, such that each instance will use the unique SKAttributes that are passed to it. Let's try that with an SKShapeNode
.
This is the fragment shader testFill.fsh
, simply coloring based on the value for a_test
:
void main()
{
gl_FragColor = vec4(vec3(a_test), 1.0);
}
And here we make two nodes `testNode0`, and `testNode1`, each using the same shader, but with a different value for `a_test`:
class GameScene: SKScene {
override func didMove(to view: SKView) {
let testShader = shaderWithFilename( "testFill", fileExtension: "fsh", uniforms: [])
testShader.attributes = [
SKAttribute(name: "a_test", type: .float)
]
let testNode0 = SKShapeNode(rect: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
testNode0.fillShader = testShader
testNode0.position = CGPoint(x: -100, y: 300)
testNode0.setValue(SKAttributeValue(float: 0.2), forAttribute: "a_test")
addChild(testNode0)
let testNode1 = SKShapeNode(rect: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
testNode1.fillShader = testShader
testNode1.position = CGPoint(x: 100, y: 300)
testNode1.setValue(SKAttributeValue(float: 0.8), forAttribute: "a_test")
addChild(testNode1)
}
}
Here is the result:
The squares are the same color, in particular the result of passing the second value 0.8
for a_test
.
Now, let's try the same thing with SKSpriteNode
:
class GameScene: SKScene {
override func didMove(to view: SKView) {
let testShader = shaderWithFilename( "testFill", fileExtension: "fsh", uniforms: [])
testShader.attributes = [
SKAttribute(name: "a_test", type: .float)
]
let testNode0 = SKSpriteNode()
testNode0.size = CGSize(width: 100.0, height: 100.0)
testNode0.shader = testShader
testNode0.position = CGPoint(x: -100, y: 300)
testNode0.setValue(SKAttributeValue(float: 0.2), forAttribute: "a_test")
addChild(testNode0)
let testNode1 = SKSpriteNode()
testNode1.size = CGSize(width: 100.0, height: 100.0)
testNode1.shader = testShader
testNode1.position = CGPoint(x: 100, y: 300)
testNode1.setValue(SKAttributeValue(float: 0.8), forAttribute: "a_test")
addChild(testNode1)
}
}
And it works!
Why does the documentation not say that this is not possible with an SKSpriteNode? Why does an SKSpriteNode have a .setValue
method if it does not function as expected?
Is this a bug? Or something that is expected to be obvious?
I am not sure, but I am sharing this in case somebody else ends up stuck on this issue as I was when otherwise trying to do something relatively straightforward.
The solution (if your shape is a simple rect
, as it is in my case) is to initialize an empty SKSpriteNode
and size it accordingly, after which SKAttributes should work as expected.
Apple, please either fix this, or update the documentation.