Swift中SKShader动画的SpriteKit问题
就我而言,我无法理解为什么这个着色器动画没有运行。感谢您的帮助。请看下面的代码。。。着色器将正确显示,但不会设置动画。多谢各位 注:Xcode 9.4.1、Swift 4.1、iOS 11.4Swift中SKShader动画的SpriteKit问题,swift,sprite-kit,shader,Swift,Sprite Kit,Shader,就我而言,我无法理解为什么这个着色器动画没有运行。感谢您的帮助。请看下面的代码。。。着色器将正确显示,但不会设置动画。多谢各位 注:Xcode 9.4.1、Swift 4.1、iOS 11.4 import SpriteKit class GameScene: SKScene { static let marquee: SKShader = { let shader = SKShader( source: "void main() {" +
import SpriteKit
class GameScene: SKScene {
static let marquee: SKShader = {
let shader = SKShader(
source: "void main() {" +
"float np = mod(a_path_phase + v_path_distance / u_path_length, 1.0);" +
"vec3 hsb = vec3(np, 1.0, 1.0);" +
"vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);" +
"vec3 p = abs(fract(hsb.xxx + K.xyz) * 6.0 - K.www);" +
"vec3 rgb = hsb.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), hsb.y);" +
"vec4 df = SKDefaultShading();" +
"gl_FragColor = vec4(rgb, df.z);" +
"}"
)
shader.attributes = [SKAttribute(name: "a_path_phase", type: .float)]
return shader
} ()
private let beat: TimeInterval = 0.05
private var phase: Float = 0
override func didMove(to view: SKView) {
let node = SKShapeNode(rectOf: CGSize(width: 256, height: 256), cornerRadius: 16)
node.fillColor = .clear
node.strokeColor = .white
node.strokeShader = GameScene.marquee
node.lineWidth = 8
node.glowWidth = 4
node.run(
SKAction.repeatForever(
SKAction.sequence(
[
SKAction.wait(forDuration: beat),
SKAction.run() { [weak self] in
if let weak = self {
weak.phase = fmodf(weak.phase + Float(weak.beat), 1)
node.setValue(SKAttributeValue(float: weak.phase), forAttribute: "a_path_phase")
}
}
]
)
)
)
addChild(node)
}
}
我在
.setValue(for属性:)
方面也遇到了问题。它似乎不起作用。经调查,我的结论是
我相信SKShapeNode.setValue(对于属性:)
不起作用
事实上,SKSpriteNode.setValue(for属性:)
在相同的条件下工作正常,这让我得出结论,这几乎肯定是iOS中SKShapeNode
中的某个bug
事实上,我可能会设置任何SKAttribute
s
SKShapeNode.fillShader
或SKShapeNode.strokeShader
保留其
无论我做了什么,值都设置为0.0
但是,SKSpriteNode.shader
没有发生同样的情况
所以我不得不想办法避开这个错误。
某种黑客。
幸运的是,就我而言,我确实找到了一种方法
幸运的是,这似乎也足以解决你的问题
在这种情况下,您可以做的是将相位的值作为
strokeColor
的一个组件传递,例如红色组件
为此,您必须将阶段标准化为0.0
到1.0
之间的值。
您可以使用shader.uniform传递一个阶段乘法器,以帮助对其进行反规范化
然后从SKDefaultShading().x
,(红色组件)读取着色器内部的阶段值
确保设置
strokeColor
到1.0
,对于SKDefaultShading()
将有其颜色
组件值已被其alpha预乘
现在,由于您的strokeColor已用于通过阶段,因此您可以将笔划线的实际颜色作为vec4 shader.uniform进行传递
- 就我而言,我还利用
来帮助执行我的任务 动画像u_time
这样的东西非常有用fract(u_时间)
下面是更正后的代码的外观: >注意:有一个更简单的解决方案。看看这篇文章的结尾。 注意:我没有编译上面发布的代码。我应该只是作为一个草图
在这篇文章的第二天,我发现属性参数不应该在片段着色器中使用,只应该在顶点着色器中使用 看看StackOverflow问题: 然而,
SKAttribute
和SKAttributeValue
的SDK文档似乎表明,“SKAttributes”和实际着色器属性参数之间可能没有直接关系。它们的名字似乎是一样的
更简单的解决方案: 然而,最终,没有任何必要像我在这里展示的那样使用任何黑客 需要做的只是通过
SKShader.uniformNamed(“u_阶段”)?.floatValue=phase来设置统一的值,而不是使用.setValue(for属性:)
,正如jmdecombe后来正确指出的那样
我将在这里保留我的答案以供参考,因为它提供了一个非常规的问题解决方案。Hi!你有没有想过这件事?到目前为止,对于我来说,属性值似乎没有到达着色器,着色器似乎总是得到值=0.0;这就好像忽略了node.setValue(,forAttribute:)命令一样。可能是iOS错误,还是我遗漏了什么?我希望这不是一只虫子。我希望我遗漏了一些东西。嗨,已经有一段时间了,但我看了一下代码,实际上解决方案是使用一致性而不是属性,然后它就成功了。也就是说,line shader.attributes=etc.必须变成:shader.uniforms=[SKUniform(名称:“a_path_phase”,float:0.0)],然后,行node.setValue等必须变成:node.strokeShader?.uniformNamed(“a_path_phase”)?.floatValue=weak.phase您在这里告诉我的是,您决定写入一个统一而不是一个属性,我没有意识到这是可能的。不过,我们实现需求的两种“替代”方法似乎都证实了一件事,那就是SKShapeNode.setValue(,forAttribute:)中存在一个bug。
import SpriteKit
class GameScene: SKScene {
private typealias Me = GameScene
static let phaseMultiplier: Float = 1000
static let marquee: SKShader = {
let shader = SKShader(
source: "void main() {" +
"float red = SKDefaultShading().x;" +
"float phase = red * u_phase_multiplier;" +
"float np = mod(phase + v_path_distance / u_path_length, 1.0);" +
"vec3 hsb = vec3(np, 1.0, 1.0);" +
"vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);" +
"vec3 p = abs(fract(hsb.xxx + K.xyz) * 6.0 - K.www);" +
"vec3 rgb = hsb.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), hsb.y);" +
"vec4 df = u_stroke_color;" +
"gl_FragColor = vec4(rgb, df.z);" +
"}"
)
let white = vector_float4.init(1, 1, 1, 1)
shader.uniforms = [
SKUniform(name: "u_phase_multiplier", float: Me.phaseMultiplier),
SKUniform(name: "u_stroke_color", vectorFloat4: white)]
return shader
} ()
private let beat: TimeInterval = 0.05
private var phase: Float = 0
override func didMove(to view: SKView) {
let node = SKShapeNode(rectOf: CGSize(width: 256, height: 256), cornerRadius: 16)
node.fillColor = .clear
node.strokeColor = .white
node.strokeShader = Me.marquee
node.lineWidth = 8
node.glowWidth = 4
node.run(
SKAction.repeatForever(
SKAction.sequence(
[
SKAction.wait(forDuration: beat),
SKAction.run() { [weak self] in
if let weak = self {
weak.phase = fmodf(weak.phase + Float(weak.beat), 1)
let phase = weak.phase / Me.phaseMultiplier
node.strokeColor = SKColor.init(red: phase, green: 0, blue: 0, alpha: 1)
}
}
]
)
)
)
addChild(node)
}
}