找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 554|回复: 3

[已解决] 可以将shader效果应用在整个游戏画面(layer)上吗?

[复制链接]
发表于 2023-11-27 17:10:02 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 birctreel 于 2023-11-28 10:49 编辑

下午好!我最近在学习shader功能,研究过程中有一些问题,想问问有没有大佬知道如何实现
目标:给游戏画面附上一层老电视那种RGB色相分离的CRT效果
进展:可以用Shader给单图附上Shader效果,但不知道怎么应用在整个Layer

详细研究过程:
在学习了章鱼大佬在知乎上的帖子和在论坛里关于shader的研究帖之后,我想到的方法是修改Shader,将其编辑为Transform,然后应用在Layer上。
https://zhuanlan.zhihu.com/p/348922729

https://zhuanlan.zhihu.com/p/349467983

学习的知乎帖

https://www.shadertoy.com/view/WdjfDy
https://www.shadertoy.com/view/wllBDM
以上是我参考的Shader站代码,下面是我据此修改的Renpy可使用的Shader代码:
[RenPy] 纯文本查看 复制代码
init python:
    renpy.register_shader("shadertoy.test", variables="""
        uniform float u_time;
        uniform vec2 u_model_size;
        uniform vec2 res0;
        uniform sampler2D tex0;
        uniform sampler2D tex1;
    """,fragment_functions="""
        vec2 curve(vec2 uv)
        {
                uv = (uv - 0.5) * 2.0;
                uv *= 1.1;
                uv.x *= 1.0 + pow((abs(uv.y) / 5.0), 2.0);
                uv.y *= 1.0 + pow((abs(uv.x) / 4.0), 2.0);
                uv  = (uv / 2.0) + 0.5;
                uv =  uv *0.92 + 0.04;
                return uv;
        }
    """,
        vertex_300="""
        //v_tex_coord = a_tex_coord;
    """,

        fragment_300="""
        //Curve
        vec2 uv = gl_FragCoord.xy / res0.xy;
            uv = curve( uv );
        vec3 col;

        // Chromatic
        col.r = texture2D(tex0,vec2(uv.x+0.003,(1-uv.y))).x;
        col.g = texture2D(tex0,vec2(uv.x+0.000,(1-uv.y))).y;
        col.b = texture2D(tex0,vec2(uv.x-0.003,(1-uv.y))).z;

        col *= step(0.0, uv.x) * step(0.0, uv.y);
        col *= 1.0 - step(1.0, uv.x) * 1.0 - step(1.0, uv.y);

        col *= 0.5 + 0.5*16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y);
        col *= vec3(0.95,1.05,0.95);

        //col *= 0.9+0.1*sin(10.0*u_time+uv.y*1000.0);

        col *= 0.99+0.01*sin(500.0*u_time);

        float comp = smoothstep( 0.2, 0.7, sin(u_time) );
        gl_FragColor = vec4(col,1.0);
    """)

init python:
    renpy.register_shader("test44.softlight", variables="""
        uniform sampler2D tex0;
        uniform sampler2D tex1;
        attribute vec2 a_tex_coord;
        varying vec2 v_tex_coord;
    """, vertex_300="""
        v_tex_coord = a_tex_coord;
    """, fragment_300="""
        vec4 base = texture2D(tex0, v_tex_coord);
        vec4 blend = texture2D(tex1, v_tex_coord);
        vec4 ctemp = base * blend;
        gl_FragColor = mix(base, ctemp+(base*(1-((1-base)*(1-blend))-ctemp)), 0.5);
    """)



然后,再把这个注册好的Shader制作成Transform效果:
[RenPy] 纯文本查看 复制代码
transform shadercrt:
    shader "shadertoy.test"


最后,可以应用于游戏的图片(scene or image)上:
[RenPy] 纯文本查看 复制代码
    scene overlay at shadercrt





但是,这个Transform存在一些问题:
1.只能应用在图像上,并不能整体应用在图层或者整个游戏画面上
2.这个效果应用于立绘等有透明背景的图片上时,透明背景会变成纯黑,无法使用

在查阅renpy文档中,发现有layer应用整个transform的代码:
https://doc.renpy.cn/zh-CN/displaying_images.html#camerashow-layer

但如果我使用
[RenPy] 纯文本查看 复制代码
camera master at shadercrt

或者
[RenPy] 纯文本查看 复制代码
show layer master at shadercrt

都会报错:
[RenPy] 纯文本查看 复制代码
  File "renpy/common/000window.rpy", line 114, in _window_auto_callback
    _window_show(auto=True)
  File "renpy/common/000window.rpy", line 69, in _window_show
    renpy.with_statement(trans)
Exception: Shader ('renpy.geometry', 'renpy.solid', 'shadertoy.test') has not been given uniform tex0.



我想到的第二种方案是利用pygame调用shader。这里我找到了一个pygame写的应用shader的工程:
https://github.com/JingShing/ModernGL-Shader-with-pygame

我不太懂python和pygame,但研究了一下代码后发现,这个python代码中定义的画面效果是crt_shader.
那么我要怎样才能把这个pygame中的crt_shader应用在整个renpy游戏界面or图层上呢?

不知道有没有办法可以实现我想要的整体应用效果,如果真的不行,也只能死了这条心了……_(:3√ L)_



效果图

效果图

应用在立绘时有黑边

应用在立绘时有黑边
发表于 2023-11-28 09:35:27 | 显示全部楼层
这是个有趣且有些复杂的问题,属于游戏制作Post-Process(后处理)的范畴。最近我没有空仔细研究,等过一段时间可能有空……

如果楼主想尝试自己解决的话,大概的方向是:
1.透明背景变黑的问题,跟着色器优先级有关。Ren'Py处理透明的着色器优先级比较低,为500。https://doc.renpy.cn/zh-CN/model.html#renpy-alpha-priority-500试试把自定义着色器的优先级数值改到比500大。
2.对整个图层(layer)应用transform的报错,可能楼主shader代码中纹理tex0、tex1的定义方式与图层的内部处理机制有冲突。暂时没有明确的解决思路,也许可以尝试把整个图层绘制到单个纹理上再做后处理(post-process)。
回复 支持 抱歉

使用道具 举报

 楼主| 发表于 2023-11-28 10:49:08 | 显示全部楼层
被诅咒的章鱼 发表于 2023-11-28 09:35
这是个有趣且有些复杂的问题,属于游戏制作Post-Process(后处理)的范畴。最近我没有空仔细研究,等过一段时 ...

非常感谢回复!
我在lemmasoft上发了同样的帖子,然后得到了一个解决思路:
https://doc.renpy.cn/zh-CN/displayables.html#Layer
将图层整体定义为image,然后再将Shader写成Transform应用在这个image上。
以下是我目前的进展:

1.关于shader代码导致图像倒置的问题,排查一圈后我发现问题出在:
[RenPy] 纯文本查看 复制代码
    vec2 uv = fragCoord.xy / iResolution.xy;//这句是Shader站上的原始语法,几乎可以在所有Shader中找到

这句上。通常在renpy中,我将它转换成了
[RenPy] 纯文本查看 复制代码
    vec2 uv = gl_FragCoord.xy / res0.xy;

而这句话会导致画面倒置。解决方式是删掉这句话,将uv这个函数改为v_vex_Coord(记得提前定义 v_tex_coord = a_tex_coord)即可

2.关于Shader导致立绘周围变黑的问题
在您提醒之后,我排查了一下shader代码,发现是关于渲染tex0的变量col,我定义成了3维对象(vec3),即其RGB色系,导致无法识别a(透明度)。
修改方案是将col定义为vec4,且加上定义col.a的相关语句:
[RenPy] 纯文本查看 复制代码
        vec4 col;
        col.r = texture2D(tex0, crt_uv + vec2(0.002, 0)).r;
        col.g = texture2D(tex0, crt_uv).g;
        col.b = texture2D(tex0, crt_uv + vec2(0., -0.002)).b;
        col.a = texture2D(tex0, crt_uv).a;
        col *= step(0.0, v_tex_coord.x) * step(0.0, v_tex_coord.y);
        col *= 1.0 - step(1.0, v_tex_coord.x) * 1.0 - step(1.0,v_tex_coord.y);
        col *= vec4(0.95,1.02,0.95,1.0);
        col *= 0.99+0.01*sin(1200.0*u_time);
        gl_FragColor = col;
    """)


之后,在script中利用定义Layer为image的方法:
[RenPy] 纯文本查看 复制代码
define config.detached_layers += [ "crt" ]
image tv = Layer("crt",)

label start:
    show tv at shadercrt#显示含shader效果的TV图层
    scene checkmate onlayer crt with dissolve:
            zoom 2.0 align(.0,.0)
            linear 60 xalign 1.0            
    show eileen happy onlayer crt 



此时,eileen happy 和背景的checkmate都会附上shader效果了!

*我目前还在丰富这个画面shader的功能,完成了的话再分享出来。
谢谢大佬指点!
回复 支持 抱歉

使用道具 举报

发表于 2023-11-29 08:37:47 | 显示全部楼层
楼主真棒~(我也没帮上什么忙)
回复 支持 抱歉

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-22 12:05 , Processed in 0.125477 second(s), 27 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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