Как получить объект в трехмерном пространстве WebGL из координаты щелчка мышью - PullRequest
17 голосов
/ 09 сентября 2011

Я создаю настольную игру в WebGL.Доска может быть повернута / увеличена.Мне нужен способ перевести щелчок по элементу холста (x, y) в соответствующую точку в трехмерном пространстве (x, y, z).В конечном итоге я хочу узнать координату (x, y, z), которая содержит точку, которая касается объекта, ближайшего к пользователю.Например, пользователь щелкает фигуру, и вы представляете, как луч, проходящий через трехмерное пространство, проходит через фигуру и игровое поле, но я хочу координаты (x, y, z) фигуры в той точке, где она былаТронутый.

Я чувствую, что это, должно быть, очень распространенная проблема, но я не могу найти решение в моих Google.Должен быть какой-то способ проецировать текущий вид трехмерного пространства в 2D, чтобы можно было сопоставить каждую точку в двухмерном пространстве с соответствующей точкой в ​​трехмерном пространстве.Я хочу, чтобы пользователь мог навести указатель мыши на пространство на доске и изменить цвет пятна.

Ответы [ 4 ]

24 голосов
/ 10 сентября 2011

Вы ищете непроектированную функцию, которая преобразует экранные координаты в луч, отлитый из положения камеры в трехмерный мир. Затем необходимо выполнить тесты пересечения луча / треугольника, чтобы найти ближайший треугольник к камере, который также пересекает луч.

У меня есть пример отмены проецирования, доступный по адресу jax / camera.js # L568 - но вам все равно потребуется реализовать пересечение лучей / треугольников. У меня есть реализация этого в jax / triangle.js # L113 .

Однако существует более простая и (обычно) более быстрая альтернатива, называемая «подбором». Используйте это, если вы хотите выделить весь объект (например, шахматную фигуру), и если вам все равно, где на самом деле щелкнула мышь. Способ WebGL сделать это состоит в том, чтобы визуализировать всю сцену в различных оттенках синего (синий является ключом, а красный и зеленый используются для уникальных идентификаторов объектов в сцене) в текстуру, а затем считывать пиксель из эта текстура. Декодирование RGB в ID объекта даст вам объект, по которому щелкнули. Опять же, я реализовал это и он доступен по адресу jax / world.js # L82 . (См. Также строки 146, 162, 175.)

Оба подхода имеют свои плюсы и минусы (обсуждается здесь и в некоторых комментариях после), и вам необходимо выяснить, какой подход лучше всего соответствует вашим потребностям. Сборка происходит медленнее с огромными сценами, но непроектирование в чистом JS является чрезвычайно медленным (поскольку сам JS не так уж быстр), поэтому моя лучшая рекомендация - поэкспериментировать с обоими.

К вашему сведению, вы также можете взглянуть на проект GLU и код непроектирования, на котором я свободно основывал свой код: http://www.opengl.org/wiki/GluProject_and_gluUnProject_code

2 голосов
/ 28 июня 2013

Это рабочая демка

function onMouseUp(event) {

    event.preventDefault();        
    x_pos = (event.clientX / window.innerWidth) * 2 - 1;
    y_pos = -(event.clientY / window.innerHeight) * 2 + 1;
    z_pos = 0.5;

    var vector = new THREE.Vector3( x_pos , y_pos , z_pos );

    var projector = new THREE.Projector();
    projector.unprojectVector(vector, camera);
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
    var intersects = raycaster.intersectObjects(intersectObjects);

    if (intersects.length > 0) {

        xp = intersects[0].point.x.toFixed(2);
        yp = intersects[0].point.y.toFixed(2);
        zp = intersects[0].point.z.toFixed(2);  
        destination = new THREE.Vector3( xp , yp , zp );

        radians =  Math.atan2( ( driller.position.x - xp) , (driller.position.z - zp));
        radians += 90 * (Math.PI / 180);
        console.log(radians);

        var tween = new TWEEN.Tween(driller.rotation).to({ y : radians },200).easing(TWEEN.Easing.Linear.None).start();

    }

weissner-doors.de / беспилотный /

2 голосов
/ 16 октября 2011

Я сейчас работаю над этой проблемой - подход, который я использую, -

  1. Визуализация объектов для выбора буфера с уникальным цветом
  2. Считать пиксель буфера, отобразить обратно на выбранный объект
  3. Рендеринг выбранного объекта в буфер с каждым цветом пикселя функцией Z-глубины
  4. Считать пиксель буфера, отобразить обратно на Z-глубину
  5. Мы выбрали объект и приблизительный Z для координат выбора
0 голосов
/ 02 июля 2013

культивируется из одного из потоков.не уверен насчет (x, y, z), но вы можете получить canvas(x,y), используя

getBoundingClientRect ()

function getCanvasCoord(){
  var mx = event.clientX;
  var my = event.clientY;
  var canvas = document.getElementById('canvasId');
  var rect = canvas.getBoundingClientRect();// check if your browser supports this
  mx = mx - rect.left;
  my = my - rect.top;
  return {x: mx , y: my};
}
...