目标
- 绘制点、线、面
- 绘制复杂图形
3D世界
在计算机的世界里,3D世界是由 点组成 ,两点成一线,三个不在一条直线上的点就能组成一个三角形面,无数个三角形面就能组成各种形状的物体。(计算机图形的理论知识)
通常把这种网络模型叫做 Mesh 模型。给物体贴上皮肤(纹理),那么这个物体就实际展现出来了。然后无数个这样的物体就组成了 3D 世界。
Threejs绘制一个点
1、定义
在三维空间中的某一个点可以用一个坐标点来表示。一个坐标点有 (x,y,z) 三个分量构成(齐次坐标)。在 three.js 中,点可以在 右手坐标系 中表示:
空间几何中,点可以用一个向量表示,在 three.js 中也是用一个向量表示的,代码如下:
1 2 3 4 5 |
THREE.Vector3 = function ( x, y, z ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; }; |
其中的 THREE.Vector3 表示 Vector3 是定义在 THREE 下面的一个类。使用 Vector3 必须加前缀 THREE。
THREE.Vector3 被赋值为一个函数。这个函数有三个参数(如上代码),分别为 x 坐标、y 坐标、 z 坐标的分量。
2、点操作
在 Threejs 的 3D 世界中,点可以用 THREE.Vector3 来表示。(对应地址源码/src/math/Vector3.js ,版本不同地址可能不同)
假设有一个点 x=4, y=8, z=9。将这样定义:
1 2 3 4 5 6 |
var point1 = new THREE.Vector3( 4, 8, 9 ); 或者 var point1 = new THREE.Vector3(); point1.set( 4, 8, 9); |
Threejs绘制一条线
效果:
理论上:两个不重合的点能够决定一条线。在 Threejs 中,可是如此。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
<!DOCTYPE html> <html> <head> <title>line</title> <meta charset="UTF-8"> <style type="text/css"> div#canvas-frame { border: none; cursor: pointer; width: 100%; height: 600px; background-color: #EEEEEE; } </style> <script src="js/Three.js"></script> <script> function threeStart() { var renderer, scene, camera, light, stats; var objects = []; var WIDTH = document.getElementById( 'canvas-frame' ).clientWidth; var HEIGHT = document.getElementById( 'canvas-frame' ).clientHeight; init(); animate(); function init() { // Init Renderer // 0xFFFFFF - White renderer = new THREE.WebGLRenderer({ antialias : true }); renderer.setSize( WIDTH, HEIGHT ); document.getElementById( 'canvas-frame' ).appendChild( renderer.domElement ); renderer.setClearColor( 0xFFFFFF, 1.0 ); // Init Camera 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( 0, 0, 0 ); // Init Scene // 0x111111 - like Black scene = new THREE.Scene(); // scene.background = new THREE.Color( 0x111111 ); // scene.fog = new THREE.Fog( 0x111111, 150, 200 ); var subdivisions = 6; var recursion = 1; // Init Light var light = new THREE.DirectionalLight( 0xFF0000, 1.0, 0 ); light.position.set( 100, 100, 200 ); scene.add( light ); // Init Object var geometry = new THREE.Geometry(); var material = new THREE.LineBasicMaterial({ vertexColors: true }); // 0xFF0000 - Red // 0x0033FF - Blue var color1 = new THREE.Color( 0x0033FF ), color2 = new THREE.Color( 0xFF0000 ); var point1 = new THREE.Vector3( -100, 0, 100 ), point2 = new THREE.Vector3( 100, 0, -100 ); geometry.vertices.push( point1 ); geometry.vertices.push( point2 ); geometry.colors.push( color1, color2 ); var line = new THREE.Line( geometry, material, THREE.LineSegments ); scene.add( line ); } function animate() { renderer.clear(); renderer.render( scene, camera ); } } </script> </head> <body onload="threeStart();"> <div id="canvas-frame"></div> </body> </html> |
代码解析:
1、声明一个几何体 Geometry
1 |
var geometry = new THREE.Geometry(); |
几何体里面有一个 vertices 变量,可以用以存放点。
2、定义线条材质,使用 THREE.LineBasicMaterial 类型定义,它接受一个集合作为参数
1 2 3 4 5 6 7 8 9 10 11 12 |
// Original LineBasicMaterial( parameters ) // parameters define lines material color: 线条的颜色,用16进制表示,默认白色 linewidth: 线条的宽度,默认1个单位宽度 linecap: 线条两段外观,默认圆角端点 linejoin: 两个线条的连接点处外观,默认round即圆角 vertexColors: 定义线条材质是否使用顶点颜色,boolean值,即线条各部分的颜色会根据顶点的颜色来进行插值 fog: 定义材质的颜色是否受全局雾效影响 // Example var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); |
3、定义2个顶点位置并放入 geomotry
1 2 3 4 5 |
var point1 = new THREE.Vector3( -100, 0, 100 ); point2 = new THREE.Vector3( 100, 0, -100 ); geometry.vertices.push( point1 ); geometry.vertices.push( point2 ); |
4、为定义的2个顶点设置不同的颜色
1 2 3 4 |
var color1 = new THREE.Color( 0x0033FF ); color2 = new THREE.Color( 0xFF0000 ); geometry.colors.push( color1, color2 ); |
geometry 中的 colors 表示顶点的颜色,必须材质中 vertexColors 等于 THREE.VertexColors 时,颜色才有效果,如果 vertexColors 等于 THREE.NoColors 时,就没有效果了。这时就会取材质中 color 的值。
5、定义一条线
定义线条,使用 THREE.Line 类,代码如下:
1 2 3 4 5 6 7 |
var line = new THREE.Line( geometry, material, THREE.LineSegments ); // 不同版本不一样的参数,102版本THREE.LineSegments // geometry : 几何体,里面包含了两个顶点和顶点的颜色 // material : 线条的材质 / 线条的属性 // THREE.LineSegments : 一组点的连接方式 scene.add( line ); // 场景添加线段 |
后记
A、线条再解析
在 Threejs 中,一条线由 点、材质和颜色 组成。
点由 THREE.Vector3 表示,但是因为 Threejs 中没有直接单独绘制点的函数,所以必须放到一个 THREE.Geometry 中,这个结构包含了一个 vertices 数组,这个参数就是用于存放无数多个点的数组。
为了绘制一条直线,首先需要定义两个点:
1 2 |
var point1 = new THREE.Vector3( -100, 0, 100 ); var point2 = new THREE.Vector3( 100, 0, -100 ); |
然后声明一个 THREE.Geometry 结构体,并把点放进去:
1 2 3 4 |
var geometry = new THREE.Geometry(); geometry.vertices.push( point1 ); geometry.vertices.push( point2 ); |
geometry.vertices 可以使用 push 方法,是因为这个参数是一个数组。
下一步就是需要给这个线段添加一种材质,可以使用转为线准备的材质结构:THREE.LineBasicMaterial
最终通过 THREE.Line 绘制一条线:
1 |
var line = new THREE.Line( geometry, material, THREE.LineSegments ); |
B、坐标平面
效果:
不说废话,献上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
<!DOCTYPE html> <html> <head> <title>plane</title> <meta charset="UTF-8"> <style type="text/css"> div#canvas-frame { border: none; cursor: pointer; width: 100%; height: 800px; background-color: #EEEEEE; } </style> <script src="js/Three.js"></script> <script> function threeStart() { var renderer, scene, camera, light; var geometry; var WIDTH = document.getElementById( 'canvas-frame' ).clientWidth; var HEIGHT = document.getElementById( 'canvas-frame' ).clientHeight; init(); animate(); function init() { // Init Renderer renderer = new THREE.WebGLRenderer({ antialias : true }); renderer.setSize( WIDTH, HEIGHT ); document.getElementById( 'canvas-frame' ).appendChild( renderer.domElement ); renderer.setClearColor( 0xFFFFFF, 1.0 ); // Init Camera camera = new THREE.PerspectiveCamera( 45, WIDTH / HEIGHT, 1, 10000); camera.position.set( 0, 1000, 0 ); camera.up.set( 0, 0, 1 ); camera.lookAt( 0, 0, 0 ); // Init Scene scene = new THREE.Scene(); scene.backgorund = new THREE.Color( 0x111111 ); // Init Light light = new THREE.DirectionalLight( 0xFFFFFF, 1.0, 0 ); light.position.set( 100, 100, 200 ); scene.add( light ); // Init Object - coordination 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 animate() { renderer.clear(); renderer.render( scene, camera ); } } </script> </head> <body onload="threeStart();"> <div id="canvas-frame"></div> </body> </html> |
解析:
最终要的部分就是 // Init Object – coordination 绘制部分的算法了
实际只是定义了一条参考线段( point1, point2 ),通过操作,复制20次:平移到z轴不同位置,形成一组平行的线段;同理围绕y轴旋转90度,平移到x轴不同的位置,形成另一组平行线段。
经过这些操作,最终绘制出坐标网格。
1 2 3 4 5 6 7 8 9 10 11 12 |
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 ); } |