摘要:學習筆記使用粒子系統模擬時空隧道本例的運行結果如圖時空隧道演示地址的粒子系統的粒子系統主要是依靠精靈體來創建的,要實現中的粒子系統創建,一般有兩種方式。
WebGL three.js學習筆記 使用粒子系統模擬時空隧道
本例的運行結果如圖:
three.js的粒子系統主要是依靠精靈體來創建的,要實現three.js中的粒子系統創建,一般有兩種方式。
第一種是在場景中使用很多歌THREE.Sprite創建單個的精靈,這樣創建的每一個精靈體,我們都可以多帶帶對它們進行操作,同時我們也可以用一個THREE.Group把他們放在一起,整合起來一起操作。具有很高的自主性。但同時也是需要大量的性能支持與開發上的不便利性,所以這里我選擇了第二種方式。
第二種創建粒子系統是依靠點云的方式,點云就是很多很多點組成的一個東西,點云里面的每一個頂點都可以看做一個粒子,而這個粒子我們就可以使用紋理去對它美化,或者是使用坐標變化來變化出好看的粒子系統,這種創建方式的缺點是不能對每一個粒子多帶帶進行操作,但是相比第一種卻給我們提供了更多的方便。
搭建場景點云的創建方法和普通的幾何體差不多,首先需要一個材質THREE.PointsMaterial,可以設置每個粒子的大小size,顏色color,透明transparent等等屬性。然后再用THREE.Points(geometry, material)這個方法就可以創建出點云了。
let cloud = new THREE.Points(geom, material);//創建點云
如果我們給了Points(),geometry這個參數,這個點云會按照我們定義好的幾何體的頂點去創建粒子。
,比如geometry是一個Box,那么這個點云就會有8粒子,分別分布在正方體的8個頂點上。如果我們不用geometry,我們就需要手動給點云創建很多的頂點,包括定義它們的坐標,這里我們也是用一個定義好的幾何體去創建粒子。
//創建點云 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);//創建點云 cloud.sortParticles = true;//可以讓所有粒子的Z軸得到正確擺放,不會互相遮擋 return cloud; }
函數形參傳過來的geom,我們使用的一個類似于管道的幾何體TorusGeometry
TorusGeometry的構造函數如下:
THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)
**radius:圓環半徑
tube:管道半徑
radialSegments:徑向的分段數
tubularSegments:管的分段數
arc:圓環面的弧度,缺省值為Math.PI 2*
let geom = new THREE.TorusGeometry( controls.radius, controls.tube, Math.round(controls.radialSegments), Math.round(controls.tubularSegments) );//TorusGeometry幾何體,管道狀的幾何體,里面的參數設置都是菜單面板上面的參數
這里的參數主要就是我們要在菜單面板中去更改的值,
controls = new function () { this.radius = 100;//整個大圓隧道的半徑 this.tube = 10;//管道的半徑 this.radialSegments = 40;//管道的段數,值越大,創造的物體更精細,也更消耗性能 this.tubularSegments = 200;//整個大圓隧道的段數,值越大,創造的物體更精細,也更消耗性能 this.useParticle = true;//是否使用粒子系統創造幾何體 this.rotationSpeed = 0.003;//攝像機的速度 this.color = 0xffffff;//此顏色會與材質中紋理本身的顏色做乘法,最后的結果就是渲染出來的顏色 }
如果我們要想創建一個好看的時空隧道還需要它的map屬性,去賦給它一個紋理,這樣每一個粒子都會比純色更美觀。紋理的話使用圖片也是可以的,在這里我選擇了制作一個漸變的畫布來當做紋理,即generateSprite()這個函數的返回值。
generateSprite函數代碼(主要用到的是canvas的繪圖函數,js的基礎部分):
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)");//從內向外的第一漸變顏色,設置為白色 gradient.addColorStop(0.2, "rgba(0,125,125,1)");//從內向外的第二漸變顏色,設置為淺藍色 gradient.addColorStop(0.5, "rgba(0,64,0,1)");//從內向外的第三漸變顏色,設置為綠色 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;//需要設置更新,否則會沒有效果 return texture; }
注意texture.needsUpdate = true這句話,否則是渲染不出來的。
到此,我們就可以開始繪制場景
this.draw = function () { cameraInit = true;//調用此函數后,對攝像機進行一次初始化 if (obj) scene.remove(obj);//如果場景的隧道已經存在,先移除 let geom = new THREE.TorusGeometry(controls.radius, controls.tube, Math.round(controls.radialSegments), Math.round(controls.tubularSegments));//TorusGeometry幾何體,管道狀的幾何體,里面的參數設置都是菜單面板上面的參數 //使用粒子系統渲染幾何體 if (controls.useParticle) { obj = createPointCloud(geom,controls.color); obj.rotation.x = Math.PI/2;//旋轉90度以后,更加方便觀測 } else {//使用普通材質系統渲染幾何體 obj = createMesh(geom); obj.rotation.x = Math.PI/2; } scene.add(obj); }
場景有了以后,攝像機還是不會動,沒有一種在時空隧道的感覺,所以這里想辦法讓攝像機在這個隧道的中間,沿著這個幾何體的形狀去移動。
因為管道不看y軸的話,其實還是一個圓形,所以可以使用圓形的參數方程來讓攝像機沿著這個函數去運動。讓y軸始終不變就可以。
let angle = 0;//初始角度 angle = angle + controls.rotationSpeed;//相機移動的速度 camera.position.set(controls.radius*Math.sin(angle),0, controls.radius*Math.cos(angle));//讓相機按照一個圓形軌跡運動 //可以理解為圓形的參數方程x=rsinα,y=rcosα,
即設置相機的x為rsinα,z為rcosα,y軸是一直都為0的。這里的r為整個隧道的半徑,α就是當前移動的角度。
雖然這樣可以讓相機開始移動了,但是相機的目標我們還沒有設置,我們需要讓相機在移動的過程中,始終看向前方,這樣才有一種在時空隧道中漫游的感覺。但是three.js的相機運動軌跡插件似乎在這里不好用,所以就想到了用其他方式實現。
我們既然已經用相機運動的圓的軌跡方程,也能很容易想到相機lookAt的方向其實就是沿著圓運動的切線方向。所以只需要求攝像機運動的當前位置的切線就可以了。
這里用到的是向量的點乘,坐標的點乘公式x1y2+x2y1,如果結果為0,就可以得到這個向量的垂直向量,我們要求的切線肯定就是垂直于半徑的。因為我們的y軸一直不變的,所以點乘公式的y我們變為z。我們首先是讓相機的位置減去隧道的中心(0,0,0),得到指向中心的向量,也就是半徑,然后再用一個向量與它點乘為0,這個向量方向就是垂直于半徑的了,也就是切線的方向。
function look(){ let view = new THREE.Vector3(camera.position.x, camera.position.y, camera.position.z);//計算當前攝像機位置點到世界中心點的向量 let vertical = (new THREE.Vector3(view.z, 0, -1.0 * view.x)).normalize(); //兩個向量的點積如果為0,則兩個向量垂直,公式為x1*y2+x2*y1=0, //這里的Y軸用Z軸代替。計算出垂直向量以后用normalize()化成單位向量 camera.lookAt(camera.position.x+vertical.x,0, camera.position.z+vertical.z);//camera.lookAt的值設置為 剛剛的單位向量加在當前攝像機的位置 //這樣就實現了在攝像機在旋轉時,一直朝前看。 }
最后得到的這個單位向量我們再加上當前相機的位置,就可以設置為相機lookAt的值。
注意我們在每次渲染的時候都要去改變這個值,因為相機的位置一直都在變化的,所以我們要把它封裝成一個函數,方便在渲染的時候調用。
其他的,相機,場景的初始化代碼:
function initThree() { //渲染器初始化 renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0x000000); document.getElementById("WebGL-output").appendChild(renderer.domElement);//將渲染添加到div中 //初始化攝像機,這里使用透視投影攝像機 camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000); camera.up.x = 0;//設置攝像機的上方向為哪個方向,這里定義攝像的上方為Y軸正方向 camera.up.y = 1; camera.up.z = 0; look();//計算攝像機在當前位置應該對準的目標點,即camera.lookAt的設置 //初始化場景 scene = new THREE.Scene(); }
至此,場景基本已經構建完成了。
完整的代碼如下:Sprite Tunnel
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103915.html
摘要:紋理貼圖的應用以及實現一個太陽系的自轉公轉點擊查看演示地址中的紋理紋理貼圖是通過將圖像應用到對象的一個或多個面,來為對象添加細節的一種方法。 紋理貼圖的應用以及實現一個太陽系的自轉公轉 點擊查看demo演示 demo地址:https://nsytsqdtn.github.io/d... three.js中的紋理 紋理貼圖是通過將圖像應用到對象的一個或多個面,來為3D對象添加細節的一種...
摘要:學習學習筆記點擊查看演示地址簡單網格材質是一種不受渲染時使用的顏色影響的材質,它只與自己每一個面從內到外的法向量有關。法向量在中用處十分廣泛,光的反射,以及三維圖形的紋理映射都與這個有關。 WebGL學習----Three.js學習筆記(5) 點擊查看demo演示 Demo地址:https://nsytsqdtn.github.io/d... 簡單網格材質 MeshNormalMat...
閱讀 1705·2021-11-02 14:47
閱讀 3653·2019-08-30 15:44
閱讀 1343·2019-08-29 16:42
閱讀 1739·2019-08-26 13:53
閱讀 942·2019-08-26 10:41
閱讀 3469·2019-08-23 17:10
閱讀 608·2019-08-23 14:24
閱讀 1724·2019-08-23 11:59