频闪效果模拟代码优化:圆等分与同频率采样异常修复
频闪效果模拟代码优化需求
我从Visualize It获取了一段频闪效果模拟代码,目前功能已接近需求,但仍需优化两点:
- 将圆分为3份及以上,且其中一个等分的一半为不同颜色;
- 修复输入频率与采样频率相同时,无法呈现采样偏移180°的频闪效果。
以下是现有代码:
JavaScript 代码
let wheel_angle, camera_angle; let wheel_rpm, angular_speed; let wheel_radius; let frames_skip, cooldown, sampling_rate, frame_no; let is_paused, direction; function update() { wheel_angle += direction * angular_speed; if (wheel_angle > 360) { wheel_angle -= 360; } else if (wheel_angle < 0) { wheel_angle += 360; } if (frame_no == 0) { camera_angle = wheel_angle; frame_no = frames_skip; } else { frame_no -= 1; } } function render() { context.fillStyle = "#000000"; context.fillRect(0, 0, canvas_width, canvas_height); context.strokeStyle = "#ffffff"; context.beginPath(); context.moveTo(canvas_width / 2, 0); context.lineTo(canvas_width / 2, canvas_height); context.stroke(); context.strokeStyle = "#ff51ff"; context.beginPath(); context.moveTo(canvas_width / 4 + wheel_radius * Math.cos(toRadian(wheel_angle)), canvas_height / 2 - wheel_radius * Math.sin(toRadian(wheel_angle)) + y_offset); if (wheel_angle >= 180) { context.lineTo(canvas_width / 4 + wheel_radius * Math.cos(toRadian(wheel_angle - 180)), canvas_height / 2 - wheel_radius * Math.sin(toRadian(wheel_angle - 180)) + y_offset); } else { context.lineTo(canvas_width / 4 + wheel_radius * Math.cos(toRadian(wheel_angle + 180)), canvas_height / 2 - wheel_radius * Math.sin(toRadian(wheel_angle + 180)) + y_offset); } context.stroke(); context.beginPath(); context.arc(canvas_width / 4, canvas_height / 2 + y_offset, wheel_radius, 0, 2 * Math.PI); context.stroke(); context.strokeStyle = "#00ff00"; context.beginPath(); context.moveTo(3 * canvas_width / 4 + wheel_radius * Math.cos(toRadian(camera_angle)), canvas_height / 2 - wheel_radius * Math.sin(toRadian(camera_angle)) + y_offset); if (wheel_angle >= 180) { context.lineTo(3 * canvas_width / 4 + wheel_radius * Math.cos(toRadian(camera_angle - 180)), canvas_height / 2 - wheel_radius * Math.sin(toRadian(camera_angle - 180)) + y_offset); } else { context.lineTo(3 * canvas_width / 4 + wheel_radius * Math.cos(toRadian(camera_angle + 180)), canvas_height / 2 - wheel_radius * Math.sin(toRadian(camera_angle + 180)) + y_offset); } context.stroke(); context.beginPath(); context.arc(3 * canvas_width / 4, canvas_height / 2 + y_offset, wheel_radius, 0, 2 * Math.PI); context.stroke(); if (mobile) { context.font = "15px Arial"; } else { context.font = "30px Arial"; } context.textAlign = "center"; context.fillStyle = "#ffffff"; context.fillText("Base", canvas_width / 4, 30); context.fillText("Teste Aliasing", 3 * canvas_width / 4, 30); } function initParams() { wheel_angle = Math.random() * 360; wheel_rpm = 60; rpm_slider.value = wheel_rpm; calcSpeed(); rpm_display.innerHTML = `Frequência do cículo base: ${(angular_speed * fps / 360).toFixed(2)} Hz (Hertz)`; frames_skip = 26; calcCooldown(); fps_slider.value = 60 - frames_skip; fps_display.innerHTML = `Frequência de Amostragem: ${sampling_rate.toFixed(2)} Hz;`; wheel_radius = (canvas_width / 4) - 20; frame_no = 0; paused = false; direction = -1; } function updateParams(variable) { if (variable == 'rpm') { wheel_rpm = rpm_slider.value; calcSpeed(); rpm_display.innerHTML = `Frequência do cículo base: ${(angular_speed * fps / 360).toFixed(2)} Hz (Hertz)`; } else if (variable == 'fps') { frames_skip = 60 - fps_slider.value; calcCooldown(); fps_display.innerHTML = `Frequência de Amostragem: ${sampling_rate.toFixed(2)} Hz;`; } else if (variable == 'pause') { if (is_paused) { is_paused = false; pause_button.innerHTML = "Parar"; } else { is_paused = true; pause_button.innerHTML = "Continuar"; } } else if (variable == 'dir') { direction *= (-1); } } function simulate(number) { if (number == 1) { rpm_slider.value = 80; fps_slider.value = 59; } else if (number == 2) { rpm_slider.value = 120; fps_slider.value = 48; } else if (number == 3) { rpm_slider.value = 120; fps_slider.value = 46; } else if (number == 4) { rpm_slider.value = 100; fps_slider.value = 55; } else if (number == 5) { rpm_slider.value = 100; fps_slider.value = 41; } else if (number == 6) { rpm_slider.value = 60; fps_slider.value = 1; } updateParams("rpm"); updateParams("fps"); window.scrollTo(0, 40); } function step() { if (!is_paused) { update(); } render(); animate(step); } function calcSpeed() { angular_speed = (wheel_rpm * 360) / (fps * 60); } function calcCooldown() { cooldown = (frames_skip + 1) / fps; sampling_rate = 1 / cooldown; } function toRadian(degree) { return (Math.PI * degree / 180); } let screen_width = window.innerWidth, screen_height = window.innerHeight; let y_offset = 30; let fps = 60; let canvas = document.getElementById("canvas"); let context = canvas.getContext("2d"); let pause_button = document.getElementById("pause-button"); let rpm_display = document.getElementById("rpm-display"); let rpm_slider = document.getElementById("rpm-slider"); let fps_slider = document.getElementById("fps-slider"); let fps_display = document.getElementById("fps-display"); if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { mobile = true; } else { mobile = false; } if (mobile) { canvas_width = 0.9 * screen_width; } else { canvas_width = 0.5 * screen_width; } canvas_height = canvas_width / 2 + y_offset; canvas.width = canvas_width; canvas.height = canvas_height; let animate = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) { window.setTimeout(callback, 1000 / (fps)); }; window.onload = function() { initParams(); animate(step); }
HTML 代码
<!DOCTYPE html> <html lang="en-US"> <head> <title>Stroboscopic Effect | Visualize It</title> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <!-- Materialize --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <!-- Jquery --> <script src="https://code.jquery.com/jquery-3.6.1.min.js"></script> <!-- CSS --> <link rel="stylesheet" href="../style.css" /> <script src="basic.js" defer></script> <script src="stroboscopic_effect.js" defer></script> </head> <script async src="https://www.googletagmanager.com/gtag/js?id=G-M95CKRP8HB"></script> <script> window.dataLayer = window.dataLayer || []; function gtag() { window.dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', 'G-M95CKRP8HB'); </script> <body> <div class="text"> <br> <div class="container" style="width:90%"> <div class="row"> <div class="col s12 l8"> <canvas id="canvas"></canvas> </div> <div class="col s12 l4"> <center> <p id="rpm-display"></p> <input type="range" min="0" max="200" value="30" id="rpm-slider" oninput="updateParams('rpm')" onchange="updateParams('rpm')" class="slider"> <p id="fps-display"></p> <input type="range" min="0" max="59" value="30" id="fps-slider" oninput="updateParams('fps')" onchange="updateParams('fps')" class="slider"> </center> </div> <div class="col s12 l4"> <button type="button" class="btn btn-danger" onclick="simulate(3);">Estacionáro</button> <button type="button" class="btn btn-success" onclick="simulate(1);">Normal</button> <button type="button" class="btn btn-success" onclick="simulate(5);">Normal lento</button> <button type="button" class="btn btn-success" onclick="simulate(6);">Alternado 180</button> <button type="button" class="btn btn-success" onclick="simulate(2);">Contrário Lento</button> </div> </div> </div> </div> </body> </html>
内容的提问来源于stack exchange,提问作者Sillas Senna
相关产品推荐
相关产品推荐

