table of content
今天這篇文章將延續上一篇
資料夾結構如下(僅列出本期有使用到的檔案) 這裡附上
root
L public
L test.jpg
|- index.html
|- main.js
L style.js
這個階段我們有兩個重要的目標
TextureLoader
uniform
、sampler2D
把檔案丟到public資料夾,由於vite的特性所以不需要額外註記public
import texture from '/test.jpg'
main.js
this.geometry = new THREE.PlaneGeometry(1,1,this.size,this.size);
this.material = new THREE.MeshNormalMaterial();
//透過uniform變數將texture傳遞給shader
this.material = new THREE.ShaderMaterial({
uniforms: {
time: {value: this.time},
uTexture: {value: new THREE.TextureLoader().load(texture)}
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
})
在shader中使用貼圖的類別聲明是sampler2D
順帶一提uniform則代表全域變數通常是由cpu傳進來得參數
varying則是需要由vertex shader傳進 fragment shader中
varying vec2 vUv;
uniform sampler2D uTexture;
void main() {
vec4 color = texture2D(uTexture, vUv);
gl_FragColor = vec4( color.xyz, 1.0 );
}
在這個階段中我們將學習
p.s. 為了方便解釋,所以階段三與階段二的成果會是相同的( ~~絕對不是我偷懶只想放一張圖~~)
what is Data Texture?
在 Three.js 中,「Data Texture」是指基於數據動態生成的一種紋理。這是一種將數據編碼到圖像像素中以可視化的方法。這些紋理可用於表示各種類型的數據,例如高度圖、顏色圖或任何其他可視化為圖像的數據類型。
Loading preview...
由於data texture是將資料寫入貼圖的方式,而貼圖一般都是2的倍數以及正方形的結構所以這邊我先聲明size表示貼圖的長跟寬、number則表示粒子的數量
//main.js
this.size = 32;
this.number = this.size * this.size;
本次的示例中將會使用貼圖來儲存每個particle的位置資訊,使用Float32Array是因為位置資訊是浮點數,其他能用得資料結構還有
而之所以要 * 4
是因為我們寫進的貼圖有RGBA四個通道,雖然我們只使用前面三個通道,但第四個通道不能為空,雖然我們不使用但還是要幫他填上一個值
//main.js
this.positions = new Float32Array(this.number * 4);
for (let i=0; i<this.size; i++){
for (let j=0; j<this.size; j++){
let index = i*this.size + j;
this.positions[4 * index] = i/(this.size-1) - 0.5;//x
this.positions[4 * index+1] = j/(this.size-1) - 0.5;//y
this.positions[4 * index+2] = Math.random() * 0.05;//z
this.positions[4 * index+2] = 1;
}
}
//main.js
this.positionsTexture = new THREE.DataTexture(this.positions, this.size, this.size,THREE.RGBAFormat, THREE.FloatType);
this.positionsTexture.needsUpdate = true;
將我們創建好的positionTexture
傳進shader
//main.js
this.material = new THREE.ShaderMaterial({
uniforms: {
time: {value: this.time},
positionTexture: {value: new THREE.TextureLoader().load(texture)},
uTexture: {value: this.positionsTexture}
},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
})
//vertex shader
uniform float time;
uniform sampler2D positionTexture;
varying vec2 vUv;
void main() {
vUv = uv;
vec4 color = texture2D(positionTexture, uv);
vec3 newpos = color.xyz;
vec4 mvPosition = modelViewMatrix * vec4( newpos, 1.0 );
gl_PointSize = 5.0;
gl_Position = projectionMatrix * mvPosition;
}
What is Buffer Geometry 在Three.js中,"BufferGeometry"(緩衝幾何體)是一種用於儲存3D模型幾何信息的高性能數據結構。與傳統的Geometry(幾何體)相比,BufferGeometry具有更高的性能和更低的內存占用。
BufferGeometry將模型的幾何信息儲存在GPU的緩衝區中,而不是在CPU的內存中。這意味著當你使用BufferGeometry時,模型的幾何信息可以直接在GPU上進行渲染,而不需要從CPU傳輸到GPU,這大大提高了渲染性能。
白話文就是一個你需要從頭建立的幾何體,你需要提供至少vertex(模型頂點)、uv(模型的貼圖座標)
//main.js
this.geometry = new THREE.BufferGeometry();
//main.js
this.positions = new Float32Array(this.number * 3);
this.uvs = new Float32Array(this.number * 2);
//main.js
for (let i=0; i<this.size; i++){
for (let j=0; j<this.size; j++){
let index = i*this.size + j;
this.positions[3 * index] = i/(this.size-1) - 0.5;//x
this.positions[3 * index+1] = j/(this.size-1) - 0.5;//y
this.positions[3 * index+2] = Math.random() * 0.05;//z
this.uvs[2* index] = i/(this.size-1);//u
this.uvs[2 * index+1] = j/(this.size-1);//v
}
}
//main.js
this.geometry.setAttribute('position', new THREE.BufferAttribute( this.positions , 3));
this.geometry.setAttribute('uv',new THREE.BufferAttribute( this.uvs, 2) );
既然我們不需要仰賴貼圖將座標傳進shader裡了,所以還需要額外將section2有使用到positionTexture的地方著解掉
//vertex shader
uniform float time;
uniform sampler2D uTexture;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 newpos = position;
vec4 mvPosition = modelViewMatrix * vec4( newpos, 1.0 );
gl_PointSize = 5.0;
gl_Position = projectionMatrix * mvPosition;
}