为何OpenGL片段着色器未呈现预期彩色波浪纹理,仅显示纯色?
着色器无法呈现预期波浪彩色图案的排查分析
问题描述
我有一个OpenGL片段着色器文件(shader.fsh),代码如下:
constant float M_PI = 3.141592653589793; constant float M_2PI = 6.283185307179586; constant vec3 c1a = vec3(0.0, 0.0, 0.0); constant vec3 c1b = vec3(0.9, 0.0, 0.4); constant vec3 c2a = vec3(0.0, 0.5, 0.9); constant vec3 c2b = vec3(0.0, 0.0, 0.0); void main() { vec2 point = (0.5 * u_sprite_size - gl_FragCoord.xy) / u_sprite_size; float angle = atan(point.y, point.x); float turn = (angle + M_PI) / M_2PI; float radius = sqrt(point.x * point.x + point.y * point.y); float sine_kf = 19.0; float ka_wave_rate = 0.94; float ka_wave = sin(ka_wave_rate * u_time); float sine_ka = 0.35 * ka_wave; float sine2_ka = 0.47 * sin(0.87 * u_time); float turn_t = turn + -0.0 * u_time + sine_ka * sin(sine_kf * radius) + sine2_ka * sin(8.0 * angle); bool turn_bit = mod(10.0 * turn_t, 2.0) < 1.0; float blend_k = pow((ka_wave + 1.0) * 0.5, 1.0); vec3 c; if(turn_bit) { c = blend_k * c1a + (1.0 -blend_k) * c1b; } else { c = blend_k * c2a + (1.0 -blend_k) * c2b; } c *= 1.0 + 1.0 * radius; gl_FragColor = vec4(c, 1.0); }
该着色器本应呈现带有波浪的彩色图案,但实际仅显示纯色。SpriteKit/Swift中的对象初始化代码如下:
override func didMove(to view: SKView) { doorShader = SKShader(fileNamed: "shader.fsh") leftDoor = SKSpriteNode(imageNamed: "wrong_door") leftDoor.shader = doorShader //<-- shader is non-null at assignment addChild(leftDoor) }
核心原因及解决方法
1. 未绑定着色器依赖的Uniform变量
着色器中使用了u_sprite_size和u_time两个Uniform变量,但Swift代码中未对它们赋值:
u_sprite_size:用于计算片段在精灵内的相对位置,未赋值会导致point计算失效,所有基于位置的波浪逻辑无法运行。u_time:控制动画的时间变量,未赋值会固定为0,波浪相关的正弦值保持静态甚至无变化,最终呈现纯色。
解决方法:
在Swift代码中添加Uniform变量的绑定与更新逻辑:
override func didMove(to view: SKView) { doorShader = SKShader(fileNamed: "shader.fsh") leftDoor = SKSpriteNode(imageNamed: "wrong_door") // 初始化Uniform变量 doorShader.uniforms = [ SKUniform(name: "u_sprite_size", vectorFloat2: vector_float2(Float(leftDoor.size.width), Float(leftDoor.size.height))), SKUniform(name: "u_time", float: 0.0) ] leftDoor.shader = doorShader addChild(leftDoor) } // 在update方法中实时更新时间变量 override func update(_ currentTime: TimeInterval) { doorShader?.uniforms.first(where: { $0.name == "u_time" })?.floatValue = Float(currentTime) }
2. 时间偏移项无效
着色器中turn_t = turn + -0.0 * u_time + ...的-0.0 * u_time等于0,完全没有起到时间偏移的作用,这大概率是笔误,原本应设置非零系数来实现图案随时间旋转的动态效果。
解决方法:
修改为有意义的时间系数,例如:
float turn_t = turn + -0.1 * u_time + sine_ka * sin(sine_kf * radius) + sine2_ka * sin(8.0 * angle);
3. 坐标计算适配问题
gl_FragCoord.xy的原点在屏幕左下角,而SpriteKit精灵默认原点在中心,可能导致point计算逻辑与预期不符,波浪效果无法正确映射到精灵上。
解决方法:
改用SpriteKit内置的v_tex_coord纹理坐标(范围0-1,原点在左下角)计算相对位置,替换原point代码:
vec2 point = v_tex_coord - vec2(0.5); // 将原点移到中心,范围-0.5至0.5
该方式无需依赖u_sprite_size,更适配SpriteKit的纹理系统。
内容的提问来源于stack exchange,提问作者quickj
相关产品推荐
相关产品推荐

