关于我的图形项目的建议

时间:2012-10-08 18:38:57

标签: c++ math scripting lua graphing

我正在开发一个程序,每隔(.1)秒更新一次对象列表。程序完成更新列表后,程序将知道任何对象是否在任何其他对象的特定距离内。每个对象在图形上都有一个X,Y位置。每个对象都有一个名为' Range'的值。每个刻度(.1s)程序将使用距离公式来计算是否有任何其他对象小于或等于正在处理的对象的范围。

例如,如果点A的范围为4且位于(1,1)且点B位于(1,2),则距离公式将返回〜1,意味着点B在点A的范围内计算结果与此类似:

objects = { A = {X = 1,Y = 1,Range = 4}, B = {X = 1,Y = 2,Range = 3}, C = {X = 4,Y = 7,Range = 9} }

while(true) do
 for i,v in pairs(objects) do
   v:CheckDistance()
 end
wait()
end

-- Point:CheckDistance() calculates the distance of all other points from Point "self".
-- Returns true if a point is within range of the Point "self", otherwise false.
--

问题:  图表可能包含超过200个点,每个点都会对存在的每个其他点应用数学。这将发生在每个.1s的每个点。我想这可能会减慢或在我正在使用的3D环境中造成延迟。

问题:  这听起来像是做到这一点的最佳方式吗?  关于如何更有效/更快地完成这项工作,你有什么想法?

2 个答案:

答案 0 :(得分:3)

正如Alex Feinamn所说:看起来你正在制造自己的碰撞探测器,虽然它是一个原始碰撞探测器。

然而,我不确定您是否在2D或3D平面上有点。你说每个对象“在图表上有一个X,Y位置”,并进一步谈论“我正在使用的3D环境中的滞后。”

嗯,2D和3D物理以及Lua都是发展良好的领域,因此不缺乏优化。

空间树

quadtree(或octree代表3D)是一种数据结构,它将整个2世界表示为一个分为四个正方形的正方形,每个正方形分为四个正方形,依此类推。 An example of a quadtree

您可以在this handy site处自己试验一个互动示例。

空间树通常为本地化点提供非常快速的访问。 An example of searching in a quadtree

圆圈表示特定粒子的相互作用半径。如您所见,很容易找到需要遍历的分支。

在处理点云时,您需要确保两个点不共享相同的位置,或者树的最大划分深度;否则,它将试图无限地划分分支。

我不知道Lua中的任何八叉树实现,但是制作一个很容易。如果需要示例,请查找Python或C实现; 在C ++中查找一个,除非你能处理模板疯狂。 或者,您可以通过Lua API绑定或FFI库使用C或C ++实现(建议参见绑定部分)。

LuaJIT

LuaJIT是一个自定义Lua 5.1解释器和即时编译器,提供显着的速度和存储优化,以及一个FFI库,允许轻松有效地使用C函数和类型,如整数

使用C类型来表示您的点和空间树将显着提高性能。

local ffi = require"ffi"
ffi.cdef[[
    // gp = graphing project
    struct gp_point_s {
        double x, y;
        double range;
    };

    struct gp_quadtree_root_s {
        // This would be extensive
    };
    struct gp_quadtree_node_s {
        // 
    };
]]

gp_point_mt = {
    __add = function(a, b)
        return gp_point(a.x+b.x, a.y+b.y)
    end,
    __tostring = function(self)
        return self.x..", "..self.y
    end
    __index = {
        -- I couldn't think of anything you might need here!
        something = function(self) return self.range^27 end,
    },
}
gp_point = ffi.metatype("struct gp_point_s", gp_point_mt)

-- Now use gp_point at will

local p = gp_point(22.5, 5.4, 6)
print(p)
print(p+gp_point(1, 1, 0))
print(p:something())

LuaJIT会将gp_point的所有运行时用法编译为本机程序集,在某些情况下表示类似C的速度。

Lua API与FFI

这是一个棘手的问题......

通过Lua API进行的调用无法正确优化,因为它们对Lua状态具有权限。 而通过LuaJIT的FFI对C函数的原始调用可以完全优化。

由您决定代码应如何互操作:

  • 直接在脚本中( Lua ,限制因素:动态语言只能在一定程度上进行优化)
  • 脚本 - >应用程序绑定( Lua - > C / C ++ ,限制因素:Lua API)
  • 脚本 - >外部库( Lua - > C ,限制因素:无,FFI调用是JIT编译的)

达美时间

不是真正的优化,但它很重要。

如果您正在制作专为用户互动而设计的应用,那么您不应该fix your time step;也就是说,你不能假设每次迭代都需要0.1秒。相反,您必须将所有时间相关的操作乘以时间。

pos = pos+vel*delta
vel = vel+accel*delta
accel = accel+jerk*delta
-- and so on!

然而,这是物理模拟;正如Glenn Fiedler所讨论的那样,物理学的固定和可变时间步骤都有明显的问题:

  

修复您的时间步长或爆炸

     

......如果你在汽车模拟中对减震器有一系列非常坚硬的弹簧限制,那么dt的微小变化实际上可以使模拟爆炸。 ...

如果使用固定时间步,那么理论上理论上每次都应该完全相同。如果使用可变时间步长,它将非常平滑但不可预测。我建议问你的教授。 (这是一个大学项目,对吗?)

答案 1 :(得分:0)

我不知道在你给定的情况下是否可能,但我肯定会使用事件而不是循环。这意味着跟踪一个点何时改变它的位置并对其作出反应。这样效率更高,因为它需要更少的处理并且比每1秒更快地刷新位置。如果您的积分浮动,您应该放入一些函数调用每次调用上限,因为这些事件通常会被称为非常