JavaScript+canvas实现一个旋转的3D球动画效果

这篇具有很好参考价值的文章主要介绍了JavaScript+canvas实现一个旋转的3D球动画效果。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

效果

canvas实现的动态3d旋转球体,JavaScript,javascript,3d


实现过程

1. 获取Canvas元素和设置初始参数

// 获取Canvas元素
const canvas = document.querySelector('#scene');
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
const ctx = canvas.getContext('2d');

// 针对高DPI屏幕进行缩放
if (window.devicePixelRatio > 1) {
    canvas.width = canvas.clientWidth * 2;
    canvas.height = canvas.clientHeight * 2;
    ctx.scale(2, 2);
}

// Canvas的宽度和高度
let width = canvas.clientWidth;
let height = canvas.clientHeight;
// 球体旋转的角度
let rotation = 0;
// 存储所有点的数组
let dots = [];

这部分代码主要是获取Canvas元素,并根据设备的DPI进行缩放。然后,定义了一些全局变量,包括Canvas的宽度、高度、球体旋转的角度和存储所有点的数组。


2. 定义一些常量

// 一些常量
const DOTS_AMOUNT = 1000; // 点的数量
const DOT_RADIUS = 2; // 点的半径
let GLOBE_RADIUS = width * 0.7; // 球半径
let GLOBE_CENTER_Z = -GLOBE_RADIUS; // 球心的Z坐标
let PROJECTION_CENTER_X = width / 2; // 画布HTML的X中心
let PROJECTION_CENTER_Y = height / 2; // 画布HTML的Y中心
let FIELD_OF_VIEW = width * 0.8;

这部分代码定义了一些常量,如点的数量、点的半径、球半径等。


3.定义点(Dot)类

// Dot类表示每个点的属性
class Dot {
    constructor(x, y, z, color) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.color = color; // 添加颜色属性

        this.xProject = 0;
        this.yProject = 0;
        this.sizeProjection = 0;
    }

    // 将三维坐标映射到二维画布上
    project(sin, cos) {
        const rotX = cos * this.x + sin * (this.z - GLOBE_CENTER_Z);
        const rotZ = -sin * this.x + cos * (this.z - GLOBE_CENTER_Z) + GLOBE_CENTER_Z;
        this.sizeProjection = FIELD_OF_VIEW / (FIELD_OF_VIEW - rotZ);
        this.xProject = (rotX * this.sizeProjection) + PROJECTION_CENTER_X;
        this.yProject = (this.y * this.sizeProjection) + PROJECTION_CENTER_Y;
    }

    // 在画布上绘制点
    draw(sin, cos) {
        this.project(sin, cos);
        ctx.beginPath();
        ctx.arc(this.xProject, this.yProject, DOT_RADIUS * this.sizeProjection, 0, Math.PI * 2);
        ctx.fillStyle = this.color; // 使用粒子的颜色属性
        ctx.closePath();
        ctx.fill();
    }
}

这部分代码定义了一个Dot类,表示球体上的每个点的属性和方法。包括构造函数、将三维坐标映射到二维画布上的project方法,以及在画布上绘制点的draw方法


4.创建和渲染球体的函数

// 创建所有点的函数
function createDots() {
    // 清空粒子数组
    dots.length = 0;

    // 创建一半蓝色粒子
    for (let i = 0; i < DOTS_AMOUNT / 2; i++) {
        const theta = Math.random() * 2 * Math.PI;
        const phi = Math.acos((Math.random() * 2) - 1);
        const x = GLOBE_RADIUS * Math.sin(phi) * Math.cos(theta);
        const y = GLOBE_RADIUS * Math.sin(phi) * Math.sin(theta);
        const z = (GLOBE_RADIUS * Math.cos(phi)) + GLOBE_CENTER_Z;
        dots.push(new Dot(x, y, z, '#981898'));
    }

    // 创建一半红色粒子
    for (let i = 0; i < DOTS_AMOUNT / 2; i++) {
        const theta = Math.random() * 2 * Math.PI;
        const phi = Math.acos((Math.random() * 2) - 1);
        const x = GLOBE_RADIUS * Math.sin(phi) * Math.cos(theta);
        const y = GLOBE_RADIUS * Math.sin(phi) * Math.sin(theta);
        const z = (GLOBE_RADIUS * Math.cos(phi)) + GLOBE_CENTER_Z;
        dots.push(new Dot(x, y, z, '#E71751'));
    }
}

这部分代码定义了createDots函数,用于生成一定数量的点,并分别将一半标记为蓝色,一半标记为红色。这里可以根据需求改动,


// 渲染函数,不断更新球体的旋转
function render(a) {
   ctx.clearRect(0, 0, width, height);
   rotation = a * 0.0004;
   const sineRotation = Math.sin(rotation);
   const cosineRotation = Math.cos(rotation);

   // 遍历所有点并绘制
   for (var i = 0; i < dots.length; i++) {
       dots[i].draw(sineRotation, cosineRotation);
   }

   window.requestAnimationFrame(render);
}

这部分代码定义了render函数,用于在每一帧更新球体的旋转角度,并循环绘制所有的点,产生连续的旋转效果。

5.监听窗口大小变化事件

// 当用户调整窗口大小时重新计算参数
function afterResize() {
    width = canvas.offsetWidth;
    height = canvas.offsetHeight;
    if (window.devicePixelRatio > 1) {
        canvas.width = canvas.clientWidth * 2;
        canvas.height = canvas.clientHeight * 2;
        ctx.scale(2, 2);
    } else {
        canvas.width = width;
        canvas.height = height;
    }
    GLOBE_RADIUS = width * 0.7;
    GLOBE_CENTER_Z = -GLOBE_RADIUS;
    PROJECTION_CENTER_X = width / 2;
    PROJECTION_CENTER_Y = height / 2;
    FIELD_OF_VIEW = width * 0.8;

    createDots(); // 重新生成所有点
}

// 变量用于存储用户调整窗口大小时的超时
let resizeTimeout;

// 当用户调整窗口大小时触发的函数
function onResize() {
    resizeTimeout = window.clearTimeout(resizeTimeout);
    resizeTimeout = window.setTimeout(afterResize, 500);
}

// 监听窗口大小变化事件
window.addEventListener('resize', onResize);

这部分代码用于监听窗口大小变化事件,并在用户调整窗口大小时重新计算参数,以保持效果的稳定性。

最后初始化一下就好了

// 初始化点数组
createDots();

// 渲染场景
window.requestAnimationFrame(render);

完整代码文章来源地址https://www.toymoban.com/news/detail-801094.html

<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>3D旋转球体</title>
   <style>
       body {
           height: 100vh;
           display: flex;
           justify-content: center;
           align-items: center;
           background: #000;
           margin: 0;
       }

       canvas {
           width: 500px;
           height: 500px;
       }
   </style>
</head>

<body>
   <canvas id="scene"></canvas>
   <script>
       // 获取Canvas元素
       const canvas = document.querySelector('#scene');
       canvas.width = canvas.clientWidth;
       canvas.height = canvas.clientHeight;
       const ctx = canvas.getContext('2d');

       // 针对高DPI屏幕进行缩放
       if (window.devicePixelRatio > 1) {
           canvas.width = canvas.clientWidth * 2;
           canvas.height = canvas.clientHeight * 2;
           ctx.scale(2, 2);
       }

       // Canvas的宽度和高度
       let width = canvas.clientWidth;
       let height = canvas.clientHeight;
       // 球体旋转的角度
       let rotation = 0;
       // 存储所有点的数组
       let dots = [];

       // 一些常量
       const DOTS_AMOUNT = 1000; // 点的数量
       const DOT_RADIUS = 2; // 点的半径
       let GLOBE_RADIUS = width * 0.7; // 球半径
       let GLOBE_CENTER_Z = -GLOBE_RADIUS; // 球心的Z坐标
       let PROJECTION_CENTER_X = width / 2; // 画布HTML的X中心
       let PROJECTION_CENTER_Y = height / 2; // 画布HTML的Y中心
       let FIELD_OF_VIEW = width * 0.8;

       // Dot类表示每个点的属性
       class Dot {
           constructor(x, y, z, color) {
               this.x = x;
               this.y = y;
               this.z = z;
               this.color = color; // 添加颜色属性

               this.xProject = 0;
               this.yProject = 0;
               this.sizeProjection = 0;
           }

           // 将三维坐标映射到二维画布上
           project(sin, cos) {
               const rotX = cos * this.x + sin * (this.z - GLOBE_CENTER_Z);
               const rotZ = -sin * this.x + cos * (this.z - GLOBE_CENTER_Z) + GLOBE_CENTER_Z;
               this.sizeProjection = FIELD_OF_VIEW / (FIELD_OF_VIEW - rotZ);
               this.xProject = (rotX * this.sizeProjection) + PROJECTION_CENTER_X;
               this.yProject = (this.y * this.sizeProjection) + PROJECTION_CENTER_Y;
           }

           // 在画布上绘制点
           draw(sin, cos) {
               this.project(sin, cos);
               ctx.beginPath();
               ctx.arc(this.xProject, this.yProject, DOT_RADIUS * this.sizeProjection, 0, Math.PI * 2);
               ctx.fillStyle = this.color; // 使用粒子的颜色属性
               ctx.closePath();
               ctx.fill();
           }
       }

       // 创建所有点的函数
       function createDots() {
           // 清空粒子数组
           dots.length = 0;

           // 创建一半蓝色粒子
           for (let i = 0; i < DOTS_AMOUNT / 2; i++) {
               const theta = Math.random() * 2 * Math.PI;
               const phi = Math.acos((Math.random() * 2) - 1);
               const x = GLOBE_RADIUS * Math.sin(phi) * Math.cos(theta);
               const y = GLOBE_RADIUS * Math.sin(phi) * Math.sin(theta);
               const z = (GLOBE_RADIUS * Math.cos(phi)) + GLOBE_CENTER_Z;
               dots.push(new Dot(x, y, z, '#981898'));
           }

           // 创建一半红色粒子
           for (let i = 0; i < DOTS_AMOUNT / 2; i++) {
               const theta = Math.random() * 2 * Math.PI;
               const phi = Math.acos((Math.random() * 2) - 1);
               const x = GLOBE_RADIUS * Math.sin(phi) * Math.cos(theta);
               const y = GLOBE_RADIUS * Math.sin(phi) * Math.sin(theta);
               const z = (GLOBE_RADIUS * Math.cos(phi)) + GLOBE_CENTER_Z;
               dots.push(new Dot(x, y, z, '#E71751'));
           }
       }

       // 渲染函数,不断更新球体的旋转
       function render(a) {
           ctx.clearRect(0, 0, width, height);
           rotation = a * 0.0004;
           const sineRotation = Math.sin(rotation);
           const cosineRotation = Math.cos(rotation);

           // 遍历所有点并绘制
           for (var i = 0; i < dots.length; i++) {
               dots[i].draw(sineRotation, cosineRotation);
           }

           window.requestAnimationFrame(render);
       }

       // 当用户调整窗口大小时重新计算参数
       function afterResize() {
           width = canvas.offsetWidth;
           height = canvas.offsetHeight;
           if (window.devicePixelRatio > 1) {
               canvas.width = canvas.clientWidth * 2;
               canvas.height = canvas.clientHeight * 2;
               ctx.scale(2, 2);
           } else {
               canvas.width = width;
               canvas.height = height;
           }
           GLOBE_RADIUS = width * 0.7;
           GLOBE_CENTER_Z = -GLOBE_RADIUS;
           PROJECTION_CENTER_X = width / 2;
           PROJECTION_CENTER_Y = height / 2;
           FIELD_OF_VIEW = width * 0.8;

           createDots(); // 重新生成所有点
       }

       // 变量用于存储用户调整窗口大小时的超时
       let resizeTimeout;

       // 当用户调整窗口大小时触发的函数
       function onResize() {
           resizeTimeout = window.clearTimeout(resizeTimeout);
           resizeTimeout = window.setTimeout(afterResize, 500);
       }

       // 监听窗口大小变化事件
       window.addEventListener('resize', onResize);

       // 初始化点数组
       createDots();

       // 渲染场景
       window.requestAnimationFrame(render);
   </script>
</body>

</html>

到了这里,关于JavaScript+canvas实现一个旋转的3D球动画效果的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 属性动画实现旋转入场效果

    属性动画和硬件加速 日常杂谈 06月07日 首先,我感觉这部分内容真的挺无聊的,没有什么让人新奇的感觉。不过为了博客的整体性,我还是想随便整理一下相关的知识和内容。 一如既往,聊聊我的日常生活,最近可能比较忙,所以可能没有那么多大段的时间来写博客。只能

    2024年02月08日
    浏览(58)
  • Canvas实现3D效果

    3D 球 效果图 代码 参考链接 https://tool.4xseo.com/a/2285.html

    2024年02月09日
    浏览(32)
  • OpenLayers入门,OpenLayers实现地图原地旋转动画效果

    专栏目录: OpenLayers入门教程汇总目录 OpenLayers实现地图原地旋转动画效果,顾名思义,就是站在原地转一圈。 使用npm安装依赖 使用Yarn安装依赖 vue项目使用请参考这篇文章:

    2024年02月13日
    浏览(52)
  • 微信小程序 - 签到打卡旋转 3D 动画功能,仿钉钉打卡签到时 “容器“ 动画翻转效果(超详细完整示例源码教程,代码简洁、丝滑流畅、示例复制即用)

    由于微信小程序的动画与普通 CSS 动画稍有不同,所以网上基本没有这方面的功能源码。 本文 实现了微信小程序开发中,类似钉钉签到打卡时的动画效果,圆形硬币形状的翻转功能, 您可以直接复制示例源码,功能都做好了只需要把你的内容放进入即可。 如下图所示,当点

    2024年02月11日
    浏览(83)
  • CSS3实现图片的3D旋转效果

    准备两张图片,尺寸一样大,本代码中是绕 Y 轴进行旋转(也可以改为 X 轴)。 先看看效果:   代码如下:

    2024年02月12日
    浏览(50)
  • VUE 实现 3D词云 旋转词云效果

     效果视频: 3D词云

    2024年02月05日
    浏览(37)
  • 利用html做一个3D 图片动态效果

    今天分享一个3D图片动态效果 不多废话上代码 在倒数第6行src=后是图片地址 可以自行更改 如有侵权请联系352648773@qq.com邮箱 插一条:如果有人想要一些好玩的脚本(vbs,bat,html)同样联系我邮箱

    2024年02月11日
    浏览(40)
  • CSS实现鼠标跟随 3D 旋转效果,让交互活起来

    一淘模板(56admin.com)给大家介绍一下如何使用CSS实现有意思的鼠标跟随 3D 旋转效果,让交互更加生动,希望对大家有所帮助! 今天,群友问了这样一个问题,如下所示的鼠标跟随交互效果,如何实现: 简单分析一下,这个交互效果主要有两个核心: 借助了 CSS 3D 的能力 元

    2024年02月10日
    浏览(87)
  • HTML + CSS + JavaScript【实战案例】 实现动画导航栏效果

    ​Hello~ 咱们今天一起来学习一个动画导航的小项目 HTML结构

    2024年02月03日
    浏览(57)
  • HTML5+CSS实现图片3D旋转效果,附音乐

    利用程序呈现图片,可以俘获一众女生的心,增加音乐可以实现图片变化的同时也带上了想要得到效果,如此一程序实乃众人之喜。 先看看程序呈现的效果,还是特别吸引人的。 先在网上爬取想要呈现的美女照片,存放在文件夹img-one,与程序路径一致。 图片像素需进行调整

    2024年02月13日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包