canvas实现webgl线圈绕组动画效果代码
代码语言:html
所属分类:动画
代码描述:canvas实现webgl线圈绕组动画效果代码,可通过dat.gui更换图形,选择圆圈、星星等图形样式、还可更改背景颜色。
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> body { background-color: #fff; margin: 0; overflow: hidden; } canvas { position: absolute; background-color: #999; width: 100%; height: 100%; vertical-align: middle; display:inline-block; } </style> </head> <body > <canvas id="canvas"></canvas> <script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/dat.gui-min.js"></script> <script > /* * The winding number of a point describes how many full revolutions a curve makes around it. * Open curves produce interesting visuals. We discretise parametric curves into linear * segments and find the signed angle between the vectors connecting a point to the segment. * The sum of these angles, divided by 2PI radians, gives the winding number. * * Based on: * https://en.wikipedia.org/wiki/Winding_number * [1] https://igl.ethz.ch/projects/winding-number/ * https://twitter.com/keenanisalive/status/1448036393012322313 * https://www.shadertoy.com/view/Wddyz2 * */ let canvas = document.getElementById("canvas"); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // MSAA let multiplier = 2.0; var AA = true; // Initialize the GL context let gl = canvas.getContext('webgl'); if (!gl) { console.error("Unable to initialize WebGL."); } let time = 0.0; let scene = 0; let palette = 0; let sceneNames = ["Circle", "Heart", "Star", "Infinity"]; let paletteNames = ["Grayscale", "Rainbow", "Red", "Blue"]; let sceneSelector = { scene: "Circle" }; let paletteSelector = { palette: "Rainbow" }; setScene(sceneSelector.scene); setPalette(paletteSelector.palette); //************* GUI *************** let gui = new dat.GUI(); gui.add(sceneSelector, 'scene').options(sceneNames).onChange(name => {setScene(name);}); gui.add(paletteSelector, 'palette').options(paletteNames).onChange(name => {setPalette(name);}); gui.add(this, 'AA').onChange(b => {b ? multiplier = 2 : multiplier = 1;onWindowResize();}).listen(); gui.close(); //******** Shader sources ********* let vertexSource = ` attribute vec2 position; void main() { // Screenspace position of vertices can use the data passed from the CPU // Set z-component to 0 gl_Position = vec4(position, 0.0, 1.0); } `; //Replace with GLSL fragment shader code let fragmentSource = ` precision highp float; uniform vec2 resolution; uniform float time; uniform float u_scene; uniform float u_palette; #define PI 3.1415926536 #define TWO_PI 6.2831853072 // https://math.stackexchange.com/questions/3020095/signed-angle-in-plane: // "the ratio of the cross product and scalar product is the tangent of the angle" // From [1]: "The tangent of the signed angle between a and b is det([ab]) / dot(ab)" float signedAngle(vec2 a, vec2 b){ // atan(y, x) returns the angle whose arctangent is y / x. Value in [-pi, pi] return atan(a.x*b.y - a.y*b.x, dot(a, b)); } // https://iquilezles.org/articles/palettes/ vec3 getColour(float t, int palette){ if(palette == 0){ // Black and white return vec3(-0.5 * t + 0.45); } vec3 a; vec3 b; vec3 c; vec3 d; if(palette == 1){ // Pastel rainbow // Animated t *= 0.45; t += 0.1 * time; a = vec3(0.65); b = 1.0 - a; c = vec3(1.0,1.0,1.0); d = vec3(0.15,0.5,0.75); }else if(palette == 2){ // Red and purple t *= -0.3; t += 0.65; a = vec3(0.55, 0.5, 0.7); b = 1.0-a; c = vec3(1.0,1.0,1.0); d = vec3(0.15,0.95,0.8); }else if(palette == 3){ // Blue // Same as above with different t t *= 0.35; t += 0.3; a = vec3(0.55, 0.5, 0.7); b = 1.0-a; c = vec3(1.0,1.0,1.0); d = vec3(0.15,0.95,0.8); } return a + b * cos(TWO_PI *(c * t + d)); } vec2 getCircle(float t){ return vec2(sin(t), cos(t)); } // http://mathworld.wolfram.com/Lemniscate.html vec2 getLemniscate(float t){ float a = 1.5; return vec2((a * cos(t)) / (1.0 + (sin(t) * sin(t))), (a * sin(t) * cos(t))/ (1.0 + (sin(t) * sin(t)))); } // http://mathworld.wolfram.com/HeartCurve.html vec2 getHeart(float t){ return 0.05 * vec2(1, -1) * vec2(16.0 * sin(t) * sin(t) * sin(t), -(13.0 * cos(t) - 5.0 * cos(2.0 * t) - 2.0 * cos(3.0 * t) - cos(4.0 * t))) + vec2(0, 0.1); } vec2 rotate2d(vec2 v, float a){ return v * mat2(cos(a),-sin(a), sin(a), cos(a)); } // https://en.wikipedia.org/wiki/Hypotrochoid // https://mathworld.wolfram.com/Hypotrochoid.html vec2 getHypotrochoid(float t){ float a = 5.0; float b = 3.0; float h = 5.0; float a_b = a - b; float t_ab = t * a_b / b; return vec2(a_b * cos(t) + h * cos(t_ab), a_b * sin(t) - h * sin(t_ab)); } vec2 getPosition(float t, int scene){ if(scene == 0){ return getCircle(t); }else if(scene == 1){ return getHeart(t); }else if(scene == 2){ return getHypotrochoid(t); }else{ return getLemniscate(t); } } void main(){ // Normalized pixel coordinates (from 0 to 1) vec2 uv = gl_FragCoord.xy/resolution; uv -= 0.5; uv.y /= resolution.x / resolution.y; uv *= 4.0 + max(0.0, (resolution.x / resolution.y) - 0.5); float angle = 0.0; float segments = 16.0; float delta = (0.25 * (TWO_PI)) / segments; float speed = 2.0; float radius = 1.0; int scene = int(u_scene); int palette = int(u_palette); // Hear.........完整代码请登录后点击上方下载按钮下载查看
网友评论0