第1章 开启Threejs之旅

什么是three.js?

  three.js就是使用javascript 来写3D程序的意思.

提示: 好的3D应用,在腾讯开放平台上,会有一个不错的收入。腾讯开发平台是通过广告和访问量来收费的,你可以写一个好的3D应用,就能够挣一些钱了。

 

Threejs源自何方?

  它源自github的一个开源项目,的地址是: https://github.com/mrdoob/three.js。

 

Three.js目录结构:

 

 

  build目录:包含两个文件,three.js 和three.min.js 。这是three.js最终被引用的文件。一个已经压缩,一个没有压缩的js文件。

  docs目录:这里是three.js的帮助文档,里面是各个函数的api,可惜并没有详细的解释。试图用这些文档来学会three.js是不可能的。

  editor目录:一个类似3D-max的简单编辑程序,它能创建一些三维物体。

  examples目录:一些很有趣的例子demo,可惜没有文档介绍。对图像学理解不深入的同学,学习成本非常高。

  src目录:源代码目录,里面是所有源代码。

  test目录:一些测试代码,基本没用。

  utils目录:存放一些脚本,python文件的工具目录。例如将3D-Max格式的模型转换为three.js特有的json模型。

  .gitignore文件:git工具的过滤规则文件,没有用。

  CONTRIBUTING.md文件:一个怎么报bug,怎么获得帮助的说明文档。

  LICENSE文件:版权信息。

  README.md文件:介绍three.js的一个文件,里面还包含了各个版本的更新内容列表。

 

一个简单的例子:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style>canvas { width: 100%; height: 100% }</style>
    <script src="js/three.js"></script>
</head>
<body>
    <script>
        var scene = new THREE.Scene();// 构建一个场景
        var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);// 透视相机
        var renderer = new THREE.WebGLRenderer();// 渲染器
        renderer.setSize(window.innerWidth, window.innerHeight);// 设置渲染器的大小为窗口的内宽度,也就是内容区的宽度
        document.body.appendChild(renderer.domElement);
var geometry = new THREE.CubeGeometry(1,1,1); var material = new THREE.MeshBasicMaterial({color: 0x00ff00}); var cube = new THREE.Mesh(geometry, material);
scene.add(cube); camera.position.z
= 5; function render() { requestAnimationFrame(render); cube.rotation.x += 0.1; cube.rotation.y += 0.1; renderer.render(scene, camera); } render(); </script> </body> </html>

代码讲解:

  在Three.js中,要渲染物体到网页中,我们需要3个组建:场景(scene)、相机(camera)和渲染器(renderer)。有了这三样东西,才能将物体渲染到网页中去。

  场景是所有物体的容器,如果要显示一个苹果,就需要将苹果对象加入场景中。

  相机决定了场景中那个角度的景色会显示出来。相机有两种,这里用到的是透视相机(THREE.PerspectiveCamera)。

  渲染器决定了渲染的结果应该画在页面的什么元素上面,并且以怎样的方式来绘制。这里我们定义了一个WebRenderer渲染器。

  注意,渲染器renderer的domElement元素,表示渲染器中的画布,所有的渲染都是画在domElement上的,所以这里的appendChild表示将这个domElement挂接在body下面,这样渲染的结果就能够在页面中显示了。

  将一个物体添加到场景中:

  var geometry = new THREE.CubeGeometry(1,1,1); 
  var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
  var cube = new THREE.Mesh(geometry, material); 
  scene.add(cube);

  代码中出现的THREE.CubeGeometry是一个几何体。CubeGeometry是一个正方体或者长方体,究竟是什么,由它的3个参数所决定,cubeGeometry的原型如下代码所示:

CubeGeometry(width, height, depth, segmentsWidth, segmentsHeight, segmentsDepth, materials, sides)

  width:立方体x轴的长度

  height:立方体y轴的长度

  depth:立方体z轴的深度,也就是长度

  以上3个参数就能够确定一个立方体。

渲染:

  渲染应该使用渲染器,结合相机和场景来得到结果画面。实现这个功能的函数是

  renderer.render(scene, camera);

  渲染函数的原型如下:

  render( scene, camera, renderTarget, forceClear )

  各个参数的意义是:

  scene:前面定义的场景

  camera:前面定义的相机

  renderTarget:渲染的目标,默认是渲染到前面定义的render变量中

  forceClear:每次绘制之前都将画布的内容给清除,即使自动清除标志autoClear为false,也会清除。

 

  实时渲染:就是需要不停的对画面进行渲染,即使画面中什么也没有改变,也需要重新渲染。下面就是一个渲染循环:

function render() {
    cube.rotation.x += 0.1;
    cube.rotation.y += 0.1;
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

  其中一个重要的函数是requestAnimationFrame,这个函数就是让浏览器去执行一次参数中的函数,这样通过上面render中调用requestAnimationFrame()函数,requestAnimationFrame()函数又让rander()再执行一次。

 

场景、相机、渲染器之间的关系:

  场景是一个物体的容器,而相机的作用就是面对场景,在场景中取一个合适的景,把它拍下来。渲染器的作用就是将相机拍摄下来的图片,放到浏览器中去显示。

 

 

上面的示例代码是将所有代码逻辑在一段脚本中完成,当逻辑复杂一点后,就比较难读懂。所以,我们将其按照功能分解成函数,代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Three框架</title>
        <script src="js/Three.js" data-ke-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: THREE.VertexColors} );
                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 render()
            {
                renderer.clear();
                renderer.render(scene, camera);
                requestAnimationFrame(render);
            }
            function threeStart() {
                initThree();
                initCamera();
                initScene();
                initLight();
                initObject();
                render();
            }

        </script>
    </head>

    <body onload="threeStart();">
        <div id="canvas-frame"></div>
    </body>
</html>

 

posted @ 2022-07-18 15:57  何以之  阅读(235)  评论(0)    收藏  举报