SpriteKit中SKTransition完成后SKShader画面翻转问题求助
SpriteKit场景过渡后Shader画面翻转的解决办法
我之前遇到过几乎一模一样的问题!这本质上是SpriteKit在过渡阶段和过渡完成后,对Shader中gl_FragCoord的Y轴坐标处理逻辑不一致导致的,给你详细拆解原因和解决办法:
问题原因
SpriteKit的节点坐标系默认原点在左上角,但OpenGL(Shader依赖的底层渲染框架)的纹理/屏幕坐标系原点在左下角:
- 过渡动画期间:SpriteKit会把新场景渲染到一个离屏纹理中,再做过渡混合,这时候
gl_FragCoord的Y轴遵循OpenGL的左下角原点,和你的Shader预期一致,所以画面正常。 - 过渡完成后:场景直接渲染到屏幕,SpriteKit会调整坐标系,导致
gl_FragCoord的Y轴方向反转,你的Shader没有适配这个变化,所以画面瞬间上下翻转。
解决办法(推荐第一种)
方法1:修改Shader适配SpriteKit坐标系
SpriteKit会自动给Shader传入内置Uniform u_sprite_size,代表当前精灵的尺寸。我们可以用它来修正gl_FragCoord的Y轴坐标,让Shader始终适配SpriteKit的坐标系:
修改你的Starfield.fsh代码,把所有gl_FragCoord替换为修正后的坐标:
#define M_PI 3.1415926535897932384626433832795 float rand(vec2 co); float rand(vec2 co) { return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } void main() { // 核心修正:翻转Y轴坐标,适配SpriteKit左上角原点的坐标系 vec2 fragCoord = vec2(gl_FragCoord.x, u_sprite_size.y - gl_FragCoord.y); float size = 50.0; float prob = 0.95; vec2 pos = floor(1.0 / size * fragCoord.xy); float color = 0.0; float starValue = rand(pos); if (starValue > prob) { vec2 center = size * pos + vec2(size, size) * 0.5; float t = 0.9 + 0.2 * sin(u_time + (starValue - prob) / (1.0 - prob) * 45.0); color = 1.0 - distance(fragCoord.xy, center) / (0.9 * size); color = color * t / (abs(fragCoord.y - center.y)) * t / (abs(fragCoord.x - center.x)); } else if (rand(v_tex_coord) > 0.996) { float r = rand(fragCoord.xy); color = r * (0.25 * sin(u_time * (r * 5.0) + 720.0 * r) + 0.75); } gl_FragColor = vec4(vec3(color), 1.0); }
方法2:调整SpriteNode的Y轴缩放(不推荐)
如果你不想修改Shader,可以尝试把星空精灵的yScale设为-1,强制翻转节点:
starField.yScale = -1
但这种方式有副作用:如果你的场景后续有其他节点变换,或者Shader依赖节点的原始坐标系,可能会引发其他布局问题,所以优先推荐方法1。
验证方式
你可以在Shader中临时添加一行代码输出颜色,来确认坐标差异:
// 临时测试:Y轴顶部输出红色,底部输出绿色 gl_FragColor = vec4(gl_FragCoord.y / u_sprite_size.y, 1.0 - gl_FragCoord.y / u_sprite_size.y, 0.0, 1.0);
运行后你会发现,过渡期间和过渡完成后,红绿色的分布是反转的,这也能佐证我们的原因分析。
内容的提问来源于stack exchange,提问作者prolific8
相关产品推荐
相关产品推荐

