RenPy中文空间

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 854|回复: 2

[原创] 使用shader绘制点线网格

[复制链接]
发表于 2021-7-27 10:19:07 | 显示全部楼层 |阅读模式

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

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

x
最近在研究shader,此贴为中间副产品。需Ren'Py 7.4.5以上版本。

此贴中使用的shader代码来源为
ShaderToy-TheUniverseWithin

我只是做了一点修改并移植到Ren'Py上。

首先是主体的shader代码(不要问我是怎么来的,问就是我也不懂):
[RenPy] 纯文本查看 复制代码
init python:

    renpy.register_shader("shadertoy.Universewithin", variables="""
        uniform float u_time;
        uniform vec2 u_model_size
        uniform float u_glow;
        uniform vec2 u_mouse_pos;
    """,fragment_functions="""
        float N21(vec2 p)
        {
            vec3 a = fract(vec3(p.xyx) * vec3(213.897, 653.453, 253.098));
            a += dot(a, a.yzx + 79.76);
            return fract((a.x + a.y) * a.z);
        }
        vec2 GetPos(vec2 id, vec2 offs, float t)
        {
            float n = N21(id+offs);
            float n1 = fract(n*10.);
            float n2 = fract(n*100.);
            float a = t+n;
            return offs + vec2(sin(a*n1), cos(a*n2)) * .4;
        }

        float GetT(vec2 ro, vec2 rd, vec2 p)
        {
            return dot(p-ro, rd); 
        }

        float LineDist(vec3 a, vec3 b, vec3 p)
        {
            return length(cross(b-a, p-a)) / length(p-a);
        }

        float df_line(in vec2 a, in vec2 b, in vec2 p)
        {
            vec2 pa = p - a, ba = b - a;
            float h = clamp(dot(pa,ba) / dot(ba,ba), 0., 1.);	
            return length(pa - ba * h);
        }

        float line(vec2 a, vec2 b, vec2 uv)
        {
            float r1 = .04;
            float r2 = .01;
            
            float d = df_line(a, b, uv);
            float d2 = length(a-b);
            float fade = smoothstep(1.5, .5, d2);
            
            fade += smoothstep(.05, .02, abs(d2-.75));
            return smoothstep(r1, r2, d) * fade;
        }

        float NetLayer(vec2 st, float n, float t)
        {
            vec2 id = floor(st)+n;

            st = fract(st)-.5;
           
            vec2 p[9];
            int i=0;
            for(float y=-1.; y<=1.; y++)
            {
                for(float x=-1.; x<=1.; x++) {
                    p[i++] = GetPos(id, vec2(x,y), t);
                }
            }
            
            float m = 0.;
            float sparkle = 0.;
            
            for(int i=0; i<9; i++)
            {
                m += line(p[4], p[i], st);

                float d = length(st-p[i]);

                float s = (.005/(d*d));
                s *= smoothstep(1., .7, d);
                float pulse = sin((fract(p[i].x) + fract(p[i].y)+t) * 5.) * .4 + .6;
                pulse = pow(pulse, 20.);

                s *= pulse;
                sparkle += s;
            }
            
            m += line(p[1], p[3], st);
            m += line(p[1], p[5], st);
            m += line(p[7], p[5], st);
            m += line(p[7], p[3], st);
            
            float sPhase = (sin(t+n) + sin(t*.1)) * .25+ .5;
            sPhase += pow(sin(t*.1)*.5 + .5, 50.) * 5.;
            m += sparkle * sPhase;
            
            return m;
        }
    """,
        vertex_300="""
        v_tex_coord = a_tex_coord;
    """,
    
        fragment_300="""
        #define NUM_LAYERS 4.
        //#define SIMPLE
        vec2 uv = (gl_FragCoord.xy - u_model_size.xy*.5) / u_model_size.y;
        vec2 M = u_mouse_pos.xy / u_model_size.xy - .5;
        float t = u_time * .1;
        float s = sin(t);
        float c = cos(t);
        mat2 rot = mat2(c, -s, s, c);
        vec2 st = uv * rot;
        M *= rot*2.;

        float m = 0.;
        for(float i=0.; i<1.; i+=1./NUM_LAYERS)
        {
            float z = fract(t+i);
            float size = mix(15., 1., z);
            float fade = smoothstep(0., .6, z) * smoothstep(1., .8, z);
            
            m += fade * NetLayer(st*size-M*z, i, u_time);
        }

        float glow = u_glow;
       
        vec3 baseCol = vec3(s, cos(t*.4), -sin(t*.24)) * .4 + .6;
        vec3 col = baseCol * m;
        col += baseCol * glow;
        
        #ifdef SIMPLE
        uv *= 10.;
        col = vec3(1)*NetLayer(uv, 0., u_time);
        uv = fract(uv);
        #else
        col *= 1.-dot(uv,uv);
        t = mod(u_time, 230.);
        col *= smoothstep(0., 20., t) * smoothstep(224., 200., t);
        #endif
        
        gl_FragColor = vec4(col,1);

    """)


然后在自定义可视组件中应用这个shader:
[RenPy] 纯文本查看 复制代码
init python:

    class Universewithin(renpy.Displayable):

        def __init__(self, child, width, height, glow=0.2, **kwargs):
            super(Universewithin, self).__init__(**kwargs)
            
            self.child = renpy.displayable(child)
            self.width = width
            self.height = height
            self.glow = glow
            self.mouse_pos = (0, 0)

        def render(self, width, height, st, at):
            render = renpy.Render(self.width, self.height)
            render.place(self.child)
            render.add_shader("shadertoy.Universewithin")
            render.add_uniform("u_time", st)
            render.add_uniform("u_model_size", (self.width, self.height))
            render.add_uniform("u_glow", self.glow)
            render.add_uniform("u_mouse_pos", self.mouse_pos)
            renpy.redraw(self, 0)
            return render

        def event(self, ev, x, y, st):
            self.mouse_pos = (x, self.height - y)


script.rpy中使用图像:
[RenPy] 纯文本查看 复制代码
image universewithin = Universewithin("texture", width = 1280, height = 720)

label main_menu:
    return


label start:

    show universewithin
    
    pause


整体效果类似于AE中的Plexus粒子插件。
shader中有一个被注释掉的预定义项 SIMPLE ,取消注释后就是简化版,大概能节省一些GPU资源。
CDD中添加了对鼠标事件的处理,画面会模拟镜头移动效果。

发表于 2021-12-23 22:38:56 | 显示全部楼层
这个效果好棒啊!
回复 支持 反对

使用道具 举报

发表于 2022-1-18 18:29:36 | 显示全部楼层
感谢大佬
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2022-6-26 06:13 , Processed in 0.025009 second(s), 12 queries , File On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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