Webgl动态海浪点

简介: Webgl动态海浪点

1.创建 webgl

function initGl(id) {
   
   
  var canvas = document.getElementById(id);
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  var gl = canvas.getContext('webgl');
  //监听window大小改变,设置窗口视图
  window.addEventListener('resize', () => {
   
   
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  });
  return gl;
}

2. 加载着色器

//加载着色器
function loadShader(gl, type, source) {
   
   
  //创建着色器
  const shader = gl.createShader(type);
  //设置着色器的代码
  gl.shaderSource(shader, source);
  //编译着色器
  gl.compileShader(shader);
  //编译错误打印日志,返回null
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
   
   
    console.log('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
    return null;
  }

  return shader;
}

顶点着色器

       attribute vec3 position;
            attribute float scale;
            attribute vec3 color;
            uniform mat4 uModelViewMatrix;
            uniform mat4 uProjectionMatrix;
            varying vec3 vColor;
      void main() {
          vec4 mvPosition = uModelViewMatrix * vec4( position, 1.0 );
          //根据距离远近显示点的大小
          gl_PointSize = scale * ( 300.0 / - mvPosition.z );
          gl_Position = uProjectionMatrix * mvPosition   ;
          vColor=color;
      }

片元着色器

precision highp float;
varying vec3 vColor;
      void main() {
      //超过一定视觉范围内,不显示
          if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;
          gl_FragColor = vec4( vColor, 1.0 );
      }

3.初始化 program

function initShaderProgram(gl, vsSource, fsSource) {
   
   
  //顶点着色器
  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
  //片元着色器
  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

  //创建
  const shaderProgram = gl.createProgram();
  //绑定顶点着色器
  gl.attachShader(shaderProgram, vertexShader);
  //绑定片元着色器
  gl.attachShader(shaderProgram, fragmentShader);
  //绑定着色器程序
  gl.linkProgram(shaderProgram);
  //使用着色器程序
  gl.useProgram(shaderProgram);
  //把着色器程序挂在gl上方便后面操作
  gl.program = shaderProgram;
  //编译错误打印日志,返回null
  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
   
   
    console.log('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
    return null;
  }

  return shaderProgram;
}

4. 批量创建波浪的点

const SEPARATION = 100,
  AMOUNTX = 50,
  AMOUNTY = 50;
const numParticles = AMOUNTX * AMOUNTY;
var count = 0;
const positions = new Float32Array(numParticles * 3);
const scales = new Float32Array(numParticles);
const colors = new Float32Array(numParticles * 3);
function createPoints() {
   
   
  let i = 0,
    j = 0;
  for (let ix = 0; ix < AMOUNTX; ix++) {
   
   
    //随即颜色
    let c = [Math.random(), Math.random(), Math.random()];
    for (let iy = 0; iy < AMOUNTY; iy++) {
   
   
      //设置点x,z位置
      positions[i] = ix * SEPARATION - (AMOUNTX * SEPARATION) / 2; // x
      positions[i + 1] = 0; // y
      positions[i + 2] = iy * SEPARATION - (AMOUNTY * SEPARATION) / 2; // z

      scales[j] = 1;
      //每一列的颜色相同
      colors[i] = c[0];
      colors[i + 1] = c[1];
      colors[i + 2] = c[2];

      i += 3;
      j++;
    }
  }
}

5. 让点动起来

移动点的 y 轴位置,对应大小的改变

function movePoints() {
   
   
  let i = 0,
    j = 0;

  for (let ix = 0; ix < AMOUNTX; ix++) {
   
   
    for (let iy = 0; iy < AMOUNTY; iy++) {
   
   
      positions[i + 1] = Math.sin((ix + count) * 0.3) * 50 + Math.sin((iy + count) * 0.5) * 50;

      scales[j] = (Math.sin((ix + count) * 0.3) + 1) * 20 + (Math.sin((iy + count) * 0.5) + 1) * 20;

      i += 3;
      j++;
    }
  }
}

清空重画

function cleanGl(gl) {
   
   
  gl.clearColor(0.0, 0.0, 0.0, 1.0); //清空背景色为黑色
  gl.clearDepth(1.0); //清空所有
  gl.enable(gl.DEPTH_TEST); //开启深度检测
  gl.depthFunc(gl.LEQUAL); //深度检测方法设置为近处物体阻挡远处物体
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); //清空缓存
}

正交投影

function initProjectionMatrix(gl) {
   
   
  //视角
  const fieldOfView = (75 * Math.PI) / 180;
  const aspect = gl.canvas.width / gl.canvas.height;
  const zNear = 1; //近处
  const zFar = 10000.0; //远处
  const projectionMatrix = mat4.create();
  //正交投影
  mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);
  gl.uniformMatrix4fv(
    gl.getUniformLocation(gl.program, 'uProjectionMatrix'),
    false,
    projectionMatrix
  );
  return projectionMatrix;
}

设置缓冲区

function initArrBuffer(gl, code, value, perLen) {
   
   
  //创建缓冲区
  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, value, gl.STATIC_DRAW);
  let aVal = gl.getAttribLocation(gl.program, code);
  //给管线指定顶点着色器数据
  gl.vertexAttribPointer(aVal, perLen, gl.FLOAT, false, 0, 0);
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.enableVertexAttribArray(aVal); //启用顶点着色器数据
}

动画帧

function animate() {
   
   
  cleanGl(gl);
  //正交投影
  var projectionMatrix = initProjectionMatrix(gl);

  const modelViewMatrix = mat4.create();
  //整体后移300,使点在视角范围内
  mat4.translate(modelViewMatrix, modelViewMatrix, [-0.0, 0.0, -300.0]);

  gl.uniformMatrix4fv(gl.getUniformLocation(program, 'uModelViewMatrix'), false, modelViewMatrix);

  movePoints();
  //设置缓存区,赋值对应着色器参数
  initArrBuffer(gl, 'position', positions, 3);
  initArrBuffer(gl, 'color', colors, 3);
  initArrBuffer(gl, 'scale', scales, 1);

  //画点
  gl.drawArrays(gl.POINTS, 0, scales.length);
  count += 0.1;
  requestAnimationFrame(animate);
}

20230805_105340.gif

github 代码地址

https://github.com/xiaolidan00/webgl-wave-points

参考: https://threejs.org/examples/#webgl_points_waves

相关文章
|
2月前
|
前端开发 JavaScript 数据可视化
WebGL 入门:开启三维网页图形的新篇章(上)
WebGL 入门:开启三维网页图形的新篇章(上)
|
2月前
|
存储 缓存 数据可视化
WebGL 入门:开启三维网页图形的新篇章(下)
WebGL 入门:开启三维网页图形的新篇章(下)
WebGL 入门:开启三维网页图形的新篇章(下)
|
存储 缓存 算法
超逼真渲染!虚幻引擎技术大牛解读全局光照系统Lumen(3)
超逼真渲染!虚幻引擎技术大牛解读全局光照系统Lumen
|
存储 数据挖掘 开发者
超逼真渲染!虚幻引擎技术大牛解读全局光照系统Lumen(2)
超逼真渲染!虚幻引擎技术大牛解读全局光照系统Lumen
|
算法 图形学 开发者
超逼真渲染!虚幻引擎技术大牛解读全局光照系统Lumen(1)
超逼真渲染!虚幻引擎技术大牛解读全局光照系统Lumen
122 0
|
存储 数据挖掘 开发者
超逼真渲染!虚幻引擎技术大牛解读全局光照系统Lumen
超逼真渲染!虚幻引擎技术大牛解读全局光照系统Lumen
|
数据可视化
【视觉高级篇】20 # 如何用WebGL绘制3D物体?
【视觉高级篇】20 # 如何用WebGL绘制3D物体?
148 0
【视觉高级篇】20 # 如何用WebGL绘制3D物体?
|
前端开发
【我的前端】玻璃拟态效果实战开发:比毛玻璃更好看的CSS背景玻璃拟态效果
玻璃拟态是目前市面上的新风格,越来越受欢迎,新拟态 (Neumorphism) 模仿受到挤压的塑料材质,这种新的视觉风格更加注重垂直空间z轴的使用。它的典型特征是:
【我的前端】玻璃拟态效果实战开发:比毛玻璃更好看的CSS背景玻璃拟态效果
从0开发游戏引擎之在3D空间中渲染出三维几何体
这个类里面会使用第9章里的三维体数据来调用OpenGL的接口绘制出来对应的形状。几何体绘制类主要是调试使用的,比如想要更直观的看到一个对象身上的碰撞框。绘制的形状非常多,大家直接看代码吧。
|
数据可视化 前端开发 算法
[译] 用 WebGL 探索动画和交互技术(一个学习案例
约束过程 主要使用 three.js 和 GreenSock 库,这些实验都是手动编码的,没有凭借任何 3D 或动画软件。 这个过程包括以编程的方式塑造角色,一次一个方块。在精炼比例上我花费了大多数工夫。通过微调代码中的值来总体渲染位置,然后通过用户输入(大多是移动鼠标,点击,拖动等等)来移动每个部分。 这个过程的优点不是很明显。但它能让我仅仅通过文本编辑器就能创造整个实验,利用 Codepen 提供的实时预览,整个过程非常灵活。 话虽如此,这个过程有自己的一套限制,以保持可管理性:角色必须用尽可能少的部分构建; 每个部分由数量很小的顶点组成; 动画必须针对数量有限的行为。 「注意」:
[译] 用 WebGL 探索动画和交互技术(一个学习案例