|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 被诅咒的章鱼 于 2021-7-30 16:58 编辑
最近在研究shader,此贴为中间副产品。需Ren'Py 7.4.5以上版本。
此贴中使用的shader代码来源为
CloudFlight
我只是做了一点修改和移植到Ren'Py上。
首先是主体的shader代码(不要问我是怎么来的,问就是我也不懂):
[RenPy] 纯文本查看 复制代码 init python:
renpy.register_shader("shadertoy.cloudflight", variables="""
uniform float u_time;
uniform vec4 a_position;
varying vec2 v_tex_coord;
uniform sampler2D tex1;
attribute vec2 a_tex_coord;
""",fragment_functions="""
vec2 MatMultiplayVec(vec4 m, vec2 v)
{
return vec2(m.x * v.x + m.z * v.y, m.y * v.x + m.w * v.y);
}
vec4 r2(in float a)
{
float c = cos(a), s = sin(a); return vec4(c, s, -s, c);
}
float smax(float a, float b, float s)
{
float h = clamp(.5 + .5*(a - b)/s, 0., 1.);
return mix(b, a, h) + h*(1. - h)*s;
}
vec3 hash33(vec3 p)
{
float n = sin(dot(p, vec3(7, 157, 113)));
return fract(vec3(2097152, 262144, 32768)*n);
}
float n3D( in vec3 p)
{
const vec3 s = vec3(7, 157, 113);
vec3 ip = floor(p);
vec4 h = vec4(0., s.yz, s.y + s.z) + dot(ip, s);
p -= ip;
p = p*p*(3. - 2.*p);
h = mix(fract(sin(h)*43758.5453), fract(sin(h + s.x)*43758.5453), p.x);
h.xy = mix(h.xz, h.yw, p.y);
return mix(h.x, h.y, p.z);
}
vec2 path(in float z)
{
return vec2(sin(z*.075)*8., cos(z*.1)*.75*2.);
}
float map(vec3 p, float u_time)
{
vec3 t = vec3(1, .5, .25)*u_time;
float mainLayer = n3D(p*vec3(.4, 1, .4))*.66 + n3D(p*vec3(.4, 1, .4)*2.*.8)*.34 - .0;
float detailLayer = n3D(p*3. + t)*.57 + n3D(p*6.015 + t*2.)*.28 + n3D(p*12.01 + t*4.)*.15 - .0;
float clouds = mainLayer*.84 + detailLayer*.16;
#if (ARRANGEMENT != 3)
p.xy -= path(p.z);
#endif
#if (ARRANGEMENT == 0)
return smax(clouds, -length(p.xy*vec2(1./32., 1.)) + 1.1 + (clouds - .5), .5) + (clouds - .5);
#elif (ARRANGEMENT == 1)
return smax((clouds - .25)*2., -smax(abs(p.x) - .5, abs(p.y) - .5, 1.), 2.);
#elif (ARRANGEMENT == 2)
return smax(clouds - .075, -length(p.xy*vec2(1./32., 1.)) + 1.1 + (clouds - .5), .5) + (clouds - .5)*.35;
#else
return (clouds - .25)*2.;
#endif
}
""",
vertex_300="""
v_tex_coord = vec2(a_tex_coord.s, 1.0 - a_tex_coord.t);
""",
fragment_300="""
#define FAR 60.
#define ARRANGEMENT 0
vec2 uv = v_tex_coord;
vec3 ro = vec3(0, 0, u_time*4.);
vec3 lk = ro + vec3(0, 0, .25);
ro.xy += path(ro.z);
lk.xy += path(lk.z);
float FOV = 3.14159/2.75;
vec3 forward = normalize(lk-ro);
vec3 right = normalize(vec3(forward.z, 0., -forward.x ));
vec3 up = cross(forward, right);
vec3 rd = normalize(forward + FOV*uv.x*right + FOV*uv.y*up);
vec2 sw = path(lk.z);
//rd.xy *= r2(-sw.x/24.);
rd.xy = MatMultiplayVec(r2(-sw.x/24.), rd.xy);
//rd.yz *= r2(-sw.y/16.);
rd.yz = MatMultiplayVec(r2(-sw.x/16.), rd.yz);
vec3 rnd = hash33(rd.yzx + fract(u_time));
float lDen = 0., td = 0., w = 0.;
float d = 1., d2 = 0., t = dot(rnd, vec3(.333));
const float h = .5;
vec3 col = vec3(0), sp;
vec3 ld = normalize(vec3(-.2, .3, .8));
vec3 sky = mix(vec3(1, 1, .9), vec3(.19, .35, .56), rd.y*0.5 + 0.5);
vec3 fakeLd = normalize(vec3(-.2, .3, .8*1.5));
float sun = clamp(dot(fakeLd, rd), 0.0, 1.0);
sky += vec3(1, .3, .05)*pow(sun, 5.)*.25;
sky += vec3(1, .4, .05)*pow(sun, 8.)*.35;
sky += vec3(1, .9, .7)*pow(sun, 128.)*.5;
sky *= sqrt(sky);
vec3 cloudCol = mix(sky, vec3(1, .9, .8), .66);
for (int i=0; i<64; i++) {
sp = ro + rd*t; // Current ray position.
d = map(sp, u_time); // Closest distance to the surface... particle.
if(d<.001*(1. + t*.125) || td>1. || t>FAR) break;
w = d<h? (1. - td)*(h - d) : 0.;
td += w + 1./64.; // Looks cleaner, but a little washed out.
d2 = map(sp + ld*.1, u_time);
float diff = max(d2 - d, 0.)*20.;
col += w*max(d*d*(1. - d2)*3. - .05, 0.)*(diff*cloudCol*2. + vec3(.95, 1, 1.05))*2.5; // Darker, brooding.
col *= .98 + fract(rnd*289. + t*41.13)*.04;
t += max(d*.5, .05); //
}
col = max(col, 0.);
col *= mix(vec3(1), sky, .25);
col = mix(col, sky, smoothstep(0., .85, t/FAR));
col = mix(col, sky*sky*2., 1. - 1./(1.+ t*t*.001));
vec3 fCol = mix(pow(vec3(1.3, 1, 1)*col, vec3(1, 2, 10)), sky, .5);
col = mix(fCol, col, dot(cos(rd*6. +sin(rd.yzx*6.)), vec3(.333))*.1 + .9);
uv = v_tex_coord;
col = mix(pow(min(vec3(1.5, 1, 1).zyx*col, 1.), vec3(1, 3, 16)), col,
pow(16.*uv.x*uv.y*(1. - uv.x)*(1. - uv.y) , .125)*.5 + .5);
gl_FragColor = vec4(sqrt(min(col, 1.)), 1.0);
"""
)
需要说明的是:原链接中提供了两种 n3D 函数,默认是使用RGBA噪声纹理贴图的方式,注释了使用代码生成噪声的方式;由于Ren'Py中使用RGBA噪声纹理贴图会报错“全局纹理需要 #130以上版本才支持”,应该是Ren'Py使用的OpenGL版本比较低的原因,所以不得不改成使用代码生成噪声(对性能有影响)。
然后是在自定义可视组件中应用这个shader:
[RenPy] 纯文本查看 复制代码 init python:
class CloudFlight(renpy.Displayable):
def __init__(self, child, width, height, **kwargs):
super(CloudFlight, self).__init__(**kwargs)
self.child = renpy.displayable(child)
self.width = width
self.height = height
def render(self, width, height, st, at):
render = renpy.Render(self.width, self.height)
render.place(self.child)
render.add_shader("shadertoy.cloudflight")
render.add_uniform("u_time", st)
renpy.redraw(self, 0)
return render
script.rpy中使用图像:
[RenPy] 纯文本查看 复制代码 image cloudflight = CloudFlight("texture", width = 1280, height = 720)
label main_menu:
return
label start:
show cloudflight
pause
注意这里使用一张名为“texture”的图片,图片内容是什么不重要,尺寸需要为1280×720(或者根据需求修改)。
没有什么参数可以调。如果要修改的话,可以试试shader中两个预编译的 FAR 和 ARRANGEMENT 。
|
|