亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

three.js 入門詳解(二)

G9YH / 2415人閱讀

摘要:首先,下載并在的中使用然后,我們需要準(zhǔn)備一個(gè)模型,在函數(shù)中,創(chuàng)建變量,用于導(dǎo)入模型導(dǎo)入模型的時(shí)候,接受兩個(gè)參數(shù),第一個(gè)表示模型路徑,第二個(gè)表示完成導(dǎo)入后的回調(diào)函數(shù),一般我們需要在這個(gè)回調(diào)函數(shù)中將導(dǎo)入的模型添加到場景中。

9. 動(dòng)畫

在本章之前,所有畫面都是靜止的,本章將介紹如果使用Three.js進(jìn)行動(dòng)態(tài)畫面的渲染。此外,將會(huì)介紹一個(gè)Three.js作者寫的另外一個(gè)庫,用來觀測每秒幀數(shù)(FPS)。

9.1 實(shí)現(xiàn)動(dòng)畫效果 9.1.1 動(dòng)畫原理

在這里,我們將動(dòng)態(tài)畫面簡稱為動(dòng)畫(animation)。正如動(dòng)畫片的原理一樣,動(dòng)畫的本質(zhì)是利用了人眼的視覺暫留特性,快速地變換畫面,從而產(chǎn)生物體在運(yùn)動(dòng)的假象。而對于Three.js程序而言,動(dòng)畫的實(shí)現(xiàn)也是通過在每秒鐘多次重繪畫面實(shí)現(xiàn)的。

為了衡量畫面切換速度,引入了每秒幀數(shù)FPS(Frames Per Second)的概念,是指每秒畫面重繪的次數(shù)。FPS越,則動(dòng)畫效果越平滑,當(dāng)FPS小于20時(shí),一般就能明顯感受到畫面的卡滯現(xiàn)象。

那么FPS是不是越大越好呢?其實(shí)也未必。當(dāng)FPS足夠大(比如達(dá)到60),再增加幀數(shù)人眼也不會(huì)感受到明顯的變化,反而相應(yīng)地就要消耗更多資源(比如電影的膠片就需要更長了,或是電腦刷新畫面需要消耗計(jì)算資源等等)。因此,選擇一個(gè)適中的FPS即可。

NTSC標(biāo)準(zhǔn)的電視FPS是30,PAL標(biāo)準(zhǔn)的電視FPS是25,電影的FPS標(biāo)準(zhǔn)為24。而對于Three.js動(dòng)畫而言,一般FPS在3060之間都是可取的。

9.1.2 setInterval方法

如果要設(shè)置特定的FPS(雖然嚴(yán)格來說,即使使用這種方法,JavaScript也不能保證幀數(shù)精確性),可以使用JavaScript DOM定義的方法:

setInterval(fn,mesc)

其中,fn是每過msec毫秒執(zhí)行的函數(shù),如果將fn定義為重繪畫面的函數(shù),就能實(shí)現(xiàn)動(dòng)畫效果。setInterval函數(shù)返回一個(gè)變量timer,如果需要停止重繪,需要使用clearInterval方法,并傳入該變量timer,具體的做法為:

1、首先,在init函數(shù)中定義每20毫秒執(zhí)行draw函數(shù)的setInterval,返回值記錄在全局變量timer中:

timer = setInterval(draw,20);

2、在draw函數(shù)中,我們首先設(shè)定在每幀中的變化(畢竟,如果每幀都是相同的,即使重繪再多次,還是不會(huì)有動(dòng)畫的效果),這里我們讓場景中的長方體繞y軸轉(zhuǎn)動(dòng)。然后,執(zhí)行渲染:

function draw() {
    // 每過20ms 就會(huì)執(zhí)行一次這個(gè)函數(shù),rotation.y就會(huì)加0.01
    // 轉(zhuǎn)完360度就會(huì)進(jìn)行取余,所以就會(huì)一直轉(zhuǎn)下去
    mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2);
    renderer.render(scene, camera);
}

這樣,每20毫秒就會(huì)調(diào)用一次draw函數(shù),改變長方體的旋轉(zhuǎn)值,然后進(jìn)行重繪。最終得到的效果就是FPS50的旋轉(zhuǎn)長方體。

3、我們在HTML中添加兩個(gè)按鈕,一個(gè)是按下后停止動(dòng)畫,另一個(gè)是按下后繼續(xù)動(dòng)畫:

 

4、對應(yīng)的stopstart函數(shù)為:

function stop() {
    if (timer !== null) {
        clearInterval(timer);
        timer = null;
    }
}

function start() {
    if (timer == null) {
        clearInterval(timer);
        timer = setInterval(draw, 20);
    }
}

完整代碼:





    
    動(dòng)畫效果
    

    



    
    
    


效果圖:

9.1.3 requestAnimationFrame方法

大多數(shù)時(shí)候,我們并不在意多久重繪一次,這時(shí)候就適合用requestAnimationFrame方法了。它告訴瀏覽器在合適的時(shí)候調(diào)用指定函數(shù),通??赡苓_(dá)到60FPS。

requestAnimationFrame同樣有對應(yīng)的cancelAnimationFrame取消動(dòng)畫:

function stop() {
    if (timer !== null) {
        cancelAnimationFrame(timer);
        timer = null;
    }
}

setInterval不同的是,由于requestAnimationFrame只請求一幀畫面,因此,除了在init函數(shù)中需要調(diào)用,在被其調(diào)用的函數(shù)中需要再次調(diào)用requestAnimationFrame

function draw() {
    mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2);
    renderer.render(scene, camera);
    timer = requestAnimationFrame(draw);
}

因?yàn)?b>requestAnimationFrame較為“年輕”,因而一些老的瀏覽器使用的是試驗(yàn)期的名字:mozRequestAnimationFramewebkitRequestAnimationFrame、msRequestAnimationFrame,為了支持這些瀏覽器,我們最好在調(diào)用之前,先判斷是否定義了requestAnimationFrame以及上述函數(shù):

var requestAnimationFrame = window.requestAnimationFrame 
        || window.mozRequestAnimationFrame
        || window.webkitRequestAnimationFrame
        || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;

完整代碼:





    
    動(dòng)畫效果
    

    



    
    
    


setInterval和requestAnimationFrame的區(qū)別:

setInterval方法與requestAnimationFrame方法的區(qū)別較為微妙。一方面,最明顯的差別表現(xiàn)在setInterval可以手動(dòng)設(shè)定FPS,而requestAnimationFrame則會(huì)自動(dòng)設(shè)定FPS;但另一方面,即使是setInterval也不能保證按照給定的FPS執(zhí)行,在瀏覽器處理繁忙時(shí),很可能低于設(shè)定值。當(dāng)瀏覽器達(dá)不到設(shè)定的調(diào)用周期時(shí),requestAnimationFrame采用跳過某些幀的方式來表現(xiàn)動(dòng)畫,雖然會(huì)有卡滯的效果但是整體速度不會(huì)拖慢,而setInterval會(huì)因此使整個(gè)程序放慢運(yùn)行,但是每一幀都會(huì)繪制出來;

總而言之,requestAnimationFrame適用于對于時(shí)間較為敏感的環(huán)境(但是動(dòng)畫邏輯更加復(fù)雜),而setInterval則可在保證程序的運(yùn)算不至于導(dǎo)致延遲的情況下提供更加簡潔的邏輯(無需自行處理時(shí)間)。

9.2 使用stat.js記錄FPS

stat.js是Three.js的作者Mr.Doob的另一個(gè)有用的JavaScript庫。很多情況下,我們希望知道實(shí)時(shí)的FPS信息,從而更好地監(jiān)測動(dòng)畫效果。這時(shí)候,stat.js就能提供一個(gè)很好的幫助,它占據(jù)屏幕中的一小塊位置(如左上角),效果為:,單擊后顯示每幀渲染時(shí)間:

首先,我們需要下載stat.js文件,可以在https://github.com/mrdoob/stats.js/blob/master/build/stats.min.js找到。下載后,將其放在項(xiàng)目文件夾下,然后在HTML中引用:

在頁面初始化的時(shí)候,對其初始化并將其添加至屏幕一角。這里,我們以左上角為例:

var stat = null;

function init() {
    stat = new Stats();
    stat.domElement.style.position = "absolute";
    stat.domElement.style.left = "0px";
    stat.domElement.style.top = "0px";
    document.body.appendChild(stat.domElement);

    // Three.js init ...
}

然后,在上一節(jié)介紹的動(dòng)畫重繪函數(shù)draw中調(diào)用stat.begin();stat.end();分別表示一幀的開始與結(jié)束:

function draw() {
    stat.begin();

    mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2);
    renderer.render(scene, camera);

    stat.end();
}

完整代碼:





    
    stats
    
    

    



    
    




9.3 彈球案例

本節(jié)我們將使用一個(gè)彈球的例子來完整地學(xué)習(xí)使用動(dòng)畫效果。

1、首先,我們把通用的框架部分寫好,按照之前的方法實(shí)現(xiàn)動(dòng)畫重繪函數(shù),并加入stat.js庫:

var requestAnimationFrame = window.requestAnimationFrame 
        || window.mozRequestAnimationFrame
        || window.webkitRequestAnimationFrame
        || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;

var stat;
var renderer;
var scene;
var camera;
var light;

function init() {
    stat = new Stats();
    stat.domElement.style.position = "absolute";
    stat.domElement.style.left= "0px";
    stat.domElement.style.top = "0px";
    document.body.appendChild(stat.domElement);

    renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById("mainCanvas")
    });
    scene = new THREE.Scene();

    timer = requestAnimationFrame(draw);
}

function draw() {
    stat.begin();

    renderer.render(scene, camera);

    timer = requestAnimationFrame(draw);

    stat.end();
}

function stop() {
    if (timer !== null) {
        cancelAnimationFrame(timer);
        timer = null;
    }
}

2、然后,為了實(shí)現(xiàn)彈球彈動(dòng)的效果,我們創(chuàng)建一個(gè)球體作為彈球模型,創(chuàng)建一個(gè)平面作為彈球反彈的平面。為了在draw函數(shù)中改變彈球的位置,我們可以聲明一個(gè)全局變量ballMesh,以及彈球半徑ballRadius

var ballMesh;
var ballRadius = 0.5;

3、在init函數(shù)中添加球體平面,使彈球位于平面上,平面采用棋盤格圖像作材質(zhì):

// 加載貼圖
texture = THREE.ImageUtils.loadTexture("images/chess.png", {}, function() {
    renderer.render(scene, camera);
});
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(4, 4);

// 平面模型
var plane = new THREE.Mesh(new THREE.PlaneGeometry(8, 8),
    new THREE.MeshLambertMaterial({
        map: texture
    }));
// 沿x軸旋轉(zhuǎn)-90度
plane.rotation.x = Math.PI / -2;
scene.add(plane);

// 球模型
ballMesh = new THREE.Mesh(new THREE.SphereGeometry(ballRadius, 40, 16),
    new THREE.MeshLambertMaterial({
        color: 0xffff00
    }));

4、為了記錄彈球的狀態(tài),我們至少需要位置速度、加速度三個(gè)矢量,為了簡單起見,這里彈球只做豎直方向上的自由落體運(yùn)動(dòng),因此位置、速度、加速度只要各用一個(gè)變量表示。其中,位置就是ballMesh.position.y,不需要額外的變量,因此我們在全局聲明速度v加速度a

var v = 0;
var a = -0.01;

這里,a = -0.01代表每幀小球向y方向負(fù)方向移動(dòng)0.01個(gè)單位。

5、一開始,彈球從高度為maxHeight(自己定義的一個(gè)高度)處自由下落,掉落到平面上時(shí)會(huì)反彈,并且速度有損耗。當(dāng)速度很小的時(shí)候,彈球會(huì)在平面上作振幅微小的抖動(dòng),所以,當(dāng)速度足夠小時(shí),我們需要讓彈球停止跳動(dòng)。因此,定義一個(gè)全局變量表示是否在運(yùn)動(dòng),初始值為false

var isMoving = false;

6、在HTML中定義一個(gè)按鈕,點(diǎn)擊按鈕時(shí),彈球從最高處下落:



7、下面就是最關(guān)鍵的函數(shù)了,在draw函數(shù)中,需要判斷當(dāng)前的isMoving值,并且更新小球的速度和位置:

function draw() {
    stat.begin();
    if (isMoving) {
        ballMesh.position.y += v;
        // a= -0.01
        v += a;
        // 當(dāng)小球從定義的高度落到小球停在平面時(shí)的高度的時(shí)候
        if (ballMesh.position.y <= ballRadius) {
            // 讓小球彈起來
            v = -v * 0.9;
        }
        // 當(dāng)小球的速度小于設(shè)定值的時(shí)候
        if (Math.abs(v) < 0.001) {
            // 讓它停下來
            isMoving = false;
            ballMesh.position.y = ballRadius;
        }
    }
    renderer.render(scene, camera);
    requestAnimationFrame(draw);
    stat.end();
}

完整代碼:





    
    彈彈彈
    
    
    
    



    


效果圖:

10. 外部模型

前面我們了解到,使用Three.js創(chuàng)建常見幾何體是十分方便的,但是對于人或者動(dòng)物這樣非常復(fù)雜的模型使用幾何體組合就非常麻煩了。因此,Three.js允許用戶導(dǎo)入由3ds Max等工具制作的三維模型,并添加到場景中。

本章以3ds Max為例,介紹如何導(dǎo)入外部模型。

10.1 支持格式

Three.js有一系列導(dǎo)入外部文件的輔助函數(shù),是在three.js之外的,使用前需要額外下載,在https://github.com/mrdoob/three.js/tree/master/examples/js/loaders可以找到,選擇對應(yīng)的模型加載器,系在下來。

*.obj是最常用的模型格式,導(dǎo)入*.obj文件需要OBJLoader.js;導(dǎo)入帶*.mtl材質(zhì)的*.obj文件需要MTLLoader.js以及OBJMTLLoader.js。另有PLYLoader.jsSTLLoader.js等分別對應(yīng)不同格式的加載器,可以根據(jù)模型格式自行選擇。

目前,支持的模型格式有:

*.obj

*.obj, *.mtl

*.dae

*.ctm

*.ply

*.stl

*.wrl

*.vtk

10.2 無材質(zhì)的模型

本節(jié)中,我們將將導(dǎo)出的沒有材質(zhì)的模型使用Three.js導(dǎo)入場景中。

首先,下載OBJLoader.js并在HTML的中使用:

然后,我們需要準(zhǔn)備一個(gè)*.obj模型,在init函數(shù)中,創(chuàng)建loader變量,用于導(dǎo)入模型:

var loader = new THREE.OBJLoader();

loader導(dǎo)入模型的時(shí)候,接受兩個(gè)參數(shù),第一個(gè)表示模型路徑,第二個(gè)表示完成導(dǎo)入后的回調(diào)函數(shù),一般我們需要在這個(gè)回調(diào)函數(shù)中將導(dǎo)入的模型添加到場景中。

loader.load("../lib/port.obj", function(obj) {
    //儲(chǔ)存到全局變量中
    mesh = obj; 
    scene.add(obj);
});

可以看到一個(gè)沒有材質(zhì)的茶壺

我們在重繪函數(shù)中讓茶壺旋轉(zhuǎn):

function draw() {
    renderer.render(scene, camera);

    mesh.rotation.y += 0.01;
    if (mesh.rotation.y > Math.PI * 2) {
        mesh.rotation.y -= Math.PI * 2;
    }
}

可以看到在某些角度時(shí),好像有些面片沒有被繪制出來,因而后方的茶嘴似乎穿越到前方了:

這是由于默認(rèn)的情況下,只有正面的面片被繪制,而如果需要雙面繪制,需要這樣設(shè)置:

var loader = new THREE.OBJLoader();
loader.load("port.obj", function(obj) {
    obj.traverse(function(child) {
        if (child instanceof THREE.Mesh) {
            child.material.side = THREE.DoubleSide;
        }
    });

    mesh = obj;
    scene.add(obj);
});

完整代碼:





    
    
    
    






效果圖:

10.3 有材質(zhì)的模型

模型的材質(zhì)可以有兩種定義方式,一種是在代碼中導(dǎo)入模型后設(shè)置材質(zhì),另一種是在建模軟件中導(dǎo)出材質(zhì)信息。下面,我們將分別介紹這兩種方法。

10.3.1 代碼中設(shè)置材質(zhì)

這種方法與上一節(jié)類似,不同之處在于回調(diào)函數(shù)中設(shè)置模型的材質(zhì):

var loader = new THREE.OBJLoader();
loader.load("port.obj", function(obj) {
    obj.traverse(function(child) {
        if (child instanceof THREE.Mesh) {
            /* 修改這里以下的代碼 */
            child.material = new THREE.MeshLambertMaterial({
                color: 0xffff00,
                side: THREE.DoubleSide
            });
            /* 修改這里以上的代碼 */
        }
    });

    mesh = obj;
    scene.add(obj);
});

效果圖:

10.3.2 建模軟件中設(shè)置材質(zhì)

導(dǎo)出3D模型的時(shí)候,選擇導(dǎo)出port.obj模型文件以及port.mtl材質(zhì)文件。

現(xiàn)在,我們不再使用OBJLoader.js,而是使用MTLLoader.jsOBJMTLLoader.js,并且要按該順序引用:


調(diào)用的方法也略有不同:

var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath("");
mtlLoader.load("port.mtl", function(materials) {
    materials.preload();
    // model loader
    var objLoader = new THREE.OBJLoader();
    objLoader.setMaterials(materials);
    objLoader.setPath("");
    objLoader.load("port.obj", function(object) {
        object.position.y = -95;
        // if has object, add to scene
        if (object.children.length > 0) {
            scene.add(object.children[0]);
        }
    });
});

完整代碼:




    
    
    

    





導(dǎo)出時(shí)自帶的效果圖:

11. 光與影

圖像渲染的豐富效果很大程度上也要?dú)w功于光與影的利用。真實(shí)世界中的光影效果非常復(fù)雜,但是其本質(zhì)—光的傳播原理卻又是非常單一的,這便是自然界繁簡相成的又一例證。為了使計(jì)算機(jī)模擬豐富的光照效果,人們提出了幾種不同的光源模型(環(huán)境光、平行光點(diǎn)光源、聚光燈等),在不同場合下組合利用,將能達(dá)到很好的光照效果。

在Three.js中,光源與陰影的創(chuàng)建和使用是十分方便的。在學(xué)會(huì)了如何控制光影的基本方法之后,如果能將其靈活應(yīng)用,將能使場景的渲染效果更加豐富逼真。在本章中,我們將探討四種常用的光源(環(huán)境光、點(diǎn)光源、平行光、聚光燈)和陰影帶來的效果,以及如何去創(chuàng)建使用光影。

11.1 環(huán)境光(AmbientLight)

環(huán)境光是指場景整體的光照效果,是由于場景內(nèi)若干光源的多次反射形成的亮度一致的效果,通常用來為整個(gè)場景指定一個(gè)基礎(chǔ)亮度。因此,環(huán)境光沒有明確的光源位置,在各處形成的亮度也是一致的。

在設(shè)置環(huán)境光時(shí),只需指定光的顏色:

var light = new THREE.AmbientLight(hex);
scene.add(light);

其中hex是十六進(jìn)制的RGB顏色信息,如紅色表示為0xff0000

但是,如果此時(shí)場景中沒有物體,只添加了這個(gè)環(huán)境光,那么渲染的結(jié)果仍然是一片黑。所以,我們添加兩個(gè)長方體看下效果:

// 創(chuàng)建一個(gè)綠色的正方體
var greenCube = new THREE.Mesh(new THREE.CubeGeometry(2, 2, 2),
        new THREE.MeshLambertMaterial({color: 0x00ff00}));
greenCube.position.x = 3;
scene.add(greenCube);

// 創(chuàng)建一個(gè)白色的正方體
var whiteCube = new THREE.Mesh(new THREE.CubeGeometry(2, 2, 2),
        new THREE.MeshLambertMaterial({color: 0xffffff}));
whiteCube.position.x = -3;
scene.add(whiteCube);

效果如圖:

如果想讓環(huán)境光暗些,可以將其設(shè)置為new THREE.AmbientLight(0xcccccc)等,效果為:

11.2 點(diǎn)光源(PointLight)

點(diǎn)光源是不計(jì)光源大小,可以看作一個(gè)點(diǎn)發(fā)出的光源。點(diǎn)光源照到不同物體表面的亮度是線性遞減的,因此,離點(diǎn)光源距離越遠(yuǎn)的物體會(huì)顯得越

點(diǎn)光源的構(gòu)造函數(shù)是:

THREE.PointLight(hex, intensity, distance);

其中,hex是光源十六進(jìn)制的顏色值;intensity是亮度,缺省值為1,表示100%亮度;distance是光源最遠(yuǎn)照射到的距離,缺省值為0。

創(chuàng)建點(diǎn)光源并將其添加到場景中的完整做法是:

var light = new THREE.PointLight(0xffffff, 2, 100);
light.position.set(0, 1.5, 2);
scene.add(light);

效果圖:

注意,這里光在每個(gè)面上的亮度是不同的,對于每個(gè)三角面片,將根據(jù)三個(gè)頂點(diǎn)的亮度進(jìn)行插值。

11.3 平行光(DirectionalLight)

我們都知道,太陽光常常被看作平行光,這是因?yàn)橄鄬Φ厍蛏衔矬w的尺度而言,太陽離我們的距離足夠遠(yuǎn)。對于任意平行的平面,平行光照射的亮度都是相同的,而與平面所在位置無關(guān)。

平行光的構(gòu)造函數(shù)是:

THREE.DirectionalLight(hex, intensity)

其中,hex是光源十六進(jìn)制的顏色值;intensity是亮度,缺省值為1,表示100%亮度。

此外,對于平行光而言,設(shè)置光源位置尤為重要。

var light = new THREE.DirectionalLight();
light.position.set(2, 5, 3);
scene.add(light);

注意,這里設(shè)置光源位置并不意味著所有光從(2, 5, 3)點(diǎn)射出(如果是的話,就成了點(diǎn)光源),而是意味著,平行光將以矢量(-2, -5, -3)的方向照射到所有平面。因此,平面亮度與平面的位置無關(guān),而只與平面的法向量相關(guān)。只要平面是平行的,那么得到的光照也一定是相同的。

示例代碼:





    
    
    






效果圖:

11.4 聚光燈(SpotLight)

可以看出,聚光燈是一種特殊的點(diǎn)光源,它能夠朝著一個(gè)方向投射光線。聚光燈投射出的是類似圓錐形的光線,這與我們現(xiàn)實(shí)中看到的聚光燈是一致的。

其構(gòu)造函數(shù)為:

THREE.SpotLight(hex, intensity, distance, angle, exponent)

相比點(diǎn)光源,多了angleexponent兩個(gè)參數(shù)。angle是聚光燈的張角,缺省值是Math.PI / 3,最大值是Math.PI / 2;exponent是光強(qiáng)在偏離target的衰減指數(shù)(target需要在之后定義,缺省值為(0, 0, 0)),缺省值是10

在調(diào)用構(gòu)造函數(shù)之后,除了設(shè)置光源本身的位置,一般還需要設(shè)置target

light.position.set(x1, y1, z1);
light.target.position.set(x2, y2, z2);

除了設(shè)置light.target.position的方法外,如果想讓聚光燈跟著某一物體移動(dòng)(就像真的聚光燈!),可以target指定為該物體

var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1),
                    new THREE.MeshLambertMaterial({color: 0x00ff00}));

var light = new THREE.SpotLight(0xffff00, 1, 100, Math.PI / 6, 25);
light.target = cube;

示例代碼:





    
    
    






效果圖:

11.5 陰影

明暗是相對的,陰影的形成也就是因?yàn)楸戎車@得的光照更少。因此,要形成陰影,光源必不可少。

在Three.js中,能形成陰影的光源只有THREE.DirectionalLightTHREE.SpotLight;而相對地,能表現(xiàn)陰影效果的材質(zhì)只有THREE.LambertMaterialTHREE.PhongMaterial。因而在設(shè)置光源和材質(zhì)的時(shí)候,一定要注意這一點(diǎn)。

下面,我們以聚光燈為例,在之前的基礎(chǔ)上增加陰影效果。

首先,我們需要在初始化時(shí),告訴渲染器渲染陰影:

renderer.shadowMapEnabled = true;

然后,對于光源以及所有要產(chǎn)生陰影的物體調(diào)用:

// 上面的案例,產(chǎn)生陰影的物體是正方體
cube.castShadow = true;

對于接收陰影的物體調(diào)用:

// 接收陰影的物體是平面
plan.receiveShadow = true;

比如場景中一個(gè)平面上有一個(gè)正方體,想要讓聚光燈照射在正方體上,產(chǎn)生的陰影投射在平面上,那么就需要對聚光燈和正方體調(diào)用castShadow = true,對于平面調(diào)用receiveShadow = true

以上就是產(chǎn)生陰影效果的必要步驟了,不過通常還需要設(shè)置光源的陰影相關(guān)屬性,才能正確顯示出陰影效果。

對于聚光燈,需要設(shè)置shadowCameraNear、shadowCameraFar、shadowCameraFov三個(gè)值,類比我們在第二章學(xué)到的透視投影照相機(jī),只有介于shadowCameraNearshadowCameraFar之間的物體將產(chǎn)生陰影,shadowCameraFov表示張角。

對于平行光,需要設(shè)置shadowCameraNearshadowCameraFar、shadowCameraLeft、shadowCameraRightshadowCameraTop以及shadowCameraBottom六個(gè)值,相當(dāng)于正交投影照相機(jī)的六個(gè)面。同樣,只有在這六個(gè)面圍成的長方體內(nèi)的物體才會(huì)產(chǎn)生陰影效果。

為了看到陰影照相機(jī)的位置,通??梢栽谡{(diào)試時(shí)開啟light.shadowCameraVisible = true

如果想要修改陰影的深淺,可以通過設(shè)置shadowDarkness,該值的范圍是01,越小越淺。

另外,這里實(shí)現(xiàn)陰影效果的方法是Shadow Mapping,即陰影是作為渲染前計(jì)算好的貼圖貼上去的,因而會(huì)受到貼圖像素大小的限制。所以可以通過設(shè)置shadowMapWidthshadowMapHeight值控制貼圖的大小,來改變陰影的精確度。

而如果想實(shí)現(xiàn)軟陰影的效果,可以通過renderer.shadowMapSoft = true;方便地實(shí)現(xiàn)。

完整代碼:





    
    
    






效果圖:

補(bǔ)充問題

本地服務(wù)器

1、下載安裝node.js,因?yàn)閚ode.js自帶npm

2、打開電腦命令行工具,輸入npm install -g live-server 全局安裝

3、在需要運(yùn)行文件的文件夾下,按住shift鍵,點(diǎn)擊鼠標(biāo)右鍵在此處打開命令窗口

4、輸入live-server回車

nmp官方說明

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/90110.html

相關(guān)文章

  • 【連載】前端個(gè)人文章整理-從基礎(chǔ)到入門

    摘要:個(gè)人前端文章整理從最開始萌生寫文章的想法,到著手開始寫,再到現(xiàn)在已經(jīng)一年的時(shí)間了,由于工作比較忙,更新緩慢,后面還是會(huì)繼更新,現(xiàn)將已經(jīng)寫好的文章整理一個(gè)目錄,方便更多的小伙伴去學(xué)習(xí)。 showImg(https://segmentfault.com/img/remote/1460000017490740?w=1920&h=1080); 個(gè)人前端文章整理 從最開始萌生寫文章的想法,到著手...

    madthumb 評(píng)論0 收藏0
  • three.js 入門詳解(一)

    摘要:一般說來,對于制圖建模軟通常使正交投影,這樣不會(huì)因?yàn)橥队岸淖兾矬w比例而對于其他大多數(shù)應(yīng)用,通常使用透視投影,因?yàn)檫@更接近人眼的觀察效果。 showImg(https://segmentfault.com/img/remote/1460000012581680?w=1920&h=1080); 1. 概述 1.1 什么是WebGL? WebGL是在瀏覽器中實(shí)現(xiàn)三維效果的一套規(guī)范 想要使用...

    Jacendfeng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<