当前位置: 首页 > news >正文

[Godot4] 水底气泡的 gdshader

水底气泡的 gdshader

来自 shadertoy 的代码

在这里,我添加了 x 方向和 y 方向上的 uv 位移

但是还是感觉太弱智

shader_type canvas_item;
// Created by greenbird10
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0uniform float bubble_size = 0.1;   // Size of the bubbles
uniform float upward_speed = 0.2;  // Speed at which bubbles rise
uniform float movable_x = 0.0;
uniform float movable_y = 0.0;float hash(vec2 p) {return 0.5*(sin(dot(p, vec2(271.319, 413.975)) + 1217.13*p.x*p.y)) + 0.5;
}float noise(vec2 p) {vec2 w = fract(p);w = w * w * (3.0 - 2.0*w);p = floor(p);return mix(mix(hash(p+vec2(0,0)), hash(p+vec2(1,0)), w.x),mix(hash(p+vec2(0,1)), hash(p+vec2(1,1)), w.x), w.y);
}// wave octave inspiration
// Alexander Alekseev - Seascape
// https://www.shadertoy.com/view/Ms2SD1
float map_octave(vec2 uv) {uv = (uv + noise(uv)) / 2.5;uv = vec2(uv.x*0.6-uv.y*0.8, uv.x*0.8+uv.y*0.6);vec2 uvsin = 1.0 - abs(sin(uv));vec2 uvcos = abs(cos(uv));uv = mix(uvsin, uvcos, uvsin);float val = 1.0 - pow(uv.x * uv.y, 0.65);return val;
}float map(vec3 p) {vec2 uv = p.xz + TIME/2.;float amp = 0.6, freq = 2.0, val = 0.0;for(int i = 0; i < 3; ++i) {val += map_octave(uv) * amp;amp *= 0.3;uv *= freq;// uv = vec2(uv.x*0.6-uv.y*0.8, uv.x*0.8+uv.y*0.6);}uv = p.xz - 1000. - TIME/2.;amp = 0.6;freq = 2.0;for(int i = 0; i < 3; ++i) {val += map_octave(uv) * amp;amp *= 0.3;uv *= freq;// uv = vec2(uv.x*0.6-uv.y*0.8, uv.x*0.8+uv.y*0.6);}return val + 3.0 - p.y;
}vec3 getNormal(vec3 p, vec2 resolution) {float eps = 1./resolution.x;vec3 px = p + vec3(eps, 0, 0);vec3 pz = p + vec3(0, 0, eps);return normalize(vec3(map(px),eps,map(pz)));
}// raymarch inspiration
// Alexander Alekseev - Seascape
// https://www.shadertoy.com/view/Ms2SD1
float raymarch(vec3 ro, vec3 rd, vec2 resolution, out vec3 outP, out float outT) {float l = 0., r = 26.;int i = 0, steps = 16;float dist = 1000000.;for(int i = 0; i < steps; ++i) {float mid = (r+l)/2.;float mapmid = map(ro + rd*mid);dist = min(dist, abs(mapmid));if(mapmid > 0.) {l = mid;}else {r = mid;}if(r - l < 1./resolution.x) break;}outP = ro + rd*l;outT = l;return dist;
}float fbm(vec2 n) {float total = 0.0, amplitude = 1.0;for (int i = 0; i < 5; i++) {total += noise(n) * amplitude; n += n;amplitude *= 0.4; }return total;
}float lightShafts(vec2 st) {float angle = -0.2;vec2 _st = st;float t = TIME / 16.;st = vec2(st.x * cos(angle) - st.y * sin(angle), st.x * sin(angle) + st.y * cos(angle));float val = fbm(vec2(st.x*2. + 200. + t, st.y/4.));val += fbm(vec2(st.x*2. + 200. - t, st.y/4.));val = val / 3.;float mask = pow(clamp(1.0 - abs(_st.y-0.15), 0., 1.)*0.49 + 0.5, 2.0);mask *= clamp(1.0 - abs(_st.x+0.2), 0., 1.) * 0.49 + 0.5;return pow(val*mask, 2.0);
}vec2 bubble(vec2 uv, float scale) {if(uv.y > 0.2) return vec2(0.);float t = TIME/4.;vec2 st = uv * scale;vec2 _st = floor(st);vec2 bias = vec2(0., 4. * sin(_st.x*128. + t));float mask = smoothstep(0.1, 0.2, -cos(_st.x*128. + t));st += bias;vec2 _st_ = floor(st);st = fract(st);float warpped_time = mod(noise(_st_) - TIME * upward_speed, 1.0);float size = noise(_st_)*bubble_size+0.01;vec2 pos = vec2(noise(vec2(t, _st_.y*64.1)) * 0.8 + 0.1, 0.5);if(length(st.xy - pos) < size) {return (st + pos) * vec2(.1, .2) * mask;}return vec2(0.);
}void fragment() {vec2 resolution = 1.0/SCREEN_PIXEL_SIZE;vec3 ro = vec3(0.,0.,2.);vec3 lightPos = vec3(8, 3, -3);vec3 lightDir = normalize(lightPos - ro);// adjust uvvec2 uv = FRAGCOORD.xy;uv = (-(1.0/SCREEN_PIXEL_SIZE).xy + 2.0*uv) / (1.0/SCREEN_PIXEL_SIZE).y;uv.y = 1.0 - uv.y; // flipuv.y *= 0.5;uv.x *= 0.45;uv.y -= 0.4;uv.x += movable_x * 0.1 * sin(TIME);uv.y += movable_y * 0.1 * cos(TIME);uv += bubble(uv, 12.) + bubble(uv, 12.) + bubble(uv, 36.) + bubble(uv, 48.); // add bubblesvec3 rd = normalize(vec3(uv, -1.));vec3 hitPos;float hitT;vec3 seaColor = vec3(11,82,142)/255.;vec3 color;// wavesfloat dist = raymarch(ro, rd, resolution, hitPos, hitT);float diffuse = dot(getNormal(hitPos, resolution), rd) * 0.5 + 0.5;color = mix(seaColor, vec3(15,120,152)/255., diffuse);color += pow(diffuse, 12.0);// refractionvec3 ref = normalize(refract(hitPos-lightPos, getNormal(hitPos, resolution), 0.05));float refraction = clamp(dot(ref, rd), 0., 1.0);color += vec3(245,250,220)/255. * 0.6 * pow(refraction, 1.5);vec3 col = vec3(0.);col = mix(color, seaColor, pow(clamp(0., 1., dist), 0.2)); // glow edgecol += vec3(225,230,200)/255. * lightShafts(uv); // light shafts// tone mapcol = (col*col + sin(col))/vec3(1.8, 1.8, 1.9);// vignette// inigo quilez - Stop Motion Fox // https://www.shadertoy.com/view/3dXGWBvec2 q = FRAGCOORD.xy / resolution.xy;col *= 0.7+0.3*pow(16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.2);COLOR = vec4(col,1.0);
}

添加水平移动的功能

shader_type canvas_item;
// Created by greenbird10
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0uniform float bubble_size = 0.1;   // Size of the bubbles
uniform float upward_speed = 0.2;  // Speed at which bubbles rise
uniform float yaw_angle = 0.0;
uniform vec3 camera_pos = vec3(0.,0.,2.);mat2 rotation_matrix(float angle) {float s = sin(angle);float c = cos(angle);return mat2(vec2(c, -s), vec2(s, c));
}float hash(vec2 p) {return 0.5*(sin(dot(p, vec2(271.319, 413.975)) + 1217.13*p.x*p.y)) + 0.5;
}float noise(vec2 p) {vec2 w = fract(p);w = w * w * (3.0 - 2.0*w);p = floor(p);return mix(mix(hash(p+vec2(0,0)), hash(p+vec2(1,0)), w.x),mix(hash(p+vec2(0,1)), hash(p+vec2(1,1)), w.x), w.y);
}// wave octave inspiration
// Alexander Alekseev - Seascape
// https://www.shadertoy.com/view/Ms2SD1
float map_octave(vec2 uv) {uv = (uv + noise(uv)) / 2.5;uv = vec2(uv.x*0.6-uv.y*0.8, uv.x*0.8+uv.y*0.6);vec2 uvsin = 1.0 - abs(sin(uv));vec2 uvcos = abs(cos(uv));uv = mix(uvsin, uvcos, uvsin);float val = 1.0 - pow(uv.x * uv.y, 0.65);return val;
}float map(vec3 p) {vec2 uv = p.xz + TIME/2.;float amp = 0.6, freq = 2.0, val = 0.0;for(int i = 0; i < 3; ++i) {val += map_octave(uv) * amp;amp *= 0.3;uv *= freq;// uv = vec2(uv.x*0.6-uv.y*0.8, uv.x*0.8+uv.y*0.6);}uv = p.xz - 1000. - TIME/2.;amp = 0.6;freq = 2.0;for(int i = 0; i < 3; ++i) {val += map_octave(uv) * amp;amp *= 0.3;uv *= freq;// uv = vec2(uv.x*0.6-uv.y*0.8, uv.x*0.8+uv.y*0.6);}return val + 3.0 - p.y;
}vec3 getNormal(vec3 p, vec2 resolution) {float eps = 1./resolution.x;vec3 px = p + vec3(eps, 0, 0);vec3 pz = p + vec3(0, 0, eps);return normalize(vec3(map(px),eps,map(pz)));
}// raymarch inspiration
// Alexander Alekseev - Seascape
// https://www.shadertoy.com/view/Ms2SD1
float raymarch(vec3 ro, vec3 rd, vec2 resolution, out vec3 outP, out float outT) {float l = 0., r = 26.;int i = 0, steps = 16;float dist = 1000000.;for(int i = 0; i < steps; ++i) {float mid = (r+l)/2.;float mapmid = map(ro + rd*mid);dist = min(dist, abs(mapmid));if(mapmid > 0.) {l = mid;}else {r = mid;}if(r - l < 1./resolution.x) break;}outP = ro + rd*l;outT = l;return dist;
}float fbm(vec2 n) {float total = 0.0, amplitude = 1.0;for (int i = 0; i < 5; i++) {total += noise(n) * amplitude; n += n;amplitude *= 0.4; }return total;
}float lightShafts(vec2 st) {float angle = -0.2;vec2 _st = st;float t = TIME / 16.;st = vec2(st.x * cos(angle) - st.y * sin(angle), st.x * sin(angle) + st.y * cos(angle));float val = fbm(vec2(st.x*2. + 200. + t, st.y/4.));val += fbm(vec2(st.x*2. + 200. - t, st.y/4.));val = val / 3.;float mask = pow(clamp(1.0 - abs(_st.y-0.15), 0., 1.)*0.49 + 0.5, 2.0);mask *= clamp(1.0 - abs(_st.x+0.2), 0., 1.) * 0.49 + 0.5;return pow(val*mask, 2.0);
}vec2 bubble(vec2 uv, float scale) {if(uv.y > 0.2) return vec2(0.);float t = TIME/4.;vec2 st = uv * scale;vec2 _st = floor(st);vec2 bias = vec2(0., 4. * sin(_st.x*128. + t));float mask = smoothstep(0.1, 0.2, -cos(_st.x*128. + t));st += bias;vec2 _st_ = floor(st);st = fract(st);float warpped_time = mod(noise(_st_) - TIME * upward_speed, 1.0);float size = noise(_st_)*bubble_size+0.01;vec2 pos = vec2(noise(vec2(t, _st_.y*64.1)) * 0.8 + 0.1, 0.5);if(length(st.xy - pos) < size) {return (st + pos) * vec2(.1, .2) * mask;}return vec2(0.);
}void fragment() {vec2 resolution = 1.0/SCREEN_PIXEL_SIZE;vec3 ro = camera_pos;vec3 lightPos = vec3(8, 3, -3);vec3 lightDir = normalize(lightPos - ro);// adjust uvvec2 uv = FRAGCOORD.xy;uv = (-(1.0/SCREEN_PIXEL_SIZE).xy + 2.0*uv) / (1.0/SCREEN_PIXEL_SIZE).y;uv.y = 1.0 - uv.y; // flipuv.y *= 0.5;uv.x *= 0.45;uv.y -= 0.4;uv = rotation_matrix(yaw_angle) * uv;uv += bubble(uv, 12.) + bubble(uv, 12.) + bubble(uv, 36.) + bubble(uv, 48.); // add bubblesvec3 rd = normalize(vec3(uv, -1.));vec3 hitPos;float hitT;vec3 seaColor = vec3(11,82,142)/255.;vec3 color;// wavesfloat dist = raymarch(ro, rd, resolution, hitPos, hitT);float diffuse = dot(getNormal(hitPos, resolution), rd) * 0.5 + 0.5;color = mix(seaColor, vec3(15,120,152)/255., diffuse);color += pow(diffuse, 12.0);// refractionvec3 ref = normalize(refract(hitPos-lightPos, getNormal(hitPos, resolution), 0.05));float refraction = clamp(dot(ref, rd), 0., 1.0);color += vec3(245,250,220)/255. * 0.6 * pow(refraction, 1.5);vec3 col = vec3(0.);col = mix(color, seaColor, pow(clamp(0., 1., dist), 0.2)); // glow edgecol += vec3(225,230,200)/255. * lightShafts(uv); // light shafts// tone mapcol = (col*col + sin(col))/vec3(1.8, 1.8, 1.9);// vignette// inigo quilez - Stop Motion Fox // https://www.shadertoy.com/view/3dXGWBvec2 q = FRAGCOORD.xy / resolution.xy;col *= 0.7+0.3*pow(16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.2);COLOR = vec4(col,1.0);
}

尝试使气泡跟随移动

本来想这么写

在这里插入图片描述

用粒子发射器来发射圆

模拟气泡的样子

但是首先这个就要对海底的 canvasitem 采样,才能做出气泡的通透的效果,这个效果我还没搞懂

然后就是我希望整个海底是可以移动的时候,气泡也跟着移动

粒子发射器发射出来的粒子似乎并不方便实现这个功能

虽然改一下 UV 确实可行,但是如果我想让所有粒子整体跟着摄像机动,并且还可以 repeat 的话,那么我感觉……一时间想不到什么方法

尝试修改原 shadertoy 的气泡尺寸

改 bubble_size 到很大的话,会超出矩形框

请添加图片描述

所以这个矩形框很烦人……理论上来讲,我是在大的 canvasitem 里面画的,不应该是像这样,好像我在单独的 sprite 里面画一样

后面有点看懂了一些

这个气泡的绘制是单纯给 UV 加一个偏移

uv += bubble(uv, bubble_scale); // add bubbles

就能得到类似透射的效果

因为你相当于直接对偏移的地方采样,但是绘制在原来的像素位置

真的很妙啊这个思路

于是我想能不能偏移 uv

uv += vec2(camera_pos.x, camera_pos.y);

但是这样会导致海面出错

请添加图片描述

于是加在 bubble 的参数里面就好了

uv += bubble(uv + 0.1 * vec2(camera_pos.x, camera_pos.y), bubble_scale); // add bubbles

请添加图片描述

气泡之所以增大半径之后会变成矩形,是因为他是 floor 取小数位作为一个新的坐标系了

    vec2 _st = floor(st);vec2 bias = vec2(0., 4. * sin(_st.x*128. + t));float mask = smoothstep(0.1, 0.2, -cos(_st.x*128. + t));

所以气泡半径就是 0.5 也合理

但是现在这个气泡的这个一列上升会很怪

所以我在想能不能从粒子发射器获得粒子的数据呢

查到了别人的问题

https://www.reddit.com/r/godot/comments/rrrty9/is_it_possible_to_get_positions_of_particles_in/?rdt=50664

so,看上去不行,没有开放这个属性

但是源码很简洁

或许我可以尝试改源码,但是这应该会花一些时间

然后我给 bubble 加上了 size 参数,本来以为我可以过渡三种形态的

	// add bubblesuv += bubble(uv + 0.05 * vec2(camera_pos.x, camera_pos.y), mod(0.1 * camera_pos.z + 0.05, 0.3), 30.0);uv += bubble(uv + 0.1 * vec2(camera_pos.x, camera_pos.y), mod(0.1 * camera_pos.z + 0.1, 0.3), 20.0);uv += bubble(uv + 0.2 * vec2(camera_pos.x, camera_pos.y), mod(0.1 * camera_pos.z + 0.2, 0.3), 5.0);

但是随着前进后退,这个变化还是太奇怪

请添加图片描述
于是放弃


http://www.mrgr.cn/news/53650.html

相关文章:

  • 域4:通信与网络安全 第12章 安全通讯和网络攻击
  • HCIA复习实验
  • 双链表的操作
  • 【二刷hot100】day 4
  • AI与测试行业调研
  • SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载
  • 引领企业数字化转型的核心驱动力:微服务架构与物联网
  • 【多模态】CLIP模型技术学习
  • 2024批量下载公众号文章内容/话题/图片/封面/视频/音频,导出excel和pdf,文章数据包含阅读数/点赞数/分享数/留言数
  • 普通java web项目转为maven项目
  • 原地移除数组中所有的元素val 含源码
  • 如何快速学会盲打
  • 2024.09.27校招 实习 内推 面经
  • 5步轻松上手!零基础也能掌握Go语言编程
  • 明日周刊-第23期
  • 性能测试中性能调优的基本原则有哪些
  • 大模型(LLM)推理体系全览
  • SFT、RLHF、DPO、IFT —— LLM 微调的进化之路_如何搭建自己的dpo
  • Cesium for UE-04-一些说明
  • Docker本地镜像发布到阿里云镜像服务的简易指南
  • 从 PDF 表到见解:在 RAG 中解析 PDF 的另一种方法
  • 基于51单片机的电子时钟数码管显示proteus仿真
  • 正则化-权重衰减
  • Vue Google 广告的配置
  • 数据库原理与应用(基于MySQL):实验六数据查询
  • rpm 命令