成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

WebGL three.js學(xué)習(xí)筆記 使用粒子系統(tǒng)模擬時(shí)空隧道(蟲洞)

Guakin_Huang / 3495人閱讀

摘要:學(xué)習(xí)筆記使用粒子系統(tǒng)模擬時(shí)空隧道本例的運(yùn)行結(jié)果如圖時(shí)空隧道演示地址的粒子系統(tǒng)的粒子系統(tǒng)主要是依靠精靈體來創(chuàng)建的,要實(shí)現(xiàn)中的粒子系統(tǒng)創(chuàng)建,一般有兩種方式。

WebGL three.js學(xué)習(xí)筆記 使用粒子系統(tǒng)模擬時(shí)空隧道

本例的運(yùn)行結(jié)果如圖:

時(shí)空隧道demo演示 Demo地址:https://nsytsqdtn.github.io/d... three.js的粒子系統(tǒng)

three.js的粒子系統(tǒng)主要是依靠精靈體來創(chuàng)建的,要實(shí)現(xiàn)three.js中的粒子系統(tǒng)創(chuàng)建,一般有兩種方式。

第一種是在場景中使用很多歌THREE.Sprite創(chuàng)建單個(gè)的精靈,這樣創(chuàng)建的每一個(gè)精靈體,我們都可以多帶帶對(duì)它們進(jìn)行操作,同時(shí)我們也可以用一個(gè)THREE.Group把他們放在一起,整合起來一起操作。具有很高的自主性。但同時(shí)也是需要大量的性能支持與開發(fā)上的不便利性,所以這里我選擇了第二種方式。

第二種創(chuàng)建粒子系統(tǒng)是依靠點(diǎn)云的方式,點(diǎn)云就是很多很多點(diǎn)組成的一個(gè)東西,點(diǎn)云里面的每一個(gè)頂點(diǎn)都可以看做一個(gè)粒子,而這個(gè)粒子我們就可以使用紋理去對(duì)它美化,或者是使用坐標(biāo)變化來變化出好看的粒子系統(tǒng),這種創(chuàng)建方式的缺點(diǎn)是不能對(duì)每一個(gè)粒子多帶帶進(jìn)行操作,但是相比第一種卻給我們提供了更多的方便。

搭建場景

點(diǎn)云的創(chuàng)建方法和普通的幾何體差不多,首先需要一個(gè)材質(zhì)THREE.PointsMaterial,可以設(shè)置每個(gè)粒子的大小size,顏色color,透明transparent等等屬性。然后再用THREE.Points(geometry, material)這個(gè)方法就可以創(chuàng)建出點(diǎn)云了。

let cloud = new THREE.Points(geom, material);//創(chuàng)建點(diǎn)云

如果我們給了Points(),geometry這個(gè)參數(shù),這個(gè)點(diǎn)云會(huì)按照我們定義好的幾何體的頂點(diǎn)去創(chuàng)建粒子。
,比如geometry是一個(gè)Box,那么這個(gè)點(diǎn)云就會(huì)有8粒子,分別分布在正方體的8個(gè)頂點(diǎn)上。如果我們不用geometry,我們就需要手動(dòng)給點(diǎn)云創(chuàng)建很多的頂點(diǎn),包括定義它們的坐標(biāo),這里我們也是用一個(gè)定義好的幾何體去創(chuàng)建粒子。

//創(chuàng)建點(diǎn)云
    function createPointCloud(geom,color) {
        let material = new THREE.PointsMaterial({
            color: color,
            size: 3,
            transparent: true,
            blending: THREE.AdditiveBlending,//混合的模式,可以讓很多的粒子的背景得到很好的融合,而不是互相干擾
            map: generateSprite()//取得漸變的canvas紋理
        });
        let cloud = new THREE.Points(geom, material);//創(chuàng)建點(diǎn)云
        cloud.sortParticles = true;//可以讓所有粒子的Z軸得到正確擺放,不會(huì)互相遮擋
        return cloud;
    }

函數(shù)形參傳過來的geom,我們使用的一個(gè)類似于管道的幾何體TorusGeometry
TorusGeometry的構(gòu)造函數(shù)如下:
THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)
    **radius:圓環(huán)半徑
    tube:管道半徑
    radialSegments:徑向的分段數(shù)
    tubularSegments:管的分段數(shù)
    arc:圓環(huán)面的弧度,缺省值為Math.PI 2*

    

let geom = new THREE.TorusGeometry(
controls.radius, controls.tube,
 Math.round(controls.radialSegments), 
 Math.round(controls.tubularSegments)
 );//TorusGeometry幾何體,管道狀的幾何體,里面的參數(shù)設(shè)置都是菜單面板上面的參數(shù)

這里的參數(shù)主要就是我們要在菜單面板中去更改的值,

controls = new function () {
            this.radius = 100;//整個(gè)大圓隧道的半徑
            this.tube = 10;//管道的半徑
            this.radialSegments = 40;//管道的段數(shù),值越大,創(chuàng)造的物體更精細(xì),也更消耗性能
            this.tubularSegments = 200;//整個(gè)大圓隧道的段數(shù),值越大,創(chuàng)造的物體更精細(xì),也更消耗性能
            this.useParticle = true;//是否使用粒子系統(tǒng)創(chuàng)造幾何體
            this.rotationSpeed = 0.003;//攝像機(jī)的速度
            this.color = 0xffffff;//此顏色會(huì)與材質(zhì)中紋理本身的顏色做乘法,最后的結(jié)果就是渲染出來的顏色
            }

如果我們要想創(chuàng)建一個(gè)好看的時(shí)空隧道還需要它的map屬性,去賦給它一個(gè)紋理,這樣每一個(gè)粒子都會(huì)比純色更美觀。紋理的話使用圖片也是可以的,在這里我選擇了制作一個(gè)漸變的畫布來當(dāng)做紋理,即generateSprite()這個(gè)函數(shù)的返回值。
generateSprite函數(shù)代碼(主要用到的是canvas的繪圖函數(shù),js的基礎(chǔ)部分):

function generateSprite() {
        let canvas = document.createElement("canvas");
        canvas.width = 16;
        canvas.height = 16;
        let context = canvas.getContext("2d");//得到canvas的繪圖上下文
        let gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2);//顏色漸變圖形
        gradient.addColorStop(0, "rgba(255,255,255,1)");//從內(nèi)向外的第一漸變顏色,設(shè)置為白色
        gradient.addColorStop(0.2, "rgba(0,125,125,1)");//從內(nèi)向外的第二漸變顏色,設(shè)置為淺藍(lán)色
        gradient.addColorStop(0.5, "rgba(0,64,0,1)");//從內(nèi)向外的第三漸變顏色,設(shè)置為綠色
        gradient.addColorStop(1, "rgba(0,0,0,0.1)");//最外層的漸變顏色,為背景色
        context.fillStyle = gradient;
        context.fillRect(0, 0, canvas.width, canvas.height);

        let texture = new THREE.Texture(canvas);//將得到的畫好的canvas作為紋理圖片
        texture.needsUpdate = true;//需要設(shè)置更新,否則會(huì)沒有效果
        return texture;
    }

注意texture.needsUpdate = true這句話,否則是渲染不出來的。
到此,我們就可以開始繪制場景

this.draw = function () {
                cameraInit = true;//調(diào)用此函數(shù)后,對(duì)攝像機(jī)進(jìn)行一次初始化
                if (obj) scene.remove(obj);//如果場景的隧道已經(jīng)存在,先移除
                let geom = new THREE.TorusGeometry(controls.radius, controls.tube, Math.round(controls.radialSegments), Math.round(controls.tubularSegments));//TorusGeometry幾何體,管道狀的幾何體,里面的參數(shù)設(shè)置都是菜單面板上面的參數(shù)
                //使用粒子系統(tǒng)渲染幾何體
                if (controls.useParticle) {
                    obj = createPointCloud(geom,controls.color);
                    obj.rotation.x = Math.PI/2;//旋轉(zhuǎn)90度以后,更加方便觀測
                } else {//使用普通材質(zhì)系統(tǒng)渲染幾何體
                    obj = createMesh(geom);
                    obj.rotation.x = Math.PI/2;
                }
                scene.add(obj);
            }

場景有了以后,攝像機(jī)還是不會(huì)動(dòng),沒有一種在時(shí)空隧道的感覺,所以這里想辦法讓攝像機(jī)在這個(gè)隧道的中間,沿著這個(gè)幾何體的形狀去移動(dòng)。

因?yàn)楣艿啦豢磞軸的話,其實(shí)還是一個(gè)圓形,所以可以使用圓形的參數(shù)方程來讓攝像機(jī)沿著這個(gè)函數(shù)去運(yùn)動(dòng)。讓y軸始終不變就可以。

let angle = 0;//初始角度
angle = angle + controls.rotationSpeed;//相機(jī)移動(dòng)的速度
camera.position.set(controls.radius*Math.sin(angle),0,
controls.radius*Math.cos(angle));//讓相機(jī)按照一個(gè)圓形軌跡運(yùn)動(dòng)
//可以理解為圓形的參數(shù)方程x=rsinα,y=rcosα,

即設(shè)置相機(jī)的x為rsinα,z為rcosα,y軸是一直都為0的。這里的r為整個(gè)隧道的半徑,α就是當(dāng)前移動(dòng)的角度。
雖然這樣可以讓相機(jī)開始移動(dòng)了,但是相機(jī)的目標(biāo)我們還沒有設(shè)置,我們需要讓相機(jī)在移動(dòng)的過程中,始終看向前方,這樣才有一種在時(shí)空隧道中漫游的感覺。但是three.js的相機(jī)運(yùn)動(dòng)軌跡插件似乎在這里不好用,所以就想到了用其他方式實(shí)現(xiàn)。

我們既然已經(jīng)用相機(jī)運(yùn)動(dòng)的圓的軌跡方程,也能很容易想到相機(jī)lookAt的方向其實(shí)就是沿著圓運(yùn)動(dòng)的切線方向。所以只需要求攝像機(jī)運(yùn)動(dòng)的當(dāng)前位置的切線就可以了。

這里用到的是向量的點(diǎn)乘,坐標(biāo)的點(diǎn)乘公式x1y2+x2y1,如果結(jié)果為0,就可以得到這個(gè)向量的垂直向量,我們要求的切線肯定就是垂直于半徑的。因?yàn)槲覀兊膟軸一直不變的,所以點(diǎn)乘公式的y我們變?yōu)閦。我們首先是讓相機(jī)的位置減去隧道的中心(0,0,0),得到指向中心的向量,也就是半徑,然后再用一個(gè)向量與它點(diǎn)乘為0,這個(gè)向量方向就是垂直于半徑的了,也就是切線的方向。

function look(){
        let view = new THREE.Vector3(camera.position.x, 
        camera.position.y, 
        camera.position.z);//計(jì)算當(dāng)前攝像機(jī)位置點(diǎn)到世界中心點(diǎn)的向量
        let vertical = (new THREE.Vector3(view.z, 0, 
        -1.0 * view.x)).normalize();
        //兩個(gè)向量的點(diǎn)積如果為0,則兩個(gè)向量垂直,公式為x1*y2+x2*y1=0,
        //這里的Y軸用Z軸代替。計(jì)算出垂直向量以后用normalize()化成單位向量
        camera.lookAt(camera.position.x+vertical.x,0,
        camera.position.z+vertical.z);//camera.lookAt的值設(shè)置為 剛剛的單位向量加在當(dāng)前攝像機(jī)的位置
        //這樣就實(shí)現(xiàn)了在攝像機(jī)在旋轉(zhuǎn)時(shí),一直朝前看。

    }

最后得到的這個(gè)單位向量我們?cè)偌由袭?dāng)前相機(jī)的位置,就可以設(shè)置為相機(jī)lookAt的值。
注意我們?cè)诿看武秩镜臅r(shí)候都要去改變這個(gè)值,因?yàn)橄鄼C(jī)的位置一直都在變化的,所以我們要把它封裝成一個(gè)函數(shù),方便在渲染的時(shí)候調(diào)用。

其他的,相機(jī),場景的初始化代碼:

function initThree() {
        //渲染器初始化
        renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x000000);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);//將渲染添加到div中
        //初始化攝像機(jī),這里使用透視投影攝像機(jī)
        camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.up.x = 0;//設(shè)置攝像機(jī)的上方向?yàn)槟膫€(gè)方向,這里定義攝像的上方為Y軸正方向
        camera.up.y = 1;
        camera.up.z = 0;
        look();//計(jì)算攝像機(jī)在當(dāng)前位置應(yīng)該對(duì)準(zhǔn)的目標(biāo)點(diǎn),即camera.lookAt的設(shè)置

        //初始化場景
        scene = new THREE.Scene();

    }

至此,場景基本已經(jīng)構(gòu)建完成了。

完整的代碼如下:



    
    Sprite Tunnel
    
    
    
    
    


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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103915.html

相關(guān)文章

  • WebGL three.js學(xué)習(xí)筆記 紋理貼圖模擬太陽系運(yùn)轉(zhuǎn)

    摘要:紋理貼圖的應(yīng)用以及實(shí)現(xiàn)一個(gè)太陽系的自轉(zhuǎn)公轉(zhuǎn)點(diǎn)擊查看演示地址中的紋理紋理貼圖是通過將圖像應(yīng)用到對(duì)象的一個(gè)或多個(gè)面,來為對(duì)象添加細(xì)節(jié)的一種方法。 紋理貼圖的應(yīng)用以及實(shí)現(xiàn)一個(gè)太陽系的自轉(zhuǎn)公轉(zhuǎn) 點(diǎn)擊查看demo演示 demo地址:https://nsytsqdtn.github.io/d... three.js中的紋理 紋理貼圖是通過將圖像應(yīng)用到對(duì)象的一個(gè)或多個(gè)面,來為3D對(duì)象添加細(xì)節(jié)的一種...

    Pandaaa 評(píng)論0 收藏0
  • WebGL three.js學(xué)習(xí)筆記 法向量網(wǎng)格材質(zhì)MeshNormalMaterial的介紹和創(chuàng)建

    摘要:學(xué)習(xí)學(xué)習(xí)筆記點(diǎn)擊查看演示地址簡單網(wǎng)格材質(zhì)是一種不受渲染時(shí)使用的顏色影響的材質(zhì),它只與自己每一個(gè)面從內(nèi)到外的法向量有關(guān)。法向量在中用處十分廣泛,光的反射,以及三維圖形的紋理映射都與這個(gè)有關(guān)。 WebGL學(xué)習(xí)----Three.js學(xué)習(xí)筆記(5) 點(diǎn)擊查看demo演示 Demo地址:https://nsytsqdtn.github.io/d... 簡單網(wǎng)格材質(zhì) MeshNormalMat...

    陸斌 評(píng)論0 收藏0

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

0條評(píng)論

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