1 ThreeJs 的第一个demo

首先,本人不是专业的WebGl开发工程师,也没有任何计算机图形学和WebGl基础,更不是开发前端的,只是一个刚刚参加工作的小白菜。
从今天开始起,我将把自己对 ThreeJs 的学习记录分享给大家。虽然并不专业,但也是自己的一些见解,也许以后再来回顾,或许会有一些不同的体会。
这个系列没有结束,但凡自己以后在工作中遇到问题都会分享在此博客,谈一下自己的思路和寻找的资料的总结,总之,加油!
本篇demo的浏览地址:http://www.ithanmang.com/threejshome/20180622/01-helloworld.html
这里写图片描述
然后我们来看示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>three hello world!</title>
    <style>
        body{
            margin: 0;
            overflow: hidden;
        }
    </style>
    <script src="../libs/build/three.js"></script>
    <script src="../libs/jquery-1.9.1.js"></script>
    <script src="../libs/examples/js/controls/TrackballControls.js"></script>
    <script src="../libs/examples/js/libs/dat.gui.min.js"></script>
    <script src="../libs/examples/js/libs/stats.min.js"></script>
</head>
<body>

<div id="WebGL-output"></div>
<div id="Stats-output"></div>

<script>

    $(function () {
        // 初始化性能插件
        var stats = initStats();
        // 创建场景
        var scene = new THREE.Scene();
        // 创建相机--透视相机
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
        // 创建WebGl渲染器
        var webGlRenderer = new THREE.WebGLRenderer();

        // 配置渲染器
        webGlRenderer.antialias = true;// 抗锯齿
        webGlRenderer.autoClear = true;// 自动清除
        webGlRenderer.setClearColor( 0x050505 );// 渲染背景色
        webGlRenderer.setSize( window.innerWidth, window.innerHeight);// 渲染范围

        // 配置相机
        camera.position.set(0, 400, 800);// 相机在三维空间的位置
        camera.lookAt(new THREE.Vector3(0, 0, 0));// 相机看向空间坐标原点

        // 创建立方体
        var cubeGeometry = new THREE.CubeGeometry(100, 100, 100);// 立方体模型
        var cubeMaterial = new THREE.MeshLambertMaterial({color : Math.random() * 0xffffff});// 立方体材质,颜色为随机色
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 创建网格实例
        cube.position.y = 90;// 立方体的 y 坐标 +90
        // 将立方体加入场景
        scene.add(cube);

        // 创建光源 ambientLight:环境光、directionalLight:平行光
        var ambientLight = new THREE.AmbientLight( 0x404040 );
        var directionalLight1 = new THREE.DirectionalLight( 0xC0C090 );
        var directionalLight2 = new THREE.DirectionalLight( 0xC0C090 );
        // 设置光源的位置
        directionalLight1.position.set(-300, -400, 300);
        directionalLight2.position.set(300, 400, -300);
        // 将光源加入场景
        scene.add(ambientLight);
        scene.add(directionalLight1);
        scene.add(directionalLight2);

        // 创建网格辅助
        var gridHelper = new THREE.GridHelper(1200, 50, 0xFF4444, 0x404040 );
        scene.add( gridHelper );

        // 创建轨迹球控件
        var trackballControls = new THREE.TrackballControls(camera, webGlRenderer.domElement);

        // 加入图形调试控件中的组件 gui
        var controls = new function () {
            this.rotationSpeed = 0.02;
            this.wireframe = cubeMaterial.wireframe;
            this.color = cubeMaterial.color.getStyle();
            this.gridHelper = false;
            this.backGround = webGlRenderer.getClearColor().getHex();
        }
        // 创建图形调试控件
        var gui = new dat.GUI();

        // 创建 helperGui 目录,下面包含 gridHelper 组件
        var helperGui = gui.addFolder('Helper');
        helperGui.add(controls,'gridHelper').onChange(function (e) {
            console.log(e);
            if (e){
                scene.remove(gridHelper);
            }else{
                scene.add(gridHelper);
            }
        });

        // 创建 meshGui 目录, 目录下包含组件 wireframe、color、rotationSpeed
        var meshGui = gui.addFolder("Mesh");
        meshGui.add(controls,'wireframe').onChange(function (e) {
            cubeMaterial.wireframe = e;
        });
        meshGui.addColor(controls,'color').onChange(function (e) {
            cubeMaterial.color.setStyle(e);
        })
        meshGui.add(controls,'rotationSpeed',0, 0.1);

        // 创建 sceneGui 目录, 目录下包含 backGround 组件
        var sceneGui = gui.addFolder('Scene');
        sceneGui.addColor(controls,'backGround').onChange(function (e) {
            webGlRenderer.setClearColor(e)
        })

        // 将渲染器添加到画布
        $("#WebGL-output").append(webGlRenderer.domElement);

        // 窗口大小改变触发的方法
        function onWindowResize() {
            // 改变相机的 aspect 为窗口的宽和长度之比
            camera.aspect = window.innerWidth / window.innerHeight;
            // 更新相机的投影矩阵
            camera.updateProjectionMatrix();
            // 重新设置渲染器的大小
            webGlRenderer.setSize(window.innerWidth, window.innerHeight);
        }
        // 添加事件监听
        window.addEventListener('resize',onWindowResize,false);

        // 初始化性能插件方法
        function initStats() {
            var stats = new Stats();

            stats.setMode(0);// 0:现实fps, 1:ms

            // 调整插件布局
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            // 加入画布
            $("#Stats-output").append(stats.domElement);
            // 将初始化的插件返回
            return stats;
        }

        // 渲染方法
        function render() {
            // 更新性能插件
            stats.update();

            // 立方体绕 x、y、z 轴旋转,速度由调试插件控制
            cube.rotation.x += controls.rotationSpeed;
            cube.rotation.y += controls.rotationSpeed;
            cube.rotation.z += controls.rotationSpeed;

            // 更新轨迹球控件的操作范围
            trackballControls.handleResize();
            // 更新物体位置
            trackballControls.update();
            // 开始渲染
            webGlRenderer.render(scene, camera);
        }
        // 实现动画效果
        function animate() {
            requestAnimationFrame(animate);
            render();
        }
        animate();
    });

</script>

</body>
</html>
代码分析

这个简单的demo实现了三维尝尽scene 的创建,加入了灯光和鼠标控制,并且添加了性能插件 stats 和 调试插件 datGUI 来控制立方体的颜色和材质的变换,以及加入了网格辅助对象,来清晰的看到立方体所处的位置。

threejs主要元素
  • 场景 (scene)
  • 相机(camera)
  • 渲染器(render)
    以上三个元素 是最主要的部分,然后来看实例中的部分代码。
  • 场景

    // 创建场景
    var scene = new THREE.Scene();
  • 相机

    // 创建相机--透视相机
    var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);

    并且对相机进行了配置

    // 配置相机
    camera.position.set(0, 400, 800);// 相机在三维空间的位置
    camera.lookAt(new THREE.Vector3(0, 0, 0));// 相机看向空间坐标原点
  • 渲染器

     // 创建WebGl渲染器
     var webGlRenderer = new THREE.WebGLRenderer();

    此处创建的是WebGL渲染器,threejs还有逼的渲染器,可以根据具体情况来选择
    对渲染器进行配置

    // 配置渲染器
    webGlRenderer.antialias = true;// 抗锯齿
    webGlRenderer.autoClear = true;// 自动清除
    webGlRenderer.setClearColor( 0x050505 );// 渲染背景色
    webGlRenderer.setSize( window.innerWidth, window.innerHeight);// 渲染范围

    此时三维场景就已经搭建完成,但是当我们运行代码的时候发现发现浏览器一片黑白,因为我们只是创建了三维场景所必须的组件,并没有开始渲染。

  • 开始渲染

    // 首先需要将渲染器添加到画布
    $("#WebGL-output").append(webGlRenderer.domElement);
    // 开始渲染
    webGlRenderer.render(scene, camera);

    上面webGlRenderer.render(scene, camera);是渲染器将场景和相机结合到一起,然后开始进行执行渲染操作。
    当我们再次执行的时候发现浏览器还是什么都没有,因为并没有向场景中添加对象,下面创建一个立方体,并将其加入到场景之中。

  • 创建立方体

    // 创建立方体
    var cubeGeometry = new THREE.CubeGeometry(100, 100, 100);// 立方体模型
    var cubeMaterial = new THREE.MeshLambertMaterial({color : Math.random() * 0xffffff});// 立方体材质,颜色为随机色
    var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);// 创建网格实例
    cube.position.y = 90;// 立方体的 y 坐标 +90
    // 将立方体加入场景
    scene.add(cube);
  • 还需要创建灯光

    // 创建光源 ambientLight:环境光、directionalLight:平行光
    var ambientLight = new THREE.AmbientLight( 0x404040 );
    var directionalLight1 = new THREE.DirectionalLight( 0xC0C090 );
    var directionalLight2 = new THREE.DirectionalLight( 0xC0C090 );
    // 设置光源的位置
    directionalLight1.position.set(-300, -400, 300);
    directionalLight2.position.set(300, 400, -300);
    // 将光源加入场景
    scene.add(ambientLight);
    scene.add(directionalLight1);
    scene.add(directionalLight2);

    然后再次打开浏览器就会发现场景中出现了一个小立方体,这里写图片描述
    并且颜色是随机的,因为var cubeMaterial = new THREE.MeshLambertMaterial({color : Math.random() * 0xffffff});// 立方体材质,颜色为随机色设置的为随机色。

  • 让立方体动起来
    想让立方体动起来就需要不断的改变立方体的三维坐标,并且改变一次浏览器就需要刷新一次,因此需要使用这个函数来实现方法的回调,实现动画的效果requestAnimationFrame();参数是一个函数名,也就是需要重复执行的函数体。
    所以若想让立方体动起来,就需要在重复执行的函数里不断改变立方体的位置坐标,即改变一次刷新一次,来实现动画的效果。

    // 实现动画效果
    function animate() {
    // 立方体绕 x、y、z 轴旋转,速度由调试插件控制
    cube.rotation.x += 0.02;
    cube.rotation.y += 0.02;
    cube.rotation.z += 0.02;
    requestAnimationFrame(animate);
    // 开始渲染
    webGlRenderer.render(scene, camera);
    }
    animate();

    这样就实现了,动画的效果,如果在这个函数中添加一行代码 console.log(cube.rotation);就会回发现此时浏览器在疯狂的刷新,来改变立方体旋转的三维坐标。
    这里写图片描述

  • 添加网格辅助
    当然这个不是必须的,它只是场景中的一个对象,而已,凭个人喜好而添加,js是面向对象的语言,可以很好的使用 通过Object3D 继承来的 add()方法 和 remove()方法为场景接口来添加和移除对象。

     // 创建网格辅助实例
    var gridHelper = new THREE.GridHelper(1200, 50, 0xFF4444, 0x404040 );
    scene.add( gridHelper );

    Object3D中的方法
    这两个方法,scene并不具有,只是从基类Object3D 继承来的。

  • 添加轨迹球控件
    threeJs用来通过鼠标和键盘来和模型交互的控件很多,这里就不一一概述了。

     // 创建轨迹球控件
     var trackballControls = new THREE.TrackballControls(camera, webGlRenderer.domElement);

    轨迹球控件是用来操控物体和相机的,因此需要将相机传给它,因为场景一直在刷新,所以也要重置轨迹球的控制范围。
    这里写图片描述

下面两个控件也不是必须的,仅仅是为了调试。
因为在场景中要把灯光和别的物体 一次放在一个合适的位置,是不可能的,因此需要调试。

  • 添加性能插件
    这里写图片描述
    这是初始化性能插件的方法。
    这里写图片描述
    在页面加载的时候就初始化。

  • 添加图形挑调试控件
    threeJs_r93\three.js-master\examples\js\libs目录可以找到dat.gui.min.js这个js库,引入。
    1.首先通过构造函数 来创建它的实例
    这里写图片描述
    2.将需要调试的对象和属性放入一个函数中
    这里写图片描述
    3.然后将要实现的逻辑添加到控件中
    这里写图片描述
    4.举个例子
    在这个完整的示例中,可以看到当点击这个按钮的时候 网格 对象就会消失。
    这里写图片描述
    这是怎么实现的呢?
  • 首先,为controls函数添加一个属性 并初始化。
    这里写图片描述

  • 然后,将这个属性添加给图形控件
    这里写图片描述
    看控制台的输出 e的变化。
    这里写图片描述
    此时 e 的值默认为false
    这里写图片描述
    这里写图片描述
    取消之后e的值又变为了默认的 fasle。别的需要调试的属性也是类似方法来创建。
    本篇文章对于 threeJs新手来说,可能会有点难度,但是也并不是很复杂,从以上解释来看,threeJs是完全面向对象的,除了所必须的场景(Scene)、相机(Camera)以及渲染器(Renderer)之外其它的对象都是可插拔的,个人认为学习,threeJs没有一些捷径,也有人认为学习三维开发应该从底层的OpenGL开始学起,但是那样对于没有任何计算机图形学基础的人来说,是很挫败自信心的,因为你学习了一周也不会创建出来一个简单的图形。
    学习,这种事,唯有坚持吧,也许刚开始比较难,坚持坚持吧!

猜你喜欢

转载自www.cnblogs.com/ithanmang/p/9214558.html