2013-10-22 37 views
1

我有一個粒子系統,其中有1000個粒子散佈在整個屏幕上。當我使用OrbitControls縮放和平移時,我想讓粒子最接近可視區域的中心。Three.js在可視區域中心獲得粒子

我在想這個有兩個部分。首先,我們需要找到可視區域的中心頂點。接下來,我們需要在所有粒子上運行距離公式以找到最接近中心頂點的距離公式。希望有一種比這更有效的方式。第二部分使用暴力相當簡單。第一部分是我不確定的。我如何找到可視區域的中心頂點?

+0

如果您使用的是OrbitControls,那麼'controls.target'就是相機旋轉的點,它是相機所看到的點,因此它位於可視區域的中心。 – WestLangley

回答

1

你應該得到一個像10個單位一樣直線前進的點,然後得到最接近的點。

這篇文章可以幫助我告訴你,我已經做了所有之前,順便說一句。

Three.js Projector and Ray objects

其用於點擊屏幕上的點,並得到一個矢量出來。

projector = new THREE.Projector(); 

// This is like clicking on the center of the screen, 0, 0 is center 
straight_ahead = new THREE.Vector3(0,0,.5); 

// Now we have straight_ahead relative to the camera 
projector.unprojectVector(straight_ahead, camera); 

// Now straight_ahead is just the direction of the camera, since we're taking away the camera's position from it 
straight_ahead.sub(camera.position) 

// It's a direction of where the camera is looking, so lets make it 10 units away(pick your own number) 
straight_ahead.normalize().multiplyScalar(10) 

// Now we we have a length of 10 units, we can get 10 units in front of the camera 
straight_ahead.add(camera.position) 

// At this point, straight ahead is a point in space 10 units in front of you, so lets find the closest point to that 

// here's where you put a simple loop in 
min_point = null 
min_distance = 999999999 
_.each(my_particles, function(particle) { 
    distance = particle.position.distanceTo(straight_ahead) 
    if (distance < min_distance) { 
    min_point = particle 
    min_distance = distance 
    } 
}); 

// now you have min_point, which should be the closest point to 10 feet in front of your face 
0
lookAt = camera.lookAt; 
pos = camera.position; 

min = MAX_FLOAT, min_index = -1; 
foreach(particle in particle_system) { 
    d = distance(particle.position, lookAt, pos); 
    if(min>d) { min_index = particle.getIndex; min = d; } 
} 

哪裏distance功能可以繞過球網中找到,例如:http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line

這是僞代碼。它發揮的作用是找到觀察射線(lookAt矢量),並從中找到最接近的粒子。

編輯:

var cam_position = camera.position, 
    cam_eyeVec = getEyeVec(camera.projectionMatrix); 

var min_dist = 10000000, 
    min_index = -1; 

for(var i=0; i<particle_count; i++) { 
    var d = distance(particle[i].position, cam_eyeVec, cam_position); 
    if(min_dist > d) { 
     min_index = i; 
     min_dist = d; 
    } 
} 

function getEyeVec(projMat) { 
    return new THREE.Vector3(projMat[8], projMat[9], projMat[10]); 
} 

function distance(p, n, a) { 
    n = n.normalize(); 
    var diff = new THREE.Vector3(a.x-p.x, a.y-p.y, a.z-p.z); 
    var diff_n = diff.multiply(n); 
    var d = ((diff.selfSubstract(diff_n)).selfMultiply(n)).length(); 
    return d; 
} 

getEyeVec計算是基於 - eye and up vectors from viewMatrix。 Calcallation for distance基於 - Distance from a point to a line

+0

你能再解釋一下嗎?我意識到這是僞代碼,但我不清楚你想傳達什麼。距離公式比較兩點,而不是三點。此外,lookAt是一個函數。你爲什麼要將它傳遞給距離函數? – wwwuser

+0

我通過查看相機的矢量,相機的位置和每個粒子的位置。有一個公式可以計算一個點與它的原點和矢量給出的直線之間的距離。這就是你用來獲得距離的東西。更清楚嗎? –

+0

我一直在尋找這最好的幾天,我仍然有一個問題計算在可視區域的中心最近的粒子。我是Three.js的新手,計算點和線之間的距離。無論如何,我們可以將距離僞代碼更改爲真正的代碼? – wwwuser

0

我不是three.js的人,但我確實有過優化算法的經驗。每次循環所有粒子都是錯誤的。

相反,粒子需要「排序」,然後當您擁有相機位置時,您只需找到排序的位置,即可獲得最近的點。這非常像數據庫上的索引。或者想想圖書館。如果有人給你一本名爲「排序」的書,並且整個圖書館都是嚴格按照字母順序排列的,那麼你不必檢查圖書館中的每一本書,只要走到S然後SO,然後SOR,然後手動比較其餘的部分。所以在幾秒鐘內,你就可以找到最接近你的書的書,而不用看所有的書。

這種工作方式在2d的情況下,你需要存儲一個「網格」的幾個級別,然後只需確定你在哪個網格,並檢查該網格中的粒子。例如,假設您有一百萬個粒子,並且每個粒子都存儲在中心的右側還是左側。現在用一個快速的「如果」,你可以檢查你的相機是在右邊還是左邊,如果是,你已經切掉了500,000個需要循環的粒子。因此,在實踐中,當每個粒子創建時,你可能會在1-9個網格中存儲2個等級,並且這會切掉99%必須檢查的粒子。一旦你找出你的相機(精確中心)在哪個象限內,你只需查看存儲在該「網格位置」中的粒子數組。所以你的粒子將被存儲在粒子[1-9] [1-9] [1-100]之類的東西中。

現在,如果你的顆粒動了不少,你就必須做一些簡單的MOD(%)類型的數學弄清楚他們在網格位置,因爲它們移動等

futher優化可以通過設置一個閾值來完成,即什麼是「足夠接近」,所以即使你有1000個粒子幾乎在另一個之上,如果你得到它在10個像素內,你會得到一個體面的結果快得多。