Shadertoy圆角矩形着色器移植到Godot 4.0后无效果问题求助
问题:Godot 4.0中转换Shadertoy圆角矩形着色器无效果
我在Shadertoy的评论里找到一个生成圆角矩形的着色器:
float udRoundBox( vec2 p, vec2 b, float r ) { return length(max(abs(p)-b+r,0.0))-r; } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { float f = udRoundBox( fragCoord-iResolution.xy/2.0, iResolution.xy/2.0, 64.0); f = (f>0.0) ? 1.0 : 0.0; fragColor = vec4(f,1.0,f,1.0); }
我尝试转换成Godot 4.0的CanvasItem着色器:
shader_type canvas_item; float udRoundBox( vec2 p, vec2 b, float r ) { return length(max(abs(p)-b+r,0.0))-r; } void fragment() { // Vague idea of how to translate these: vec2 iResolution = SCREEN_PIXEL_SIZE; vec2 fragCoord = FRAGCOORD.xy; vec4 fragColor = COLOR; vec2 p = fragCoord-iResolution.xy/2.0; vec2 b = iResolution.xy/2.0; float r = 64.0; float f = udRoundBox(p, b, r); f = (f>0.0) ? 1.0 : 0.0; fragColor = vec4(f,1.0,f,1.0); }
将这个着色器材质加到带GradientTexture1D的TextureRect后,纹理完全没变化,调整参数r也没用,问题出在哪?
问题分析与修复
你的着色器没生效的核心问题是坐标系统理解错误,以及对Godot CanvasItem着色器的变量使用不当,具体问题和修复方法如下:
1. 错误的分辨率/坐标变量
- Shadertoy的
iResolution是画布的像素尺寸,但你用的SCREEN_PIXEL_SIZE是单个屏幕像素的大小(比如1920x1080屏幕下是vec2(1/1920, 1/1080)),二者完全不是同一概念。 - Godot的
FRAGCOORD是当前片段在纹理/控件上的绝对像素坐标,直接使用会导致圆角矩形尺寸和屏幕绑定,而非和TextureRect的尺寸绑定。
正确做法是使用UV坐标(范围0到1)做相对定位,或用TEXTURE_SIZE获取当前纹理的像素尺寸。
2. 未结合原有纹理
你直接覆盖了fragColor,完全忽略了TextureRect上的GradientTexture1D。如果要保留原有纹理,需要将圆角矩形作为遮罩与原纹理混合。
修复后的着色器代码
shader_type canvas_item; float udRoundBox(vec2 p, vec2 b, float r) { return length(max(abs(p) - b + r, 0.0)) - r; } void fragment() { // UV坐标范围(0,0)到(1,1),中心在(0.5,0.5) vec2 uv = UV - 0.5; // 修正UV的宽高比,避免圆角矩形拉伸变形 vec2 aspect = vec2(1.0, TEXTURE_SIZE.y / TEXTURE_SIZE.x); vec2 p = uv * aspect; // 用相对值定义矩形大小和圆角半径,适配不同尺寸的控件 vec2 b = vec2(0.4); float r = 0.1; float f = udRoundBox(p, b, r); // smoothstep实现抗锯齿,避免边缘出现锯齿感 float mask = smoothstep(0.0, fwidth(f), -f); // 结合原纹理颜色与圆角遮罩 COLOR = texture(TEXTURE, UV) * vec4(1.0, 1.0, 1.0, mask); }
额外说明
- 如果需要用绝对像素作为圆角半径,可以这样计算:
这样能保证在不同尺寸的TextureRect上,圆角半径始终为64像素。float pixel_radius = 64.0; float r = pixel_radius / min(TEXTURE_SIZE.x, TEXTURE_SIZE.y) * 0.5; fwidth(f)会根据当前片段的像素密度自动计算平滑范围,让抗锯齿效果适配不同分辨率。
内容的提问来源于stack exchange,提问作者jakub
相关产品推荐
相关产品推荐

