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

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

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM