zoukankan      html  css  js  c++  java
  • rotate 3d基础

    基础

      看了岑安大大的教程学习了3d基础,之前写了篇总结,觉得写的太散废话太多,重写一篇。

      本文需要实现的效果如下:3d球

      岑安的两篇教程写的很棒,但我感觉改变下顺序或许会更好理解。

      我们把画布(此文所讲所见所得均基于canvas)的中心当做是一个空间三维系的中心,画布的x和y轴正方向分别当做三维系的x和y轴的正方向,把垂直画布向内当做z轴正方向,那么三维系大致如下图:

      我们假设空间中有个点在围绕y轴转动,那么转动的轨迹就是个圆;如果画面感强的画,可以想象出就像地球上的某个点由于地球的自转做的向心运动。那么问题来了,如果三维系里的某个点围绕y轴转动确定的角度后,能计算出转动后的三维坐标吗?

      答案是肯定的,空间上的某个点(已知三维坐标)围绕x轴y轴或者z轴转动一定角度后,都能计算出相应的三维坐标。

      过程貌似是个线性代数里的矩阵变换,数学渣渣跪...

      直接把它写在矢量类里了:

    // 矢量旋转
    Vector3.prototype.rotateX = function(angleX) {
      var cosx = Math.cos(angleX);
      var sinx = Math.sin(angleX);
      var y1 = this.y * cosx - this.z * sinx;
      var z1 = this.y * sinx + this.z * cosx;
      this.y = y1;
      this.z = z1;
    };
    
    Vector3.prototype.rotateY = function(angleY) {
      var cosy = Math.cos(angleY);
      var siny = Math.sin(angleY);
      var x1 = this.z * siny + this.x * cosy;
      var z1 = this.z * cosy - this.x * siny;
      this.x = x1;
      this.z = z1;
    };

      更近一步,空间上的某个点围绕任意轴转动一定角度,都能计算出转动后的三维坐标。有兴趣的可以参考【自己给自己题目做】:如何在Canvas上实现魔方效果

      那么就好办了,我们在三维空间初始化一些点(当做球心),随意赋给他们xyz坐标值,随意设定旋转角度,那么旋转后的xyz值也能很轻松地得到了!当然有了这些还只是成功了一半,我们的canvas只支持2d,如果支持3d问题就解决了,我们还得把三维降到二维上。我们知道,如果一个球在三维系上围绕y轴转动,球的大小是不会变化的,但是如果体现在二维上,z值越大时,球体在视觉上的体现就是越小(跟z值有关);在三维上,y值是不会变化的,但是在二维视觉上的体现不应该是这样,y值是应该变化的(跟z值有关)。另一方面,球体的任意角度视图都是一个圆形。

      于是我们需要“把z方向扁平化”,即把z轴数值的大小体现在x和y上:

    // focalLength 表示当前焦距,一般可设为一个常量
    var focalLength = 250;
    
    // 把z方向扁平化
    var scale = focalLength / (focalLength + this.z);
    this.x2 = this.garden.vpx + this.x * scale;
    this.y2 = this.garden.vpy + this.y * scale;
    this.radius = this.ballR * scale;

      z方向扁平化使得z方向的值体现在x、y和r的大小以及球的透明度等变量上,一方面由于球体的旋转我们需要时刻调整球体在三维系上的坐标,另一方面在draw的时候需要计算二维上的坐标。

      所以简单的来说:

      1. 初始化球心在三维系上的坐标以及球的颜色半径等属性(三维系原点的设定)
      2. 将三维降到二维,绘制
      3. 根据旋转角度重新计算三维坐标
      4. 将三维降到二维,绘制
      5. 反复重复

      这里还有个注意点就是每帧重绘时,根据小球在三维系的z值排个序,因为后面的会被前面的挡住,所以绘制应该有个顺序。

     

    3d标签云

      有了以上的基础,可以动手做个3d标签云。理论上3d标签云中的标签应该是个a标签,是可以点击跳转的,这里为了方便,不添加点击跳转功能了(直接在canvas上)。

      思路应该很简单,在一个球面上初始化一些点,把球换成文字就可以了。

      怎样构造球体获得坐标?充分认识到了数学的必要性...

      不懂数学,试了下觉得角度的取值有两种方法:

    • (0 <= θ <= PI && 0 <= Φ <= 2 * PI)
    • (0 <= θ <= 2 * PI && 0 <= Φ <= PI)

      可以验证x*x+y*y+z*z确实等于r*r。

      有了公式,我们可以枚举角度获得坐标。

      如果有n个点,我需要平均分配在球面上,怎么做?我们引入第二个公式:

      初始化坐标:

    var all = 100;  // 100个
    for(var i = 1; i <= all; i++) {
      var a1 = Math.acos(1 - (2 * i) / all);
      var a2 = a1 * Math.sqrt(all * Math.PI);
      var x = 150 * Math.sin(a1) * Math.cos(a2);  // r = 150
      var y = 150 * Math.sin(a1) * Math.sin(a2);
      var z = 150 * Math.cos(a1);
      garden.createBall(x, y, z);
    }
     
      其实利用这个球面公式还能做很多好看的效果,例如:3D旋转球(W·Axes)
     

    点-线-面

      有了点,根据点-线-面的原理,线和面也呼之欲出了。

      稍微动点脑筋搞点创意,就能搞点看起来炫酷(实际上没花头)的小东东。

      比如下面这样:

      或者这样: 
      再添点东西加点文字音效,表个白什么的还是不错的。
      更多demo:
      不得不感叹数学的奇妙,有时改变一个数值就能出现完全不同的效果。
      更多数学公式请参考:Famous Curves Index
     

    总结

      学习3d主要是为了做粒子特效。

      这只是很基础的入门,我也只会这么点,有更进一步兴趣的可以参考岑安当耐特W·Axes或者miloyip的博客。

      岑安的JCanvas也可以看看,添加了很多事件代理。

  • 相关阅读:
    htb系列-Web Challenges-Console
    htb系列-Web Challenges-FreeLancer
    离散数学1复习要点
    样本均值和总体均值的区别
    chapter7.参数估计
    计算机系统基础复习指北
    C语言学生信息管理系统
    数学的意义
    计算机系统基础第一章
    C语言文件读写的操作
  • 原文地址:https://www.cnblogs.com/lessfish/p/4287187.html
Copyright © 2011-2022 走看看