Three.js學習筆記 – “我和小伙伴都驚呆了”的特效和Three.js初探


three-js-study-notes-study-on-three-js

什么是Three.js

three.js是JavaScript編寫的WebGL第三方庫。提供了非常多的3D顯示功能。Three.js 是一款運行在瀏覽器中的 3D 引擎,你可以用它創建各種三維場景,包括了攝影機、光影、材質等各種對象。你可以在它的主頁上看到許多精采的演示。不過,這款引擎目前還處在比較不成熟的開發階段,其不夠豐富的 API 以及匱乏的文檔增加了初學者的學習難度(尤其是文檔的匱乏)three.js的代碼托管在github上面。

上面摘自百度百科。依我來看就是一個在HTML5畫布(canvas)上顯示的3D引擎。如果你之前折騰過本地3D引擎,比如Steam,寒霜,那上手這個就非常簡單了。

學習這個引擎難處有幾點:第一,正如上面所說,沒有比較系統的文檔,只有一些大神寫的Demo,對於一些js基礎不好或者英語不好的童鞋來說簡直不能歷屆;第二,一般人對游戲引擎里面的紋理、光源、材質等詞不甚理解。第三,不曉得怎么去調試。

在開始正式介紹之前,可以先看看Demo,了解一下這個引擎能做什么。

官方網站上的例子:http://threejs.org/

GitHub上的例子:http://stemkoski.github.io/Three.js/

其中幾個比較有特色的列一下(提提你們的胃口~)(都不要使用IE或基於IE的瀏覽器打開!推薦使用Chrome):

最基本的Hello World:http://stemkoski.github.io/Three.js/HelloWorld.html

調用你的攝像頭http://stemkoski.github.io/Three.js/Webcam-Texture.html

體感操作(你沒有看錯!):http://stemkoski.github.io/Three.js/Webcam-Motion-Detection-Texture.html

支持你的游戲手柄(XBox等):http://stemkoski.github.io/Three.js/Mesh-Movement-Gamepad.html

3D建模和方向鍵控制移動方向:http://stemkoski.github.io/Three.js/Model-Animation-Control.html

SkyBox和3個氣泡渲染(可見Three.js的渲染真心不賴):http://stemkoski.github.io/Three.js/Metabubbles.html

3D紅藍偏光的名車展(打開前自備偏光鏡):http://threejs.org/examples/webgl_materials_cars_anaglyph.html

帥爆了的元素周期表:http://threejs.org/examples/css3d_periodictable.html

跑車游戲:http://hexgl.bkcore.com/

有沒有和小伙伴們都驚呆了?——至少我是的。沒有使用Flash,沒有大量的圖片拼接,絕大多數的特效靠代碼實現,包括文章配圖那款SS跑車,AMAZING!

Three.js環境的准備

正文現在開始。

我整個例子有不少地方參考的是http://www.hiwebgl.com/?p=1058。向這樣的譯者表示絕對的敬意!(話說原文是日文的,我這個看英語文檔無壓力的無論如何也受不鳥日文啊……)

Three.js從GitHub庫中獲取:https://github.com/mrdoob/three.js/,下載請點擊在頁面右邊的“Download ZIP”按鈕。比較齊活的例子在:https://github.com/stemkoski/stemkoski.github.com可以下載。

Three.js至少需要build目錄下的three,js,three.min.js是前者的壓縮版。docs下的index.html是器官方文檔(我還沒細致看過,質量怎么樣沒法說)。example目錄下都是例子,值得一提的是,這些例子必須要掛到服務器里面預覽,本地打開會有問題,IIS或者Tomcat或者Apache都可以(以后會說到為什么)。

運行第一個Three.js

第一個例子也用來確定一下Three.js是否能正常運行。在WebRoot下建一個js文件夾,把three,js拷貝進去(three.min.js也行)。

在WebRoot下建一個index.html,內容如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Three.js チュートリアル1</title>
<script src="Three.js"></script>
<style type="text/css">
div#canvas-frame {
    border: none;
    cursor: pointer;
    width: 600px;
    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.setClearColorHex(0xFFFFFF, 1.0);
    }

    var camera;
    function initCamera() {
        camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
        camera.position.x = 100;
        camera.position.y = 20;
        camera.position.z = 50;
        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() {
        cube = new THREE.Mesh(new THREE.CubeGeometry(50, 50, 50), //形狀の設定
        new THREE.MeshLambertMaterial({
            color : 0xff0000
        }) //材質の設定
        );
        scene.add(cube);
        cube.position.set(0, 0, 0);
    }
    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>

執行的結構應該是這樣,Three.js也比較大,網的質量可能不好,看不到效果的多刷幾次:http://tonythegod.eu5.org/three.js/1/demo1.html

1
自二個例子:一個可控制的長方體

最后的效果(沒看到效果多刷幾次http://tonythegod.eu5.org/three.js/1/demo2.html

2

我沒有給李興華打廣告……只是這本書在我寫Demo時就在我手邊,然后就當了模特了~

貼出主要的代碼,附上一些主要的注釋:

<!doctype html>
<html lang="en">
<head>
<title>Template (Three.js)</title>
<meta charset="utf-8">
<meta name="viewport"
    content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel=stylesheet href="css/base.css" /> <!-- 這個樣式表主要寫了body的背景為#F5F5F5,就是整個網頁的背景顏色 -->
</head>

<body>
    <script src="../js/Three.js"></script> <!-- 這個是Three.js引擎的js -->
    <script src="../js/Detector.js"></script>
    <script src="../js/Stats.js"></script>
    <script src="../js/OrbitControls.js"></script>
    <script src="../js/THREEx.KeyboardState.js"></script>
    <script src="../js/THREEx.FullScreen.js"></script>
    <script src="../js/THREEx.WindowResize.js"></script>
    <script src="../js/Texture.js"></script> <!-- 一些js工具類,現在不深究 -->

    <div id="ThreeJS"
        style="z-index: 1; position: absolute; left: 0px; top: 0px"></div> <!--這個div就是整個畫布 -->
    <script>
        //////////    
        // MAIN //
        //////////
        // standard global variables
        var container, scene, camera, renderer, controls, stats; <!-- 幾個變量代表的含義:容器、場景、攝像機(視角)、渲染器、控制裝置 -->
        var keyboard = new THREEx.KeyboardState();
        var clock = new THREE.Clock();

        // custom global variables
        var cube;

        // initialization
        init();

        // animation loop / game loop
        animate();

        ///////////////
        // FUNCTIONS //
        ///////////////

        function init() { <!-- 初始化 -->
            ///////////
            // SCENE //
            ///////////
            scene = new THREE.Scene(); <!-- 定義場景 -->

            ////////////
            // CAMERA //
            ////////////

            // set the view size in pixels (custom or according to window size)
            // var SCREEN_WIDTH = 400, SCREEN_HEIGHT = 300;
            var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
            // camera attributes
            var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
            // set up camera
            camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR); <!-- 定義視角 -->
            // add the camera to the scene
            scene.add(camera);
            // the camera defaults to position (0,0,0)
            // so pull it back (z = 400) and up (y = 100) and set the angle towards the scene origin
            camera.position.set(-400, 150, 200); <!--視角的位置 -->
            camera.lookAt(scene.position);

            //////////////
            // RENDERER //
            //////////////

            // create and start the renderer; choose antialias setting.
            if (Detector.webgl)
                renderer = new THREE.WebGLRenderer({
                    antialias : true
                });
            else
                renderer = new THREE.CanvasRenderer();

            renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);

            // attach div element to variable to contain the renderer
            container = document.getElementById('ThreeJS');
            // alternatively: to create the div at runtime, use:
            // container = document.createElement( 'div' );
            // document.body.appendChild( container );

            // attach renderer to the container div
            container.appendChild(renderer.domElement);

            ////////////
            // EVENTS //
            ////////////

            // automatically resize renderer
            THREEx.WindowResize(renderer, camera);
            // toggle full-screen on given key press
            THREEx.FullScreen.bindKey({
                charCode : 'm'.charCodeAt(0)
            });

            //////////////
            // CONTROLS //
            //////////////

            // move mouse and: left   click to rotate, 
            //                 middle click to zoom, 
            //                 right  click to pan
            controls = new THREE.OrbitControls(camera, renderer.domElement); <!-- 設置控制,這里只有鼠標操作 -->

            ///////////
            // STATS //
            ///////////

            // displays current and past frames per second attained by scene
            stats = new Stats();
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.bottom = '0px';
            stats.domElement.style.zIndex = 100;
            container.appendChild(stats.domElement);

            ///////////
            // LIGHT //
            ///////////

            // create a light
            var light = new THREE.PointLight(0xffffff); <!-- 設置光源 -->
            light.position.set(0, 250, 0);
            scene.add(light);

            // CUBE
            var cubeGeometry = new THREE.CubeGeometry(260, 35, 185, 1, 1, 1); <!-- 定義一個立方體,就是那本書的模型 -->

            var cubeMaterialArray = [];
            cubeMaterialArray.push(new THREE.MeshBasicMaterial({
                map : new THREE.ImageUtils.loadTexture('img/side-up.png') <!-- 給每一面上貼圖,下同 -->
            }));
            cubeMaterialArray.push(new THREE.MeshBasicMaterial({
                map : new THREE.ImageUtils.loadTexture('img/side-up.png')
            }));
            cubeMaterialArray.push(new THREE.MeshBasicMaterial({
                map : new THREE.ImageUtils.loadTexture('img/up.png')
            }));
            cubeMaterialArray.push(new THREE.MeshBasicMaterial({
                map : new THREE.ImageUtils.loadTexture('img/down.png')
            }));
            cubeMaterialArray.push(new THREE.MeshBasicMaterial({
                map : new THREE.ImageUtils.loadTexture('img/side-right.png')
            }));
            cubeMaterialArray.push(new THREE.MeshBasicMaterial({
                map : new THREE.ImageUtils.loadTexture('img/side-left.png')
            }));
            var cubeMaterials = new THREE.MeshFaceMaterial(cubeMaterialArray);

            cube = new THREE.Mesh(cubeGeometry, cubeMaterials);
            cube.position.set(0, 0, 0); <!-- 立方體放置的位置 -->
            scene.add(cube);

        }

        function animate() {
            requestAnimationFrame(animate);
            render();
            update();
        }

        function update() {
            // delta = change in time since last call (in seconds)
            var delta = clock.getDelta();

            controls.update();
            stats.update();
        }

        function render() {
            renderer.render(scene, camera);
        }
    </script>

</body>
</html>

其實學習Three.js大多是這樣,因為缺少相應的文檔,看大牛們寫的注釋是最快上手的辦法。

這次就先到這兒,下次再說怎么一點點在畫布上作畫。

本文轉載自tony的小站: http://tonythegod.eu5.org/three-js-study-notes-study-on-three-js/ | Tony的工作站


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM