Three.js绘制点、线、面

时间:2021-10-29 06:37:14

一、综述

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

Three.js绘制点、线、面

  我们通常把这种网格模型叫做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轴由屏幕从里向外。

Three.js绘制点、线、面

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,就是它看到的那一个聚焦点,就像眼睛看到的聚焦点一样。

 

四、出处

刚接触Three.js,这算是记录网上找资料学习的笔记,主要来源于WebGL中文网,如有侵权,请联系我删除。