3D龙卷风旋转特效
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 2 3 <embed src="D:\音乐\G.E.M.邓紫棋 - 龙卷风.mp3 " width="0" height="0" type="audio/mpeg loop="ture" autostart="ture" volume="0" .></EMBED> 4 <HTML> 5 <HEAD> 6 <TITLE> New Document </TITLE> 7 <META NAME="Generator" CONTENT="EditPlus"> 8 <META NAME="Author" CONTENT=""> 9 <META NAME="Keywords" CONTENT=""> 10 <META NAME="Description" CONTENT=""> 11 <style> 12 html, body { 13 margin: 0px; 14 width: 100%; 15 height: 100%; 16 overflow: hidden; 17 background: #000; 18 } 19 20 #canvas { 21 position: absolute; 22 width: 100%; 23 height: 100%; 24 } 25 </style> 26 </HEAD> 27 28 <BODY> 29 <canvas id="canvas"></canvas> 30 <script> 31 function project3D(x, y, z, vars) { 32 33 var p, d; 34 x -= vars.camX; 35 y -= vars.camY - 8; 36 z -= vars.camZ; 37 p = Math.atan2(x, z); 38 d = Math.sqrt(x * x + z * z); 39 x = Math.sin(p - vars.yaw) * d; 40 z = Math.cos(p - vars.yaw) * d; 41 p = Math.atan2(y, z); 42 d = Math.sqrt(y * y + z * z); 43 y = Math.sin(p - vars.pitch) * d; 44 z = Math.cos(p - vars.pitch) * d; 45 var rx1 = -1000; 46 var ry1 = 1; 47 var rx2 = 1000; 48 var ry2 = 1; 49 var rx3 = 0; 50 var ry3 = 0; 51 var rx4 = x; 52 var ry4 = z; 53 var uc = (ry4 - ry3) * (rx2 - rx1) - (rx4 - rx3) * (ry2 - ry1); 54 var ua = ((rx4 - rx3) * (ry1 - ry3) - (ry4 - ry3) * (rx1 - rx3)) / uc; 55 var ub = ((rx2 - rx1) * (ry1 - ry3) - (ry2 - ry1) * (rx1 - rx3)) / uc; 56 if (!z) z = 0.000000001; 57 if (ua > 0 && ua < 1 && ub > 0 && ub < 1) { 58 return { 59 x: vars.cx + (rx1 + ua * (rx2 - rx1)) * vars.scale, 60 y: vars.cy + y / z * vars.scale, 61 d: (x * x + y * y + z * z) 62 }; 63 } else { 64 return { d: -1 }; 65 } 66 } 67 68 69 function elevation(x, y, z) { 70 71 var dist = Math.sqrt(x * x + y * y + z * z); 72 if (dist && z / dist >= -1 && z / dist <= 1) return Math.acos(z / dist); 73 return 0.00000001; 74 } 75 76 77 function rgb(col) { 78 79 col += 0.000001; 80 var r = parseInt((0.5 + Math.sin(col) * 0.5) * 16); 81 var g = parseInt((0.5 + Math.cos(col) * 0.5) * 16); 82 var b = parseInt((0.5 - Math.sin(col) * 0.5) * 16); 83 return "#" + r.toString(16) + g.toString(16) + b.toString(16); 84 } 85 86 87 function interpolateColors(RGB1, RGB2, degree) { 88 89 var w2 = degree; 90 var w1 = 1 - w2; 91 return [w1 * RGB1[0] + w2 * RGB2[0], w1 * RGB1[1] + w2 * RGB2[1], w1 * RGB1[2] + w2 * RGB2[2]]; 92 } 93 94 95 function rgbArray(col) { 96 97 col += 0.000001; 98 var r = parseInt((0.5 + Math.sin(col) * 0.5) * 256); 99 var g = parseInt((0.5 + Math.cos(col) * 0.5) * 256); 100 var b = parseInt((0.5 - Math.sin(col) * 0.5) * 256); 101 return [r, g, b]; 102 } 103 104 105 function colorString(arr) { 106 107 var r = parseInt(arr[0]); 108 var g = parseInt(arr[1]); 109 var b = parseInt(arr[2]); 110 return "#" + ("0" + r.toString(16)).slice(-2) + ("0" + g.toString(16)).slice(-2) + ("0" + b.toString(16)).slice(-2); 111 } 112 113 114 function process(vars) { 115 116 117 if (vars.points.length < vars.initParticles) for (var i = 0; i < 5; ++i) spawnParticle(vars); 118 var p, d, t; 119 120 p = Math.atan2(vars.camX, vars.camZ); 121 d = Math.sqrt(vars.camX * vars.camX + vars.camZ * vars.camZ); 122 d -= Math.sin(vars.frameNo / 80) / 25; 123 t = Math.cos(vars.frameNo / 300) / 165; 124 vars.camX = Math.sin(p + t) * d; 125 vars.camZ = Math.cos(p + t) * d; 126 vars.camY = -Math.sin(vars.frameNo / 220) * 15; 127 vars.yaw = Math.PI + p + t; 128 vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2; 129 130 var t; 131 for (var i = 0; i < vars.points.length; ++i) { 132 133 x = vars.points[i].x; 134 y = vars.points[i].y; 135 z = vars.points[i].z; 136 d = Math.sqrt(x * x + z * z) / 1.0075; 137 t = .1 / (1 + d * d / 5); 138 p = Math.atan2(x, z) + t; 139 vars.points[i].x = Math.sin(p) * d; 140 vars.points[i].z = Math.cos(p) * d; 141 vars.points[i].y += vars.points[i].vy * t * ((Math.sqrt(vars.distributionRadius) - d) * 2); 142 if (vars.points[i].y > vars.vortexHeight / 2 || d < .25) { 143 vars.points.splice(i, 1); 144 spawnParticle(vars); 145 } 146 } 147 } 148 149 function drawFloor(vars) { 150 151 var x, y, z, d, point, a; 152 for (var i = -25; i <= 25; i += 1) { 153 for (var j = -25; j <= 25; j += 1) { 154 x = i * 2; 155 z = j * 2; 156 y = vars.floor; 157 d = Math.sqrt(x * x + z * z); 158 point = project3D(x, y - d * d / 85, z, vars); 159 if (point.d != -1) { 160 size = 1 + 15000 / (1 + point.d); 161 a = 0.15 - Math.pow(d / 50, 4) * 0.15; 162 if (a > 0) { 163 vars.ctx.fillStyle = colorString(interpolateColors(rgbArray(d / 26 - vars.frameNo / 40), [0, 128, 32], .5 + Math.sin(d / 6 - vars.frameNo / 8) / 2)); 164 vars.ctx.globalAlpha = a; 165 vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size); 166 } 167 } 168 } 169 } 170 vars.ctx.fillStyle = "#82f"; 171 for (var i = -25; i <= 25; i += 1) { 172 for (var j = -25; j <= 25; j += 1) { 173 x = i * 2; 174 z = j * 2; 175 y = -vars.floor; 176 d = Math.sqrt(x * x + z * z); 177 point = project3D(x, y + d * d / 85, z, vars); 178 if (point.d != -1) { 179 size = 1 + 15000 / (1 + point.d); 180 a = 0.15 - Math.pow(d / 50, 4) * 0.15; 181 if (a > 0) { 182 vars.ctx.fillStyle = colorString(interpolateColors(rgbArray(-d / 26 - vars.frameNo / 40), [32, 0, 128], .5 + Math.sin(-d / 6 - vars.frameNo / 8) / 2)); 183 vars.ctx.globalAlpha = a; 184 vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size); 185 } 186 } 187 } 188 } 189 } 190 191 function sortFunction(a, b) { 192 return b.dist - a.dist; 193 } 194 195 function draw(vars) { 196 197 vars.ctx.globalAlpha = .15; 198 vars.ctx.fillStyle = "#000"; 199 vars.ctx.fillRect(0, 0, canvas.width, canvas.height); 200 201 drawFloor(vars); 202 203 var point, x, y, z, a; 204 for (var i = 0; i < vars.points.length; ++i) { 205 x = vars.points[i].x; 206 y = vars.points[i].y; 207 z = vars.points[i].z; 208 point = project3D(x, y, z, vars); 209 if (point.d != -1) { 210 vars.points[i].dist = point.d; 211 size = 1 + vars.points[i].radius / (1 + point.d); 212 d = Math.abs(vars.points[i].y); 213 a = .8 - Math.pow(d / (vars.vortexHeight / 2), 1000) * .8; 214 vars.ctx.globalAlpha = a >= 0 && a <= 1 ? a : 0; 215 vars.ctx.fillStyle = rgb(vars.points[i].color); 216 if (point.x > -1 && point.x < vars.canvas.width && point.y > -1 && point.y < vars.canvas.height) vars.ctx.fillRect(point.x - size / 2, point.y - size / 2, size, size); 217 } 218 } 219 vars.points.sort(sortFunction); 220 } 221 222 223 function spawnParticle(vars) { 224 225 var p, ls; 226 pt = {}; 227 p = Math.PI * 2 * Math.random(); 228 ls = Math.sqrt(Math.random() * vars.distributionRadius); 229 pt.x = Math.sin(p) * ls; 230 pt.y = -vars.vortexHeight / 2; 231 pt.vy = vars.initV / 20 + Math.random() * vars.initV; 232 pt.z = Math.cos(p) * ls; 233 pt.radius = 200 + 800 * Math.random(); 234 pt.color = pt.radius / 1000 + vars.frameNo / 250; 235 vars.points.push(pt); 236 } 237 238 function frame(vars) { 239 240 if (vars === undefined) { 241 var vars = {}; 242 vars.canvas = document.querySelector("canvas"); 243 vars.ctx = vars.canvas.getContext("2d"); 244 vars.canvas.width = document.body.clientWidth; 245 vars.canvas.height = document.body.clientHeight; 246 window.addEventListener("resize", function () { 247 vars.canvas.width = document.body.clientWidth; 248 vars.canvas.height = document.body.clientHeight; 249 vars.cx = vars.canvas.width / 2; 250 vars.cy = vars.canvas.height / 2; 251 }, true); 252 vars.frameNo = 0; 253 254 vars.camX = 0; 255 vars.camY = 0; 256 vars.camZ = -14; 257 vars.pitch = elevation(vars.camX, vars.camZ, vars.camY) - Math.PI / 2; 258 vars.yaw = 0; 259 vars.cx = vars.canvas.width / 2; 260 vars.cy = vars.canvas.height / 2; 261 vars.bounding = 10; 262 vars.scale = 500; 263 vars.floor = 26.5; 264 265 vars.points = []; 266 vars.initParticles = 2000; 267 vars.initV = .01; 268 vars.distributionRadius = 800; 269 vars.vortexHeight = 25; 270 } 271 272 vars.frameNo++; 273 requestAnimationFrame(function () { 274 frame(vars); 275 }); 276 277 process(vars); 278 draw(vars); 279 } 280 frame(); 281 282 </script> 283 </BODY> 284 </HTML>
诚者,君子之所守也。