threejs紋理

紋理

紋理用來表現物體的細節。理論上可以將物體的每個細節建模出來,但是這樣時間成本和性能成本都太高,因此,將物體的一些細節用紋理來表示。

圖片紋理

圖片紋理直接在物體表面應用圖片。可以使用TextureLoader類的load方法來加載紋理。

function loadImgTexture(){
    var loader = new THREE.TextureLoader();
    loader.load("metal-rust.jpg",function(texture){
        var geometry = new THREE.BoxGeometry(10,10,10);
        var material = new THREE.MeshBasicMaterial({color:0x739783,map:texture});
        mesh = new THREE.Mesh(geometry,material);
        scene.add(mesh);
    })
}

注意加載圖片是異步的,所以這裏我們使用render循環來渲染:

function render(){
    requestAnimationFrame(render);
    renderer.render(scene,camera);
}

凹凸貼圖

凹凸貼圖可以使紋理也有厚度,看起來更立體。凹凸貼圖一般使用一張灰度圖,設置成材料的bumpMap屬性

function loadImgTexture(){
    var loader = new THREE.TextureLoader();
    loader.load("stone.jpg",function(texture){
        loader.load("stone-bump.jpg",function(bumpTexture){
            var geometry = new THREE.BoxGeometry(10,10,10);
            var material = new THREE.MeshPhongMaterial({map:texture,bumpMap:bumpTexture,bumpScale:0.2});
            mesh = new THREE.Mesh(geometry,material);
            mesh.rotation.x = 30/180Math.PI;
            scene.add(mesh);
        })
    })
}

凹凸貼圖雖然看起來更立體,但是其只是有深度,沒有方向,所以只有在某個方向看是很立體,在其它方向看又不好。如果貼圖的對象不怎麼轉動,光線也不怎麼變化,倒可以使用凹凸貼圖。

法向貼圖

法向貼圖使用一張法向圖來表示紋理圖片某個點的法向量。即用一張圖片保存另一張圖片的法向量信息,然後再在threejs中將這兩個圖片的信息合在一起,就形成了一個細節豐富的立體紋理。創建法向貼圖如下,注意這裏不要再使用MeshBasicMaterial:

function loadImgTexture(){
    var loader = new THREE.TextureLoader();
    loader.load("plaster.jpg",function(texture){
        loader.load("plaster-normal.jpg",function(normalTexture){
            var geometry = new THREE.BoxGeometry(10,10,10);
            var material = new THREE.MeshPhongMaterial({map:texture,normalMap:normalTexture,bumpScale:0.2});
            mesh = new THREE.Mesh(geometry,material);
            mesh.rotation.x = 30/180Math.PI;
            scene.add(mesh);
        })
    })
}

法向貼圖可以生成細節豐富的紋理,同時不損害渲染性能。但是法向圖這張圖片創建起來稍有困難,使用Blender或Photo創建。

光照貼圖

環境貼圖

環境貼圖是使用上下左右前後六張圖或者一張全景圖來模擬真實的環境,threejs會將這些圖片渲染成無縫的環境盒子,例子可看【threejs-cubeMap例子】,其中貌似真實的環境,球的反光效果,都是用這張全景圖渲染出來的:

球的反光看起來非常逼真,但其實是假的,也就四並沒有使用光線追蹤來表現出反光效果。光線追蹤是很耗cpu的,所以,使用環境貼圖即節約性能,又能表現出很逼真的效果。

UV貼圖

關於uv貼圖,【blender wiki】裏面說得很好:


UV貼圖是將2D紋理映射到3D物體最靈活的一種方式.在這個過程中三維曲面網絡("mesh")的X Y Z被展平到一副二維(X Y 或者說 我們將要看到的 U V)圖片中,這樣圖片中的顏色就被映射到曲面網絡("mesh")中。
有助於理解UV貼圖的最形象的比喻是切開一個硬紙盒.盒子是一個三維物體,正如同加到場景中的一個曲面網絡("mesh")方塊.
如果沿着邊縫或摺痕剪開盒子,可以把盒子攤開在一個桌面上.當我們從上往下俯視桌子時,我們可以認爲U是左右方向,V是上下方向.盒子上的圖片就在一個二維座標中.我們使用U V代表"紋理座標系"來代替通常在三維空間使用的 X Y.

如果給模型的每個面都用一張圖片去貼紋理,這將要加載很多紋理圖片,如果可以只將圖片的某個部分映射到模型,那就只需要一張圖片就夠了。uv貼圖就能夠將圖片的某部分映射到模型的某個面,如果還不好理解,類比一下CSS Sprite技術。比如,上一篇【加載3D模型例子】例子中,我們用到了一張圖片:

這張圖裏面凌亂的放着攤開的人皮、衣服、手、眼睛等圖片元素。而我們加載出來的模型是這樣的:

在這張圖中,臉是臉,衣服是衣服,都在它們應該出現的位置。這便是使用了uv映射,將圖中的某部分作爲紋理,貼到模型中的對應部分。

但是,圖中的各個部分,是怎麼和模型對應起來的呢?一個人的模型有那麼多個面,純手工編碼一個個去對應,感覺會出人命。其實,uv貼圖一般是做模型的時候就做好了,圖和模型的對應關係也包含在模型文件(就是那個.dae文件)中了,編程的時候一般是不用關心這個。

雖說如此,我們加載模型之後,也可以通過Geometry對象的faceVertexUvs屬性看看具體是怎麼映射的。簡單起見,創建一個BoxGometry,查看一個其內置的uv映射:

var geom = new THREE.BoxGeometry(24, 24, 24);
console.log(geom.faceVertexUvs);

打印出:

是一個有12個元素的數組,12代表的就是立方體的12個三角面。再看數組的具體某一個元素:

又是一個長度爲3的Vector2數組,代表紋理圖片中的三個位置,這三個點圍成的部分就是這個三角面的紋理。上面的(0,0),(1,0),(1,1)都是比例,0代表0%,1代表100%。點是從右下角開始按逆時針排列的,比如A(0,0),B(1,0),C(1,1)三點,在圖片中圍成的區域如下:

將這張圖加載到立方體,能更清晰立方體是如何通過uv映射來處理紋理的,【例子】。


持續更新看這裏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章