three.js 著色器材質之變數(二)

郭先生的部落格發表於2020-08-06

上一篇郭先生在例子中用到了著色器變數中的uniform和varying。這篇繼續結合例子將一下attribute變數,在使用過程中也發現由於three.js的版本迭代,之前的一些屬性和引數已經發生了改變,ShaderMaterial也不需要傳遞attributes屬性值,檢視原始碼我們可以看到如果傳遞了attributes引數,會給出下面這樣的錯誤。

attributes should now be defined in THREE.BufferGeometry instead.

因為我們現在想傳遞attributes時,幾何體需要設定對應的緩衝型別,然後將使用setAttribute方法(老版本使用addAttribute方法)將屬性新增到BufferGeometry的attributes中,然後我們在頂點著色器中定義使用即可。

先看看今天要完成的效果,靈感還是在iview主頁上看到的。線上案例請點選部落格原文

1. 製作幾何體

之前的版本有這樣一個方法THREE.BufferGeometryUtils.mergeBufferGeometries,它可以將幾何體組合起來,並保留幾何體的中心座標,但是現在已經找不到了。建議使用merge方法。

let geometry = new THREE.Geometry();
for(let i=0; i<39; i++) { //39行
    for(let j=0; j<39; j++) { //39列
        let sphere = new THREE.SphereGeometry(2, 15, 10);
        sphere.translate(i * 50 - 950, 0, j * 50 - 950); //這裡我們使用Geometry的translate方法將間隔調成50
        geometry.merge(sphere);//結合幾何體
    }
}
let bufferGeometry = new THREE.BufferGeometry().fromGeometry(geometry); //最後將幾何體替換成對應的緩衝型別

2. 設定attributes屬性

因為現在所有的球已經失去了中心座標,如果不增加一些屬性,我們很難在頂點著色器中操作這些點(因為不知道哪個點對應哪個球),因此這個時候我們就需要使用attributes屬性。這裡我們設定一個叫做centers的attribute屬性,每一個球上面的點都對應同一個centers。

total = bufferGeometry.attributes.position.count; //幾何體點的個數
every = total / 39 /39; //每個球體點的個數
centers = new Float32Array(total * 3);//初始化型別陣列,並設定長度
//將中心點儲存到centers中
for(let i=0; i<39; i++) {
    for(let j=0; j<39; j++) {
        for(let k=0; k<every; k++) {
            centers[(i*39*every + j*every + k) * 3] = i * 50 - 950;
            centers[(i*39*every + j*every + k) * 3 + 1] = 0;
            centers[(i*39*every + j*every + k) * 3 + 2] = j * 50 - 950;
        }
    }
}
bufferGeometry.setAttribute('centers', new THREE.BufferAttribute(centers, 3));//為bufferGeometry設定屬性

3. 設定著色器材質

這裡重點就是頂點著色器,要做出水波的效果其實是兩個方向正弦效果的疊加,所以設定一個centery,它是中心點的y座標,它會隨時間高低變化。有一個centery其實波浪效果就實現了,接來下還需要動態的改變球的大小。center向量是每個球中心點靜止時的座標,target是球中心點到球上一點的向量(也是球的法向量),newPosition是position沿法向量變換的點,我們回過頭看一下centery,它值的範圍是[-80,80],因此(centery + 80.0) / 80.0的範圍是[0, 2],我們在centery最高是,讓球最大,newPosition = center + target * 2。最後設定gl_Position,newPosition控制縮放,centery控制小球上下浮動。

uniforms = {
    time: {
        type: 'f',
        value: 0
    }
}
var material = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: `
        attribute vec3 centers;
        uniform float time;
        void main() {
            float centery = sin(centers.x / 100.0 + time) * 40.0 + sin(centers.z / 100.0 + time) * 40.0;
            vec3 center = vec3(centers.x, 0, centers.z);
            vec3 target = position - center;
            vec3 newPosition = center + target * ((centery + 80.0) / 80.0);
            gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition.x, newPosition.y + centery, newPosition.z, 1.0 );
        }
    `,
    fragmentShader: `
        void main() {
            gl_FragColor = vec4(0.0,0.5,0.8,1.0);
        }
    `
});

好了,到此為止,我們結合案例說了著色器變數uniform,varying和attribute,感覺還好的話就點咋贊吧!

轉載請註明地址:郭先生的部落格

相關文章