閱讀本部落格可以獲取到的知識
- 建立一個3d的空間
- 粒子效果
- three.js點選事件的處理
- 著色器的初步使用
- 實現一個光暈效果
1.建立一個3d的空間
可以想象一下我們在房間內,房間是一個立方體,如果你有生活品味,可能會在房間內貼上桌布,three.js可以很方便的建立一個立方體,並且給它的周圍貼上紋理,讓照相機在立方體之中,照相機可以360旋轉,就模擬了一個真實的場景。
轉換為程式碼:
const path = 'assets/image/'
const format = '.jpg'
const urls = [
`${path}px${format}`, `${path}nx${format}`,
`${path}py${format}`, `${path}ny${format}`,
`${path}pz${format}`, `${path}nz${format}`
]
const materials = []
urls.forEach(url => {
const textureLoader = new TextureLoader()
textureLoader.setCrossOrigin(this.crossOrigin)
const texture = textureLoader.load(url)
materials.push(new MeshBasicMaterial({
map: texture,
overdraw: true,
side: BackSide
}))
})
const cube = new Mesh(new CubeGeometry(9000, 9000, 9000), new MeshFaceMaterial(materials))
this.scene.add(cube)
複製程式碼
- CubeGeometry建立一個超大的立方體
- MeshFaceMaterial給立方體貼上文理,由於視角是在立方體內部,所以side:BackSide
2.粒子效果
一個3d模型是由點,線,面組成的,可以遍歷模型的每一個點,把每一個點轉換為幾何模型,並且給它貼上文理,拷貝每一個點的位置,用這些幾何模型重新構成一個只有點的模型,這就是粒子效果的基本原理。
this.points = new Group()
const vertices = []
let point
const texture = new TextureLoader().load('assets/image/dot.png')
geometry.vertices.forEach((o, i) => {
// 記錄每個點的位置
vertices.push(o.clone())
const _geometry = new Geometry()
// 拿到當前點的位置
const pos = vertices[i]
_geometry.vertices.push(new Vector3())
const color = new Color()
color.r = Math.abs(Math.random() * 10)
color.g = Math.abs(Math.random() * 10)
color.b = Math.abs(Math.random() * 10)
const material = new PointsMaterial({
color,
size: Math.random() * 4 + 2,
map: texture,
blending: AddEquation,
depthTest: false,
transparent: true
})
point = new Points(_geometry, material)
point.position.copy(pos)
this.points.add(point)
})
return this.points
複製程式碼
- new Group建立一個群,可以說是粒子的集合
- 通過point.position.copy(pos)設定粒子和位置,座標和模型中對應點的位置相同
3.點選事件的處理
three.js的點選事件需要藉助光線投射器(Raycaster),為了方便理解,請先看一張圖:
Raycaster發射一個射線,intersectObject監測射線命中的物體
this.raycaster = new Raycaster()
// 把你要監聽點選事件的物體用陣列儲存起來
this.seats.push(seat)
onTouchStart(event) {
event.preventDefault()
event.clientX = event.touches[0].clientX;
event.clientY = event.touches[0].clientY;
this.onClick(event)
}
onClick(event) {
const mouse = new Vector2()
mouse.x = ( event.clientX / this.renderer.domElement.clientWidth ) * 2 - 1
mouse.y = - ( event.clientY / this.renderer.domElement.clientHeight ) * 2 + 1;
this.raycaster.setFromCamera(mouse, this.camera)
// 檢測命中的座位
const intersects = this.raycaster.intersectObjects(this.seats)
if (intersects.length > 0) {
intersects[0].object.material = new MeshLambertMaterial({
color: 0xff0000
})
}
}
複製程式碼
- intersects.length > 0 表示射線命中了某個幾何體
- 偷懶只實現了移動端的點選實現,如果想看pc怎麼實現,請看thee.js官網
4.著色器的初步使用
著色器分為頂點著色器和片元著色器,用GLSL語言編寫,是一種和GPU溝通的的語言,這裡只講如何使用
const vertext = `
void main()
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
`
const fragment = `
uniform vec2 resolution;
uniform float time;
vec2 rand(vec2 pos)
{
return fract( 0.00005 * (pow(pos+2.0, pos.yx + 1.0) * 22222.0));
}
vec2 rand2(vec2 pos)
{
return rand(rand(pos));
}
float softnoise(vec2 pos, float scale)
{
vec2 smplpos = pos * scale;
float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x;
float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x;
float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x;
float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x;
vec2 a = fract(smplpos);
return mix(
mix(c0, c1, smoothstep(0.0, 1.0, a.x)),
mix(c2, c3, smoothstep(0.0, 1.0, a.x)),
smoothstep(0.0, 1.0, a.y));
}
void main(void)
{
vec2 pos = gl_FragCoord.xy / resolution.y;
pos.x += time * 0.1;
float color = 0.0;
float s = 1.0;
for(int i = 0; i < 8; i++)
{
color += softnoise(pos+vec2(i)*0.02, s * 4.0) / s / 2.0;
s *= 2.0;
}
gl_FragColor = vec4(color);
}
`
// 設定物體的質材為著色器質材
let material = new ShaderMaterial({
uniforms: uniforms,
vertexShader: vertext,
fragmentShader: fragment,
transparent: true,
})
複製程式碼
5.光暈效果
由於是模擬電影院,我想做一個投影儀,模擬投影儀射出的光線。
// 光暈效果必須設定alpha = true
const renderer = this.renderer = new WebGLRenderer({alpha: true, antialias: true})
let textureFlare = new TextureLoader().load('assets/image/lensflare0.png')
let textureFlare3 = new TextureLoader().load('assets/image/lensflare3.png')
let flareColor = new Color(0xffffff)
let lensFlare = new LensFlare(textureFlare, 150, 0.0 , AdditiveBlending, flareColor)
lensFlare.add(textureFlare3, 60, 0.6, AdditiveBlending);
lensFlare.add(textureFlare3, 70, 0.7, AdditiveBlending);
lensFlare.add(textureFlare3, 120, 0.9, AdditiveBlending);
lensFlare.add(textureFlare3, 70, 1.0, AdditiveBlending);
lensFlare.position.set(0, 150, -85)
複製程式碼
- 主要的光線還是靠lensflare0.png模擬
- textureFlare3設定光暈的範圍
後記:
原創不易,辛苦各位大大點個star