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轴为上方)
就是躺着看,趴着看,侧着看的区别(我是这么认为的)
还不明白就是,手机正着拍,倒着拍,旋转拍~~~