2015-07-02 3 views
1

Я работаю над проектом в трех js. Я пытаюсь проецировать 2D-координаты на сферу в мире.Threejs Vector3 Unrpoject Camera

Код ниже отлично работает, когда я связала функцию на MouseDown событие:

function project(point){ 
    var x = 2 * (point[0] - width/2)/width; 
    var y = 2 * (point[1] - height/2)/height; 
    var l = new THREE.Vector3(x, y, 0.5); 
    l.unproject(camera); 
    l.sub(camera.position).normalize(); // ray/direction of click on world coordinates 

    // Below is code for Ray Sphere Intersection (I'm certain this works) 
    var omc = camera.position.clone().sub(sphere.position); 
    var ldomc = l.dot(omc); 
    var d = -ldomc - Math.sqrt(ldomc*ldomc - omc.lengthSq() + radius*radius); 
    if (d == d){ // if there was an intersection 
    return camera.position.clone().add(l.multiplyScalar(d)); 
    } 
    return null; // If no intersection was found 
} 

Однако, когда я пытался использовать вышеуказанную функцию в следующем коде функция только возвращенного нуль (не было никакого пересечения найденный).

get_random_point(scale){ // scale is the projected radius (in pixels) of the sphere 
    while (true){ // continue until a point works 
    var a = Math.random(); 
    var b = Math.sqrt(Math.random()); 
    var x = width/2 + scale * b * Math.cos(2 * Math.PI * a); 
    var y = height/2 + scale * b * Math.sin(2 * Math.PI * a); 
    if (width > x && x >= 0 && height > y && y >= 0){ 
     var projp = project([x,y]); 
     if (projp != null){ 
     return toSpherical(projp); // Return spherical coordinates of point 
     } 
    } 
    } 
} 

приведенный выше код называется ~ 100 раз каждый цикл анимации, чтобы выбрать случайную точку видимым для камеры на поверхности сферы.

Проблема возникает только после перемещения камеры. Я управляю камерой с помощью мыши, чтобы сделать ее орбитой.

Мне удалось сбросить все переменные, объявленные внутри проекта, на консоль javascript, когда это произойдет. Затем я тестировал функцию проекта на другой вкладке с той же позицией камеры и точкой и обнаружил, что рассчитанный луч был неправильным.

Вот функции для управления камерой:

d3.select("body").on("mousedown", function(event){ 
    m0 = d3.mouse(this); 
}); 

d3.select("body").on("mousemove", function(event){ 
    if (m0 != null){ 
    var m1 = d3.mouse(this); 
    var mv = [m1[0] - m0[0], m1[1] - m0[1]]; 
    theta -= mv[0]*0.25/180.0*Math.PI; 
    phi += mv[1]*0.25/180.0*Math.PI*camera.up.y; 
    if (phi > Math.PI/2){ phi = Math.PI - phi; camera.up.y *= -1; theta += Math.PI} 
    if (-Math.PI/2 > phi){ phi = -Math.PI -phi; camera.up.y *= -1; theta += Math.PI} 
    while (theta >= 2 * Math.PI){ theta -= 2 * Math.PI; } 
    while (0 > theta){ theta += 2 * Math.PI; } 
    camera.position.x = r * Math.sin(theta) * Math.cos(phi); 
    camera.position.y = r * Math.sin(phi); 
    camera.position.z = r * Math.cos(theta) * Math.cos(phi); 
    camera.lookAt(new THREE.Vector3(0, 0, 0)); 
    m0 = m1; 
    } 
}); 

d3.select("body").on("mouseup", function(event){ 
    m0 = null; 
}).on("mouseleave", function(event){ m0 = null; }); 

function Zoom(event){ 
    var movement; 
    if (event.wheelDelta){ 
    movement = event.wheelDelta/120; // wheelDelta is in increments of 120 
    } else { 
    movement = event.deltaY/-3; // DeltaY is in increments of 3; 
    } 
    r -= 0.05 * movement; 
    if (0.9 > r){ 
    r = 0.9; 
    } else if (r > 2.5){ 
    r = 2.5; 
    } 
    camera.position.x = r * Math.sin(theta) * Math.cos(phi); 
    camera.position.y = r * Math.sin(phi); 
    camera.position.z = r * Math.cos(theta) * Math.cos(phi); 
    camera.lookAt(new THREE.Vector3(0, 0, 0)); 
} 

Я не могу показаться, чтобы выяснить, почему функция проекта будет работать на одной и той же точки и камеры представляют, когда не вызывается из цикла анимации.

Я предполагаю, что камера была изменена во время обратного вызова мыши, но одна из матриц камеры не обновляется, и функция Three.Vector3.unproject() не дает желаемого результата.

EDIT: Я смог исправить проблему, перемещая анимацию непосредственно после вызова рендеринга. Это делает меня почти уверенным, что это была проблема с отсутствием обновления матриц камеры. Я знаю, как обновить матрицу проекции камеры. Как я могу заставить матричный мир камеры обновить?

+0

Я не могу отлаживать код для вас, но попробуйте позвонить 'camera.updateMatrixWorld()' сразу после того, изменения положения камеры. Кроме того, в сложных циклах избегайте 'new' и' clone() '. Создайте один экземпляр и повторно используйте его с помощью метода 'copy()'. – WestLangley

+0

Привет, Спасибо за ответ. Я попробую метод updateMatrixWorld. Также хорошее предложение о том, чтобы не использовать новый/clone() в плотных петлях. Я должен избегать дополнительных затрат на создание новых экземпляров объектов повторно. –

ответ

2

В three.js визуализатор вызывает camera.updateMatrixWorld() для каждого цикла визуализации.

Если изменить камеру position, rotation или quaternion, и затем использовать метод, который опирается на camera.matrixWorld, и, если этот метод не обновляет camera.matrixWorld себя, вы должны обновить матрицу вручную.

camera.updateMatrixWorld(); 

Three.js R.71