飞行者动画 根据Three.js动画飞行者改编而成
程序员文章站
2022-03-10 16:57:32
...
飞行者动画 根据Three.js动画飞行者改编而成
这是图片
HTML部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
#world {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
background: linear-gradient(#e4e0ba, #f7d9aa);
}
</style>
</head>
<body>
<div id="world"></div>
</body>
<script src="js/three.js"></script>
<script src="js/stats.js"></script>
<script src="js/main.2.js"></script>
</html>
JS部分
var Colors = {
red: 0xf25346,
yellow: 0xedeb27,
white: 0xd8d0d1,
brown: 0x59332e,
pink: 0xF5986E,
brownDark: 0x23190f,
blue: 0x404040,
green: 0x458248,
purple: 0x551A8B,
lightgreen: 0x629265,
a: 0x666666,
b: 0x7B68EE,
c: 0x8C8C8C,
d: 0xDBDBDB
};
//
var scene,
camera, fieldOfView, aspectRatio, nearPlane, farPlane,
renderer, container;
//不可以使用width,height小写 不了你都不知道自己错在哪
var WIDTH,HEIGHT,
mousePos = {x:0,y:0};
function createScene() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
//创建场景
scene = new THREE.Scene();
//设置相机宽高比
aspectRatio = WIDTH / HEIGHT;
//设置相机垂直视角角度
fieldOfView = 60;
//设置最近距离
nearPlane = 1;
//设置最远距离
farPlane = 10000;
//创建相机
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane
);
scene.fog = new THREE.Fog(0xf7d9aa, 100, 950);
//设置相机位置
// camera.position.x = 0;
// camera.position.z = 200;
// camera.position.y = 100;
camera.position.x = -300;
camera.position.z = 0;
camera.position.y = 300;
camera.lookAt(scene.position);
//创建渲染器
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
//定义渲染器尺寸
renderer.setSize(WIDTH, HEIGHT);
//打开渲染器阴影地图
renderer.shadowMap.enabled = true;
//将渲染器添加到HTML中
container = document.getElementById('world');
container.appendChild(renderer.domElement);
//监听屏幕尺寸,如果屏幕尺寸发生变化 我们需要更新渲染器和相机
window.addEventListener('resize', windowResize, false);
}
function windowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
//渲染器大小重新赋值
renderer.setSize(WIDTH, HEIGHT);
//相机宽高比重新赋值
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
//创建光源函数
var ambientLight,hemisphereLight,shadowLight;
function createLights() {
//半球光//
hemisphereLight = new THREE.HemisphereLight(0xaaaaaa, 0x000000, 0.9);
// scene.add(hemisphereLight);
//平行光
shadowLight = new THREE.DirectionalLight(0xffffff, 0.9);
//设置平行光方向
shadowLight.position.set(150, 350, 350);
//开启投影
shadowLight.castShadow = true;
//定义可见投影
shadowLight.shadow.camera.left = -400;
shadowLight.shadow.camera.right = 400;
shadowLight.shadow.camera.top = 400;
shadowLight.shadow.camera.bottom = -400;
shadowLight.shadow.camera.near = 1;
shadowLight.shadow.camera.far = 1000;
// 定义阴影的分辨率(精准度)
shadowLight.shadow.mapSize.width = 1024;
shadowLight.shadow.mapSize.height = 1024;
//将光源添加到场景中
scene.add(hemisphereLight);
scene.add(shadowLight);
// 环境光源修改场景中的全局颜色和使阴影更加柔和
ambientLight = new THREE.AmbientLight(0xdc8874, .5); scene.add(ambientLight);
scene.add(ambientLight);
}
//现在开始我们要制作飞机了
var AirPlane = function () {
//老套路 先创建一个容器
this.mesh = new THREE.Object3D();
this.mesh.name = "airPlane";
//创建机舱(长宽高分段)
var geomCockpit = new THREE.BoxGeometry(60,50,50,1,1,1);
//这里 访问它的定点改变定点的位置
//4 5是在飞机尾部上方的两个点
//6 7是飞机尾部下方的两个点
geomCockpit.vertices[4].y -= 10;
geomCockpit.vertices[4].z += 20;
geomCockpit.vertices[5].y -= 10;
geomCockpit.vertices[5].z -= 20;
geomCockpit.vertices[6].y += 20;
geomCockpit.vertices[6].z += 20;
geomCockpit.vertices[7].y += 20;
geomCockpit.vertices[7].z -= 20;
//创建材质
var matCockpit = new THREE.MeshPhongMaterial({
color: Colors.red,
//着色模式
shading: THREE.FlatShading
});
var cockpit = new THREE.Mesh(geomCockpit, matCockpit);
//设置机舱接收阴影和生成阴影
cockpit.castShadow = true;
cockpit.receiveShadow = true;
//把机舱添加到容器中
this.mesh.add(cockpit);
//创建引擎
var geomEngine = new THREE.BoxGeometry(20,50,50,1,1,1);
//创建引擎材质
var matEngine = new THREE.MeshPhongMaterial({
color: Colors.white,
shading: THREE.FlatShading
});
var engine = new THREE.Mesh(geomEngine, matEngine);
//改变引擎位置
engine.position.x = 40;
//设置引擎生成阴影和接收阴影
engine.castShadow = true;
engine.receiveShadow = true;
//将引擎添加到容器中
this.mesh.add(engine);
// 创建机尾(长 宽 高 分段)
var geomTailPlane = new THREE.BoxGeometry(15,20,5,1,1,1);
//这里我们访问机尾的定点
geomTailPlane.vertices[1].x -= 5;
geomTailPlane.vertices[0].x -= 5;
//创建机尾材质
var matTailPlane = new THREE.MeshPhongMaterial({
color: Colors.red,
shading: THREE.FlatShading
});
var tailPlane = new THREE.Mesh(geomTailPlane, matTailPlane);
//机尾位置
tailPlane.position.set(-22, 15, 0);
//生成阴影和接收阴影
tailPlane.castShadow = true;
tailPlane.receiveShadow = true;
//添加至容器
this.mesh.add(tailPlane);
var geomSideWing = new THREE.BoxGeometry(40, 8, 150, 1, 1, 1);
var matSideWing = new THREE.MeshPhongMaterial({
color: Colors.red,
shading: THREE.FlatShading
});
var sideWing = new THREE.Mesh(geomSideWing, matSideWing);
sideWing.position.set(0, 0, 0);
sideWing.castShadow = true;
sideWing.receiveShadow = true;
this.mesh.add(sideWing);
// 创建螺旋桨
var geomPropeller = new THREE.BoxGeometry(20,10,10,1,1,1);
var matPropeller = new THREE.MeshPhongMaterial({
color: Colors.brown,
shading: THREE.FlatShading
});
this.propeller = new THREE.Mesh(geomPropeller, matPropeller);
this.propeller.castShadow = true;
this.propeller.receiveShadow = true;
// 创建螺旋桨的桨叶
var geomBlade = new THREE.BoxGeometry(1,100,20,1,1,1);
var matBlade = new THREE.MeshPhongMaterial({
color: Colors.brownDark,
shading: THREE.FlatShading
});
var blade = new THREE.Mesh(geomBlade, matBlade);
blade.position.set(8,0,0);
blade.castShadow = true;
blade.receiveShadow = true;
//将螺旋桨叶添加到螺旋桨中
this.propeller.add(blade);
//定义螺旋桨位置
this.propeller.position.set(50, 0, 0);
this.mesh.add(this.propeller);
};
// 定义一个天空对象
Sky = function () {
// 创建一个空的容器
this.mesh = new THREE.Object3D();
// 选取若干朵云散布在天空中
this.nClouds = 50;
this.clouds = [];
// 把云均匀地散布
// 我们需要根据统一的角度放置它们
var stepAngle = Math.PI * 2 / this.nClouds;
// 创建云对象
for (var i = 0; i < this.nClouds; i++) {
var c = new Cloud();
// 设置每朵云的旋转角度和位置
// 因此我们使用了一点三角函数
var a = stepAngle * i; //这是云的最终角度
var h = 750 + Math.random() * 100; // 这是轴的中心和云本身之间的距离
// 三角函数!!!希望你还记得数学学过的东西 :)
// 假如你不记得:
// 我们简单地把极坐标转换成笛卡坐标
c.mesh.position.y = Math.sin(a) * h;
c.mesh.position.x = Math.cos(a) * h;
// 根据云的位置旋转它
c.mesh.rotation.z = a + Math.PI / 2;
// 为了有更好的效果,我们把云放置在场景中的随机深度位置
c.mesh.position.z = -800 + Math.random() * 1900;
// c.mesh.position.z = -400 - Math.random() * 400;
// 而且我们为每朵云设置一个随机大小
var s = 1 + Math.random() * 2;
c.mesh.scale.set(s, s, s);
// 不要忘记将每朵云的网格添加到场景中
this.mesh.add(c.mesh);
}
}
Sea = function () {
//创建大海 先创建一个圆柱体(顶面半径,底部半径,高,半径分段,高分段)
var geom = new THREE.CylinderGeometry(600, 600, 1400, 40, 10);
//在x轴向上逆时针旋转90 //这里用rosition不可以吗?
geom.applyMatrix(new THREE.Matrix4().makeRotationX(-Math.PI / 2));
//创建材质
var mat = new THREE.MeshPhongMaterial({
//颜色
color: Colors.blue,
//透明度
opacity: 1,
//貌似是是否透明
transparent: true,
//shading着色模式可选值:THREE.SmoothShading、THREE.FlatShading。
shading: THREE.FlatShading,
});
this.mesh = new THREE.Mesh(geom, mat);
this.mesh.receiveShadow = true;
}
Cloud = function () {
//一个容器
this.mesh = new THREE.Object3D();
this.mesh.name = "cloud";
//正方体
var geom = new THREE.BoxGeometry(20, 20, 20);
//材质
var mat = new THREE.MeshPhongMaterial({
color: Colors.white
});
//随机复制3-8个几何体
var nBlocs = 3 + Math.floor(Math.random() * 3);
//开始循环创建
for (var i = 0; i < nBlocs; i++) {
//创建网络
var m = new THREE.Mesh(geom.clone(), mat);
//随机设置每个正方体的旋转角度以及每个正方体的位置
m.position.x = i * 15; //固定x
m.position.y = Math.random() * 10; //随机y轴位置 大于0
m.position.z = Math.random() * 10; //随机z轴位置
m.rotation.y = Math.random() * Math.PI * 2;//随机y轴旋转角度
m.rotation.z = Math.random() * Math.PI * 2;//随机z轴旋转角度
// 随机设置正方体的大小
var s = .1 + Math.random() * 0.9;
m.scale.set(s, s, s);
// 允许每个正方体生成投影
m.castShadow = true;
//允许每个正方体接收投影
m.receiveShadow = true;
//添加至容器
this.mesh.add(m);
}
}
var petalColors = [Colors.a, Colors.b, Colors.c];
Build = function () {
//创建一个容器
this.mesh = new THREE.Object3D();
//设置一个长方体
var geonBuildBase = new THREE.BoxGeometry(30, 170, 30);
var petalColor = petalColors[Math.floor(Math.random() * 3)];
//设置材质
var matBuildBase = new THREE.MeshPhongMaterial({ color: petalColor });
//添加到BuildBase中
var buildBase = new THREE.Mesh(geonBuildBase, matBuildBase);
buildBase.castShadow = true;
buildBase.receiveShadow = true;
//加入容器中
this.mesh.add(buildBase);
}
Building = function () {
this.mesh = new THREE.Object3D();
// 建筑物的数量
this.nBuilds = 900;
// 根据统一的角度平均放置他们
var stepAngle = Math.PI * 2 / this.nBuilds;
// 创建建筑物
for (var i = 0; i < this.nBuilds; i++) {
var t = new Build();
//这是建筑物最终的角度
var a = stepAngle * i;
// 这是轴中心与地面之间的距离
var h = 605;
t.mesh.position.y = Math.sin(a) * h;
t.mesh.position.x = Math.cos(a) * h;
//摆正建筑物的角度
t.mesh.rotation.z = a + (Math.PI / 2) * 3;
// 随机放到0到1400的随机位置
t.mesh.position.z = 0 - Math.random() * 1400;
// 0.3到1之间随机创建大小
var s = .3 + Math.random() * .75;
t.mesh.scale.set(s, s, s);
this.mesh.add(t.mesh);
}
}
var sea;
var airplane;
var building;
function createPlane() {
airplane = new AirPlane();
airplane.mesh.scale.set(.25, .25, .25);
airplane.mesh.position.y = 100;
scene.add(airplane.mesh);
}
function createSea() {
sea = new Sea();
sea.mesh.position.y = -600;
// sea.mesh.position. = -300;
scene.add(sea.mesh);
}
// 现在我们实例化天空对象,而且将它放置在屏幕中间稍微偏下的位置。
function createSky() {
sky = new Sky();
sky.mesh.position.y = -600;
scene.add(sky.mesh);
}
function createBuildings() {
building = new Building();
building.mesh.position.y = -600;
building.mesh.position.z = 600;
scene.add(building.mesh);
}
//渲染我们的场景
function loop() {
updatePlane();
// 螺旋桨旋转
airplane.propeller.rotation.x += 0.3;
//天空沿z轴旋转
sea.mesh.rotation.z += .005;
//大海沿z轴旋转
sky.mesh.rotation.z += .01;
building.mesh.rotation.z += .005;
// 更新每帧的飞机
// updatePlane();
// 重新渲染场景
renderer.render(scene, camera);
// 重新调用 render() 函数
requestAnimationFrame(loop);
}
var mousePos = {x:0,y:0};
function init(event) {
//监听器监听鼠标移动
document.addEventListener('mousemove', getMousePos, false);
createScene();
createLights();
createPlane();
createSea();
createSky();
createBuildings();
loop();
}
//当鼠标发生移动时 调用getMousePos函数
function getMousePos(event) {
var tx = + (event.clientX / WIDTH) * 2 - 1;
// 对于 y 轴,我们需要一个逆公式
// 因为 2D 的 y 轴与 3D 的 y 轴方向相反
var ty = 1 - (event.clientY / HEIGHT) * 2;
mousePos = { x: tx, y: ty };
//推到过程 https://blog.csdn.net/ruangong1203/article/details/60476721
}
function updatePlane() {
var targetZ = normalize(mousePos.x, -1, 1, -200, 200);
var targetY = normalize(mousePos.y, -1, 1, 50, 175);
// var targetY = mousePos.y;
airplane.mesh.position.z = targetZ;
airplane.mesh.position.y = targetY;
//airplane.mesh.position.y = targetY;
}
//
function normalize(v, vmin, vmax, tmin, tmax) {
var nv = Math.max(Math.min(v, vmax), vmin);
var dv = vmax - vmin;
var pc = (nv - vmin) / dv;
var dt = tmax - tmin;
var tv = tmin + (pc * dt);
return tv;
}
window.addEventListener('load', init, false)