![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4f6efb2189904555adccfb8d596a2a0b.gif#pic_center在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
用deepseek生成的
首先得有个能运行的shader作为模版

这是提示词

// Effect Syntax Guide: https://docs.cocos.com/creator/manual/zh/shader/index.html

// Copyright © 2017-2020 Xiamen Yaji Software Co., Ltd.
// Copyright © 2017-2020 Xiamen Yaji Software Co., Ltd.
// Copyright © 2017-2020 Xiamen Yaji Software Co., Ltd.
// Copyright © 2017-2020 Xiamen Yaji Software Co., Ltd.
// Effect Syntax Guide: https://docs.cocos.com/creator/manual/zh/shader/index.html

// Copyright © 2017-2020 Xiamen Yaji Software Co., Ltd.
// Effect Syntax Guide: https://docs.cocos.com/creator/manual/zh/shader/index.html

// Copyright © 2017-2020 Xiamen Yaji Software Co., Ltd.
// 最简兼容版光柱Shader

/** glow-simple.effect **/

CCEffect %{
techniques:

  • name: glow
    passes:
    • vert: vs:vert
      frag: fs:frag
      blendState:
      targets:
      • blend: true
        blendSrc: src_alpha
        blendDst: one_minus_src_alpha
        depthStencilState:
        depthTest: false
        depthWrite: false
        rasterizerState:
        cullMode: none
        properties:
        glowColor: { value: [1.0, 0.8, 0.3, 1.0], editor: { type: color } }
        moveSpeed: { value: 1.0, editor: { range: [0.1, 5.0, 0.1] } }
        beamWidth: { value: 0.1, editor: { range: [0.01, 0.5, 0.01] } }
        curveIntensity: { value: 0.2, editor: { range: [0.0, 1.0, 0.01] } }
        noiseTexture: { value: white, editor: { type: texture } }
        noiseScale: { value: 5.0, editor: { range: [0.1, 20.0, 0.1] } }
        noiseSpeed: { value: 0.5, editor: { range: [0.0, 2.0, 0.01] } }
        hexSize: { value: 0.8, editor: { range: [0.2, 1.0, 0.01] } }
        hexFeather: { value: 0.05, editor: { range: [0.0, 0.3, 0.01] } }
        }%

CCProgram vs %{
precision highp float;
#include
#if USE_LOCAL
#include <builtin/uniforms/cc-local>
#endif
in vec3 a_position;
in vec2 a_texCoord;
out vec2 uv;
#if USE_LOCAL
in vec4 a_color;
out vec4 v_color;
#endif

vec4 vert() {
vec4 pos = vec4(a_position, 1);
#if USE_LOCAL
pos = cc_matWorld * pos;
v_color = a_color;
#endif
pos = cc_matViewProj * pos;
uv = a_texCoord;
return pos;
}
}%

CCProgram fs %{
precision highp float;
#include
#include
in vec2 uv;
uniform sampler2D noiseTexture;

uniform UBO {
vec4 glowColor;
float moveSpeed;
float beamWidth;
float curveIntensity;
float noiseScale;
float noiseSpeed;
float hexSize;
float hexFeather;
};

float hexDistance(vec2 p) {
vec2 q = abs§;
float d1 = q.x * 0.866075 + q.y * 0.5;
return max(d1, q.y) - 0.5;
}

vec4 frag() {
vec4 o = texture(cc_spriteTexture, uv);
vec4 original = o;

vec2 p = (uv - 0.5) / hexSize;
float d = hexDistance(p);
float mask = 1.0 - smoothstep(0.0, hexFeather, d);
if(original.a > 0.0) {
  o.a = original.a * mask;
}

return o;

}
}%

这是cocos shader 请你让让光效按照原图的纹理进行流动,原理就是获取原图的明暗,原图亮的地方让光效向某个方向偏移,暗的地方向反方向偏移

**

请解释下原理 啥叫亮的推动 为啥现在有立体的效果了

**
我们需要解释“亮的地方让光效向某个方向偏移”的原理,以及为什么这样会产生立体感。

首先,回顾用户最初的需求:“让光效按照原图的明暗,原图亮的地方让光效向某个方向偏移,暗的地方向反方向偏移”。在两个 shader 中,我们实现的方式都是:

提取原图像素的亮度(luminance),常用公式 dot(rgb, vec3(0.299, 0.587, 0.114))。

计算一个偏移量 (lum - 0.5) * 强度因子。这意味着当亮度大于0.5时,偏移为正;小于0.5时,偏移为负。

将这个偏移量加到用于生成光效的坐标上。在第一个 shader 中,光效是沿 x 方向移动的光束,偏移加在 uv.x 上(phase = uv.x + brightnessOffset + time * moveSpeed);在第二个 shader 中,彩色光栅的输入相位是 (uv.x + brightnessOffset) * rasterScale + …。

这样做的结果是:原本均匀流动的光束或条纹,在遇到图像中较亮的区域时,会表现出提前到达(因为偏移为正,相当于该点的光束相位更大,也就是光束来得更早);在较暗的区域,光束会滞后。这就在视觉上扭曲了光效的直线形状,让它跟随底下图像的明暗变化而“弯曲”。

现在解释为什么会有立体效果:

人脑通过阴影、高光等明暗信息感知物体的三维形状。一张卡牌或图像上的角色、物体本身已经通过光影表现出了立体感(比如角色的亮面、暗面、高光)。

当一束光或条纹扫过这个平面图像时,如果光的形状随着图像的明暗发生相应的弯曲,就会产生一种错觉:这束光不是照在一个平面上,而是照在一个有高低起伏的表面上。即,亮的地方像是突出来的,把光束“推”向前(提早到达),暗的地方像是凹进去的,把光束“拉”向后(延迟)。这符合光学中光线在凸起表面会提前到达,在凹陷处会延迟的直觉。

这种现象类似于法线贴图或视差映射的原理,但实际上我们只是对屏幕坐标进行了一个简单的亮度驱动的扰动。由于图像本身已经包含了立体信息(亮暗),扰动光效使得光效与这个立体信息同步,加强了立体感。可能还因为彩色光栅和扫描线本身具有色散效果,更增强了金属或全息贴纸般的质感。

需要注意的是,偏移的方向选择也很重要:我们选择沿光效流动方向(多为水平方向)偏移,这样流动感仍然保持。如果改为垂直方向,效果会不同。目前这种沿流动方向的偏移能最大化地暗示表面的凹凸。

回答时应该用通俗的语言解释,避免过于技术化,但又要阐明原理。可以向用户说明:

亮度提取:得到每个像素的明暗程度。

偏移映射:亮处加正偏移(向右推),暗处加负偏移(向左拉)。

光效变形:光束相位被扭曲,不再是平行直线,而是随着纹理起伏。

立体感来源:图像本身的明暗已经暗示了立体形状,光效的扭曲与之一致,大脑就会认为光是在一个起伏的表面上滑过。

还要强调这本质上是一种视觉错觉,但效果强烈。可以比喻为“光在凹凸不平的金属表面流动”。

因此,我的回答结构可以如下:

简要概述所做的事情。

分步解释原理:亮度提取 -> 偏移计算 -> 作用到光效坐标。

解释为什么产生立体感:与图像已有的立体信息匹配,欺骗大脑。

可能补充提及 shader 中具体的代码行位置。

我将以亲切易懂的语气回答,并确保没有代码片段(除非用户要求)。

这个效果的核心原理其实很简单:我们让扫过的光线“读”懂了底下图像的明暗,并跟着这些明暗起伏变形。亮的地方让光“跑得快一点”提前到达,暗的地方让光“走慢一点”滞后出现,于是原本平平直直的光束(或彩色条纹)就变得弯弯扭扭,仿佛贴在了一个有凹凸的表面上。

下面拆开讲一下到底是怎么做到的,以及你为什么看到了立体感。

  1. 先给图像“测个光”
    在 shader 里,我们做的第一件事就是计算出当前这个像素到底有多亮:

text
float lum = dot(original.rgb, vec3(0.299, 0.587, 0.114));
这行代码用了一个心理学亮度公式,把人眼对红绿蓝不同敏感度的权重乘进去,得到一个 0~1 的亮度值 lum。
越接近 1 就越亮(比如高光、白色区域),越接近 0 就越暗(比如黑色阴影)。

  1. 把亮度变成“推拉”的偏移量
    接着,我们把亮度映射成一个位置偏移:

text
float brightnessOffset = (lum - 0.5) * 强度因子;
当 lum > 0.5(偏亮),brightnessOffset 为正——向正方向(右)推。

当 lum < 0.5(偏暗),brightnessOffset 为负——向反方向(左)拉。

如果亮度刚好是中间灰 0.5,偏移为 0,光不动。

这个“强度因子”通常就是你面板上的 rasterStrength 或 curveIntensity,控制扭曲的剧烈程度。

  1. 把偏移“喂”给流动的光
    最关键的一步在这里。
    原本光效(光束或彩虹条纹)是用一个随着时间和坐标变化的函数生成的,比如:

text
float rasterValue = uv.x * rasterScale + uv.y * 0.618 + time;
现在我们把亮度偏移加到空间坐标上:

text
float rasterValue = (uv.x + brightnessOffset) * rasterScale + uv.y * 0.618 + time;
这会带来什么结果呢?

对一个亮像素,brightnessOffset 是正的,就相当于把这个像素的光效“相位”往前拨了——本来应该等到下一毫秒才扫到这里的彩虹条纹,现在提前出现了。视觉上就是条纹在这个地方向右凸起、向前推移。

对一个暗像素,偏移为负,相位被推后——条纹来得更晚,看起来就像向左凹陷、落后了。

于是,原本笔直的光束/条纹,就变得像被底下的图像捏过一样,随着图像的明暗起伏而扭曲。

  1. 为什么这样就会有立体感?
    因为你的原始图像本身就已经包含了立体信息:角色脸上的高光、衣服的褶皱阴影、金属边框的反光……这些明暗关系本来就是大脑用来判断“哪里凸、哪里凹”的线索。

现在,我们又加了一条“会读明暗”的光。

光在凸起的高亮部分加速向前冲,在凹陷的暗部减速落后,恰好模拟了光线射到真实凹凸表面时的行为——在真·3D 表面,凸起的地方光线会先到达,凹陷的地方光线会后到达。

大脑接收到这两个完全一致的信号:

图像自己的明暗 →

光效随之同步的扭曲 →

就会自动把它们“融合”,产生一种强烈错觉:哦,这束光不是照在一张平平的卡片上,而是照在一个有高低起伏的立体表面上。

所以你会感觉卡面好像变立体了,光好像真的在沿着角色、边框的轮廓“流淌”,特别有物理质感。如果配合彩虹色衍射和扫描线,甚至会有全息贴纸、烫金工艺那种实体凹凸的观感。

一句话总结:
我们用原始图像的亮度作为“地形高度”,让扫过的光束顺着这个地形上下起伏,你的眼睛就把这当成真的立体凹凸了。

// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
// Effect Syntax Guide: https://docs.cocos.com/creator/manual/zh/shader/index.html

// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
// Effect Syntax Guide: https://docs.cocos.com/creator/manual/zh/shader/index.html

// Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
// 最简兼容版光柱Shader

/** glow-simple.effect **/

CCEffect %{
  techniques:
  - name: glow
    passes:
    - vert: vs:vert
      frag: fs:frag
      blendState:
        targets:
        - blend: true
          blendSrc: src_alpha
          blendDst: one_minus_src_alpha
      depthStencilState:      
          depthTest: false  
          depthWrite: false 
      rasterizerState:
        cullMode: none
      properties:
        glowColor:  { value: [1.0, 0.8, 0.3, 1.0], editor: { type: color } }
        moveSpeed: { value: 1.0, editor: { range: [0.1, 5.0, 0.1] } }
        beamWidth: { value: 0.1, editor: { range: [0.01, 0.5, 0.01] } }
        curveIntensity: { value: 0.2, editor: { range: [0.0, 1.0, 0.01] } }
        noiseTexture: { value: white, editor: { type: texture } } 
        noiseScale: { value: 5.0, editor: { range: [0.1, 20.0, 0.1] } } 
        noiseSpeed: { value: 0.5, editor: { range: [0.0, 2.0, 0.01] } } 
}%

CCProgram vs %{
  precision highp float;
  #include <cc-global>
  #if USE_LOCAL
    #include <builtin/uniforms/cc-local>
  #endif
  in vec3 a_position;
  in vec2 a_texCoord;
  out vec2 uv;
  #if USE_LOCAL
    in vec4 a_color;
    out vec4 v_color;
  #endif

  vec4 vert() {
    vec4 pos = vec4(a_position, 1);
    #if USE_LOCAL
      pos = cc_matWorld * pos;
      v_color = a_color;
    #endif
    pos = cc_matViewProj * pos;
    uv = a_texCoord;
    return pos;
  }
}%

CCProgram fs %{
  precision highp float;
  #include <sprite-texture>
  #include <cc-global>
 
  in vec2 uv;
  #if USE_LOCAL
    in vec4 v_color;
  #endif

  uniform sampler2D noiseTexture;

  uniform UBO {
    vec4 glowColor;
    float moveSpeed;
    float beamWidth;
    float curveIntensity;
    float noiseScale;
    float noiseSpeed;
  };

  vec4 frag() {
    vec4 o = texture(cc_spriteTexture, uv);
    vec4 original = o;
    if (original.a < 0.05) discard;

    // 1. 提取原图亮度
    float lum = dot(original.rgb, vec3(0.299, 0.587, 0.114));

    // 2. 亮度驱动 x 方向偏移:亮处为正(向右),暗处为负(向左)
    float brightnessOffset = (lum - 0.5) * curveIntensity * 2.0;

    // 3. 光束基础移动位置(时间驱动)
    float time = cc_time.x * moveSpeed;
    float beamPosX = mod(time, 1.5) - 0.25;

    // 4. y 方向沿用噪声偏移
    vec2 noiseUV = vec2(beamPosX * noiseScale, cc_time.x * noiseSpeed);
    float noiseVal = texture(noiseTexture, noiseUV).r;
    float curveOffset = (noiseVal - 0.5) * 2.0 * curveIntensity;
    float beamPosY = 0.5 ;

    // 5. 关键:计算当前像素到光点的距离时,x 坐标加上亮度偏移
    float dist = distance(vec2(uv.x + brightnessOffset, uv.y),
                          vec2(beamPosX, beamPosY));

    // 6. 如果像素在光束范围内,叠加光效
    if (dist < beamWidth) {
      float strength = 1.0 - dist / beamWidth;
      vec3 glowEffect = mix(vec3(1.0), glowColor.rgb, dist / beamWidth);
      o.rgb = original.rgb + glowEffect * strength;
      o.a = max(original.a, strength);
    }

    return o;
  }
}%







Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐