No problem. Here's an example that colors the stroke with a gradient:
Shader file "gradientStroke.fsh":
void main()
{
if ( u_path_length == 0.0 ) {
gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 ); // error as u_path_length should never be zero, draw magenta
} else if ( v_path_distance / u_path_length <= u_current_percentage ) { // draw color up to the current stroke percentage
float c = v_path_distance / u_path_length; // c is a small number that becomes 1.0 toward the end of the stroke
float v = 1.0 - c; // v is 1.0 at the start and approaches 0 toward the end of the stroke.
// at any point in the stroke, v + c = 1.0
vec4 s = u_color_start;
vec4 e = u_color_end;
gl_FragColor = vec4( clamp( s.r*v + e.r*c, 0.0, 1.0 ), // clamp between 0.0-1.0 just in case
clamp( s.g*v + e.g*c, 0.0, 1.0 ),
clamp( s.b*v + e.b*c, 0.0, 1.0 ),
clamp( s.a*v + e.a*c, 0.0, 1.0 ) );
} else { // draw nothing!
gl_FragColor = vec4( 0.0, 0.0, 0.0, 0.0 );
}
}
Scene subclass:
import SpriteKit
import GameplayKit
func shaderWithFilename( _ filename: String?, fileExtension: String?, uniforms: [SKUniform] ) -> SKShader {
let path = Bundle.main.path( forResource: filename, ofType: fileExtension )
let source = try! NSString( contentsOfFile: path!, encoding: String.Encoding.utf8.rawValue )
let shader = SKShader( source: source as String, uniforms: uniforms )
return shader
}
class GameScene: SKScene {
let strokeSizeFactor = CGFloat( 2.0 )
var strokeShader: SKShader!
var strokeLengthUniform: SKUniform!
// define the start and end colors here
var startColorUniform = SKUniform( name: "u_color_start", vectorFloat4: vector_float4( [1.0, 1.0, 0.0, 1.0] ) )
var endColorUniform = SKUniform( name: "u_color_end", vectorFloat4: vector_float4( [1.0, 0.0, 0.0, 1.0] ) )
var _strokeLengthFloat: Float = 0.0
var strokeLengthKey: String!
var strokeLengthFloat: Float {
get {
return _strokeLengthFloat
}
set( newStrokeLengthFloat ) {
_strokeLengthFloat = newStrokeLengthFloat
strokeLengthUniform.floatValue = newStrokeLengthFloat
}
}
override func didMove( to view: SKView ) {
// percentage is the only variable uniform since start and end color don't change
strokeLengthUniform = SKUniform( name: "u_current_percentage", float: 0.0 )
// pass all uniforms to the shader
let uniforms: [SKUniform] = [strokeLengthUniform, startColorUniform, endColorUniform]
strokeShader = shaderWithFilename( "gradientStroke", fileExtension: "fsh", uniforms: uniforms )
strokeLengthFloat = 0.0
let cameraNode = SKCameraNode()
self.camera = cameraNode
let path = CGMutablePath()
path.addRoundedRect(in: CGRect( x: 0, y: 0, width: 200, height: 150 ), cornerWidth: 35, cornerHeight: 35, transform: CGAffineTransform.identity )
let strokeWidth = 17.0 * strokeSizeFactor
let shapeNode = SKShapeNode( path: path )
shapeNode.lineWidth = strokeWidth
shapeNode.lineCap = .round
addChild( shapeNode )
shapeNode.addChild( cameraNode )
shapeNode.strokeShader = strokeShader
let rect = shapeNode.calculateAccumulatedFrame()
cameraNode.position = CGPoint( x: rect.size.width/2.0, y: rect.size.height/2.0 )
}
override func update(_ currentTime: TimeInterval) {
strokeLengthFloat += 0.01
if strokeLengthFloat > 1.0 {
strokeLengthFloat = 0.0
}
}
}