Ориентируясь на пример кода из ответа
Немного поэкспериментировал с кодом, я рассеял точки по экрану
textGeo.vertices.forEach(function (vertex) {
vertex.x = THREE.Math.randFloat(-20, 20)//.copy(vertex.startPoint).addScaledVector(vertex.direction, 5 + Math.sin(Date.now() * 0.001) * 5);
vertex.y = THREE.Math.randFloat(-20, 20)//.copy(vertex.startPoint).addScaledVector(vertex.direction, 5 + Math.sin(Date.now() * 0.001) * 5);
vertex.z = THREE.Math.randFloat(-10, 10)//.copy(vertex.startPoint).addScaledVector(vertex.direction, 5 + Math.sin(Date.now() * 0.001) * 5);
});
Добавил пару функций и изменил функцию render
function setPosition(vertex, curent, orign, step) {
let curentPoint = Math.round(curent * 10) / 10;
let orignPoint = Math.round(orign * 10) / 10;
if (curentPoint !== orignPoint) {
curent = orign < curent ? curent - step : curent + step;
} else {
curent = orign;
vertex.complate = true;
}
return curent;
}
function isComplated(vertices) {
let result = true;
vertices.forEach(function(vertex, i) {
if(!vertex.complate) {
result = false;
}
});
return result;
}
function render() {
let animationId = requestAnimationFrame(render);
if (!isComplated(textGeo.vertices)) {
textGeo.vertices.forEach(function (vertex) {
vertex.x = setPosition(vertex, vertex.x, vertex.startPoint.x, 0.1);
vertex.y = setPosition(vertex, vertex.y, vertex.startPoint.y, 0.1);
vertex.z = setPosition(vertex, vertex.z, vertex.startPoint.z, 0.1);
});
} else {
cancelAnimationFrame(animationId);
}
textGeo.verticesNeedUpdate = true;
renderer.render(scene, camera);
}
Идея была следующей:
Рассеиваем точки по экрану, а затем начинаем их возвращать на начальные места, когда все точки займут свое начальное положение завершить анимацию остановкой AnimationFrame. Но проблема в том, что cancelAnimationFrame(animationId) вызывается раньше, чем все точки возвращаются на свои места.
Рабочий пример:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 10, 20);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// var controls = new OrbitControls(camera, renderer.domElement);
camera.lookAt(scene.position);
var light = new THREE.DirectionalLight(0xffffff, 2);
light.position.setScalar(100);
scene.add(light);
var textGeo = null;
var textPoints = null;
var loader = new THREE.FontLoader();
loader.load('https://threejs.org/examples/fonts/droid/droid_serif_bold.typeface.json', function (response) {
var font = response;
setText(font);
render();
});
function setText(font) {
textGeo = new THREE.TextGeometry('ABC', {
font: font,
size: 4,
height: 0.5,
curveSegments: 4,
bevelEnabled: false,
bevelSize: 10,
bevelThickness: 50
});
textGeo.computeBoundingBox();
textGeo.computeVertexNormals();
textGeo.center();
fillWithPoints(textGeo, 10);
textGeo.vertices.forEach(function (vertex) {
vertex.startPoint = vertex.clone();
vertex.direction = vertex.clone().normalize();
})
textGeo.vertices.forEach(function (vertex) {
vertex.x = THREE.Math.randFloat(-20, 20)//.copy(vertex.startPoint).addScaledVector(vertex.direction, 5 + Math.sin(Date.now() * 0.001) * 5);
vertex.y = THREE.Math.randFloat(-20, 20)//.copy(vertex.startPoint).addScaledVector(vertex.direction, 5 + Math.sin(Date.now() * 0.001) * 5);
vertex.z = THREE.Math.randFloat(-10, 10)//.copy(vertex.startPoint).addScaledVector(vertex.direction, 5 + Math.sin(Date.now() * 0.001) * 5);
});
window.p = textGeo.vertices[0]
//console.log(textGeo.vertices[0]);
//textGeo.verticesNeedUpdate = true;
//textGeo.applyMatrix( new THREE.Matrix4().makeTranslation( 1, 1, 1 ) );
textPoints = new THREE.Points(textGeo, new THREE.PointsMaterial({
color: 0xf00008,
size: 0.1
}));
scene.add(textPoints);
}
function fillWithPoints(geometry, pointNumber) {
geometry.computeBoundingBox();
for (var i = 0; i < pointNumber; i++) {
setRandomPoint(geometry);
}
}
function setRandomPoint(geometry) {
var point = new THREE.Vector3(
THREE.Math.randFloat(geometry.boundingBox.min.x, geometry.boundingBox.max.x),
THREE.Math.randFloat(geometry.boundingBox.min.y, geometry.boundingBox.max.y),
THREE.Math.randFloat(geometry.boundingBox.min.z, geometry.boundingBox.max.z)
);
//console.log(point);
if (isPointInside(point, geometry)) {
geometry.vertices.push(point);
} else {
setRandomPoint(geometry);
}
}
var a = new THREE.Vector3();
var b = new THREE.Vector3();
var c = new THREE.Vector3();
var face = new THREE.Face3();
function isPointInside(point, geometry) {
var retVal = false;
for (var i = 0; i < geometry.faces.length; i++) {
face = geometry.faces[i];
a = geometry.vertices[face.a];
b = geometry.vertices[face.b];
c = geometry.vertices[face.c];
//console.log(face, a, b, c);
if (ptInTriangle(point, a, b, c)) {
var retVal = true;
break;
}
}
return retVal;
}
function ptInTriangle(p, p0, p1, p2) {
// credits: http://jsfiddle.net/PerroAZUL/zdaY8/1/
var A = 1 / 2 * (-p1.y * p2.x + p0.y * (-p1.x + p2.x) + p0.x * (p1.y - p2.y) + p1.x * p2.y);
var sign = A < 0 ? -1 : 1;
var s = (p0.y * p2.x - p0.x * p2.y + (p2.y - p0.y) * p.x + (p0.x - p2.x) * p.y) * sign;
var t = (p0.x * p1.y - p0.y * p1.x + (p0.y - p1.y) * p.x + (p1.x - p0.x) * p.y) * sign;
return s > 0 && t > 0 && (s + t) < 2 * A * sign;
}
function setPosition(vertex, curent, orign, step) {
let curentPoint = Math.round(curent * 10) / 10;
let orignPoint = Math.round(orign * 10) / 10;
if (curentPoint !== orignPoint) {
curent = orign < curent ? curent - step : curent + step;
} else {
curent = orign;
vertex.complate = true;
}
return curent;
}
function isComplated(vertices) {
let result = true;
vertices.forEach(function(vertex, i) {
if(!vertex.complate) {
result = false;
}
});
return result;
}
function render() {
let animationId = requestAnimationFrame(render);
if (!isComplated(textGeo.vertices)) {
textGeo.vertices.forEach(function (vertex) {
vertex.x = setPosition(vertex, vertex.x, vertex.startPoint.x, 0.1);
vertex.y = setPosition(vertex, vertex.y, vertex.startPoint.y, 0.1);
vertex.z = setPosition(vertex, vertex.z, vertex.startPoint.z, 0.1);
});
} else {
cancelAnimationFrame(animationId);
}
textGeo.verticesNeedUpdate = true;
/* complated = isComplated(textGeo.vertices);
if (complated) {
//console.log(complated);
cancelAnimationFrame(animationId);
console.log('end')
} */
renderer.render(scene, camera);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>
Известна рандомная позиция точки, известна конечная позиция точки, известно расстояние между ними, известна скорость. Можем найти время анимации разделив наибольшее из всех расстояний на скорость, и как только текущее время анимации стало больше или равно расчетному - производим какое-то действие.
Кроме того, есть метод .clampLength()
, упрощающий жизнь и не дающий длине вектора приращения выходить за заданные пределы:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(2, 3, 5);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var tempDist = new THREE.Vector3();
var boxGeom = new THREE.BoxGeometry(2, 2, 2, 10, 10, 10);
boxGeom.vertices.forEach(v => {
v.init = v.clone();
v.random = new THREE.Vector3(THREE.Math.randFloatSpread(10), THREE.Math.randFloatSpread(10), THREE.Math.randFloatSpread(5));
v.dir = new THREE.Vector3().copy(v.init).sub(v.random).normalize();
v.dist = tempDist.copy(v.init).sub(v.random).length();
v.copy(v.random);
});
var boxMat = new THREE.PointsMaterial({
size: 0.1,
color: "red"
});
var box = new THREE.Points(boxGeom, boxMat);
scene.add(box);
var speed = 2; // единиц в секунду
var longestDist = 0;
boxGeom.vertices.forEach(v => {
longestDist = Math.max(longestDist, v.dist);
});
var fullTime = longestDist / speed; // продолжительность анимации определяется по самой длинной дистанции, так как скорость постоянная
console.log({
fullTime
});
var clock = new THREE.Clock();
var delta = 0;
var globalTime = 0;
var clampedDirLength = new THREE.Vector3();
render();
function render() {
let req = requestAnimationFrame(render);
delta = clock.getDelta();
globalTime += delta;
boxGeom.vertices.forEach(v => {
clampedDirLength.copy(v.dir).multiplyScalar(globalTime * speed).clampLength(0, v.dist); // clamp the length!
v.copy(v.random).add(clampedDirLength);
});
boxGeom.verticesNeedUpdate = true;
if (globalTime >= fullTime) { // если текущая продолжительность больше или равна заданной, то останавливаем цикл прорисовки или делаем что-то другое
//cancelAnimationFrame(req);
boxMat.color.set("aqua");
}
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
Референс
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Подскажите, как сделать скроллбар для каруселиЧтобы скролл реагировал когда переключаешь изображения
Собственно вот в чём вопрос: если верить https://developermozilla
Задача программы - сортировать команды в группы так, чтобы в одной группе не было команд с одной и той же страныПроблема заключается в следующем:...
Дан массив объектовНайти введенное значение в массиве и выести порядковый номер элемента массива с ключом, в котором оно записано