Threejs從入門到入門


前言
threejs官網:https://threejs.org/
github各個版本:https://github.com/mrdoob/three.js/tags
版本更迭很快,我用的時候還是r90秒秒鍾r91出來了

剛入門的時候可以看看這個教程:http://www.hewebgl.com/article/articledir/1
初級教程是免費的,中高級是收費的,寫的不是很枯燥,也不用跟着敲代碼,有個相機,渲染器,場景,光源的概念就可以了。它適配的版本是比較舊的,我當時用新版本跟着寫有些demo無法完成,新手更談不上根據版本之間的差別找到問題,慢慢就失去興趣了。

我的這個教程用的是r90版本,它有個比較好的地方是,當你使用高版本的threejs卻使用低版本的語法時,瀏覽器console會有警告告訴你新的寫法是什么樣的。

我的DEMO下載
演示地址: 太窮了,帶寬很小,加載卡頓請諒解(哭泣)
相機轉動做的比較倉促沒有考慮細節,導致鼠標拖拽或是放大縮小卡頓,emmm小問題暫時不想改了
https://www.hugeoyzy.top/threejs/src/demo1.html
https://www.hugeoyzy.top/threejs/src/demo2.html
下載:https://download.csdn.net/download/u010588262/10288776

開發工具
因為我主要是做java開發,所以就用idea了,因為idea寫js也是有提示的,所以還挺方便,就建個Static Web項目就可以了: 
 

 我的項目結構是這樣的: 
 

 調試需要做兩點配置: 
1. 瀏覽器路徑: 

  瀏覽器啟動參數,因為threejs要加載本地的圖片文件,obj文件之類的,看網上教程都說是不允許的,要部署在apache和tomcat之類的,我沒試,看到說可以加啟動參數就加了,調試沒問題 

–allow-file-access-from-files 

  調試的時候就在html文件上鼠標移到右上角,點擊相應的瀏覽器圖標就可以了 

 

如果修改了html的話直接保存文件在瀏覽器刷新就能看到效果了,但是修改了js的話就要關閉頁面重新點擊瀏覽器圖標。

官方DEMO(肥腸重要)
我入門最快的時候就是找到了官方DEMO之后

一個是:http://stemkoski.github.io/Three.js/#hello-world
這里的demo很入門,很好理解,頁面最上方有github地址,可以去下載。唯一不好的是使用的版本很老。r60版本的,不過對於初學者一開始最重要的是理解大概的使用,不用糾結於最新版本。

還有一個是:https://threejs.org/examples/#webgl_animation_cloth
這里的demo相比第一個是比較高大上的,源代碼就在你下載的threejs包里的examples目錄下

代碼講解
這一塊針對初學者中的初學者了,只要看過前言中的初級教程之后再看我的demo應該沒問題了,demo的代碼也比較整潔。

demo中的css,fonts,images和objs基本都是從官方demo中搞過來的,頁面上引用的js分別是什么作用也做了注釋了:
 

util.js是我把公用的東西放在一起了,要看懂util.js需要對threejs基本的組件有一些了解。

threejs的三圍坐標是這樣的,比如你現在對着電腦屏幕吧,把你屏幕的左下角想象成二維坐標原點,那往右就是x正方向,網上就是y正方向,從屏幕往外直蓋臉的就是z正方向了。

最上面的src()是用來初始化場景,相機和渲染器的,最開始的textureLoader = new THREE.TextureLoader();是用來加載圖片材質的,在大多數教程里用的都是ImageUtils來加載的,這個是新版本的改動,我說一下我對這仨玩意兒的理解吧

場景:就是一個黑盒子唄,把你要展示的東西全往里面裝,地板啊,天花板啊,盒子啊,球啊,貨架啊,三D字體啊全塞進去。為什么是黑盒子?因為你看不見它,也不看不見塞進去的東西。場景的初始化很簡答就一句話scene = new THREE.Scene();

相機:相機可以在任意的位置,任意的角度”拍攝”黑盒子里的場景,相機的初始化稍微復雜一些。

    var SCREEN_WIDTH = window.innerWidth;
    var SCREEN_HEIGHT = window.innerHeight;
    var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
    camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
    scene.add(camera);
    camera.position.set(0, 600, 1000);
    cameraRadius = Math.sqrt(camera.position.x * camera.position.x + camera.position.z * camera.position.z);
    camera.up.set(0, 1, 0);
    camera.lookAt(new THREE.Vector3(0, 0, 0));

關於相機比較難理解的是position,up和lookAt的關系。你可看看這個視頻http://www.hewebgl.com/video/2,雖然我看完了也沒怎么看懂。
嘗試解釋一下吧。
現在,把你的手機打開攝像頭,正對着屏幕,想象它就像單反一樣上面右邊有個快門,這就是threejs中相機的初始方向,就是從z軸正方向看向z軸負方向。position是什么意思呢,現在把手機往右平移,意思是position.x在增加。lookAt也很容易,就是相機往哪兒拍唄。比較難理解的是up,好現在把手機位置固定,只能旋轉哦,也就是說position固定了,好了現在把手機旋轉鏡頭對着屏幕左下角,也就是咱們的三維坐標原點,也就是說lookAt也固定了。up的作用就是你現在可以旋轉手機了,保持鏡頭對着屏幕左下角的方向,手機的中心點位置不要變,旋轉手機,拍出來的畫面就會是正的,或者斜着的,或者上下倒過來的。隨着你旋轉手機快門的朝向也在變是吧,默認快門是對着Y軸正方向的,也就是(0,1,0)如果把手機顛倒,up就變成了(0,-1,0),拍出來的畫面也就是上下顛倒的,因為你雖然可以倒着手機拍,但是看照片的時候得把手機正過來看,畫面也就是反的咯。

渲染器
可以看到相機的初始化過程中沒有與場景綁定,他們倆就像在兩個平行世界一樣,看似在一起,其實沒在一起,需要用渲染器把他們倆關聯起來,這樣,相機就拍到了場景里的東西,再通過渲染器展示在瀏覽器上被我們看到了。Decetor是通過Detector.js引入進來的東西,用於判斷瀏覽器兼容性的。

    if (Detector.webgl)
        renderer = new THREE.WebGLRenderer({antialias: true});
    else
        renderer = new THREE.CanvasRenderer();
    renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    container = document.getElementById('ThreeJS');
    container.appendChild(renderer.domElement);

以地板為例怎么搞一個東西放在場景里,CSDN的代碼注釋沒有這么詳細,寫博客的時候加的,對不住只下資源不看文章的朋友。PlaneGeometry就是一個平面,SphereGeometry就是一個球,CubeGeometry就是一個立方體…….感興趣的可以百度多了解一下其他組件。材質就是各種Material,也有很多種,有受光照影響的,有不受光照影響的。把組件和材質組合起來就是一個完整的物體啦,就是THREE.Mesh這個方法把他們組合起來,第一個參數是組件,第二個參數是材質,材質還可以傳入一個數組,你可能覺得設置多個有啥意義啊一個蓋住一個的,材質是可以設置透明度的,明白了吧。

function addfloor() {
    // 加載圖片作為地板材質
    var floorTexture = textureLoader.load('images/checkerboard.jpg');
    // 沿x方向和Y方向都重復填充
    floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
    // x方向和y方向各重復幾次,不理解的話改改這個值看看效果就知道了
    floorTexture.repeat.set(4, 4);
    // 將材質包裝成表面材料,設置正反兩面都要鋪上
    var floorMaterial = new THREE.MeshBasicMaterial({map: floorTexture, side: THREE.DoubleSide});
    // 平面對象
    var floorGeometry = new THREE.PlaneGeometry(1000, 1000, 1, 1);
    // 把對象和材料包裝成Mesh
    floor = new THREE.Mesh(floorGeometry, floorMaterial);
    // 設置位置放入場景啦
    floor.position.y = -0.5;
    floor.rotation.x = Math.PI / 2;
    scene.add(floor);
}

others()方法里是一些可有可無的輔助,看注釋就明白了。
animate()就是開始持續渲染,渲染就是通過renderer.render(scene, camera);把渲染器搞到的東西放在瀏覽器上給你看,持續渲染就是通過重復調用方法本身可以實現動畫的效果requestAnimationFrame(animate);,除了這兩個東西還調用了update();方法,update方法里就是慢慢的移動組件或者刷新其他需要更新得組件。requestAnimationFrame方法是比較平滑的動畫,我之前想用Tween.js實現相機轉動的效果,很卡頓,不流暢。

woodycube()就是封裝了獲得木箱,因為兩個demo里都用到了木頭箱子。

后面有空再說一下demo中的代碼

2018年3月16日
更新了一下util.js中的代碼,把鼠標點擊選中事件和getMeshed方法從demo2中移到util里面了
點擊事件

document.addEventListener("mousedown", onDocumentMouseDown, false);
function onDocumentMouseDown(e) {
    e.preventDefault();
    // 點擊頁面時停止相機旋轉,因為相機旋轉的時候無法選中物體,這個問題沒有解決,有點麻煩
    rotate = false;
    //將鼠標點擊位置的屏幕坐標轉成threejs中的標准坐標,具體解釋見代碼釋義
    var mouse = {};
    mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
    //新建一個三維單位向量 假設z方向就是0.5
    //根據照相機,把這個向量轉換到視點坐標系
    var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5).unproject(camera);
    var sub = vector.sub(camera.position);=
    var param2 = sub.normalize();
    var raycaster = new THREE.Raycaster(camera.position, param2);

    //射線和模型求交,選中一系列直線,getMeshs方法用於獲得場景中可以被選中的所有Mesh
    var intersects = raycaster.intersectObjects(getMeshs());

    if (intersects.length > 0) {
        // outlineMesh是物體邊框組件,每次只會有一個物體被選中,就把這個東西定義為全局的
        // 每次選中另一個物體之前先刪除,相當於取消前一個物體的選中
        scene.remove(outlineMesh);
        //選中第一個射線相交的物體
        var SELECTED = intersects[0].object;
        var outlineMaterial2 = new THREE.MeshBasicMaterial({color: 0x00ff00, side: THREE.BackSide});
        outlineMesh = new THREE.Mesh(SELECTED.geometry.clone(), outlineMaterial2);
        outlineMesh.position.set(SELECTED.position.x, SELECTED.position.y, SELECTED.position.z);
        outlineMesh.scale.multiplyScalar(1.05);
        scene.add(outlineMesh);
    }
}

 


免責聲明!

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



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