基于 three.js 的圣诞树
前言
快到圣诞节了,用当前所学的做个简易版圣诞树送给女朋友。
五角星
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 = falsetop_corner.receiveShadow = falseconst 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.04let amount = 500let 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 = 0bloomPass.strength = 1.5bloomPass.radius = 0bloomComposer = new EffectComposer(renderer)bloomComposer.renderToScreen = falsebloomComposer.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 = truefinalComposer = 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()...}