Three.js绘制点、线、面
一、综述
在计算机世界里,3D世界是由点组成,两个点能够组成一条直线,三个不在一条直线上的点就能够组成一个三角形面,无数三角形面就能够组成各种形状的物体,如下图:

我们通常把这种网格模型叫做Mesh模型。给物体贴上皮肤,或者专业点就叫做纹理,那么这个物体就活灵活现了。最后无数的物体就组成了我们的3D世界。
二、两点连成直线
在Three.js中用一个向量来表示点:
var point1 =
new THREE.Vecotr3(4,8,9);
另外也可以使用set方法,代码如下:
var point1 =
new
THREE.Vector3(); point1.set(4,8,9);
1.画一条彩色的线代码
<!
DOCTYPE html
>
<
html
>
<
head
>
<
meta
charset
="UTF-8"
>
<
title
>Three框架
</
title
>
<
script
src
="js/Three.js"
></
script
>
<
style
type
="text/css"
>
div#canvas-frame
{
border
:
none
;
cursor
:
pointer
;
width
:
100%
;
height
:
600px
;
background-color
:
#EEEEEE
;
}
</
style
>
<
script
>
var
renderer;
function
initThree() { width
=
document.getElementById(
'
canvas-frame
'
).clientWidth; height
=
document.getElementById(
'
canvas-frame
'
).clientHeight; renderer
=
new
THREE.WebGLRenderer({ antialias :
true
}); renderer.setSize(width, height); document.getElementById(
'
canvas-frame
'
).appendChild(renderer.domElement); renderer.setClearColor(
0xFFFFFF
,
1.0
); }
var
camera;
function
initCamera() { 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
}); }
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();
var
material
=
new
THREE.LineBasicMaterial( { vertexColors:
true
} );
var
color1
=
new
THREE.Color(
0x444444
), color2
=
new
THREE.Color(
0xFF0000
);
//
线的材质可以由2点的颜色决定
var
p1
=
new
THREE.Vector3(
-
100
,
0
,
100
);
var
p2
=
new
THREE.Vector3(
100
,
0
,
-
100
); geometry.vertices.push(p1); geometry.vertices.push(p2); geometry.colors.push( color1, color2 );
var
line
=
new
THREE.Line( geometry, material, THREE.LinePieces ); scene.add(line); }
function
threeStart() { initThree(); initCamera(); initScene(); initLight(); initObject(); renderer.clear(); renderer.render(scene, camera); }
</
script
>
</
head
>
<
body
onload
="threeStart();"
>
<
div
id
="canvas-frame"
></
div
>
</
body
>
</
html
>
2.画线
两点确定一条直线,要画一条直线,思路是:
- 定义一个几何体geometry用来存放两端点的坐标和颜色
- 定义线条材质
- 创建线条并加入到场景中
3.代码解析
定义点的坐标和颜色
var color1 =
new THREE.Color( 0x444444 ), color2 =
new THREE.Color( 0xFF0000
);
var p1 =
new THREE.Vector3( -100, 0, 100
);
var p2 =
new THREE.Vector3( 100, 0, -100 );
声明几何体并存放点和顶点颜色
var geometry =
new
THREE.Geometry(); geometry.vertices.push(p1); geometry.vertices.push(p2); geometry.colors.push( color1, color2 );
几何体里面有一个vertices变量,可以用来存放点。
geometry中colors表示顶点的颜色,必须材质中vertexColors等于THREE.VertexColors 时,颜色才有效,如果vertexColors等于THREE.NoColors时,颜色就没有效果了。那么就会去取材质中color的值 。
定义线条材质
var material =
new THREE.LineBasicMaterial( { vertexColors:
true } );
使用THREE.LineBasicMaterial类型来定义线条材质,它接受一个集合作为参数,其原型如下:
LineBasicMaterial( parameters )
Parameters是一个定义材质外观的对象,它包含多个属性来定义材质,这些属性是:
- Color:线条的颜色,用16进制来表示,默认的颜色是白色。
- Linewidth:线条的宽度,默认时候1个单位宽度。
- Linecap:线条两端的外观,默认是圆角端点,当线条较粗的时候才看得出效果,如果线条很细,那么你几乎看不出效果了。
- Linejoin:两个线条的连接点处的外观,默认是“round”,表示圆角。
- VertexColors:定义线条材质是否使用顶点颜色,这是一个boolean值。意思是,线条各部分的颜色会根据顶点的颜色来进行插值。
- Fog:定义材质的颜色是否受全局雾效的影响。
创建线条并加入场景
var line =
new
THREE.Line( geometry, material, THREE.LinePieces ); scene.add(line);
第一个参数是几何体geometry,里面包含了2个顶点和顶点的颜色。第二个参数是线条的材质,或者是线条的属性,表示线条以哪种方式取色。第三个参数是一组点的连接方式。
然后,将这条线加入到场景中,代码如下:
scene.add(line);
这样,场景中就会出现刚才的那条线段了。
4.线条深入理解
点由THREE.Vector3表示,Threejs中没有提供单独画点的函数,它必须被放到一个THREE.Geometry形状中,这个结构中包含一个数组vertices,这个vertices就是存放无数的点(THREE.Vector3)的数组。
三、网格面
1.右手坐标系
Threejs使用的是右手坐标系。x轴正方向向右,y轴正方向向上,z轴由屏幕从里向外。

2.画坐标平面
<!
DOCTYPE html
>
<
html
>
<
head
>
<
meta
charset
="UTF-8"
>
<
title
>Three框架
</
title
>
<
script
src
="js/Three.js"
></
script
>
<
style
type
="text/css"
>
div#canvas-frame
{
border
:
none
;
cursor
:
pointer
;
width
:
100%
;
height
:
600px
;
background-color
:
#EEEEEE
;
}
</
style
>
<
script
>
var
renderer;
function
initThree() { width
=
document.getElementById(
'
canvas-frame
'
).clientWidth; height
=
document.getElementById(
'
canvas-frame
'
).clientHeight; renderer
=
new
THREE.WebGLRenderer({ antialias :
true
}); renderer.setSize(width, height); document.getElementById(
'
canvas-frame
'
).appendChild(renderer.domElement); renderer.setClearColor(
0xFFFFFF
,
1.0
); }
var
camera;
function
initCamera() { 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
}); }
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
) );
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
; scene.add( line ); } }
function
threeStart() { initThree(); initCamera(); initScene(); initLight(); initObject(); renderer.clear(); renderer.render(scene, camera); }
</
script
>
</
head
>
<
body
onload
="threeStart();"
>
<
div
id
="canvas-frame"
></
div
>
</
body
>
</
html
>
3.代码解析
定义几何体并加入两个点。
var geometry =
new
THREE.Geometry(); geometry.vertices.push(
new THREE.Vector3( - 500, 0, 0
) ); geometry.vertices.push(
new THREE.Vector3( 500, 0, 0 ) );
这两个点决定了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 ); }
4.补充
相机的position,是相机的位置。如果把人头比作相机,那么就是人头的中心的位置。
up是头顶的方向。
lookat是眼睛,看的方向,或者说是眼睛的聚焦点。
最后要说明的是 up 和lookat这两个方向必须垂直,无论怎么设置,他们必须互相垂直。不然相机看到的结果无法预知。
另外,相机没有朝向的说法,只有lookat,就是它看到的那一个聚焦点,就像眼睛看到的聚焦点一样。