找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 187|回复: 3

[已解决] shader的完全透明问题

[复制链接]
发表于 2026-3-15 15:28:47 来自手机 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 aiRadioS 于 2026-3-17 16:51 编辑

混合模式是“normal”
gl_FragColor=vec4(color.rgb,alpha);
当alpha=0时,还是会有一点color的颜色残留在屏幕上,并不是完全透明。
要用if语句 当alpha=0时,color.rgb*=alpha,然后gl_FragColor=vec4(color.rgb,alpha)这样才是完全透明。
这是为什么,renpy里不是有alpha预乘吗,(color.rgb,alpha)会变成(color.rgb*alpha,alpha)传给遮罩函数,为什么还要用if语句把rgb设置成0才能完全透明


发表于 2026-3-17 15:52:09 | 显示全部楼层
这个问题跟OpenGL或者说GPU对半透明像素的处理方式有关。

楼主说的“renpy中的alpha预乘”是指,renpy将纹理中的rgb值传入内置shader之前,就会乘上alpha。而我们自己写shader,就是通过OpenGL控制GPU,从纹理中获取原始rgb值,不存在“alpha预乘”。

[RenPy] 纯文本查看 复制代码
vec4 color=texture2D(tex0,uv);


渲染结果与预期不符的原因,是背景图与使用“ring.pulse”shader的前景混合时,受到了前景半透明像素的“污染”。OpenGL在处理blend时,有两个独立计算过程,分别为rgb_equation和alpha_equation,对应颜色与不透明度的计算。虽然前景的alpha是0,但rgb不是0,最终渲染结果就可能不符合预期。这也是Ren'Py内部处理图片时做“alpha预乘”的重要原因之一。

建议的处理方法是自己的shader中也实现“alpha预乘”,片元着色器最后一步改为:
[RenPy] 纯文本查看 复制代码
gl_FragColor=color * alpha;

回复 支持 1 抱歉 0

使用道具 举报

发表于 2026-3-16 12:34:08 | 显示全部楼层
建议楼主把shader和引用该shader的transform代码发出来。
回复 支持 抱歉

使用道具 举报

 楼主| 发表于 2026-3-16 15:52:35 | 显示全部楼层
本帖最后由 aiRadioS 于 2026-3-16 17:47 编辑

这是shader代码
[RenPy] 纯文本查看 复制代码
    renpy.register_shader("ring.pulse",variables="""
        uniform float u_frequency; //波密度 控制波的数量
        uniform float u_time;
        uniform vec2 u_anchor; //圆环出现的锚点坐标
        uniform float u_width; //控制波宽 范围(-1,1)越小波越宽
        uniform float u_speed; //频率 控制波速
        uniform sampler2D tex0;
        uniform vec2 u_model_size; //使用的素材尺寸,为renpy内置变量
        varying vec2 v_tex_coord;
    """,vertex_200="""
        v_tex_coord=a_tex_coord;
    """,fragment_300="""
        vec2 uv=v_tex_coord; //因为v_tex_coord不能被修改 所以赋值给uv
        uv.x*=u_model_size.x/u_model_size.y; //因为图片不是正方形,归一化坐标对应的像素长度不一样,消除宽高差,防止圆环变成椭圆换 变换后u_anchor的坐标记得改呦 例如(1920,1080)的中心是(8/9,0.5)
        float dist=distance(uv,u_anchor); //计算各点到锚点的距离 
        float phase=u_frequency*dist-u_time*u_speed; //行波相位公式 phase=k*x-wt
        float wave=sin(phase); //震动到的位置 为1时是u_time时间点 位置对应波峰
        float alpha=step(u_width,wave); //step(edge,x) 当x<edge时,x均取0 当x>edge时,x取1 利用这个函数 把震动到(u_width,1)的点显示出来 其他点完全透明
        vec4 color=texture2D(tex0,uv); //采集纹理颜色赋值给color
        //if(alpha==0){
        //    gl_FragColor=vec4(0.0,0.0,0.0,0.0); //防止颜色残留
        //}else{
        //    gl_FragColor=vec4(color.rgb,alpha);        
        //}
        gl_FragColor=vec4(color.rgb,alpha);
    """)
transform ring_pulse:
    shader "ring.pulse"
    blend "normal" 
    u_frequency 100
    u_speed 15
    u_width 0.99
    u_anchor(8/9,0.5)
    pause 0.0 #和下面那一行一起防止卡顿
    repeat


效果:
IMG_8558.png

下面是去掉注释让alpha=0时,gl_FragColor=vec4(0.0,0.0,0.0,0.0);的代码
[RenPy] 纯文本查看 复制代码
    renpy.register_shader("ring.pulse",variables="""
        uniform float u_frequency; //波密度 控制波的数量
        uniform float u_time;
        uniform vec2 u_anchor; //圆环出现的锚点坐标
        uniform float u_width; //控制波宽 范围(-1,1)越小波越宽
        uniform float u_speed; //频率 控制波速
        uniform sampler2D tex0;
        uniform vec2 u_model_size; //使用的素材尺寸,为renpy内置变量
        varying vec2 v_tex_coord;
    """,vertex_200="""
        v_tex_coord=a_tex_coord;
    """,fragment_300="""
        vec2 uv=v_tex_coord; //因为v_tex_coord不能被修改 所以赋值给uv
        uv.x*=u_model_size.x/u_model_size.y; //因为图片不是正方形,归一化坐标对应的像素长度不一样,消除宽高差,防止圆环变成椭圆换 变换后u_anchor的坐标记得改呦 例如(1920,1080)的中心是(8/9,0.5)
        float dist=distance(uv,u_anchor); //计算各点到锚点的距离 
        float phase=u_frequency*dist-u_time*u_speed; //行波相位公式 phase=k*x-wt
        float wave=sin(phase); //震动到的位置 为1时是u_time时间点 位置对应波峰
        float alpha=step(u_width,wave); //step(edge,x) 当x<edge时,x均取0 当x>edge时,x取1 利用这个函数 把震动到(u_width,1)的点显示出来 其他点完全透明
        vec4 color=texture2D(tex0,uv); //采集纹理颜色赋值给color
        if(alpha==0){
            gl_FragColor=vec4(0.0,0.0,0.0,0.0); //防止颜色残留
        }else{
            gl_FragColor=vec4(color.rgb,alpha);        
        }
        //gl_FragColor=vec4(color.rgb,alpha);
    """)
transform ring_pulse:
    shader "ring.pulse"
    blend "normal" 
    u_frequency 100
    u_speed 15
    u_width 0.99
    u_anchor(8/9,0.5)
    pause 0.0 #和下面那一行一起防止卡顿
    repeat

效果:
IMG_8557.png
回复 支持 抱歉

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|RenPy中文空间 ( 苏ICP备17067825号 )

GMT+8, 2026-4-15 07:59 , Processed in 0.023717 second(s), 12 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表