上一篇說頂點著色器和片元著色器的皮毛,這篇郭先生說一說著色器變數,通過變數可以設定材質。先看看今天要做的如下圖。線上案例請點選部落格原文。
在這個案例之前,我們先複習一下著色器變數
- Uniforms是所有頂點都具有相同的值的變數。 比如燈光,霧,和陰影貼圖就是被儲存在uniforms中的資料。 uniforms可以通過頂點著色器和片元著色器來訪問。
- Varyings 是從頂點著色器傳遞到片元著色器的變數。因此需要在兩個著色器中同時定義,對於每一個片元,每一個varying的值將是相鄰頂點值的平滑插值。
- Attributes 與每個頂點關聯的變數。例如,頂點位置,法線和頂點顏色都是儲存在attributes中的資料。attributes 只可以在頂點著色器中訪問。
嗯,現在我們知道了這些變數的用法,接下來我們使用它。
1. 製作紅綠燈幾何體
要製作這樣一個紅綠燈,我們考慮使用Geometry的merge方法
var shape = new THREE.Shape(); shape.moveTo(-10, 20); shape.absarc(0, 20, 10, Math.PI, Math.PI * 2, true); shape.lineTo(10, -20); shape.absarc(0, -20, 10, 0, Math.PI, true ); shape.lineTo(-10, 20); var extrudeSettings = { steps: 2, //用於沿著擠出樣條的深度細分的點的數量,預設值為1 depth: 5, //擠出的形狀的深度,預設值為100 bevelEnabled: true, //對擠出的形狀應用是否斜角,預設值為true bevelThickness: 1, //設定原始形狀上斜角的厚度。預設值為6 bevelSize: 1, //斜角與原始形狀輪廓之間的延伸距離 bevelSegments: 10, //斜角的分段層數,預設值為3 curveSegments: 12, //曲線上點的數量,預設值是12 }; var frame = new THREE.ExtrudeGeometry(shape, extrudeSettings); // var material = new THREE.MeshPhongMaterial({color: 0x222222, emissive: 0x222222}); var cylinGeom = new THREE.CylinderGeometry(6, 6, 6, 30, 20); frame.merge(cylinGeom.clone(), new THREE.Matrix4().compose(new THREE.Vector3(0, 15, 3.1), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2), new THREE.Vector3(1,1,1))); frame.merge(cylinGeom.clone(), new THREE.Matrix4().compose(new THREE.Vector3(0, 0, 3.1), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2), new THREE.Vector3(1,1,1))); frame.merge(cylinGeom.clone(), new THREE.Matrix4().compose(new THREE.Vector3(0, -15, 3.1), new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2), new THREE.Vector3(1,1,1)));
通過ExtrudeGeometry擠壓出我們想要的幾何體,然後新增三個圓柱體,形成我們想要的幾何體。
2. 設定uniform變數
現在使用uniform變數
uniforms = { time: { type: 'f', value: 0.0 } }
這裡我們在其中設定一個叫做time的變數,它的型別是一個float型別,預設值設定成0.0。然後我們在requestAnimationFrame的每一幀動畫中呼叫uniforms.time.value += 0.01;讓著色器動起來。
3. 頂點著色器
頂點著色器我們不做太多操作
varying vec3 vPosition; uniform float time; void main() { vPosition = position; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); }
這裡我們定義一個三維向量vPosition,用來將頂點著色器裡面的position屬性傳遞到片元著色器中(three.js會預設傳入一些屬性,像uv,position,normal等)
4. 片元著色器
varying vec3 vPosition; uniform float time; void main() { float time = mod(time, 3.0);//time值對3取模,得到[0,3)範圍內的值。 //由於我們製作紅綠燈時用了小技巧,讓其z分量比較大,所以可以根據z的值判斷是否為紅綠燈面。然後在根據y值,判斷為哪個燈。 if(vPosition.z == 6.1 && vPosition.y > 8.0) { if(time < 1.0) {//時間為[0,1)紅燈 gl_FragColor=vec4(1.0, 0.0, 0.0, 1.0); } else { gl_FragColor=vec4(0.2, 0.0, 0.0, 1.0); } } else if(vPosition.z == 6.1 && vPosition.y > -8.0) {//時間為[1,2)黃燈 if(time >= 1.0 && time < 2.0) { gl_FragColor=vec4(1.0, 0.7, 0.0, 1.0); } else { gl_FragColor=vec4(0.2, 0.1, 0.0, 1.0); } } else if(vPosition.z == 6.1) {//時間為[2,3)綠燈 if(time >= 2.0) { gl_FragColor=vec4(0.0, 1.0, 0.0, 1.0); } else { gl_FragColor=vec4(0.0, 0.2, 0.0, 1.0); } } else {//其餘部分為灰色 gl_FragColor=vec4(0.2, 0.2, 0.2, 1.0); } }
這裡我們使用頂點著色器傳過來的向量vPosition和uniform中的time值做一些判斷,實現對每個點顏色進行控制(根據顏色插值從而實現顏色面的控制),裡面使用了一些方法,例如mod,請參見上一篇文章。
雖然這個小案例很簡單,但是我相信大家肯定有了很好的想法,前面幾篇都是比較基礎的,後面還有很多好看的案例,喜歡就點個贊吧!
轉載請註明地址:郭先生的部落格