上一篇說頂點着色器和片元着色器的皮毛,這篇郭先生說一說着色器變量,通過變量可以設置材質。先看看今天要做的如下圖。在線案例請點擊博客原文。
在這個案例之前,我們先復習一下着色器變量
- 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,請參見上一篇文章。
雖然這個小案例很簡單,但是我相信大家肯定有了很好的想法,前面幾篇都是比較基礎的,后面還有很多好看的案例,喜歡就點個贊吧!
轉載請注明地址:郭先生的博客