今天郭先生說一說如何在three.js著色器中新增紋理,先看看今天要完成的效果,線上案例請點選部落格原文。
這裡我們分別引入三個紋理,分別是地球的表面紋理,對應的海拔灰度圖,和雲朵的紋理。使用表面紋理還是地球的外貌,海拔灰度圖給地球新增凹凸效果,雲朵紋理給地球新增雲朵效果。下面我們說一說程式碼。
1. 繪製幾何體,載入貼圖
我們只需要在一個球體中進行操作,所以新建一個球體。然後分別載入三張紋理。
var sphere = new THREE.SphereBufferGeometry(10, 128, 64); var texture1 = new THREE.TextureLoader().load('/static/images/texture/planets/diqiu-s.jpg'); var texture2 = new THREE.TextureLoader().load('/static/images/texture/planets/dixing.jpg'); var texture3 = new THREE.TextureLoader().load('/static/images/base/water.jpg');
2. 使用uniform變數
這裡除了將三張紋理傳到著色器中,還傳遞了一個時間,這個時間來讓紋理動起來。雲朵的紋理的wrapS和wrapT設定成THREE.RepeatWrapping,這是讓紋理簡單地重複到無窮大,而不至於[0,0]到[1,1]的範圍。
uniforms = { time: { value: 0 }, texture1: { value: texture1 }, texture2: { value: texture2 }, texture3: { value: texture3 }, } uniforms[ "texture3" ].value.wrapS = uniforms[ "texture3" ].value.wrapT = THREE.RepeatWrapping;
3. 頂點著色器
頂點著色器我們只是用地球的灰度圖,這裡面是用texture2D( texture2, vUv )來獲取圖片中每個點的顏色值。新建三維向量newPosition,這個向量代表球體上的點經過灰度貼圖操作後新點的位置。由於是灰度圖,那麼他的r,g,b應該是相同的,並且保證新的頂點座標是沿著球表面法向量方向,所以vec3 newPosition = position + normal * tcolor.r / 2.0;
vertexShader: ` varying vec2 vUv; uniform sampler2D texture2; void main() { vUv = uv; vec4 tcolor = texture2D( texture2, vUv ); vec3 newPosition = position + normal * tcolor.r / 2.0; gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 ); } `
4. 片元著色器
片元著色器使用兩個紋理,還是頂點著色器傳過來的uv以及時間。這裡tcolor1就是地圖點的顏色,tcolor3代表雲朵的紋理,但是他的uv是隨時間變化的(這裡要求紋理設定重複)。這裡還是用了mix方法,mix方法返回線性混合的x和y,如:x*(1−a)+y*a。
fragmentShader: ` varying vec2 vUv; uniform sampler2D texture1; uniform sampler2D texture3; uniform float time; void main() { vec4 tcolor1 = texture2D( texture1, vUv ); vec4 tcolor3 = texture2D( texture3, vUv - vec2(time, - time * 0.4) ); gl_FragColor = mix(tcolor1, tcolor3 * 1.3, tcolor3.r / 2.0); } `
這樣就獲得了一個動態的地球。是不是很簡單呢?
轉載請註明地址:郭先生的部落格