You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Godot的GDScript中读取Shader变量的值?

在Godot中读取Shader变量及灯光效果排查方案

问题说明

我正在学习Godot的Shader开发,遇到两个问题:

  1. 没法从挂载在同一节点的GDScript里读取Shader中varying float value变量,试过自定义Viewport和ComputeBuffers都没成功。
  2. 做类灯光效果时,想让像素透明度随鼠标距离增加而降低,但效果不对,想通过GDScript打印Shader里的dist变量排查问题。

给出的两份Shader代码:
测试用Shader:

shader_type canvas_item;

varying float value;

void fragment()
{
    value = some_data;
}

灯光效果Shader:

shader_type canvas_item;

uniform vec2 mousePos; // 由另一段GDScript赋值
uniform float lightRadius = 10.0;

void fragment() {
    // 对材质可见的每个像素调用
    //COLOR = vec4(sin(UV.x), cos(UV.y), 0.0, 1.0);
    COLOR = texture(TEXTURE, UV);
    float dist = distance(mousePos, FRAGCOORD.xy);
    COLOR.a = dist;
}

解决方案

一、读取Shader变量的可行方法

首先明确:varying是GPU渲染管线里的临时传递变量,没法直接从CPU端的GDScript读取。要获取Shader计算结果,有两种实用方案:

  1. RenderTexture读取像素数据(适合调试)

    • 新建一个Viewport,把要渲染的节点设为它的子节点,开启render_target_enabled,设置好分辨率。
    • 在GDScript里通过viewport.get_texture().get_data()拿到Image对象,用get_pixel(x,y)读取对应像素的颜色值——如果把Shader计算的变量存到颜色通道里,就能间接拿到数据。
    • 注意:频繁读取会有性能损耗,只适合调试用。
  2. 用Storage Buffer传递数据(适合高频读取)

    • 在Shader里声明存储缓冲区,把计算结果写入:
      shader_type canvas_item;
      storage_buffer DataBuffer {
          float value;
      } data;
      
      void fragment() {
          data.value = some_data;
      }
      
    • 在GDScript里创建对应Buffer,绑定到ShaderMaterial后读取:
      var buffer = StorageBuffer.new()
      buffer.data = PackedFloat32Array([0.0])
      var material = $Sprite.material_override as ShaderMaterial
      material.set_storage_buffer("DataBuffer", buffer)
      # 读取数据时
      buffer.update()
      var value = buffer.data[0]
      print(value)
      
    • 注意:要确保GPU写完数据后CPU再读取,避免同步问题。

二、灯光效果的调试与修复

你的灯光Shader有明显问题:COLOR.a = dist会让透明度直接等于距离值,但透明度范围是0-1,距离值远大于1的话,透明度会被强制设为1,完全看不到衰减效果。

调试dist变量的方法

把dist映射到颜色通道,方便读取或直观查看:

void fragment() {
    COLOR = texture(TEXTURE, UV);
    float dist = distance(mousePos, FRAGCOORD.xy);
    // 把距离值映射到0-1范围,存到红色通道
    float normalized_dist = clamp(dist / lightRadius, 0.0, 1.0);
    COLOR.r = normalized_dist;
    COLOR.a = 1.0 - normalized_dist; // 先做正确的透明度衰减逻辑
}

然后在GDScript里读取对应像素的红色通道值:

func _process(delta):
    var viewport = $Viewport
    var image = viewport.get_texture().get_data()
    image.lock()
    // 转换鼠标坐标到Viewport本地
    var local_pos = viewport.get_local_mouse_position()
    var pixel_color = image.get_pixel(round(local_pos.x), round(local_pos.y))
    print("归一化距离值: ", pixel_color.r)
    image.unlock()

修复灯光效果

正确的逻辑是:距离小于lightRadius时,透明度从1降到0;超过半径后透明度为0。修改Shader:

shader_type canvas_item;

uniform vec2 mousePos;
uniform float lightRadius = 100.0; // 调大半径,避免范围太小
uniform float edgeSmooth = 10.0; // 让边缘过渡更自然

void fragment() {
    COLOR = texture(TEXTURE, UV);
    float dist = distance(mousePos, FRAGCOORD.xy);
    // 计算衰减值:距离越近,值越接近1;超过半径后为0
    float alpha = smoothstep(lightRadius, lightRadius - edgeSmooth, dist);
    COLOR.a *= alpha; // 保留原图的透明信息
}

内容的提问来源于stack exchange,提问作者lemmgua

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 08:18:28