three.js 坐标系、camera位置属性、点、线、面

  1. 云栖社区>
  2. 博客>
  3. 正文

three.js 坐标系、camera位置属性、点、线、面

姚飞亮 2019-01-16 14:33:56 浏览2740
展开阅读全文

three.js 坐标系、camera位置属性、点、线、面

知识补充:坐标系

右手坐标系

图中右边那个手对应的坐标系,就是右手坐标系。在Threejs中,坐标和右边的坐标完全一样。x轴正方向向右,y轴正方向向上,z轴由屏幕从里向外。

线条的深入理解

在Threejs中,一条线由材质颜色组成。

Threejs中没有提供单独画点的函数,它必须被放到一个THREE.Geometry形状中,这个结构中包含一个数组vertices,这个vertices就是存放无数的点的数组。这个表示可以如下图所示:

为了绘制一条直线,首先我们需要定义两个点,如下代码所示:

var p1 = new THREE.Vector3( -100, 0, 100);
var p2 = new THREE.Vector3( 100, 0, -100);

请大家思考一下,这两个点在坐标系的什么位置,然后我们声明一个THREE.Geometry,并把点加进入,代码如下所示:

THREE.Geometry形状

var geometry = new THREE.Geometry();
geometry.vertices.push(p1);
geometry.vertices.push(p2);

THREE.LineBasicMaterial线材质

geometry.vertices的能够使用push方法,是因为geometry.vertices是一个数组。这样geometry 中就有了2个点了。
然后我们需要给线加一种材质,可以使用专为线准备的材质,THREE.LineBasicMaterial
最终我们通过THREE.Line绘制了一条线,如下代码所示:

var material = new THREE.LineBasicMaterial( { color: 0x0000ff } );
var line = new THREE.Line(geometry,material);

也可以写成

var geometry = new THREE.Geometry();
  geometry.vertices.push(new THREE.Vector3(-100, 0, 100);
  geometry.vertices.push(new THREE.Vector3(100, 0, -100);
  var material = new THREE.LineBasicMaterial( { color: 0x0000ff } );
  var color1 = new THREE.Color( 0x444444 ),
color2 = new THREE.Color( 0xFF0000 );
geometry.colors.push( color1, color2 );
  var line = new THREE.Line(geometry,material);

画坐标平面


它横竖分别绘制了20条线段,在摄像机的照射下,就形成了这般模样。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Three框架</title>
    <style>
        body { margin: 0; }
        canvas { width: 100%; height: 100% }
    </style>
    <script src="/javascripts/three.min.js"></script>

</head>
<body>
<script>
  var renderer;
  function initThree() {
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setClearColor(0xFFFFFF, 1.0);
    document.body.appendChild( renderer.domElement );
  }
  var camera;
  function initCamera() {
    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.z = 0;
    camera.position.x = 0;
    camera.position.y = 1000;
    camera.rotation.x = -89.5 ;
  }
  var scene;
  function initScene() {
    scene = new THREE.Scene();
  }
  var light;
  function initLight() {
    light = new THREE.DirectionalLight(0xFF0000, 1.0, 0);
    light.position.set(100, 100, 200);
    scene.add(light);
  }
  var cube;
  function initObject() {
    var geometry = new THREE.Geometry();
    geometry.vertices.push( new THREE.Vector3( -500, 0, 0 ) );
    geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );
    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x0000ff, opacity: 0.2 } ) );
    scene.add( line );
    for ( var i = 0; i <= 20; i ++ ) {
      var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x0000ff, opacity: 0.2 } ) );
      line.position.z = ( i * 50 ) - 500;
      scene.add( line );
      var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x0000ff, opacity: 0.2 } ) );
      line.position.x = ( i * 50 ) - 500;
      line.rotation.y = 90 * Math.PI / 180;
      scene.add( line );
    }
  }
  function threeStart() {
    initThree();
    initCamera();
    initScene();
    initLight();
    initObject();
    renderer.clear();
    renderer.render(scene, camera);
  }
  threeStart();
</script>
</body>
</html>

画网格关键之处initObject函数中,我们不浪费纸,但是浪费一些电,在下面重复一下上面的代码:

var cube;
  function initObject() {
    var geometry = new THREE.Geometry();
    geometry.vertices.push( new THREE.Vector3( -500, 0, 0 ) );
    geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );
    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x0000ff, opacity: 0.2 } ) );
    scene.add( line );
    for ( var i = 0; i <= 20; i ++ ) {
      var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x0000ff, opacity: 0.2 } ) );
      line.position.z = ( i * 50 ) - 500;
      scene.add( line );
      var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x0000ff, opacity: 0.2 } ) );
      line.position.x = ( i * 50 ) - 500;
      line.rotation.y = 90 * Math.PI / 180;
      scene.add( line );
    }
  }

思路:我们要画一个网格的坐标,那么我们就应该找到线的点。把网格虚拟成正方形,在正方形边界上找到几个等分点,用这些点两两连接,就能够画出整个网格来。

1、定义2个点

在x轴上定义两个点p1(-500,0,0),p2(500,0,0)。

geometry.vertices.push( new THREE.Vector3( -500, 0, 0 ) );
geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );

2、算法

这两个点决定了x轴上的一条线段,将这条线段复制20次,分别平行移动到z轴的不同位置,就能够形成一组平行的线段。
同理,将p1p2这条线先围绕y轴旋转90度,然后再复制20份,平行于z轴移动到不同的位置,也能形成一组平行线。
经过上面的步骤,就能够得到坐标网格了。代码如下:

for ( var i = 0; i <= 20; i ++ ) {
    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
    line.position.z = ( i * 50 ) - 500;
    scene.add( line );
    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
    line.position.x = ( i * 50 ) - 500;
    line.rotation.y = 90 * Math.PI / 180;   //  旋转90度
    scene.add( line );
}

相机camera位置属性设置up、position、lookat

看了中文文档很早之前的例子

camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 0;
                camera.position.y = 1000;
                camera.position.z = 0;
                camera.up.x = 0;
                camera.up.y = 0;
                camera.up.z = 1;
                camera.lookAt({
                    x : 0,
                    y : 0,
                    z : 0
                });

开始很懵逼,完全不能理解,有个position,还要up和lookAt干嘛。
自己换了个方式实现

 camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.z = 0;
    camera.position.x = 0;
    camera.position.y = 1000;
    camera.rotation.x = -89.5 ;

既然是位置属性不明白,还是要端正学习态度,把它搞懂。
上坐标轴:

先来第一个position属性,可以设置xyz。
假设设置y为 1000
position(0,1000,0);
相机的位置是下图:

单独设置xz轴都和以上类似,位置z或者x轴某个位置。
那lookAt,字面上的意思就是,看向哪里。
相机默认是由正z轴看像-z轴(相机镜头对着-z轴方向拍),就是我们由屏幕外向屏幕内看一样。

camera.lookAt({//相机看向哪个坐标
                    x : 0,
                    y : 0,
                    z : 0
                });

以下为实例为 相机看向原点0,0,0。(相机位置position(500,500,1000))

以下为不设置lookAt

因为相机的位置在x轴500上,y轴500,z轴1000。默认是看向-z轴,所以只能看到y轴500位置的线条了。
那up属性又是什么鬼,相机位置代码如下设置情况下:

camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 500;//相机的位置
                camera.position.y = 500;
                camera.position.z = 1000;
//                camera.up.x = 0;//相机以哪个方向为上方
//                camera.up.y = 1;
//                camera.up.z = 0;
                camera.lookAt({//相机看向哪个坐标
                    x : 0,
                    y : 0,
                    z : 0
                });


 

一切正常。
加个up属性试试:

camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 500;//相机的位置
                camera.position.y = 500;
                camera.position.z = 1000;
                camera.up.x = 0;//相机以哪个方向为上方
                camera.up.y = 0;
                camera.up.z = 1;
                camera.lookAt({//相机看向哪个坐标
                    x : 0,
                    y : 0,
                    z : 0
                });

代码设置z轴为1,表示以z轴为相机的上方。(默认y轴为上方)
就是躺着看,趴着看,侧着看的区别(我是这么认为的)
还不明白就是,手机正着拍,倒着拍,旋转拍~~~

网友评论

登录后评论
0/500
评论
姚飞亮
+ 关注