前段时间,女朋友生日,人在外地出差,不知道如何给她过生日,所以想了个办法,做一个程序送给她,完事后再补一个生日过去,考虑到有兄弟会找相关的素材,所以今天公布出来一下,做的不怎么完善,还望海涵!
效果截图:
话不多说,直接上代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>生日快乐</title>
<style>
body {
margin: 0;
overflow: hidden;
/*隐藏body区域滚动条*/
}
</style>
<script src="js/three.min.js"></script>
<script src="js/OrbitControls.js"></script>
</head>
<body>
<script>
//窗口宽度
const width = window.innerWidth;
//窗口高度
const height = window.innerHeight;
//窗口宽高比
const k = width / height;
//三维场景显示范围控制系数,系数越大,显示的范围越大
const s = 200;
/**
* 创建文字载体
*/
const loader = new THREE.FontLoader();
/**
* 创建分组
*/
const asteroids = new THREE.Group();
/**
* 创建场景对象
*/
const scene = new THREE.Scene();
/**
* 创建相机
*/
const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
/**
* 创建渲染器
*/
const renderer = new THREE.WebGLRenderer();
/**
* 花瓣分组
*/
const petal = new THREE.Group();
/**
* 底部祝福
*/
const bottomBlessingCurveObjectGroup = new THREE.Group();
/**
* 蛋糕装饰组
*/
const decorationGroup = new THREE.Group();
create()
render()
// renderPetal()
function create() {
loader.load('font/gentilis_bold.typeface.json', function (font) {
/**
* 光源设置
*/
const point = new THREE.AmbientLight(0xCCCCCC);
// 点光源位置
point.position.set(200, 200, 200)
// 将点光源添加到场景中
scene.add(point)
// 环境光
const ambient = new THREE.AmbientLight(0x404040);
scene.add(ambient)
/**
* 相机设置
*/
//设置相机位置
camera.position.set(0, 100, 500)
//设置相机方向(指向的场景对象)
camera.lookAt(scene.position)
/**
* 创建渲染器对象
*/
//设置渲染区域尺寸
renderer.setSize(width, height)
//设置背景颜色
renderer.setClearColor(0xFFC0CB, 1)
//body元素中插入canvas对象
document.body.appendChild(renderer.domElement)
//执行渲染操作 指定场景、相机作为参数
renderer.render(scene, camera)
// 辅助坐标系 参数250表示坐标系大小,可以根据场景大小去设置
// const axisHelper = new THREE.AxisHelper(2500);
// scene.add(axisHelper)
/**
* 蛋糕主体
*/
// 图片加载器
// const texture = THREE.ImageUtils.loadTexture('img/img_3.png');
// const texture2 = THREE.ImageUtils.loadTexture(`img/image2.png`);
// const texture3 = THREE.ImageUtils.loadTexture('img/img_1.png');
// const texture4 = THREE.ImageUtils.loadTexture('img/img.png');
// const texture5 = THREE.ImageUtils.loadTexture('img/image_2.png');
// const texture6 = THREE.ImageUtils.loadTexture('img/image_4.png');
// const texture7 = THREE.ImageUtils.loadTexture('img/img_4.png');
const texture = new THREE.TextureLoader().load('img/img_3.png');
const texture2 = new THREE.TextureLoader().load(`img/image2.png`);
const texture3 = new THREE.TextureLoader().load('img/img_1.png');
const texture4 = new THREE.TextureLoader().load('img/img.png');
const texture5 = new THREE.TextureLoader().load('img/image_2.png');
const texture6 = new THREE.TextureLoader().load('img/image_4.png');
const texture7 = new THREE.TextureLoader().load('img/img_4.png');
const material = new THREE.MeshPhongMaterial({
specular: 0xffffff,
color: 0x7777ff
});
const caizhi1 = [
new THREE.MeshPhongMaterial({map: texture3}),
new THREE.MeshPhongMaterial({map: texture3}),
new THREE.MeshPhongMaterial({map: texture3})
];
const caizhi2 = [
new THREE.MeshPhongMaterial({map: texture}),
new THREE.MeshPhongMaterial({map: texture4}),
material
];
const caizhi3 = [
new THREE.MeshPhongMaterial({map: texture2}),
new THREE.MeshPhongMaterial({map: texture4}),
material
];
const caizhi4 = [
new THREE.MeshPhongMaterial({map: texture5}),
new THREE.MeshPhongMaterial({map: texture6}),
material
];
const bottom = new THREE.CylinderBufferGeometry(160, 160, 10, 40);
const mesh1 = new THREE.Mesh(bottom, new THREE.MeshFaceMaterial(caizhi1));
mesh1.translateY(-120)
asteroids.add(mesh1)
const central1 = new THREE.CylinderBufferGeometry(140, 140, 60, 40);
const meshCentral1 = new THREE.Mesh(central1, new THREE.MeshFaceMaterial(caizhi2));
meshCentral1.translateY(-90)
asteroids.add(meshCentral1)
const central2 = new THREE.CylinderBufferGeometry(120, 120, 70, 40);
const meshCentral2 = new THREE.Mesh(central2, new THREE.MeshFaceMaterial(caizhi3));
meshCentral2.translateY(-25)
asteroids.add(meshCentral2)
const central3 = new THREE.CylinderBufferGeometry(100, 100, 70, 40);
const meshCentral3 = new THREE.Mesh(central3, new THREE.MeshFaceMaterial(caizhi4));
meshCentral3.translateY(45)
asteroids.add(meshCentral3)
asteroids.position.y = -500
/**
* 18字体
*/
var fontGeometry = new THREE.TextGeometry('18', {
font: font,
size: 50,
height: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 8,
bevelSegments: 5
})
const fontMaterial = [
new THREE.MeshPhongMaterial({map: texture5}),
new THREE.MeshPhongMaterial({map: texture6}),
material
];
const curveObject = new THREE.Mesh(fontGeometry, new THREE.MeshFaceMaterial(fontMaterial));
curveObject.translateY(100)
curveObject.translateX(-35)
asteroids.add(curveObject)
scene.add(asteroids);
/**
* 创建底部祝福字体
*/
var bottomBlessingGeometry = new THREE.BoxGeometry(700, 50, 10);
const bottomBlessingMaterial = [
new THREE.MeshPhongMaterial({map: texture3}),
new THREE.MeshPhongMaterial({map: texture3}),
new THREE.MeshPhongMaterial({map: texture3}),
new THREE.MeshPhongMaterial({map: texture3}),
new THREE.MeshPhongMaterial({map: texture7}),
new THREE.MeshPhongMaterial({map: texture3})
];
var bottomBlessingCurveObject = new THREE.Mesh(bottomBlessingGeometry, new THREE.MeshFaceMaterial(bottomBlessingMaterial));
bottomBlessingCurveObject.translateY(-800)
bottomBlessingCurveObject.translateZ(400)
bottomBlessingCurveObjectGroup.add(bottomBlessingCurveObject)
bottomBlessingCurveObjectGroup.position.y = 100
scene.add(bottomBlessingCurveObjectGroup)
/**
* 精灵创建下雨效果
*/
// 加载雨滴理贴图
var textureTree1 = new THREE.TextureLoader().load("img/h1.png");
var textureTree2 = new THREE.TextureLoader().load("img/h2.png");
var textureTree3 = new THREE.TextureLoader().load("img/h3.png");
var textureTree4 = new THREE.TextureLoader().load("img/h4.png");
var textureTree5 = new THREE.TextureLoader().load("img/h5.png");
var imageList = [textureTree1, textureTree2, textureTree3, textureTree4, textureTree5]
// 批量创建表示雨滴的精灵模型
for (let i = 0; i < 400; i++) {
var spriteMaterial = new THREE.SpriteMaterial({
map: imageList[Math.floor(Math.random() * imageList.length)],//设置精灵纹理贴图
});
// 创建精灵模型对象
var sprite = new THREE.Sprite(spriteMaterial);
petal.add(sprite);
// 控制精灵大小,
sprite.scale.set(8, 10, 1); 只需要设置x、y两个分量就可以
var k1 = Math.random() - 0.5;
var k2 = Math.random() - 0.5;
var k3 = Math.random();
// 设置精灵模型位置,在整个空间上上随机分布
sprite.position.set(2000 * k1, 1000 * k3, 2000 * k2)
}
scene.add(petal)
/**
* 音频
*/
// 非位置音频可用于不考虑位置的背景音乐
// 创建一个监听者
var listener = new THREE.AudioListener();
// camera.add( listener );
// 创建一个非位置音频对象 用来控制播放
var audio = new THREE.Audio(listener);
// 创建一个音频加载器对象
var audioLoader = new THREE.AudioLoader();
// 加载音频文件,返回一个音频缓冲区对象作为回调函数参数
audioLoader.load('./63771.ogg', function (AudioBuffer) {
console.log(AudioBuffer)
// 音频缓冲区对象关联到音频对象audio
audio.setBuffer(AudioBuffer);
audio.setLoop(true); //是否循环
audio.setVolume(0.5); //音量
// 播放缓冲区中的音频数据
audio.play(); //play播放、stop停止、pause暂停
});
// for (let i = 0; i < 20; i++) {
// var buffer = new THREE.IcosahedronBufferGeometry(10, 0)
// var material1 = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
// var cube = new THREE.Mesh( buffer, material1 );
// decorationGroup.add(cube)
// }
// scene.add( decorationGroup );
})
}
function render() {
// 每次渲染遍历雨滴群组,刷新频率30~60FPS,两帧时间间隔16.67ms~33.33ms
// 每次渲染都会更新雨滴的位置,进而产生动画效果
petal.children.forEach(sprite => {
// 雨滴的y坐标每次减1
sprite.position.y -= 1;
sprite.position.x += 0.5;
if (sprite.position.y < -400) {
// 如果雨滴落到地面,重置y,从新下落
sprite.position.y = 800;
}
if (sprite.position.x > 1000) {
sprite.position.x = -1000
}
});
renderer.render(scene, camera)
//默认保持60FPS的频率,大约每16.7ms调用一次
asteroids.rotation.y += 0.005
if (asteroids.position.y < 10) {
asteroids.position.y += 1
}
if (bottomBlessingCurveObjectGroup.position.y < 705) {
bottomBlessingCurveObjectGroup.position.y += 1
}
// mesh2.rotateY(0.01)
// mesh3.rotateY(0.01)
requestAnimationFrame(render)
}
const controls = new THREE.OrbitControls(camera);
</script>
</body>
</html>
这部分是主要代码,其中用到了three.js,和一些图片,文字全部使用图片来代替,因为发现three.js不支持中文汉字,所以没有使用中文汉字的结构来描写祝福,如果有建模功底的朋友可以使用建模来完成
源代码地址:https://gitee.com/lk666/happy-birthday