使用threejs实现辉光大气层效果
? ? ? ? 最近想使用threejs實現輝光的特效,在查閱了一些資料之后,不僅實現了輝光的特效,還順帶實現了大氣層特效,在寫著色器的過程中有了一些理解~
? ? ? ? 首要目標:為了實現輝光的著色器,我們把輝光分為幾個步驟來實現:
? ? ? ? 1.創建兩個球體,一個作為原始物體,一個略大一些作為它的輝光。
? ? ? ? 2.作為輝光的球體從內到外片元透明度逐漸減小(線性減小或是指數減小都可以)
? ? ? ? 3.將覆蓋原始物體的部分丟棄掉
? ? ? ? 有了這3點步驟,做起來就會容易很多,這里我著重介紹一下著色器的部分:
? ? ? ? 首先是片元著色器
'varying vec3 vVertexWorldPosition;', 'varying vec3 vVertexNormal;', 'varying vec4 vFragColor;', 'void main(){', ' vVertexNormal = normalize(normalMatrix * normal);',//將法線轉換到視圖坐標系中 ' vVertexWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;',//將頂點轉換到世界坐標系中 ' // set gl_Position', ' gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);', '}'
? ? ? ? 這里做的事情比較簡單,主要就是把法線轉換到視圖坐標系中和把頂點轉換到世界坐標系中,因為在片元著色器中需要用到這兩個參數,必須對他們進行一下轉換,這里還要說一下的就是OpenGL用的是左乘,也就是頂點左乘矩陣,進行轉換(對坐標系轉換不熟悉的同學可以看一下我之前總結的文章:http://blog.csdn.net/srk19960903/article/details/77970630)。
? ? ? ? 然后是輝光的片元著色器:
'uniform vec3 glowColor;', 'uniform float coeficient;', 'uniform float power;', 'varying vec3 vVertexNormal;', 'varying vec3 vVertexWorldPosition;', 'varying vec4 vFragColor;', 'void main(){', ' vec3 worldVertexToCamera= cameraPosition - vVertexWorldPosition;', //世界坐標系中頂點位置到相機位置到的距離 ' vec3 viewCameraToVertex = (viewMatrix * vec4(worldVertexToCamera, 0.0)).xyz;',//視圖坐標系中 ' viewCameraToVertex = normalize(viewCameraToVertex);',//規一化 ' float intensity = coeficient + dot(vVertexNormal, viewCameraToVertex);', ' if(intensity > 0.55){ intensity = 0.0;}', ' gl_FragColor = vec4(glowColor, intensity);', ? ? ? ? 這里首先得到了兩個向量,一是頂點到相機的向量然后將其轉換到視圖坐標系中,在進行歸一化。二是直接傳過來的視圖坐標系中的法向量,這時將兩個向量進行點乘就可以獲得它們夾角的cos值,從圓心到圓邊這個角度依次增大,所以乘積依次減小,最后把這個值加上一個常量賦給最終片元的不透明度,從而實現輝光的效果。
? ? ? ? 這里的難點主要在于兩個:1.將頂點到相機的距離和法向量,統統轉換到view坐標系中來計算。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.兩個向量的乘積所代表的意義,所夾角度的cos值,通過觀察cos的函數圖像我們可以看出他的變換規律,再根據規律寫著色器。
大氣層著色器
? ? ? ? 既然我們會寫從內向外透明度逐漸降低的著色器,那么從外向內透明度逐漸降低的呢~
? ? ? ? 還記得在算點積的時候我們用的是那兩個向量嗎?頂點到攝像機&頂點向外的法向量,嗯,那么我們可以用從攝像機到頂點&頂點向外的法向量來重新算一次!這次由于角度開始就是大于180度的,從球心到球邊,cos值從負值到正值進行變換,我們再用一個指數函數的形式來影響它的變換過程,就是這么簡單,大氣層的著色器就研究出來啦!
'uniform vec3 glowColor;', 'uniform float coeficient;', 'uniform float power;', 'varying vec3 vVertexNormal;', 'varying vec3 vVertexWorldPosition;', 'varying vec4 vFragColor;', 'void main(){', ' vec3 worldCameraToVertex= vVertexWorldPosition - cameraPosition;', //世界坐標系中從相機位置到頂點位置的距離 ' vec3 viewCameraToVertex = (viewMatrix * vec4(worldCameraToVertex, 0.0)).xyz;',//視圖坐標系中從相機位置到頂點位置的距離 ' viewCameraToVertex = normalize(viewCameraToVertex);',//規一化 ' float intensity = pow(coeficient + dot(vVertexNormal, viewCameraToVertex), power);', ' gl_FragColor = vec4(glowColor, intensity);', '}'//vVertexNormal視圖坐標系中點的法向量 //viewCameraToVertex視圖坐標系中點到攝像機的距離向量 //dot點乘得到它們的夾角的cos值 //從中心向外面角度越來越小(從鈍角到銳角)從cos函數也可以知道這個值由負變正,不透明度最終從低到高
效果如圖:
Github:https://github.com/StringKun/ThreeJSGlow-Atmosphere
總結
以上是生活随笔為你收集整理的使用threejs实现辉光大气层效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 真正标准,规范的企业网站建设合同书
- 下一篇: 第12周项目2:太乐了(先听故事,再编程