Three.js将粒子放在可视区域的中心

时间:2013-10-22 16:13:29

标签: javascript three.js

我有一个粒子系统,屏幕上散布着1000个粒子。当我使用OrbitControls进行缩放和平移时,我想让粒子最接近可视区域的中心。

我认为这有两个部分。首先,我们需要找到可视区域的中心顶点。接下来,我们需要在所有粒子上运行距离公式,以找到最接近中心顶点的粒子。希望有一种比这更有效的方法。第二部分使用蛮力非常简单。第一部分是我不确定的。如何找到可视区域的中心顶点?

3 个答案:

答案 0 :(得分:1)

你可能应该像10个单位那样直接领先于你,然后得到最接近的粒子。

这篇文章可以帮助我告诉你,我在btw之前完成了这一切。

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

答案 1 :(得分: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 viewMatrixdistance的计算基于 - Distance from a point to a line

答案 2 :(得分:0)

我不是一个三人,但我确实有优化算法方面的经验。每次循环所有粒子是错误的。

相反,粒子需要排序&#34;然后当你拥有你的相机位置时,你只需找到它在那里的位置,你就会立即得到最近的点。它非常像数据库的索引。或者想想图书馆。如果有人给你一本名为&#34;排序&#34;整个图书馆按照严格的字母顺序排列,你不必检查图书馆里的每一本书,你只需走到S然后SO,然后是SOR,然后手动比较其余的。因此,在几秒钟内,您可以找到最接近您图书的书籍,而无需查看所有书籍。

这种方式在2d情况下的工作方式是,您需要存储几个级别的网格&#34;然后只需确定您所在的网格,并检查该网格中的粒子。例如,假设您有100万个粒子,并且每个粒子都存储在中心的右侧或左侧。现在有一个快速&#34;如果&#34;您可以检查您的相机是在右侧还是左侧,如果您已经切断了需要循环的500,000个粒子。因此,在实际操作中,您可以在每个粒子上创建可能存储2个1-9格的级别,这些级别在创建时将会截断99%的粒子。一旦你弄清楚你的相机(确切的中心)所在的象限,你只需查看存储在那个&#34;网格位置&#34;中的粒子数组。因此,您的粒子将存储在粒子[1-9] [1-9] [1-100]或类似的东西中。

现在,如果你的粒子移动很多,你必须做一些简单的mod(%)类型的数学计算,以确定它们移动时所处的网格位置等。

进一步的优化可以通过设置一个阈值来完成,即什么是&#34;足够接近&#34;,所以即使你有1000个粒子几乎在彼此之上,如果你在10个像素内得到它,你和& #39;会更快地得到一个不错的结果。