Как получить объект в пространстве WebGL 3d с помощью координаты щелчка мыши

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

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

4 ответов


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

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

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

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

FYI, вы также можете посмотреть на проект GLU и код unproject, на котором я основывал свой код свободно:http://www.opengl.org/wiki/GluProject_and_gluUnProject_code


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

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/drone/


Я работаю над этой проблемой в данный момент - этот подход я взял это

  1. объекты рендеринга, чтобы выбрать буфер каждый с уникальным цветом
  2. Read buffer pixel, map back to picked object
  3. визуализация выбранного объекта в буфер с каждым цветом пикселя функция Z-depth
  4. прочитайте пиксел буфера, сопоставьте назад к Z-глубине
  5. мы выбрали объект и приблизительный Z для выбора координат

выделено из одной из нитей. не уверен в (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};
}