Reputation: 393
I am trying to draw gradient in SKShapeNode object.
I draw a triangle with a color using alpha component and it works fine. And I would like to add gradient so one edge of the triangle disappears slowly to the background. What I want to achieve is to simulate sight range of a character.
I have found one answer regarding this challenge: How to apply a gradient to SKShapeNode created from a path, but the answer doesn't work in XCode 13.1. The reason is that proposed solution of adding SKTexture can't be compiled:
var testTexture = SKTexture(size: CGSize(width: 200, height: 1), color1: CIColor(red: 1.0, green: 0.0, blue: 1.0, alpha: 1.0), color2: CIColor(red: 1.0, green: 0.0, blue: 1.0, alpha: 0.0), direction: GradientDirection.Left)
It results in the error "Cannot find 'GradientDirection' in scope...". And I cannot find any other method to add gradient.
I have found another answer which says that it isn't possible, but it is from 2013, so maybe something changed (How to create a Gradient in Spritekit?).
I also tried this solution: https://augmentedcode.io/2017/11/12/drawing-gradients-in-spritekit/, but it doesn't produce any effect and decreases performance of the application.
Upvotes: 1
Views: 520
Reputation: 393
Some sources from the internet directed my to OpenGL Shading Language: https://www.khronos.org/opengl/wiki/Core_Language_(GLSL).
Here is partly solution:
let sight = SKShapeNode()
let gradientShader = SKShader(source: "void main() {" +
"float distanceFromCenter = distance(v_tex_coord, vec2(0.5,0.5));" +
"gl_FragColor = vec4(0.6, 0.3, 0.0, distanceFromCenter*6.0);" +
"}")
sight.fillColor = .clear
sight.fillShader = gradientShader
Here are helpful links: Drawing a circle with a shader in SpriteKit, https://thebookofshaders.com/02/, Add shader for SKShapeNode, https://developer.apple.com/documentation/spritekit/skshapenode/controlling_shape_drawing_with_shaders.
The above solution was half way, but after another couple of hours I managed to achieve what I wanted to.
let pos = n.sprite.position
let frame = n.sight.frame
let x = (pos.x - frame.minX) / frame.width
let y = (pos.y - frame.minY) / frame.height
let gradientShader = SKShader(source: "void main() {" +
"float distanceFromCenter = distance(v_tex_coord, npcLocation);" +
"float alpha = 0.8 - distanceFromCenter;" +
"if (alpha < 0) { alpha = 0.0;}" +
"gl_FragColor = vec4(0.0, 0.0, 0.0, alpha);" +
"}")
gradientShader.uniforms = [SKUniform(name: "npcLocation", vectorFloat2: vector_float2(Float(x), Float(y)))]
n.sight.fillColor = .clear
n.sight.fillShader = gradientShader
Upvotes: 4