Como obter object no espaço 3D WebGL de uma coordenada de clique do mouse

Estou construindo um jogo de tabuleiro no WebGL. A placa pode ser girada / ampliada. Eu preciso de uma maneira de traduzir um clique no elemento canvas (x, y) no ponto relevante no espaço 3D (x, y, z). O resultado final é que eu quero saber a coordenada (x, y, z) que contém o ponto que toca o object mais próximo do usuário. Por exemplo, o usuário clica em uma peça, e você imagina um raio viajando pelo espaço 3D que passa pela peça e pelo tabuleiro, mas eu quero a coordenada (x, y, z) da peça no ponto em que estava tocado.

Eu sinto que isso deve ser um problema muito comum, mas não consigo encontrar uma solução no meu googles. Deve haver alguma maneira de projetar a visualização atual do espaço 3D em 2D para que você possa mapear cada ponto no espaço 2D para o ponto relevante no espaço 3D. Eu quero que o usuário possa passar o mouse sobre um espaço no quadro e fazer com que o local mude de cor.

    Você está procurando uma function de não-projeto, que converte as coordenadas da canvas em um raio da posição da câmera para o mundo 3D. Você deve então realizar testes de interseção de raio / triângulo para encontrar o triângulo mais próximo da câmera, que também intercepta o raio.

    Eu tenho um exemplo de desprojeto disponível em jax / camera.js # L568 – mas você ainda precisará implementar a interseção de raio / triângulo. Eu tenho uma implementação disso em jax / triangle.js # L113 .

    Existe uma alternativa mais simples e (geralmente) mais rápida, chamada ‘picking’. Use isto se você quiser selecionar um object inteiro (por exemplo, uma peça de xadrez), e se você não se importar com onde o mouse realmente clicou. A maneira do WebGL de fazer isso é renderizar toda a cena em vários tons de azul (o azul é uma tecla, enquanto vermelho e verde são usados ​​para identificações exclusivas dos objects na cena) em uma textura, e então ler um pixel de essa textura. Decodificar o RGB no ID do object fornecerá o object que foi clicado. Novamente, eu implementei isso e está disponível em jax / world.js # L82 . (Veja também as linhas 146, 162, 175.)

    Ambas as abordagens têm prós e contras (discutidas aqui e em alguns comentários posteriores) e você precisará descobrir qual abordagem atende melhor às suas necessidades. Escolher é mais lento com cenas enormes, mas desprojetar em JS puro é extremamente lento (já que JS em si não é tão rápido), então minha melhor recomendação seria experimentar ambos.

    FYI, você também pode olhar para o projeto GLU e código de desprojeto, que eu baseei meu código livremente em: http://www.opengl.org/wiki/GluProject_and_gluUnProject_code

    Esta é a demonstração de trabalho

    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/

    Estou trabalhando neste problema no momento – a abordagem que estou tomando é

    1. Renderizar objects para escolher o buffer, cada um com colors exclusivas
    2. Ler o pixel do buffer, mapear de volta para o object escolhido
    3. Renderize o object escolhido para o buffer com cada cor de pixel em uma function de profundidade Z
    4. Leia o pixel de buffer, mapeie de volta para Z-depth
    5. Nós escolhemos object e aproximamos Z para as coordenadas de escolha

    Culto de um dos segmentos. não tenho certeza sobre (x, y, z), mas você pode obter a canvas(x,y) usando

    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}; }