前言
快到圣诞节了,用当前所学的做个简易版圣诞树送给女朋友。
五角星
const top_corner_g = new THREE.ConeBufferGeometry(0.5, 1, 4)
top_corner_g.applyMatrix4(new THREE.Matrix4().makeTranslation(0, 0.5, 0))
const top_m = new THREE.MeshStandardMaterial({
color: 'rgb(255, 215, 0)',
roughness: 0.5,
metalness: 0.5
})
const top_corner = new THREE.Mesh(top_corner_g, top_m)
top_corner.layers.enable(1) // 发光效果通道
top_corner.castShadow = false
top_corner.receiveShadow = false
const top = new THREE.Group()
const top_c1 = top_corner.clone()
top.add(top_c1)
const top_c2 = top_corner.clone()
top_c2.rotation.set(1 * 2 * Math.PI / 5, 0, 0)
top.add(top_c2)
const top_c3 = top_corner.clone()
top_c3.rotation.set(2 * 2 * Math.PI / 5, 0, 0)
top.add(top_c3)
const top_c4 = top_corner.clone()
top_c4.rotation.set(3 * 2 * Math.PI / 5, 0, 0)
top.add(top_c4)
const top_c5 = top_corner.clone()
top_c5.rotation.set(4 * 2 * Math.PI / 5, 0, 0)
top.add(top_c5)
top.position.set(0, 12, 0)
tree.add(top)
雪花飘落
let fallSpeen = 0.04
let amount = 500
let sprite_m = new THREE.SpriteMaterial({ map: snow_map })
for (let i = 0; i < amount; i ++){
let particle = new THREE.Sprite(sprite_m)
particle.position.x = randomRange(-20, 20)
particle.position.y = randomRange(-5, 40)
particle.position.z = randomRange(-20, 20)
particle.scale.x = particle.scale.y = particle.scale.z = 0.5
particle.v = new THREE.Vector3(0, -fallSpeen, 0)
particle.v.z = (randomRange(-fallSpeen, fallSpeen))
particle.v.x = (randomRange(-fallSpeen, fallSpeen))
particle.rotation.x = Math.PI / 2
particles.push(particle)
scene.add(particle)
}
function animate() {
...
for (let i = 0; i < particles.length; i++) {
letparticle = particles[i]
let pp = particle.position
pp.add(particle.v)
if (pp.y < -5) pp.y = 40
if (pp.x > 20) pp.x = -20
else if (pp.x < -20) pp.x = 20
if (pp.z > 20) pp.z = -20
else if (pp.z < -20) pp.z = 20
}
...
}
发光通道
<script type="x-shader/x-vertex" id="vertexshader">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script type="x-shader/x-fragment" id="fragmentshader">
uniform sampler2D baseTexture;
uniform sampler2D bloomTexture;
varying vec2 vUv;
void main() {
gl_FragColor = (texture2D(baseTexture, vUv) + vec4(1.0) * texture2D(bloomTexture, vUv));
}
</script>
const renderScene = new RenderPass(scene, camera)
constbloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85)
bloomPass.threshold = 0
bloomPass.strength = 1.5
bloomPass.radius = 0
bloomComposer = new EffectComposer(renderer)
bloomComposer.renderToScreen = false
bloomComposer.addPass(renderScene)
bloomComposer.addPass(bloomPass)
const finalPass = new ShaderPass(
new THREE.ShaderMaterial({
uniforms: {
baseTexture: { value: null },
bloomTexture: { value: bloomComposer.renderTarget2.texture },
},
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
defines: {},
}),
'baseTexture'
)
finalPass.needsSwap = true
finalComposer = new EffectComposer(renderer)
finalComposer.addPass(renderScene)
finalComposer.addPass(finalPass)
function darkenNonBloomed(obj) {
if (obj instanceof THREE.Scene) {
materials.scene = obj.background
obj.background = null
return
}
if (obj instanceof THREE.Sprite || (obj.isMesh && bloomLayer.test(obj.layers) === false)) {
materials[obj.uuid] = obj.material
obj.material = darkMaterial
}
}
function restoreMaterial(obj) {
if (obj instanceof THREE.Scene) {
obj.background = materials.scene
delete materials.background
return
}
if (materials[obj.uuid]) {
obj.material = materials[obj.uuid]
delete materials[obj.uuid]
}
}
function animate() {
...
scene.traverse(darkenNonBloomed)
bloomComposer.render()
scene.traverse(restoreMaterial)
finalComposer.render()
...
}