Repository navigation
|
@domchen 不知道是否有考虑提供 SkRuntimeEffect 类似的支持 |
Replies: 3 comments 14 replies
|
感谢建议!现状确实如你所说:
|
|
我试了下 figma 的 shader fill 后面是 figma 自己的AI 生成的 shader 看着效果应该就是非常纯粹的假定在一个矩形内绘制。然后按顺序执行,应该是一个模版化的 至于你说的需要引入一套着色语言编译器或跨后端 IR。我感觉按照 tgfx 现在的发展路线其实可以不用的。 所以开发者只需要照常用GLSL 编写就行了。通过离线化工具自动转化。Shader 的设计本应该就是一个模版化轻量化的,但就是这个轻量化的方案 而 RuntimeEffect 是作为一个最大自由度的方案,用于实现一些 Shader 轻量化所不能实现的复杂效果
diagnostic(off,derivative_uniformity);
struct Uniforms {
frameData: vec4f,
inputDimsData: vec4f,
rippleCount: vec4f,
};
@group(0) @binding(0) var<uniform> u: Uniforms;
struct VsIn {
@location(0) pos: vec2f,
@location(1) uv: vec2f,
};
struct VsOut {
@builtin(position) position: vec4f,
@location(0) uv: vec2f,
};
@vertex fn vs_main(in: VsIn) -> VsOut {
var out: VsOut;
out.position = vec4f(in.pos, 0.0, 1.0);
out.uv = in.uv;
return out;
}
@fragment fn fs_main(@location(0) outputUv_in: vec2f) -> @location(0) vec4f {
let time = u.frameData.x;
let outputUv = outputUv_in;
let dims = max(u.frameData.yz, vec2f(1.0));
let inputDims = max(u.inputDimsData.xy, vec2f(1.0));
let inputTexel = vec2f(1.0) / inputDims;
let uv = outputUv;
let texel = inputTexel;
let aspect = inputDims.x / max(inputDims.y, 1.0);
let rippleCount = u.rippleCount.x;
// Aspect-correct coordinates centered at layer center
let p = (uv - vec2f(0.5)) * vec2f(aspect, 1.0);
let dist = length(p);
// Sinusoidal ripple wave
let wave = sin(dist * rippleCount * 6.2831853 - 0.0) * 0.5 + 0.5;
// Gentle radial falloff toward edges
let falloff = 1.0 - smoothstep(0.3, 0.7, dist);
// Blue-to-white water palette
let deepBlue = vec3f(0.04, 0.18, 0.55);
let midBlue = vec3f(0.15, 0.55, 0.9);
let white = vec3f(0.85, 0.95, 1.0);
var color: vec3f;
if (wave < 0.5) {
color = mix(deepBlue, midBlue, wave * 2.0);
} else {
color = mix(midBlue, white, (wave - 0.5) * 2.0);
}
// Apply falloff: fade to deep blue at edges
color = mix(deepBlue, color, falloff);
return vec4f(color, 1.0);
}
|
|
看了下你的 RuntimeShaderTest.mm,整体没问题,就是这个思路。回答你的问题,另外有个坑要提醒:
shader 写法这个文档里确实没讲清楚,注释说的是"用当前后端的着色语言",和实际约定对不上,我们后面把注释改一下。 |


感谢建议!现状确实如你所说:
为什么现在没做。tgfx 要同时跑 GL/Vulkan/Metal/WebGPU,
RuntimeEffect的做法是把最底层开放出来——你直接用当前后端的原生着色语言(重写onDraw操作CommandEncoder),自由度开到最大,不做中间层的限制。所以能力上业务方已经可以自足:想生成什么内容都可以自己实现。原生支持SkRuntimeEffect::MakeForShader的价值主要剩两点——性能(作为颜色源直接画,不用像变通方案那样多一次离屏 RT)和易用性(一份代码跨后端、能作为真正的Shader参与 Blend 等组合)。但要做到那样得引入一套着色语言编译器或跨后端 IR,相对这两点收益,投入产出不划算,所以一直没排期。现有能力下怎么实现自定义填充。三条路:一是用
RuntimeEffect做 ImageFilter,onDraw里忽略源图、自己输出颜色,重写filterBounds扩大输出范围,再画个占位矩形挂上 filter;二是离屏画成Image后用Shader::MakeImageShader填充;三是更彻底——直接用tgfx/gpu的公开接口(Device / CommandEncoder / RenderPipeline)自己管理 pipeline 绘制,RuntimeEffect::onDraw拿到的CommandEncoder就是这套接口。都能用,就是没有 runtime shader 来得直接。以后会不会做。这个方向我们考虑过,但按现有架构实现起来难度不小…