Изменение объекта вслед за движением мыши — Dragon3DGraff_Blog

Изменение объекта вслед за движением мыши

1+

Решение этого вопроса заставило меня вспомнить тригонометрию и векторную алгебру.

Постановка задачи: при создании изменять объект вслед за движением мыши.

Что мы имеем: координаты курсора в экранных координатах, угол обзора камеры, соотношение сторон.
Нужно определить: насколько отличается масштаб вида в мировых координатах в данный момент времени от масштаба экрана, найти расстояние от положения объекта в экранных координатах и умножить его на масштаб вида в текущий момент времени.

Чтоб смотреть на камеру со стороны (сверху), я создал третий рендер и поместил его во второй канвас. При нажатии на канвас он увеличивается на весь экран. В последствии сделаю там ортогональную камеру.

Первое, что мы сделаем – определим положение объекта в экранных координатах. Для этого спроецируем вектор положения объекта на экран. В three.js предусмотрена функция project(). Клонируем вектор положения объекта, иначе функция изменит положение объекта.

let pos = scope.currentEntity.position.clone().project( sceneCamera.camera ); // это в координатах вида.

Переводим в координаты экрана:

scope.centerOfObjectScreen.x = ( pos.x * window.innerWidth/2 ) + window.innerWidth/2;
scope.centerOfObjectScreen.y = - ( pos.y * window.innerHeight/2 ) + window.innerHeight/2;

На видео первый желтый шарик показывает положение создаваемого объекта.

Теперь определим положение камеры в 3D пространстве и запишем его в новый вектор. Для этого также предусмотрена функция:

let cameraPosition = new THREE.Vector3();
cameraPosition = camera.position.clone();

Аналогично определим направление камеры, выраженный единичным вектором:

let cameraDirection = new THREE.Vector3();
camera.getWorldDirection ( cameraDirection );

Определим расстояние от камеры до объекта:

let distance = point.distanceTo( cameraPosition );

Теперь из центра из камеры получим точку, отстоящую на расстояние равное расстоянию от камеры до объекта:

cameraPosition.add(cameraDirection.multiplyScalar(distance) );

На видео это второй желтый шарик и зеленая линия, я создал их для того, чтобы понимать, правильно ли я делаю.

Проецируем точку положения объекта на линию, проходящую из центра камеры по оси камеры

let line3 = new THREE.Line3(camera.position, cameraPosition);
let pointOnLine = new THREE.Vector3();
line3.closestPointToPoint( point, true, pointOnLine);

Это вторая зеленая линия от первого желтого шарика перпендикулярно к оси камеры.

Определяем расстояние от камеры до точки пересечения.

distance = pointOnLine.distanceTo( camera.position );

Это и будет расстояние от камеры до плоскости, перпендикулярной оси камеры и проходящей через объект.
По формулам тригонометрии найдем размер экрана в этой плоскости в мировых координатах

let angle = camera.fov/2;
let sizeOfViewX = distance * Math.tan( angle * Math.PI / 180 ) * 2;
let sizeOfViewY = sizeOfViewX * camera.aspect * 2;

определяем коэффициент (1000000000 – для точности, это же Javascript)

let ratio = ( 1000000000 * window.innerHeight)/(1000000000 * worldSizeOfScreen.height );

Определяем расстояние от центра объекта до указателя мыши в экранных координатах

let distance = currentCoordsScreen.distanceTo( scope.centerOfObjectScreen );

и делим его на полученный коэффициент

width = distance / ratio; // получили размер куба в мировых координатах.

PS. Сначала я хотел перерисовать схемки для этого поста, но потом передумал, так живее, видно мои умственные мучения ))

1+

Добавить комментарий