Polygon2D
shader_type canvas_item;
render_mode unshaded;
uniform vec4 color : source_color;
uniform float angle : hint_range(0,360);
uniform float max_dist : hint_range(0,1000) = 100;
uniform sampler2D gradientTexture;
vec4 get_gradient_color(float position) {
return texture(gradientTexture, vec2(position, 0.5));
}
void fragment() {
float ang_rad = angle * 3.1416 / 180.0;
vec2 dir = vec2(sin(ang_rad),cos(ang_rad));
vec2 at = screen_uv_to_sdf(SCREEN_UV);
float accum = 0.0;
while(accum < max_dist) {
float d = texture_sdf(at);
accum+=d;
if (d < 0.01) {
break;
}
at += d * dir;
}
float alpha = 1.0-min(1.0,accum/max_dist);
// the gradient controls the falloff of the shadow
alpha = get_gradient_color(alpha).r;
COLOR = vec4(color.rgb,alpha * color.a);
}
| 平台 | 渲染模式 | SDF支持 | 原因 |
|---|---|---|---|
| 桌面 | Forward Plus/Vulkan | ✅ | 完全支持 |
| Web | WebGL 2 | ✅ | SDF作为普通纹理上传 |
| Web | WebGL 1 (gl_compatibility) | ⚠️ | 可能受限,但Godot 4.x默认用WebGL 2 |
┌──────────────────────────────┐
│ 帧渲染流程 │
├──────────────────────────────┤
│ 1. CPU收集所有OccluderPolygon2D │
│ ↓ │
│ 2. CPU软件计算生成SDF纹理(距离场) │
│ ↓ │
│ 3. 将SDF纹理上传到GPU作为普通纹理 │
│ ↓ │
│ 4. 着色器执行光线步进算法: │
│ - screen_uv_to_sdf() 转换坐标 │
│ - texture_sdf() 采样距离值 │
│ - 沿光线方向累加距离直到碰到遮挡物 │
│ ↓ │
│ 5. 根据累计距离计算阴影透明度 │
└──────────────────────────────┘
这个项目能在Web上运行的核心原因是:
- Godot 4.x默认使用WebGL 2,而非WebGL 1的
gl_compatibility模式 - SDF数据是CPU预先计算后作为普通纹理上传的,不依赖GPU的特殊SDF支持
- 着色器只需要普通的纹理采样能力,这在所有WebGL环境中都支持
只要确保项目设置为WebGL 2渲染模式(Godot 4.x默认),就能正常运行这个阴影效果。
Web 平台文件系统限制 + 资源路径读写规则
res:// 路径在 Web 端是只读的
Web 导出后,res:// 是打包后的压缩资源包,不能创建文件夹、不能写入文件,这是最根本的原因。
DirAccess 操作res://在 Web 端无权限
浏览器环境不允许 JS 修改原始资源包,你的make_dir、文件保存都会静默失败。 Web 端唯一可写入路径:user:// Godot 所有平台(Web/PC/ 移动端
唯一通用的可读写路径是 user://,Web 端会映射到浏览器的本地存储(IndexedDB)。
我想知道你改的这个存档逻辑是新建存档放在user里面,然后加载的时候从user拿存档加载到res?
新存档:
res://resources/bag.tres (源资源,模板)
↓ 深拷贝/取空实例
{archives_dir}/{slot}/bag.tres ← 我改了:web 走 user://web_archives/
加载存档:
res://resources/bag.tres (源)
{archives_dir}/{slot}/bag.tres (存档)
↓ 把存档的值覆盖到源资源 (in-memory)
res://resources/bag.tres (源,已覆盖)
↓ ResourceSaver.save 写回磁盘
res://resources/bag.tres ← !! 这里又写回 res:// 了,我没改