用html写一个雨的特效

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>雨特效</title>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="wrap-texture">
    <div id="canvas"></div>
    <div class="plane">
        <img data-sampler="dispImage" id="texture" src="https://source.unsplash.com/MFW8BGYKNIE" crossorigin="anonymous"/>
    </div>
</div>
<!-- partial -->
  <script src="https://www.curtainsjs.com/build/curtains.min.js"></script>
<script src="./script.js"></script>
</body>
</html>

window.onload = () => {
    const shader = {
      vertex: `    
      #ifdef GL_ES
      precision mediump float;
      #endif
      
      // lib设置的强制属性
      attribute vec3 aVertexPosition;
      attribute vec2 aTextureCoord;
  
      // lib设置的强制统一,包含模型视图和投影矩阵
      uniform mat4 uMVMatrix;
      uniform mat4 uPMatrix;
  
      uniform mat4 dispImageMatrix;
  
      // 将顶点和纹理坐标传递给着色器
      varying vec3 vVertexPosition;
      varying vec2 vTextureCoord;
  
      void main() {
          vec3 vertexPosition = aVertexPosition;
          gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0);
  
          // 设置varyings
          vTextureCoord = (dispImageMatrix * vec4(aTextureCoord, 0., 1.)).xy;
          vVertexPosition = vertexPosition;
      }`,
      fragment: `
      #ifdef GL_ES
      precision mediump float;
      #endif
      
      #define PI2 6.28318530718
      #define PI 3.14159265359
      #define S(a,b,n) smoothstep(a,b,n)
      
      // 获得varyings
      varying vec3 vVertexPosition;
      varying vec2 vTextureCoord;
  
      // 用uniform声明
      uniform float uTime;
      uniform vec2 uReso;
      uniform vec2 uMouse;
  
      // 纹理采样器
      uniform sampler2D dispImage;
      uniform sampler2D blurImage;
    
      // 噪声
      float N12(vec2 p){
        p = fract(p * vec2(123.34, 345.45));
        p += dot(p, p + 34.345);
  
        return fract(p.x * p.y);
      }
  
      vec3 Layer(vec2 uv0, float t){
  
        vec2 asp = vec2(2., 1.);
  
        vec2 uv1 = uv0 * 3. * asp;
  
        uv1.y += t * .25;
  
        vec2 gv = fract(uv1) - .5;
        vec2 id = floor(uv1);
  
        float n = N12(id);
  
        t+= n * PI2;
  
        float w = uv0.y * 10.;
        float x = (n - .5) * .8;
        x += (.4 - abs(x)) * sin(3. * w) * pow(sin(w), 6.) * .45;
        float y = -sin(t + sin(t + sin(t) * .5)) * (.5 - .06);
        y -= (gv.x - x) * (gv.x - x); // sesgar;
  
        vec2 dropPos = (gv - vec2(x, y)) / asp; 
        float drop = S(.03, .02, length(dropPos));
  
        vec2 trailPos = (gv - vec2(x, t * .25)) / asp; 
        trailPos.y = (fract(trailPos.y * 8.) - .5) / 8.;
        float trail = S(.02, .015, length(trailPos));
  
        float fogTrail = S(-.05, .05, dropPos.y);
  
        fogTrail *= S(.5, y, gv.y);
        trail *= fogTrail;
        fogTrail *= S(.03, .015, abs(dropPos.x));
  
        vec2 off = drop * dropPos + trail * trailPos;
  
        return vec3(off, fogTrail);
      }
    
      void main() {      
            float dist = 5.;
            float blurSize = 5.;
            float t = mod(uTime * .03, 7200.);
  
            vec4 c = vec4(0);
            vec2 uv = vTextureCoord;    
  
            vec3 drops = Layer(uv, t);
            drops += Layer(uv * 1.25 + 7.54, t);
            drops += Layer(uv * 1.35 + 1.54, t);
            drops += Layer(uv * 1.57 - 7.54, t);
  
            float blur = blurSize * 7. * (1. - drops.z);
  
            vec4 col = vec4(0.);
            int numSamples = 32;
            float a = N12(uv) * PI2;
        
            blur *= .0005;
            uv += drops.xy * dist;
              
            for(int n = 0; n < 32; n++){
              vec2 off = vec2(sin(a), cos(a)) * blur;
              float d = fract(sin((float(n) + 1.) * 546.) * 5424.);
              d = sqrt(d);         
              off *= d;
              col += texture2D(dispImage, uv + off);
              a++;
            }
        
            col /= float(numSamples);
   
            gl_FragColor = col;
      }
      `
    };
  
    // canvas
    const canvasContainer = document.getElementById("canvas");
    const mouse = {
      x: 0,
      y: 0
    };
    // 设置WebGL,并将canvas附加到container
    const webGLCurtain = new Curtains({container: "canvas"});
    
    // 获取平面元素
    const planeElement = document.getElementsByClassName("plane")[0];
    
    // 设置初始参数
    const params = {
      vertexShader: shader.vertex, // 顶点着色器
      fragmentShader: shader.fragment, // framgent着色器
      widthSegments: 40,
      heightSegments: 40, // 现在有40*40*6=9600个顶点
      uniforms: {
        time: {
          name: "uTime", // 传递给着色器统一名称
          type: "1f", 
          value: 0
        },
        mousepos: {
          name: "uMouse",
          type: "2f",
          value: [mouse.x, mouse.y]
        },
        resolution: {
          name: "uReso",
          type: "2f",
          value: [innerWidth, innerHeight]
        }
      }
    };
  
    // 创建平面网格
    const plane = webGLCurtain.addPlane(planeElement, params);
  
    plane.onRender(() => {
      plane.uniforms.time.value++; // 更新统一值
  
      plane.uniforms.resolution.value = [innerWidth, innerHeight];
    });
  
    canvasContainer.addEventListener("mousemove", ({ clientX, clientY }) => {
      mouse.x = clientX;
      mouse.y = clientY;
  
      plane.uniforms.mousepos.value = [mouse.x, mouse.y];
    });
  };

body {
    position: relative;
    width: 100%;
    height: 100vh;
    margin: 0;
    overflow: hidden;
}

#wrap-texture {
    position: relative;
}

#canvas {
    /* canvas 的大小 */
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
}

.plane {
    /* 限制 plane 的大小 */
    width: 100%;
    height: 100vh;
}

.plane img {
    /* 隐藏 img 对象 */
    display: none;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/538363.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文掌握 React 开发中的 JavaScript 基础知识

前端开发中JavaScript是基石。在 React 开发中掌握掌握基础的 JavaScript 方法将有助于编写出更加高效、可维护的 React 应用程序。 在 React 开发中使用 ES6 语法可以带来更简洁、可读性更强、功能更丰富,以及更好性能和社区支持等诸多好处。这有助于提高开发效率,并构建出更…

Stable Diffusion——SDXL Turbo让 AI 出图速度提高10倍

摘要 在本研究中&#xff0c;我们提出了一种名为对抗扩散蒸馏&#xff08;ADD&#xff09;的创新训练技术&#xff0c;它能够在1至4步的采样过程中&#xff0c;高效地对大规模基础图像扩散模型进行处理&#xff0c;同时保持图像的高质量。该方法巧妙地结合了分数蒸馏技术&…

【企业场景】设计模式重点解析

设计模式 在平时的开发中&#xff0c;涉及到设计模式的有两块内容&#xff1a; 我们平时使用的框架&#xff08;比如spring、mybatis等&#xff09;我们自己开发业务使用的设计模式。 在平时的业务开发中&#xff0c;其实真正使用设计模式的场景并不多&#xff0c;虽然设计号…

企业业务遇到CC攻击,为何让人如此头疼。

随着互联网的普及和应用&#xff0c;网络安全已经成为人们越来越关注的一个问题。 随着网络信息化不断发展&#xff0c;用户对网站体验有着更高的要求&#xff0c;在网络时代&#xff0c;网站的稳定性至关重要&#xff0c;活跃在网络中的恶意攻击者惯用各类攻击手段破坏网站的稳…

C# Solidworks二次开发:几何公差IGot相关操作API详解

大家好&#xff0c;今天要介绍的是关于几何公差IGot相关操作的API。 几何公差之前没有讲过&#xff0c;具体API如下面所示&#xff1a; &#xff08;1&#xff09;第一个为GetText&#xff0c;这个API的含义为获取此几何公差的指定文本部分&#xff0c;下面是官方的具体解释&…

每日OJ题_01背包①_牛客DP41 【模板】01背包(滚动数组优化)

目录 牛客DP41 【模板】01背包 问题一解析 问题二解析 解析代码 滚动数组优化代码 牛客DP41 【模板】01背包 【模板】01背包_牛客题霸_牛客网 #include <iostream> using namespace std;int main() {int a, b;while (cin >> a >> b) { // 注意 while 处…

智慧污水井物联网远程监控案例

智慧污水井物联网远程监控案例 在当今数字化转型的浪潮中&#xff0c;智慧水务已成为城市基础设施建设的重要组成部分。其中&#xff0c;基于物联网技术的智慧污水井远程监控系统以其高效、精准、实时的特性&#xff0c;在提升污水处理效能、保障城市水环境安全、实现精细化管…

Jmeter安装与测试

一&#xff1a;JMeter简介&#xff1a; JMeter&#xff0c;一个100&#xff05;的纯Java桌面应用&#xff0c;由Apache组织的开放源代码项目&#xff0c;它是功能 和性能测试的工具。具有高可扩展性、支持Web(HTTP/HTTPS)、SOAP、FTP、JAVA 等多种协议的特点。 官方网站&#x…

利用虚拟机建ITtools

网上给的虚拟机多数都是VMX格式的封包&#xff0c;而我这次用的是ovf 我先把虚拟机在导出为ovf 生成了三个文件 去服务器上创建虚拟机&#xff0c;选择从OVF或OVA文件部署虚拟机&#xff0c;点下一页 给虚拟机起个名字 把相应的文件扡到里面去&#xff08;这里生成的四个文件中…

【软件使用-MEGA】基于NJ和ML方法构建进化树结果比较

文章目录 概要对比细节小结 概要 构建进化树有很多可选的算法&#xff0c;其中比较常用的NJ&#xff08;邻接法&#xff09;&#xff0c;也有基于似然法NL&#xff0c;如下图所示&#xff0c;构建进化树具体方法可以参考我之前写的【软件使用-MEGA】如何基于ML方法构建进化树 …

STM32笔记---CAN采样点设置和报错

STM32笔记---CAN采样点设置和报错 采样点设置再同步补偿宽度&#xff08;SJW&#xff09;设置 报错分析CAN中断使能寄存器CAN错误状态寄存器 采样点设置 以前配置CAN参数的BS1和BS2参数时认为总线波特率符合要求就可以了&#xff0c;其实同一个波特率可能对应多组参数设置的情…

LC 515.在每个树行中找最大值

515. 在每个树行中找最大值 给定一棵二叉树的根节点 root &#xff0c;请找出该二叉树中每一层的最大值。 示例1&#xff1a; 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9] 示例2&#xff1a; 输入: root [1,2,3] 输出: [1,3] 提示&#xff1a; 二叉树的节点个数的范围是…

内存函数memcpy、mommove、memset、memcmp

1、memcpy函数 描述&#xff1a; C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。 声明&#xff1a; void *memcpy(void *str1, const void *str2, size_t n)参数&#xff1a; str1 -- 指向用于存储复制内容的目标…

windows环境下实现ffmpeg本地视频进行rtsp推流

摘要&#xff1a;有时候服务端&#xff08;如linux&#xff09;或者边缘端&#xff08;jetson盒子&#xff09;需要接受摄像头的视频流输入&#xff0c;而摄像头的输入视频流一般为rtsp&#xff0c;测试时需要搭建摄像头环境&#xff0c;很不方便&#xff0c;因此需要对本地视频…

MySQL SQL基础入门-你想要的我尽可能覆盖全

什么是SQL&#xff1f; SQL&#xff08;Structured Query Language) ,结构化查询语言。SQL是一种专用语言&#xff0c;用户关系型数据库管理系统或者在关系流数据管理系统中进行流处理。 SQL怎么读&#xff1f;两种读法&#xff1a;一个字母一个字母读或者连起来读。 一个字母…

PostgreSQL入门到实战-第二十二弹

PostgreSQL入门到实战 PostgreSQL中表连接操作(六)官网地址PostgreSQL概述PostgreSQL中self-join命令理论PostgreSQL中self-join命令实战更新计划 PostgreSQL中表连接操作(六) 使用PostgreSQL自联接技术来比较同一表中的行 官网地址 声明: 由于操作系统, 版本更新等原因, 文…

springCloud项目打包 ,maven package或install打包报错

解决思路一&#xff1a; <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version></plugin><plugin>&…

新天龙八部3永恒经典之江山策仿官方_源码架设教程

本教程仅限学习使用&#xff0c;禁止商用&#xff0c;一切后果与本人无关&#xff0c;此声明具有法律效应&#xff01;&#xff01;&#xff01;&#xff01; 教程是本人亲自搭建成功的&#xff0c;绝对是完整可运行的&#xff0c;踩过的坑都给你们填上了 一. 效果演示 新天龙…

opencv 多线程读取和显示摄像头【python源码】

在Python中&#xff0c;使用OpenCV库实现多线程读取和显示摄像头通常涉及创建多个线程&#xff0c;每个线程负责从摄像头捕获视频帧并显示它们。但是&#xff0c;请注意&#xff0c;OpenCV本身并不直接支持多线程显示&#xff0c;因为cv2.imshow通常是在主线程中运行的。然而&a…

【C++ STL序列容器】deque 双端队列

文章目录 【 1. 基本原理 】【 1. deque 的创建 】1.1 创建一个空的 deque1.2 创建一个 n 个默认值的 deque1.3 创建一个 n 个指定值的 deque1.4 通过一个 deque 初始化另一个 deque1.5 通过基础容器来初始化 queue 容器适配器 【 3. deque 支持的成员函数 】 【 1. 基本原理 】…