10.ThreeJs開發指南-第十章-載入和使用紋理
第十章 載入和使用紋理
在材質中使用紋理
function createMesh(geom,imageFile){
var texture = THREE.ImageUtils.loadTexture('../assets/textures/general/' + imageFile);
var mat = new THREE.MeshPhongMaterial();
mat.map = texture;
var mesh = new THREE.Mesh(geom,mat);
return mesh;
}
這裡的紋理圖片可以是:png、gif、jpeg
紋理載入是非同步的。這是沒有問題的,因為我們有一個render迴圈,每秒大概渲染場景60次,所以一旦紋理載入完畢就會立即在場景中顯示。
如果你想紋理載入前一致等待。
texture = THREE.ImageUtils.loadTexture('texture.png',{},function(){
renderer.render(scene);
});
幾乎所有的圖片都可以作為紋理。
為了達到最好的效果,最好使用正方形的圖片,其長寬都是2的次方。
由於紋理需要放大和縮小,所以通常紋理上的畫素(紋理單元:texel)不會一對一地對映成面上的畫素。因此WebGL和Three.js提供了幾種選擇。
magFilter屬性:指定紋理如何放大。預設值:THREE.LinearFilter
minFilter屬性:指定紋理如何縮小。預設值:THREE.LinearMipMapLinearFilter
屬性值:
THREE.NearestFilter 最鄰近過濾
THREE.LinearFilter 線性過濾
mipmap:一個mipmap是一組紋理圖片,每個圖片的尺寸都是前一張圖片的一半。這些圖片實在載入紋理時建立的,可以生成較平滑的過濾效果。
mipmap的屬性值:
THREE.NearestMipMapNearestFilter:選擇最貼近目標解析度的mipmap,然後使用最鄰近過濾原則。
THREE.NearestMipMapLinarFilter:選擇層次最近的兩個mipmap,然後在這兩層之間使用最鄰近過濾原則獲取兩個中間值,然後這兩個中間值傳遞給線性過濾器,以獲得最終效果。
THREE.LinearMipMapNearestFilter:選擇最貼近目標解析度的mipmap,然後使用線性過濾原則。
THREE.LinearMipMapLinearFilter:選擇層次最近的兩個mipmap,然後在這兩層之間使用線性過濾原則獲得兩個中間值,然後這兩個中間值傳遞給線性過濾器,以獲得最終結果。
凹凸紋理貼圖建立皺紋
凹凸紋理的目的是為材質增加厚度。
function createMesh(geom,imageFile,bump){
var texture = THREE.ImageUtils.loadTexture('../assets/textures/general/'+imageFile);
var mat = new THREE.MeshPhongMaterial();
mat.map = texture;
var bump = THREE.ImageUtils.loadTexture('../assets/textures/general/'+bump);
mat.bumpMap = bump;
mat.bumpScale = 0.2;//凹凸的高度,負數表示凹下去的深度。
var mesh = new THREE.Mesh(geom,mat);
return mesh;
}
凹凸貼圖中只有畫素的相對高度,沒有任何坡度的方向性資訊。所以凹凸貼圖所能達到的厚度和細節程度是有限的。更多的細節可以使用法向貼圖。
使用法向貼圖建立更加細緻的凹凸和皺紋
法向貼圖中儲存的不是每個畫素的高度,而是畫素的法向向量。使用法向貼圖,只需使用很少的頂點和麵,就可以創建出細節非常豐富的模型。
function createMesh(geom,imageFile,normal){
var t = THREE.ImageUtils.loadTexture('../assets/textures/general/'+imageFile);
var m = THREE.ImageUtils.loadTexture('../assets/textures/general/'+normal);
var mat2 = new THREE.MeshPhongMaterial({
mat:t,
normalMap:m
});
var mesh = new THREE.Mesh(geom,mat2);
return mesh;
}
我們還可以指定凹凸的程度,方法是設定:mat.normalScale.set(1,1);通過這個屬性,可以沿著x軸和y軸縮放。不過最好將他們設定成一樣的。
法向貼圖的問題是不容易建立。需要使用特殊的工具,例如:Blender和Photoshop,它們可以將高解析度的渲染結果或圖片作為輸入,從中建立法向貼圖。
使用光照貼圖建立假陰影
光照貼圖是預先渲染好的陰影,可以用它來模擬真實的陰影。
只對靜態場景起效果。
var lm = THREE.ImageUtils.loadTexture('../assets/textures/lightmap/lm-1.png');
var wood = THREE.ImageUtils.loadTexture('../assets/textures/general/floor-wood.jpg');
var groundMaterial = new THREE.MeshBasicMaterial({
lightMap:lm,
map:wood
});
groundGeom.faceVertexUvs[1] = groundGeom.faceVertexUvs[0];
要想光照貼圖顯示出來,我們需要為光照貼圖明確指定UV對映(將紋理的哪一部分應用到表面)。只有這樣,我們才能將光照貼圖和其他的紋理獨立開來。
用環境貼圖建立虛假的反光效果
計算反光非常消耗CPU,而且通常會使用法線追蹤演算法。
所以,我們可以建立一個物件所處環境的紋理來偽裝反光,並將它應用到特定的物件上。
步驟:
1、建立一個CubeMap物件
2、建立一個帶有這個CubeMap物件的方塊(天空盒)
3、將CubeMap作為紋理
function createCubeMap(){
var path = "../assets/textures/cubemap/parliament/";
var format = '.jpg';
var urls= [
path + 'posx' + format , path + 'negx' + format,
path + 'posy' + format , path + 'negy' + format,
path + 'posz' + format , path + 'negz' + format,
];
var textureCube = THREE.ImageUtils.loadTextureCube(urls);
return textureCube;
}
建立一個方塊:
var textureCube = createCubeMap();
var shader = THREE.ShaderLib['cube'];
shader.uniforms['tCube'].value = textureCube;
var material = new THREE.ShaderMaterial({
fragmentShader:shader.fragmentShader,
vertexShader:shader.vertexShader,
uniforms:shader.uniforms,
depthWrite:false,
side:THREE.BackSide
});
cubeMesh = new THREE.Mesh(new THREE.CubeGeometry(100,100,100),material);
同一個Cube物件可以應用到某個網格上,用來建立虛假的反光。
var sphere1 = createMesh(new THREE.SphereGeometry(10,15,15),'plaster.jpg');
sphere1.material.envMap = textureCube;
sphere1.rotation.y = -0.5;
sphere1.position.x = 12;
sphere1.position.y = 5;
scene.add(sphere1);
var sphere2 = createMesh(new THREE.CubeGeometry(10,15,15),'plaste.jpg','plaster-normal.jpg');
sphere2.material.envMap = textureCube;
sphere2.rotation.y = 0.5;
sphere2.position.x = -12;
sphere2.position.y = 5;
scene.add(sphere2);
折射:
var textureCube = THREE.ImageUtils.loadTextureCube(urls,new THREE.CubeRefractionMapping);
通過材質的refraction屬性可以控制折射率。
在這個示例中,我們使用的是靜態環境貼圖。即我們只能看到環境的反光,而無法看到其他網格。
高光貼圖
可以為材質指定一個閃亮的、色彩明快的貼圖。
一般高光貼圖會同specular屬性一起使用。
var specularTexture = THREE.ImageUtils.loadTexture('../assets/textures/planets/EarthSpec.png');
var normalTexture = THREE.ImageUtils.loadTexture('../assets/textures/planets/EarthNormal.png');
var planetMaterial = new THREE.MeshPhongMaterial();
planetMaterial.specularMap = specularTexture;
planetMaterial.specular = new THREE.Color(0xff0000);
planetMaterial.shininess = 1;
planetMaterial.normalMap = normalTexture;
最好的效果往往是使用低光亮度實現的,但高光貼圖還會受到光照的影響。
紋理的高階用途
一、定製UV對映
通過UV對映,可以指定紋理的哪一部分顯示在物體表面。當你在Three.js中建立幾何體時,根據幾何體的型別,這些對映也一併自動建立。
UV定製一般是在諸如Blender這樣的軟體中完成的,特別是在模型變得複雜的時候。
UV對映有兩個維度,U和V,分別取值範圍是0-1.
需要為構成面的每一個頂點指定u和v。
重複對映
cube.material.map.wrapS = THREE.RepeatWrapping;//沿x方向的行為
cube.material.map.wrapT = THREE.RepeatWrapping;//沿y方向的行為
THREE.RepeatWrapping 允許紋理重複自己
THREE.ClampToEdgeWrapping 預設設定,紋理邊緣的畫素會被拉伸,以填滿剩下的空間。
如果使用了THREE.RepeatWrapping,我們可以使用下面的程式碼代替repeat屬性:
cube.material.map.repeat.set(repeatX,repeatY);
引數:
repeatX:指定在x軸方向多久重複一次。
repeatY:指定在y軸方向多久重複一次。
如果設定為1,都不會重複。
如果設定<1,紋理就會被放大。
如果設定為負數,就會產生紋理映象。
當修改repeat屬性時,Three.js會自動更新紋理,並用新的設定進行渲染。
當然,你從 THREE.RepeatWrapping 切換到 THREE.ClampToEdgeWrapping 時,你就要明確更新紋理:
cube.material.map.needsUpdate = true;
在畫布上繪製圖案並作為紋理
互動式畫布:literally庫
<div class="fs-container">
<div id="canvas-output" style='float:left'></div>
<div>
...
var canvas = document.createElement('canvas');
$('#canvas-output')[0].appendChild(canvas);
//建立繪圖工具
$('#canvas-output').literallycanvas(
{imageURLPrefix:'../libs/literally/img'}
);
//將在畫布上的繪圖結果作為輸入建立一個紋理
function createMesh(geom){
var canvasMap = new THREE.Texture(canvas);
var mat = new THREE.MeshPhongMaterial();
mat.map = canvasMap;
var mesh = new THREE.Mesh(geom,mat);
return mesh;
}
更新材質:
function render(){
stats.update();
cube.rotation.y += 0.01;
cube.rotation.x += 0.01;
cube.material.map.needsUpdate = true;
requeatAnimationFrame(render);
webGLRenderer.render(scene,camera);
}
用畫布作凹凸紋理
凹凸圖只是簡單的黑白圖片。
貼圖中的畫素的密集程度越高,貼圖看上去越皺。
在畫布上隨機產生一副灰度圖。
Perlin噪聲,可以產生看上去非常自然的隨機紋理。
var ctx = canvas.getContext('2d');
function fillWithPerlin(perlin,ctx){
for(var x = 0 ;x < 512; x++){
for(var y = 0 ;y <512;y++){
var base = new THREE.Color(0xffffff);
var value = perlin.noise(x/10,y/10,0);//在畫布x座標和y座標的基礎上生成一個0到1之間的值。該值可以在畫布上畫一個畫素點。
base.multiplyScalar(value);
ctx.fillStyle = '#' + base.getHexString();
ctx.fillRect(x,y,1,1);
}
}
}
function createMesh(geom){
var bumpMap = new THREE.Texture(canvas);
var mat = new THREE.MeshPhongMaterial();
mat.color = new THREE.Color(0x77ff77);
mat.bumpMap = bumpMap;
bumpMap.needsUpdate = true;
var mesh = new THREE.Mesh(geom,mat);
return mesh;
}
用視訊輸出作為紋理
webgl已經直接支援HTML視訊元素。
<video id = 'video'
style='display:none;position: absolute;left:15px;top:75px;'
src='../assets/movies/Big_Buck_Bunny_small.ogv'
controls='true'
autoplay='true'
</video>
var video = document.getElementById('video');
texture = new THREE.Texture(video);
texture.minFilter = Three.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.generateMipmaps = false;
注意:
1.由於我們的視訊不是正方形,所以要保證材質不會生成mipmap。
2.由於材質變化得很頻繁,所以我們需要設定簡單高效的過濾器。
var materialArray =[];
materialArray.push(new THREE.MeshBasicMaterial(color:0x0051ba));
materialArray.push(new THREE.MeshBasicMaterial(color:0x0051ba));
materialArray.push(new THREE.MeshBasicMaterial(color:0x0051ba));
materialArray.push(new THREE.MeshBasicMaterial(color:0x0051ba));
materialArray.push(new THREE.MeshBasicMaterial(color:0x0051ba));
materialArray.push(new THREE.MeshBasicMaterial(color:0x0051ba));
var faceMaterial = new THREE.MeshFaceMaterial(materialArray);
var mesh = new THREE.Mesh(geom,faceMaterial);
在幀迴圈中更新材質
if(video.readyState === video.HAVE_ENOUGH_DATA){
if(texture)
texture.needsUpdate = true;
}
小結:
使用紋理時的注意事項:
1.紋理圖片的型別可以是png、jpg或gif格式的。圖片載入是非同步的,所以要麼使用渲染迴圈,要麼在載入紋理時提供一個回撥函式。
2.使用正方形紋理。這樣就可以使用mipmap來達到更好的效果。
3.標準情況下,Three.js並不支援反光,可以使用環境貼圖創建出虛假的反光。
4.要想直接控制物體表面的光亮貼圖,可以使用高光貼圖。,
5.紋理的repeat屬性,可以讓紋理自我複製。還要記住將材質的包裹屬性從 ClampToEdgeWrapping 改成 RepeatWrapping
6.Thee.js中可以用HTML5畫布元素或者視訊元素建立動態紋理。
相關推薦
10.ThreeJs開發指南-第十章-載入和使用紋理
第十章 載入和使用紋理 在材質中使用紋理 function createMesh(geom,imageFile){ var texture = THREE.ImageUtils.loadTexture('../assets/textures/g
05.ThreeJs開發指南-第五章-幾何體
第五章 學習使用幾何體 二維幾何體: 一、PlaneGeometry:平面 var plane = new THREE.PlaneGeometry(width,height,widthSegments,heightSegments); width:
07.ThreeJs開發指南-第七章-粒子系統
第七章 粒子系統 function createParticles(){ var meaterial = new THREE.ParticleBasicMaterial(); for(var x = -5 ; x < 5 ; x +
Unix/Linux下的Curses庫開發指南——第三章curses庫視窗
第3 章 curses 庫視窗 3 .1 curses 視窗簡介 3.1.1視窗概念 視窗是 curses 庫中最重要的一個元件,它實際上是螢幕上的一塊矩形區域,在上面我們可以進行各種輸出以及操作。 curses 庫中提供了大量的函式以允許我們建立和操作自己的視
Vert.x Java開發指南——第九章 利用RxJava進行響應式程式設計
第九章 利用RxJava進行響應式程式設計 截止目前,我們已經探索了Vert.x技術棧的多個部分,使用基於回撥的API。它僅僅可以正常工作,而且這個程式設計模型對於開發者在許多語言中是非常熟悉的。儘管如此,它可能有點繁瑣,尤其當你組合幾個事件源或者處理複雜
PHPUnit袖珍指南 第十章 程式碼覆蓋率分析
第十章程式碼覆蓋率分析 你已經學會了怎麼使用單元測試程式碼,但你怎麼測試你的測試呢?你怎麼發現沒被測試的程式碼,換句話說,沒被測試覆蓋的程式碼?怎麼衡量測試的完整性?所有這些問題的答案就是程式碼覆蓋率分析。程式碼覆蓋率分析告訴你當測試進行時,那些產品程式碼執行過了。 PH
第十章 CALL和RET指令
一、ret和retf ①ret:用棧中的資料修改IP的值,從而實現近轉移。 ret指令的兩步操作: (IP)=((SS)*16+(SP));(SP)=(SP)+2。 ②retf:用棧中的資料修改CS和IP的值,從而實現遠轉移。 retf指令的四步操作: (IP)=((SS)*16+(SP));(S
第十章——陣列和指標
陣列初始化 當初始化列表中的值少於陣列元素個數時,編譯器會把剩餘的元素都初始化為0;個數多於陣列元素個數時,會視為錯誤 省略陣列中括號中的數字,編譯器會根據初始化列表中的專案來確定陣列的大小。 days是陣列 sizeof days是整個陣列的大小 sizeof
C++ primer plus 第十章 物件和類
重要的面向物件程式設計特性:抽象、封裝和資料隱藏、多型、繼承和程式碼的可重用性。為了實現這些特性並將它們組合在一起,C++所做的最重要的改進是提供了類。 類是一種將抽象轉換為使用者定義型別的C++工具,它將資料表示和操縱資料的方法組合成一個整潔的包。 類宣告:以資料成員的方式描述資料部分,以
【翻譯】Sklearn與TensorFlow機器學習實用指南 ——第12章 裝置和伺服器上的分散式TensorFlow(上)
在第 11 章,我們討論了幾種可以明顯加速訓練的技術:更好的權重初始化,批量標準化,複雜的優化器等等。 但是,即使採用了所有這些技術,在具有單個 CPU 的單臺機器上訓練大型神經網路可能需要幾天甚至幾周的時間。在本章中,我們將看到如何使用 TensorFlow 在多個裝置(C
組合語言學習第十章-CALL和RET指令
(sp)=(sp)-2 ((ss)*16+(sp))=(IP)(IP與CS壓棧) (2) (CS)=標號處所在的段地址 (IP)=標號處所在的偏移地址 call far ptr 標號相當於: push CS push IP jmp far ptr 標號 10.
C Primer Plus 第十章——陣列和指標
與普通變數相似,在初始化之前陣列元素的數值是不定的。編譯器使用的數值是儲存單元中已有的數值。初始化陣列元素時(int),當數值數目少於陣列元素數目時(部分初始化),多餘的陣列元素被初始化為0。如果初始化列表中專案的個數大於陣列大小,編譯器則會認為這是一個錯誤。可以在初始化
thinkpython第十章練習10-5
Points: >sorted()內建函式,不改變原來列表,新建一個升序排列的列表,並把這個新列表返回。 >.sort()方法,直接改變原來列表,返回值為None。 編寫一個名為is_sorted的函式,接收一個列表為形參,並當列表是按照升序排好序的時候返回True,否則返回
.NET Core實戰專案之CMS 第十章 設計篇-系統開發框架設計
這兩天比較忙,週末也在加班,所以更新的就慢了一點,不過沒關係,今天我們就進行千呼萬喚的系統開發框架的設計。不知道上篇關於架構設計的文章大家有沒有閱讀,如果閱讀後相信一定對架構設計有了更近一部的理解,如果你沒有閱讀也希望大家能好好閱讀一下!其實說白了,架構是為了應對軟體系統複雜度而提出的一個解決方案,架構設計的
2018.10.16——第十章-10.1概述-10.2初識泛型演算法
10.1 #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int val = 1;
C++Primer第五版 第十章習題答案(1~10)
1:這個比較簡單,類比下 find() 函式也就知道了。 #include<iostream> #include<algorithm> #include<vector> using namespace std; void main() {
【《Real-Time Rendering 3rd》 提煉總結】(九) 第十章 · 遊戲開發中基於影象的渲染技術總結
毛星雲,網路ID「淺墨」,90後,熱愛遊戲開發、遊戲引擎、計算機圖形、實時渲染等技術,就職於騰訊互娛。 微軟最有價值專家 著作《Windows遊戲程式設計之從零開始》、《OpenCV3程式設計入門》 碩士就讀於南京航空航天大學航天學院(2013級碩士研究生),已於2016年三月畢業。本科
第十章 k-均值演算法 10.4 對地圖上的點進行聚類
將地圖上的點進行聚類,安排交通工具抵達這些簇的質心,然後步行到每個簇內地址。 這裡我們直接用給出的檔案進行操作,跳過10.4.1節。 新增程式碼: def distSLC(vecA, vecB):
從零開始Desire HD刷機指南——第十一章:利用第三方recovery備份與還原系統
原文地址:http://blog.sina.com.cn/s/blog_722b43a60100q5jf.html 本教程由symen 原創,轉載請註明出處。 上一章我們介紹瞭如何把第三方recovery 刷進手機,本章來介紹如何利用它來備份與還原系統。 先來看一下
從零開始Desire HD刷機指南——第十八章:如何給DHD進行廣告免疫
原文地址:http://blog.sina.com.cn/s/blog_722b43a60100q5kf.html 本教程由symen 原創,轉載請註明出處。 很多免費軟體都會帶有廣告條幅,看起來甚是惱人,下面教大家一種方法,來給你的DHD 進行廣告免疫。 原理