Об авторе Wuyue Ant Financial Data Experience Техническая команда
Наше путешествие - это море звезд
- Манифест Али
Как построить море Али из звезд с кодом?
Во-первых, мы представляем сценарий, происходящий в настоящее время, звездное небо, метеор по небу время от времени, вращение Земли, удобные услуги для миллионов людей в разных местах, потому что Али предоставил в сделке.
Эффект следующий:
embed: sky.mov
Структурная декомпозиция
Как построить приведенную выше сцену, разложить, чтобы получить следующую структуру:
звездное небо
В первую очередь должно быть небо, прямоугольник и черный фон.
Мы предварительно устанавливаем ширину, высоту и высоту, а трехмерное пространство должно иметь глубину, предварительно установленную как глубина.
В соответствии с куском мерцающих звезд, во-первых, в пространстве должна быть сгенерирована связка звезд, а во-вторых, звезды должны продолжать мерцать.Предварительно изменяется в соответствии с линейной разностью.Темная) часть кода ключа составляет:
var starts = [];
for (let i = 0; i < 10000; i++) {
starts.push({
x: Math.random() * width,
y: Math.random() * height,
z: Math.random() * depth,
//当前进度 0 - 1, 当前大小按 (1 - t) * minSize + t * maxSize
t: Math.random(),
//变化方向
direction: Math.random(),
//变化步长 暂定为常量 后面可以根据需要每个星星都不一样
step: 0.01,
//最小
minSize: 10,
//最大
maxSize: 20
});
}
animate();
function animate () {
requestAnimationFrame(animate);
starts.forEach((item) => {
let { t, minSize, maxSize } = item;
//计算当前尺寸
item.size = (1 - t) * minSize + t * maxSize;
//改变进度
if (t > 1) {
//如果已经最大了 则开始减少
item.direction = -1;
} else if (t < 0) {
//最小了 则开始变大
item.direction = 1;
}
//修改进度
item.t += item.step * item.direction;
});
//根据上面的值进行渲染
render();
}
На данный момент мы завершили звезды. Но звезды мерцают на небе, и должны быть падающие звезды, чтобы было достаточно красиво. Метеор — это звезда, которая быстро пересекает линию на небе. Итак, это может быть следующим образом:
//流星处理逻辑
var falls = [];
for (let i = 0; i < 10; i++) {
falls.push({
//流星的起点
start: {
x: Math.random() * width,
y: Math.random() * height,
z: Math.random() * depth
},
//流星的终点
end: {
x: Math.random() * width,
y: Math.random() * height,
z: Math.random() * depth
},
//当前进度 0 - 1, 当前位置按 二次贝塞尔曲线计算即可
t: Math.random(),
step: 0.01
});
}
function animate () {
requestAnimationFrame(animate);
starts.forEach((item) => {
let { t, start as p0, end as p2} = item;
//随意设置一个控制点
let p1 = {
x: p0.x,
y: (p0.y + p2.y) / 2,
z: p2.z
};
//按二次贝塞尔曲线 计算当前位置
//(1 - t) * (1 - t) * p0 + 2 * t * (1 - t ) * p1 + t * t * p2
let tmp = {
x: (1 - t) * (1 - t) * p0.x + 2 * t * (1 - t ) * p1.x + t * t * p2.x,
y: (1 - t) * (1 - t) * p0.y + 2 * t * (1 - t ) * p1.y + t * t * p2.y,
z: (1 - t) * (1 - t) * p0.z + 2 * t * (1 - t ) * p1.z + t * t * p2.z
};
item.t += item.step;
item.tmp = tmp;
//改变进度
if (t > 1) {
//如果已经最大了变为0
item.t = 0;
//重置起始点
item.start = {
x: Math.random() * width,
y: Math.random() * height,
z: Math.random() * depth
};
item.end = {
x: Math.random() * width,
y: Math.random() * height,
z: Math.random() * depth
};
}
});
//根据上面的值进行渲染
render();
}
Конечно, вышесказанное только для удобства объяснения.闪烁
а также流星
Эффект разделен.Фактически две части имеют перекрывающуюся логику.Добавьте флаг к состоянию звезды, будь то мерцание или метеор, и тогда две логики могут быть объединены.Подробности см. в части реализации кода на github. многословный.
земной шар
Со звездным небом мы собираемся построить землю. Земля примерно разделена на две части, сначала создайте шар в начале трехмерного пространства, а затем покройте землю текстурированной кожей, которая представляет собой плоскую карту от -90 ~ 90, -180 -180. плоская карта выглядит следующим образом:
Затем ключевым моментом является то, что торговые точки на земле должны быть выделены, чтобы дать некоторые эффекты выделения на соответствующих широте и долготе. Конкретный код позиционирования выглядит следующим образом:
//经纬度转x,y平面坐标
lnglatToXY ({lng, lat}, width, height) {
let x = (lng - (-180)) / 360 * width;
let y = Math.abs((lat - 90) / 180) * height;
return {
x,y
};
}
Затем нужно произвести текстуры, большие фоновые картинки и нарисовать картинки по положению на горячем холсте.
//渲染纹理
async function render () {
//全球背景图片
let worldBg = await util.loadImg(worldSrc);
//热点背景图片
let hotBg = await util.loadImg(hotSrc);
//画大背景
ctx.drawImage(worldBg, 0, 0, width, height);
//按经纬度绘制热点
data.forEach((item) => {
let lng = item.lnglat[0];
let lat = item.lnglat[1];
let {x, y} = util.lnglatToXY({lng, lat}, width, height);
ctx.drawImage(hotBg, x - size / 2, y - size / 2, size, size);
});
//生产纹理,然后 直接映射蒙到球上就可以了
let texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
return texture;
}
хорошо, земля формируется здесь. Затем позвольте земле вращаться вокруг оси Y каждый кадр.
animate();
function animate () {
requestAnimationFrame(animate);
earth.rotation.y += 0.01;
render();
}
торговая линия
ok Вращающаяся земля также доступна, и ниже следует нарисовать линию транзакции на земле. Или сначала должно быть преобразование широты и долготы в пространственные координаты. Конкретный принцип заключается в следующем.
//经纬度转空间坐标的具体代码, r 为球体半径
lnglatToXYZ ({lng, lat}, r) {
var phi = (90 - lat) * Math.PI / 180;
var theta = -1 * lng * Math.PI / 180;
return {
x: r * Math.sin(phi) * Math.cos(theta),
y: r * Math.cos(phi),
z: r * Math.sin(phi) * Math.sin(theta)
};
}
Итак, совершенно ясно, что линия, перпендикулярная земле, имеет одну и ту же долготу и широту, но разные радиусы. Следовательно, p1 и p2 можно рассчитать по приведенной выше формуле для определения прямой линии. Затем добавьте контрольные точки и переменные направления, такие как мерцающее звездное небо, и большое количество отрезков линий будет колебаться. Код ключа следующий:
//原始数据
let lines = [
{lng, lat },
{lng, lat },
....
];
//生成一些控制参数
lines.forEach((item) => {
//控制点 0 - 1 用来计算直线的终点 t * length 这里随机数是为了 不同的线初始状态不同
item.t = Math.random();
//变化方向
item.direction = Math.random() > 0.5 ? 1 : -1;
//变化速度 暂定都一样
item.step = 0.01;
//线段的长度 这里可以根据实际数据 比如 value来映射长度 本出为了示意 用随机数了
item.length = Math.random() * r;
});
animate();
function animate () {
requestAnimationFrame(animate);
lines.forEach((item) => {
let p1 = lnglatToXYZ(item.lng, item.lat, r);
//当前的终点 用 t
let p2 = lnglatToXYZ(item.lng, item.lat, r + item.length * t);
//根据 p1, p2 即可绘制一条直线
if (item.t > 1) {
item.direction = -1;
} else if (item.t < 0) {
item.direction = 1;
}
item.t += item.direction * item.step;
});
render();
}
ok Вышеупомянутые мерцающие звезды, метеоры, проносящиеся по горизонту, вращающаяся земля и дышащие торговые линии, объединенные в соответствии с соответствующими позициями, это море звезд. Конечно, увидев это, вы можете спросить, звезды есть, а как же море, ведь если присмотреться, то поверхность земли полна воды, то есть моря.
Наконец, исходный код прилагается для справки. https://github.com/liuwuyue/земля Конкретный эффект можно найти здесь http://yiqihaiqilai.com, http://yiqihaiqilai.com?line (персональный сервер, может быть исчерпан, если вы его не видите, пожалуйста, скачайте исходный код и запустите его, не Не используйте его, чтобы найти меня)
Последнее, что важно, в нашей группе еще много таких сценариев. Добро пожаловать, присоединяйтесь. Заинтересованные студенты могут следить за колонкой или отправлять свои резюме на 'wuyue.lwy####alibaba-inc.com'.replace('# # ##', '@'), давайте вместе нарисуем Али море звезд. ~
Оригинальный адрес:GitHub.com/proto team/no…