养成习惯先赞后看

效果图展示
1.初始化 WebGL 上下文,并创建顶点着色器和片元着色器。
| // 获取 canvas 元素,并设置 WebGL 上下文 |
| var canvas = document.getElementById('myCanvas'); |
| var gl = canvas.getContext('webgl'); |
| |
| // 定义顶点着色器 |
| var vertexShaderSource = ` |
| attribute vec2 position; |
| void main() { |
| gl_Position = vec4(position, 0, 1.0); |
| } |
| `; |
| |
| // 定义片元着色器 |
| var fragmentShaderSource = ` |
| void main() { |
| gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); |
| } |
| `; |
| |
| // 创建顶点着色器 |
| var vertexShader = gl.createShader(gl.VERTEX_SHADER); |
| gl.shaderSource(vertexShader, vertexShaderSource); |
| gl.compileShader(vertexShader); |
| |
| // 创建片元睝色器 |
| var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); |
| gl.shaderSource(fragmentShader, fragmentShaderSource); |
| gl.compileShader(fragmentShader); |
复制
2.创建程序,并设置视口大小和背景颜色。
| // 创建程序 |
| var program = gl.createProgram(); |
| gl.attachShader(program, vertexShader); |
| gl.attachShader(program, fragmentShader); |
| gl.linkProgram(program); |
| gl.useProgram(program); |
| |
| // 设置视口大小和背景颜色 |
| gl.viewport(0, 0, canvas.width, canvas.height); |
| gl.clearColor(0.0, 0.0, 0.0, 1.0); |
| gl.clear(gl.COLOR_BUFFER_BIT); |
复制
3.创建顶点数据,并传入缓冲区。
| // 创建顶点数据 |
| var vertices = new Float32Array([ |
| -0.5, 0.5, |
| -0.5, -0.5, |
| 0.5, -0.5, |
| 0.5, 0.5 |
| ]); |
| |
| // 创建缓冲区并传入顶点数据 |
| var vertexBuffer = gl.createBuffer(); |
| gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); |
| gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); |
复制
4.获取位置属性并启用,然后定义绘制函数。
| // 获取位置属性并启用 |
| var position = gl.getAttribLocation(program, 'position'); |
| gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0); |
| gl.enableVertexAttribArray(position); |
| |
| // 绘制函数 |
| function draw() { |
| // 更新线条位置和形状的逻辑 |
| |
| // 清除画布 |
| gl.clear(gl.COLOR_BUFFER_BIT); |
| |
| // 绘制三角形 |
| gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); |
| |
| // 请求下一帧动画 |
| requestAnimationFrame(draw); |
| } |
复制
5.最后通过 requestAnimationFrame() 方法开始绘制动画。
| // 开始绘制动画 |
| requestAnimationFrame(draw); |
复制
全部代码如下:
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> |
| <HTML> |
| <HEAD> |
| <TITLE> New Document </TITLE> |
| <META NAME="Generator" CONTENT="EditPlus"> |
| <META NAME="Author" CONTENT=""> |
| <META NAME="Keywords" CONTENT=""> |
| <META NAME="Description" CONTENT=""> |
| <style>@import "compass/css3"; |
| |
| @import "compass/reset"; |
| @import "compass/css3"; |
| |
| body{ |
| overflow: hidden; |
| } |
| |
| canvas{ |
| width: 100%; |
| height: 100%; |
| }</style> |
| </HEAD> |
| |
| <BODY> |
| |
| <canvas id="c"></canvas> |
| |
| <script id="shader-fs" type="x-shader/x-fragment"> |
| #ifdef GL_ES |
| precision highp float; |
| #endif |
| void main(void) { |
| gl_FragColor = vec4(0.2, 0.3, 0.4, 1.0); |
| } |
| </script> |
| |
| <script id="shader-vs" type="x-shader/x-vertex"> |
| attribute vec3 vertexPosition; |
| |
| uniform mat4 modelViewMatrix; |
| uniform mat4 perspectiveMatrix; |
| |
| void main(void) { |
| gl_Position = perspectiveMatrix * modelViewMatrix * vec4( vertexPosition, 1.0); |
| } |
| </script> |
| |
| <script>window.onload = loadScene; |
| |
| var canvas, gl, |
| ratio, |
| vertices, |
| velocities, |
| freqArr, |
| cw, |
| ch, |
| colorLoc, |
| thetaArr, |
| velThetaArr, |
| velRadArr, |
| boldRateArr, |
| drawType, |
| numLines = 40000; |
| var target = []; |
| var randomTargetXArr = [], randomTargetYArr = []; |
| drawType = 2; |
| |
| |
| |
| |
| |
| function loadScene() { |
| |
| canvas = document.getElementById("c"); |
| |
| gl = canvas.getContext("experimental-webgl"); |
| |
| |
| if (!gl) { |
| alert("There's no WebGL context available."); |
| return; |
| } |
| |
| cw = window.innerWidth; |
| ch = window.innerHeight; |
| canvas.width = cw; |
| canvas.height = ch; |
| gl.viewport(0, 0, canvas.width, canvas.height); |
| |
| |
| |
| |
| |
| |
| |
| |
| var vertexShaderScript = document.getElementById("shader-vs"); |
| var vertexShader = gl.createShader(gl.VERTEX_SHADER); |
| gl.shaderSource(vertexShader, vertexShaderScript.text); |
| gl.compileShader(vertexShader); |
| if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { |
| alert("Couldn't compile the vertex shader"); |
| gl.deleteShader(vertexShader); |
| return; |
| } |
| |
| |
| |
| var fragmentShaderScript = document.getElementById("shader-fs"); |
| var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); |
| gl.shaderSource(fragmentShader, fragmentShaderScript.text); |
| gl.compileShader(fragmentShader); |
| if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { |
| alert("Couldn't compile the fragment shader"); |
| gl.deleteShader(fragmentShader); |
| return; |
| } |
| |
| |
| gl.program = gl.createProgram(); |
| gl.attachShader(gl.program, vertexShader); |
| gl.attachShader(gl.program, fragmentShader); |
| gl.linkProgram(gl.program); |
| if (!gl.getProgramParameter(gl.program, gl.LINK_STATUS)) { |
| alert("Unable to initialise shaders"); |
| gl.deleteProgram(gl.program); |
| gl.deleteProgram(vertexShader); |
| gl.deleteProgram(fragmentShader); |
| return; |
| } |
| |
| gl.useProgram(gl.program); |
| |
| var vertexPosition = gl.getAttribLocation(gl.program, "vertexPosition"); |
| |
| |
| |
| gl.enableVertexAttribArray(vertexPosition); |
| |
| |
| gl.clearColor(0.0, 0.0, 0.0, 1.0); |
| |
| |
| gl.clearDepth(1.0); |
| |
| |
| |
| |
| |
| |
| gl.enable(gl.BLEND); |
| gl.disable(gl.DEPTH_TEST); |
| gl.blendFunc(gl.SRC_ALPHA, gl.ONE); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| var vertexBuffer = gl.createBuffer(); |
| |
| gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); |
| |
| |
| |
| |
| setup(); |
| |
| |
| |
| |
| vertices = new Float32Array(vertices); |
| velocities = new Float32Array(velocities); |
| |
| thetaArr = new Float32Array(thetaArr); |
| velThetaArr = new Float32Array(velThetaArr); |
| velRadArr = new Float32Array(velRadArr); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW); |
| |
| |
| gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| |
| |
| |
| |
| var fieldOfView = 30.0; |
| var aspectRatio = canvas.width / canvas.height; |
| var nearPlane = 1.0; |
| var farPlane = 10000.0; |
| var top = nearPlane * Math.tan(fieldOfView * Math.PI / 360.0); |
| var bottom = -top; |
| var right = top * aspectRatio; |
| var left = -right; |
| |
| |
| |
| |
| var a = (right + left) / (right - left); |
| var b = (top + bottom) / (top - bottom); |
| var c = (farPlane + nearPlane) / (farPlane - nearPlane); |
| var d = (2 * farPlane * nearPlane) / (farPlane - nearPlane); |
| var x = (2 * nearPlane) / (right - left); |
| var y = (2 * nearPlane) / (top - bottom); |
| var perspectiveMatrix = [ |
| x, 0, a, 0, |
| 0, y, b, 0, |
| 0, 0, c, d, |
| 0, 0, -1, 0 |
| ]; |
| |
| |
| |
| |
| var modelViewMatrix = [ |
| 1, 0, 0, 0, |
| 0, 1, 0, 0, |
| 0, 0, 1, 0, |
| 0, 0, 0, 1 |
| ]; |
| |
| var vertexPosAttribLocation = gl.getAttribLocation(gl.program, "vertexPosition"); |
| |
| |
| |
| gl.vertexAttribPointer(vertexPosAttribLocation, 3.0, gl.FLOAT, false, 0, 0); |
| |
| |
| |
| var uModelViewMatrix = gl.getUniformLocation(gl.program, "modelViewMatrix"); |
| |
| |
| var uPerspectiveMatrix = gl.getUniformLocation(gl.program, "perspectiveMatrix"); |
| |
| gl.uniformMatrix4fv(uModelViewMatrix, false, new Float32Array(perspectiveMatrix)); |
| gl.uniformMatrix4fv(uPerspectiveMatrix, false, new Float32Array(modelViewMatrix)); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| animate(); |
| setTimeout(timer, 1500); |
| } |
| var count = 0; |
| var cn = 0; |
| |
| function animate() { |
| requestAnimationFrame(animate); |
| drawScene(); |
| } |
| |
| |
| function drawScene() { |
| draw(); |
| |
| gl.lineWidth(1); |
| gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW); |
| |
| gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); |
| |
| |
| gl.drawArrays(gl.LINES, 0, numLines); |
| |
| |
| gl.flush(); |
| } |
| |
| |
| function setup() { |
| setup2(); |
| } |
| |
| |
| function draw() { |
| switch (drawType) { |
| case 0: |
| draw0(); |
| break; |
| case 1: |
| draw1(); |
| break; |
| case 2: |
| draw2(); |
| break; |
| } |
| } |
| |
| |
| |
| function setup1() { |
| |
| vertices = []; |
| velThetaArr = []; |
| velRadArr = []; |
| ratio = cw / ch; |
| velocities = []; |
| |
| |
| |
| for (var i = 0; i < numLines; i++) { |
| |
| var rad = Math.random() * 2 + .5; |
| var theta = Math.random() * Math.PI * 2; |
| var velTheta = Math.random() * Math.PI * 2; |
| |
| vertices.push(rad * Math.cos(theta), rad * Math.sin(theta), 1.83); |
| vertices.push(rad * Math.cos(theta), rad * Math.sin(theta), 1.83); |
| |
| velocities.push((Math.random() * 2 - 1) * .05, (Math.random() * 2 - 1) * .05, .93 + Math.random() * .02); |
| velThetaArr.push(velTheta); |
| velRadArr.push(rad); |
| |
| } |
| |
| } |
| |
| |
| |
| function setup2() { |
| |
| vertices = []; |
| velThetaArr = []; |
| velRadArr = []; |
| ratio = cw / ch; |
| velocities = []; |
| thetaArr = []; |
| freqArr = []; |
| boldRateArr = []; |
| |
| |
| |
| for (var ii = 0; ii < numLines; ii++) { |
| var rad = ( 0.1 + .2 * Math.random() ); |
| var theta = Math.random() * Math.PI * 2; |
| var velTheta = Math.random() * Math.PI * 2 / 30; |
| var freq = Math.random() * 0.12 + 0.03; |
| var boldRate = Math.random() * .04 + .01; |
| var randomPosX = (Math.random() * 2 - 1) * window.innerWidth / window.innerHeight; |
| var randomPosY = Math.random() * 2 - 1; |
| |
| vertices.push(rad * Math.cos(theta), rad * Math.sin(theta), 1.83); |
| vertices.push(rad * Math.cos(theta), rad * Math.sin(theta), 1.83); |
| |
| thetaArr.push(theta); |
| velThetaArr.push(velTheta); |
| velRadArr.push(rad); |
| freqArr.push(freq); |
| boldRateArr.push(boldRate); |
| |
| |
| randomTargetXArr.push(randomPosX); |
| randomTargetYArr.push(randomPosY); |
| } |
| |
| freqArr = new Float32Array(freqArr); |
| |
| } |
| |
| |
| |
| |
| |
| |
| function draw0() { |
| |
| var i, n = vertices.length, p, bp; |
| var px, py; |
| var pTheta; |
| var rad; |
| var num; |
| var targetX, targetY; |
| |
| for (i = 0; i < numLines * 2; i += 2) { |
| count += .3; |
| bp = i * 3; |
| |
| vertices[bp] = vertices[bp + 3]; |
| vertices[bp + 1] = vertices[bp + 4]; |
| |
| num = parseInt(i / 2); |
| targetX = randomTargetXArr[num]; |
| targetY = randomTargetYArr[num]; |
| |
| |
| px = vertices[bp + 3]; |
| px += (targetX - px) * (Math.random() * .04 + .06); |
| vertices[bp + 3] = px; |
| |
| |
| |
| py = vertices[bp + 4]; |
| py += (targetY - py) * (Math.random() * .04 + .06); |
| vertices[bp + 4] = py; |
| |
| } |
| } |
| |
| |
| |
| function draw1() { |
| |
| var i, n = vertices.length, p, bp; |
| var px, py; |
| var pTheta; |
| var rad; |
| var num; |
| var targetX, targetY; |
| |
| for (i = 0; i < numLines * 2; i += 2) { |
| count += .3; |
| bp = i * 3; |
| |
| vertices[bp] = vertices[bp + 3]; |
| vertices[bp + 1] = vertices[bp + 4]; |
| |
| num = parseInt(i / 2); |
| pTheta = thetaArr[num]; |
| rad = velRadArr[num]; |
| |
| pTheta = pTheta + velThetaArr[num]; |
| thetaArr[num] = pTheta; |
| |
| targetX = rad * Math.cos(pTheta); |
| targetY = rad * Math.sin(pTheta); |
| |
| px = vertices[bp + 3]; |
| px += (targetX - px) * (Math.random() * .1 + .1); |
| vertices[bp + 3] = px; |
| |
| |
| |
| py = vertices[bp + 4]; |
| py += (targetY - py) * (Math.random() * .1 + .1); |
| vertices[bp + 4] = py; |
| } |
| } |
| |
| |
| |
| function draw2() { |
| cn += .1; |
| |
| var i, n = vertices.length, p, bp; |
| var px, py; |
| var pTheta; |
| var rad; |
| var num; |
| |
| for (i = 0; i < numLines * 2; i += 2) { |
| count += .3; |
| bp = i * 3; |
| |
| |
| vertices[bp] = vertices[bp + 3]; |
| vertices[bp + 1] = vertices[bp + 4]; |
| |
| num = parseInt(i / 2); |
| pTheta = thetaArr[num]; |
| |
| rad = velRadArr[num]; |
| |
| pTheta = pTheta + velThetaArr[num]; |
| thetaArr[num] = pTheta; |
| |
| px = vertices[bp + 3]; |
| px = rad * Math.cos(pTheta) * 0.1 + px; |
| vertices[bp + 3] = px; |
| |
| |
| |
| py = vertices[bp + 4]; |
| |
| py = py + rad * Math.sin(pTheta) * 0.1; |
| |
| vertices[bp + 4] = py; |
| } |
| } |
| |
| |
| |
| |
| function timer() { |
| drawType = (drawType + 1) % 3; |
| |
| setTimeout(timer, 1500); |
| } |
| </script> |
| </BODY> |
| </HTML> |
复制
光看不点赞,罚款50