sar*_*tak 6 shader opengl-es glsl sprite-kit
着色器中的变量u_time
告诉您当前时间。但是,如果您重复使用着色器(根据Apple 的最佳实践:“如果多个精灵需要相同的行为,请创建一个着色器对象并将其与每个精灵 [\xe2\x80\xa6] 关联”),然后u_time
继续从第一次将其添加到场景中时。这使得使用着色器产生某些类型的效果变得困难,例如从黑色到白色的简单淡入淡出,如下所示:
void main() {\n float duration = 3.0; // seconds\n float progress = u_time / duration;\n\n gl_FragColor = vec4(progress, progress, progress, 1.0);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n该着色器第一次添加到精灵时会按预期工作,u_time
从零开始。但是,后续重用相同的着色器代码会以非零开始u_time
。因此,后续着色器将开始完全白色,并且不会渲染预期的从黑到白的淡入淡出。这似乎极大地限制了可能的效用SKShader
。
我找到了一种可行的方法,但我对此不满意。甚至可能不满意,我宁愿每次将着色器添加到场景时都重新编译它。
总体思路是为着色器提供特定于精灵的属性,用于跟踪着色器何时添加到该精灵。要计算该值,请跟踪着色器第一次添加到场景中的时间(即我们知道u_time
应该为零的时间)。然后,每次我们将着色器添加到精灵时,都会计算第一个时间戳和当前时间之间的差异。提供该差异作为属性a_startTime
(对应于我们希望u_time
或其他东西为零的情况)。然后在着色器中,a_startTime - u_time
是自添加着色器以来的当前时间戳,从零开始。
这是整个实现的样子。跟踪第一次将着色器附加到全局变量中的精灵,如下所示:
static dispatch_once_t firstStartToken;
static float firstStart;
dispatch_once(&firstStartToken, ^{
firstStart = (float)CACurrentMediaTime();
});
Run Code Online (Sandbox Code Playgroud)
该变量标记着色器的制服为零firstStart
时的时间戳。u_time
我们还必须a_startTime
为SKShader
实例声明一个属性,以便有一个地方可以填写当前精灵的开始时间:
[shader setAttributes:@[
[SKAttribute attributeWithName:@"a_startTime" type:SKAttributeTypeFloat]]];
Run Code Online (Sandbox Code Playgroud)
然后,每次将着色器添加到 时SKSpriteNode
,将精灵的属性设置为相对于初始 的a_startTime
当前时间。u_time
float startTime = CACurrentMediaTime() - firstStart;
[sprite setValue:[SKAttributeValue valueWithFloat:startTime]
forAttributeNamed:@"a_startTime"];
Run Code Online (Sandbox Code Playgroud)
最后,让着色器实现使用a_startTime
:
void main() {
float duration = 3.0; // seconds
float progress = (u_time - a_startTime) / duration;
gl_FragColor = vec4(progress, progress, progress, 1.0);
}
Run Code Online (Sandbox Code Playgroud)
这种方法似乎有效。每次我将此着色器添加到精灵中时,它都会根据需要从黑色淡入白色。
然而,我担心它依赖于SKShader
. 第一个是它u_time
总是会继续上升:如果在 iOS 的未来版本中存在暂停或重置为零的情况,那么此代码将通过为当前时间提供负值或巨大值而中断。另一个潜在的破坏是我假设u_time
使用 进行计数CACurrentMediaTime()
,它似乎只与 中的内容直接对应u_time
;在某些情况下,例如夏令时转换,这些计时器可能会出现偏差。
归档时间: |
|
查看次数: |
795 次 |
最近记录: |