three.js 着色器材質之變量(一)

上一篇說頂點着色器和片元着色器的皮毛,這篇郭先生說一說着色器變量,通過變量可以設置材質。先看看今天要做的如下圖。在線案例請點擊博客原文

在這個案例之前,我們先複習一下着色器變量

  • 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,請參見上一篇文章。

雖然這個小案例很簡單,但是我相信大家肯定有了很好的想法,前面幾篇都是比較基礎的,後面還有很多好看的案例,喜歡就點個贊吧!

 

轉載請註明地址:郭先生的博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章