你好获取登录信息中




首页 主站 文章列表 分类列表
查看文章返回文章列表

three教程:鼠标控制

发布时间:2016-08-08 19:51:52 by:



>上一部分的three.js教程还是很久前写的,因为种种原因一直没有更新了(放心,除了这次的教程,还至少会有一篇的,大部分代码我是早就写好测试过了的,更新上来只是迟早的事,以后可能还会对前面几篇做一些调整,一是解决一些没讲清的地方,顺便加入几张图片便于。

好了,看看我们上次讲到哪了,先回顾下上次的代码吧,如果我没弄错,现在文件基本上是这样了:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>webgl互交测试</title>
  6. <style>
  7. *{
  8. padding: 0;
  9. margin: 0;
  10. }
  11. #b{
  12. width: 200px;
  13. height: 500px;
  14. background: #000;
  15. }
  16. </style>
  17. </head>
  18. <body>
  19. <div id="b">
  20. <div id="canvas-frame"></div>
  21. </div>
  22. <script src="three-js/build/three.js" data-ke-src="https://raw.github.com/mrdoob/three.js/master/build/three.js"></script>
  23. <script src="three-js/examples/js/libs/stats.min.js"></script>
  24. <script>
  25. function mythree(id){
  26. this.dom=document.getElementById(id);
  27. this.dom.style.width=window.innerWidth+"px";
  28. this.dom.style.height=window.innerHeight+"px";
  29. this.scene = new THREE.Scene();//场景
  30. this.camera=new THREE.PerspectiveCamera(75, this.dom.offsetWidth / this.dom.offsetHeight, 0.1, 1000);
  31. this.camera.position.set(0,200,0);
  32. this.camera.lookAt(this.scene.position);
  33. this.renderer = new THREE.WebGLRenderer();//渲染器
  34. this.renderer.setSize(this.dom.offsetWidth,this.dom.offsetHeight);//设置渲染器大小
  35. this.renderer.setClearColorHex(0x000000, 1);//设置渲染器颜色
  36. this.dom.appendChild(this.renderer.domElement);
  37. this.stats = new Stats();
  38. this.stats.domElement.style.position = 'absolute';
  39. this.stats.domElement.style.left = '0px';
  40. this.stats.domElement.style.top = '0px';
  41. this.dom.appendChild(this.stats.domElement);
  42. this.rander=(function (obj){
  43. return function(){
  44. obj.renderer.render(obj.scene, obj.camera);//渲染
  45. requestAnimationFrame(obj.rander);
  46. obj.stats.update();
  47. }
  48. })(this);
  49. this.rander();
  50. }
  51. var mt=new mythree('b');
  52. var light = new THREE.DirectionalLight(0xffffff,1.0,0); //设置平行光源
  53. light.position.set(200,100,200); //设置光源向量
  54. mt.scene.add(light); //追加光源到场景
  55. var c=new THREE.Mesh(
  56. new THREE.CubeGeometry(40,40,40),
  57. new THREE.MeshLambertMaterial({color: 0x0088ff})
  58. );//创建实物
  59. c.position.set(0,0,0);
  60. mt.scene.add(c);
  61. window.onkeydown=function(ev){
  62. //alert(ev.keyCode);
  63. switch(ev.keyCode){
  64. case 65:
  65. mt.camera.position.z++;
  66. break;
  67. case 68:
  68. mt.camera.position.z--;
  69. break;
  70. case 87:
  71. mt.camera.position.x--;
  72. break;
  73. case 83:
  74. mt.camera.position.x++;
  75. break;
  76. }
  77. }
  78. </script>
  79. </body>
  80. </html>

接下来应该是通过键盘控制摄像机移动了吧,那我们接下来试试让它接受鼠标的控制改变视角(控制参照某些游戏,比如mc)。

首先我们需要弄清楚怎样控制摄像头的旋转:在three.js中,很多对象都有rotation属性,他是一个用于控制旋转对象,下面有x、y、z三个方向的旋转。不过在动工前,首先弄清一个关于它旋转方式的问题要少走很多的弯路。当是我没弄清这个,写了一段更复杂的js,然后发现效果不对(我的脖子怎么断了啊喂)。弄清它这个旋转是以自身坐标系的轴为中心旋转,并且这个坐标系会随着前面设定的参数而旋转,并不是一个固定的坐标系。

明白了它的旋转方式,我们应该知道了不同轴的旋转顺序会影响旋转效果,可以参考这张图:

旋转顺序不同的区别

画的丑了点,轻喷(昨天画这个耽误了好多时间)。

然后我们来看看我们应该怎么做吧:首先,左右移动鼠标这个“摄像头”也应该向左或向右看,那么就是绕着y轴旋转;上下移动鼠标则应该是上下看的效果,这似乎X轴和Z轴的旋转都会要,但是仔细想想之前说到了两个关键问题,首先,这个旋转是按照一定顺序依次绕三个轴旋转,并且整个坐标系也会跟着转,那么的话,如果我们让Y轴的转动最先转(实际上如果先转动了其他的轴左右转的部分也会需要调整)的话,上下看就只有X方向需要调整了。(当然如果要实现的话,办法还是很多,的我这里取了一种比较简单的方法,建议自己仔细思考下这个旋转的问题,前面几次写出来发现控制变得很迷也没有什么关系,你自己那个长方体模拟一下看看发生了什么会有一些帮助,另外默认的旋转顺序是先X轴再Y轴最后Z轴)。

接下来我们就该看看怎么样改变旋转顺序:我们可以发现一个叫eulerOrder的属性,它就是用来设置旋转顺序的。我们按如下方法实现:

  1. mt.camera.eulerOrder='YXZ';

接下里就是实现鼠标的控制,我们首先定义一个变量,它将用于存放上一次鼠标指针的位置,然后监听鼠标onmousemove事件,计算出鼠标移动的方向和距离然后然后让把这个值加到rotation上去就好了,当然在此之前你需要自己是;试一下它究竟是顺时针旋转还是逆时针旋转,这个不是很难,就留给大家自己试一试了,我这里也给出了一个示例代码片段:

  1. list=null;
  2. mt.dom.onmousemove=function(ev){
  3. if(!ev.x) ev.x=ev.layerX;//兼容火狐等浏览器
  4. if(!ev.y) ev.y=ev.layerY;
  5. if(list){
  6. mt.camera.rotation.y-=(ev.x-list.x)*0.01;
  7. mt.camera.rotation.x-=(ev.y-list.y)*0.01;
  8. }
  9. list={x:ev.x,y:ev.y};
  10. }

为了更好的检测我们的代码,我们在场景中增加一些东西之类的调整这样更能看词效果来(我可以比较轻松的移动到一个合适的角度,当然方向控制现在还有问题,因为我们的前后左右都改变了):

效果图

附上我的最终代码(注意有些地方调整了,虽然没有在教程中说我改过,不过用到的对象和函数应该都是讲过的,就不多说了。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>webgl互交测试2</title>
  6. <style>
  7. *{
  8. padding: 0;
  9. margin: 0;
  10. }
  11. #b{
  12. width: 200px;
  13. height: 500px;
  14. background: #000;
  15. }
  16. </style>
  17. </head>
  18. <body>
  19. <div id="b">
  20. <div id="canvas-frame"></div>
  21. </div>
  22. <script src="three-js/build/three.js" data-ke-src="https://raw.github.com/mrdoob/three.js/master/build/three.js"></script>
  23. <script src="three-js/examples/js/libs/stats.min.js"></script>
  24. <script>
  25. function mythree(id){
  26. this.dom=document.getElementById(id);
  27. this.dom.style.width=window.innerWidth+"px";
  28. this.dom.style.height=window.innerHeight+"px";
  29. this.scene = new THREE.Scene();//场景
  30. this.camera=new THREE.PerspectiveCamera(75, this.dom.offsetWidth / this.dom.offsetHeight, 0.1, 1000);
  31. this.camera.position.set(0,200,0);
  32. //this.camera.lookAt(this.scene.position);
  33. this.renderer = new THREE.WebGLRenderer();//渲染器
  34. this.renderer.setSize(this.dom.offsetWidth,this.dom.offsetHeight);//设置渲染器大小
  35. this.renderer.setClearColorHex(0x000000, 1);//设置渲染器颜色
  36. this.dom.appendChild(this.renderer.domElement);
  37. //document.body.appendChild(this.renderer.domElement);
  38. //this.camera.position.z = 180;//设置相机位置
  39. this.stats = new Stats();
  40. this.stats.domElement.style.position = 'absolute';
  41. this.stats.domElement.style.left = '0px';
  42. this.stats.domElement.style.top = '0px';
  43. this.dom.appendChild(this.stats.domElement);
  44. this.rander=(function (obj){
  45. return function(){
  46. obj.renderer.render(obj.scene, obj.camera);//渲染
  47. requestAnimationFrame(obj.rander);
  48. obj.stats.update();
  49. }
  50. })(this);
  51. this.rander();
  52. /*this.renderer.domElement.onmousemove=function(ev){
  53. alert(4)
  54. }*/
  55. }
  56. var mt=new mythree('b');
  57. var light = new THREE.DirectionalLight(0xffffff,1.0,0); //设置平行光源
  58. light.position.set(200,100,150); //设置光源向量
  59. mt.scene.add(light); //追加光源到场景
  60. var ca=new THREE.Mesh(
  61. new THREE.CubeGeometry(40,100,40),
  62. new THREE.MeshLambertMaterial({color: 0x0088ff})
  63. );//创建实物
  64. ca.position.set(0,0,0);
  65. mt.scene.add(ca);
  66. c=new THREE.Mesh(
  67. new THREE.CubeGeometry(1,400,400),
  68. new THREE.MeshLambertMaterial({color: 0x0088ff})
  69. );//创建实物
  70. c.position.set(-200,200,0);
  71. mt.scene.add(c);
  72. c=new THREE.Mesh(
  73. new THREE.CubeGeometry(400,1,400),
  74. new THREE.MeshLambertMaterial({color: 0x0088ff})
  75. );//创建实物
  76. c.position.set(0,-1,0);
  77. mt.scene.add(c);
  78. c=new THREE.Mesh(
  79. new THREE.CubeGeometry(400,400,1),
  80. new THREE.MeshLambertMaterial({color: 0x0088ff})
  81. );//创建实物
  82. c.position.set(0,200,-200);
  83. mt.scene.add(c);
  84. window.onkeydown=function(ev){
  85. //alert(ev.keyCode);
  86. switch(ev.keyCode){
  87. case 65:
  88. mt.camera.position.x--//=Math.sin();
  89. break;
  90. case 68:
  91. mt.camera.position.x++;
  92. break;
  93. case 87:
  94. mt.camera.position.z--;
  95. break;
  96. case 83:
  97. mt.camera.position.z++;
  98. break;
  99. }
  100. }
  101. list=null;
  102. mt.camera.eulerOrder='YXZ';//修改旋转顺序 默认为xyz
  103. //这一步可以使得绕x轴旋转时参考已经旋转的y轴的量(相当于让x轴也随y轴旋转了),能减少后续工作
  104. //不做这一步还会出现很多问题
  105. mt.dom.onmousemove=function(ev){
  106. if(!ev.x) ev.x=ev.layerX;
  107. if(!ev.y) ev.y=ev.layerY;
  108. if(list){
  109. mt.camera.rotation.y-=(ev.x-list.x)*0.01;
  110. mt.camera.rotation.x-=(ev.y-list.y)*0.01;
  111. }
  112. list={x:ev.x,y:ev.y};
  113. }
  114. </script>
  115. </body>
  116. </html>
评论
    还没有评论
发表评论
正在等候用户中心返回数据
杂项
。。。