Very fast 3D distance check?

后端 未结 13 1867
南方客
南方客 2021-01-31 15:40

Is there a way to do a quick and dirty 3D distance check where the results are rough, but it is very very fast? I need to do depth sorting. I use STL sort like this

13条回答
  •  鱼传尺愫
    2021-01-31 16:24

    What I usually do is first filter by Manhattan distance

    float CBox::Within3DManhattanDistance( Vec3 c1, Vec3 c2, float distance )
    {
        float dx = abs(c2.x - c1.x);
        float dy = abs(c2.y - c1.y);
        float dz = abs(c2.z - c1.z);
    
        if (dx > distance) return 0; // too far in x direction
        if (dy > distance) return 0; // too far in y direction
        if (dz > distance) return 0; // too far in z direction
    
        return 1; // we're within the cube
    }
    

    Actually you can optimize this further if you know more about your environment. For example, in an environment where there is a ground like a flight simulator or a first person shooter game, the horizontal axis is very much larger than the vertical axis. In such an environment, if two objects are far apart they are very likely separated more by the x and y axis rather than the z axis (in a first person shooter most objects share the same z axis). So if you first compare x and y you can return early from the function and avoid doing extra calculations:

    float CBox::Within3DManhattanDistance( Vec3 c1, Vec3 c2, float distance )
    {
        float dx = abs(c2.x - c1.x);
        if (dx > distance) return 0; // too far in x direction
    
        float dy = abs(c2.y - c1.y);
        if (dy > distance) return 0; // too far in y direction
    
        // since x and y distance are likely to be larger than
        // z distance most of the time we don't need to execute
        // the code below:
    
        float dz = abs(c2.z - c1.z);
        if (dz > distance) return 0; // too far in z direction
    
        return 1; // we're within the cube
    }
    

    Sorry, I didn't realize the function is used for sorting. You can still use Manhattan distance to get a very rough first sort:

    float CBox::ManhattanDistance( Vec3 c1, Vec3 c2 )
    {
        float dx = abs(c2.x - c1.x);
        float dy = abs(c2.y - c1.y);
        float dz = abs(c2.z - c1.z);
    
        return dx+dy+dz;
    }
    

    After the rough first sort you can then take the topmost results, say the top 10 closest players, and re-sort using proper distance calculations.

提交回复
热议问题