Как получить объект в пространстве 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/
Я работаю над этой проблемой в данный момент - этот подход я взял это
- объекты рендеринга, чтобы выбрать буфер каждый с уникальным цветом
- Read buffer pixel, map back to picked object
- визуализация выбранного объекта в буфер с каждым цветом пикселя функция Z-depth
- прочитайте пиксел буфера, сопоставьте назад к Z-глубине
- мы выбрали объект и приблизительный 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};
}