如何让Godot中2D着色器与ParallaxBackground节点实现滚动星空?
问题分析
星星能显示但不滚动的核心原因有两点:
- 星空着色器依赖
FRAGCOORD(画布绝对像素坐标)和SCREEN_UV(屏幕归一化坐标),这两个坐标完全不受ParallaxBackground的scroll_offset影响——Parallax的滚动是通过调整ParallaxLayer的变换实现的,但你的着色器未使用任何与节点变换相关的坐标(如UV、WORLD_POS)。 - 若
ParallaxLayer的motion_scale未正确设置(默认应为(1,1)),也会导致滚动偏移无法作用于图层。
解决方案
方案1:修改着色器使用世界坐标(推荐)
将着色器中基于绝对坐标的计算替换为WORLD_POS(世界空间坐标),这样当ParallaxLayer随scroll_offset移动时,世界坐标会同步变化,星星自然会跟着滚动:
修改后的着色器代码:
shader_type canvas_item; uniform vec4 bg_color: hint_color; float rand(vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123); } void fragment() { float size = 100.0; float prob = 0.9; // 使用世界空间坐标替代绝对画布坐标 vec2 pos = floor(1.0 / size * WORLD_POS.xy); float color = 0.0; float starValue = rand(pos); if (starValue > prob) { vec2 center = size * pos + vec2(size, size) * 0.5; float t = 0.9 + 0.2 * sin(TIME * 8.0 + (starValue - prob) / (1.0 - prob) * 45.0); // 用世界坐标计算星星距离 color = 1.0 - distance(WORLD_POS.xy, center) / (0.5 * size); color = color * t / (abs(WORLD_POS.y - center.y)) * t / (abs(WORLD_POS.x - center.x)); } else if (rand(WORLD_POS.xy / 20.0) > 0.996) { float r = rand(WORLD_POS.xy); color = r * (0.85 * sin(TIME * (r * 5.0) + 720.0 * r) + 0.95); } COLOR = vec4(vec3(color),1.0) + bg_color; }
方案2:给着色器传递滚动偏移参数
如果不想依赖世界坐标,可通过脚本将滚动偏移直接传递给着色器,让着色器基于偏移计算星星位置:
步骤1:修改ParallaxBackground脚本
extends ParallaxBackground onready var stars_layer = $StarsLayer onready var stars_material = $StarsLayer/Stars.material var bg_offset = 0.0 func _ready(): stars_layer.motion_mirroring = Vector2(0, Helpers.WINDOW_SIZE.y) // 初始化着色器的偏移参数 stars_material.set_shader_param("scroll_offset", Vector2.ZERO) // 确保motion_scale生效(默认值,显式设置更稳妥) stars_layer.motion_scale = Vector2(1, 1) func _process(delta): bg_offset += 30 * delta scroll_offset = Vector2(0, bg_offset) // 将偏移传递给着色器 stars_material.set_shader_param("scroll_offset", Vector2(0, bg_offset))
步骤2:修改着色器添加偏移参数
shader_type canvas_item; uniform vec4 bg_color: hint_color; uniform vec2 scroll_offset; // 新增滚动偏移参数 float rand(vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123); } void fragment() { float size = 100.0; float prob = 0.9; // 给画布坐标加上滚动偏移 vec2 adjusted_coord = FRAGCOORD.xy + scroll_offset; vec2 pos = floor(1.0 / size * adjusted_coord); float color = 0.0; float starValue = rand(pos); if (starValue > prob) { vec2 center = size * pos + vec2(size, size) * 0.5; float t = 0.9 + 0.2 * sin(TIME * 8.0 + (starValue - prob) / (1.0 - prob) * 45.0); color = 1.0 - distance(adjusted_coord, center) / (0.5 * size); color = color * t / (abs(adjusted_coord.y - center.y)) * t / (abs(adjusted_coord.x - center.x)); } else if (rand(adjusted_coord / 20.0) > 0.996) { float r = rand(adjusted_coord); color = r * (0.85 * sin(TIME * (r * 5.0) + 720.0 * r) + 0.95); } COLOR = vec4(vec3(color),1.0) + bg_color; }
额外检查项
- 确认
ParallaxLayer的motion_scale设置为Vector2(1,1),该参数控制滚动偏移对图层的影响程度。 - 将
Stars节点的stretch_mode设置为Tile,确保星空滚动时能无缝重复显示。
内容的提问来源于stack exchange,提问作者MAGS94
相关产品推荐
相关产品推荐

