【问题标题】:Fast Voxel Traversal Algorithm with negative direction负方向快速体素遍历算法
【发布时间】:2015-02-09 04:40:36
【问题描述】:

我正在尝试实现快速体素遍历算法并根据this answer(T 是 tDelta,M 是 tMax)计算 T 和 M。如果方向向量 V 的两个分量是正的,那么一切都很好。但如果其中至少有一个是负数,那就大错特错了。

绿点是开始,红色是结束。一切似乎都是正确的。

现在从大到小。

遍历方法:

private IEnumerable<Vector2> GetCrossedCells(Vector2 pPoint1, Vector2 pPoint2)
{
    Vector2 V = pPoint2 - pPoint1; // direction & distance vector
    if (V != Vector2.Zero)
    {
        Vector2 U = Vector2.Normalize(V); // direction unit vector
        Vector2 S = new Vector2(Math.Sign(U.X), Math.Sign(U.Y)); // sign vector
        Vector2 P = pPoint1; // position
        Vector2 G = new Vector2((int) Math.Floor(P.X / CELL_SIZE), (int) Math.Floor(P.Y / CELL_SIZE)); // grid coord
        Vector2 T = new Vector2(Math.Abs(CELL_SIZE / U.X), Math.Abs(CELL_SIZE / U.Y));
        Vector2 M = new Vector2(
            Single.IsInfinity(T.X) ? Single.PositiveInfinity : T.X * (1.0f - (P.X / CELL_SIZE) % 1),
            Single.IsInfinity(T.Y) ? Single.PositiveInfinity : T.Y * (1.0f - (P.Y / CELL_SIZE) % 1));

        Vector2 D = Vector2.Zero;
        bool isCanMoveByX = S.X != 0;
        bool isCanMoveByY = S.Y != 0;

        while (isCanMoveByX || isCanMoveByY)
        {
            yield return G;

            D = new Vector2(
                S.X > 0 ? (float) (Math.Floor(P.X / CELL_SIZE) + 1) * CELL_SIZE - P.X :
                S.X < 0 ? (float) (Math.Ceiling(P.X / CELL_SIZE) - 1) * CELL_SIZE - P.X :
                0,
                S.Y > 0 ? (float) (Math.Floor(P.Y / CELL_SIZE) + 1) * CELL_SIZE - P.Y :
                S.Y < 0 ? (float) (Math.Ceiling(P.Y / CELL_SIZE) - 1) * CELL_SIZE - P.Y :
                0);

            if (Math.Abs(V.X) <= Math.Abs(D.X))
            {
                D.X = V.X;
                isCanMoveByX = false;
            }

            if (Math.Abs(V.Y) <= Math.Abs(D.Y))
            {
                D.Y = V.Y;
                isCanMoveByY = false;
            }

            if (M.X <= M.Y)
            {
                M.X += T.X;
                G.X += S.X;
                if (isCanMoveByY)
                {
                    D.Y = U.Y / U.X * D.X; // U.X / U.Y = D.X / D.Y => U.X * D.Y = U.Y * D.X
                }
            }
            else
            {
                M.Y += T.Y;
                G.Y += S.Y;
                if (isCanMoveByX)
                {
                    D.X = U.X / U.Y * D.Y;
                }
            }

            V -= D;
            P += D;
        }
    }
}

在调试中我可以看到,例如 M.Y > M.X 如果 S.X

请告诉我,我的代码在负方向上哪里出错了?

【问题讨论】:

    标签: xna raytracing


    【解决方案1】:

    所以,我解决了。 我让代码更干净,问题就消失了。

    private IEnumerable<Vector2> GetCrossedCells(Vector2 pPoint1, Vector2 pPoint2)
    {
        if (pPoint1 != pPoint2)
        {
            Vector2 V = (pPoint2 - pPoint1) / CELL_SIZE; // direction & distance vector
            Vector2 U = Vector2.Normalize(V); // direction unit vector
            Vector2 S = new Vector2(Math.Sign(U.X), Math.Sign(U.Y)); // sign vector
            Vector2 P = pPoint1 / CELL_SIZE; // position in grid coord system
            Vector2 G = new Vector2((int) Math.Floor(P.X), (int) Math.Floor(P.Y)); // grid coord
            Vector2 T = new Vector2(Math.Abs(CELL_SIZE / U.X), Math.Abs(CELL_SIZE / U.Y));
            Vector2 D = new Vector2(
                S.X > 0 ? 1 - P.X % 1 : S.X < 0 ? P.X % 1 : 0,
                S.Y > 0 ? 1 - P.Y % 1 : S.Y < 0 ? P.Y % 1 : 0);
            Vector2 M = new Vector2(
                Single.IsInfinity(T.X) || S.X == 0 ? Single.PositiveInfinity : T.X * D.X,
                Single.IsInfinity(T.Y) || S.Y == 0 ? Single.PositiveInfinity : T.Y * D.Y);
    
            bool isCanMoveByX = S.X != 0;
            bool isCanMoveByY = S.Y != 0;
    
            while (isCanMoveByX || isCanMoveByY)
            {
                yield return G;
    
                D = new Vector2(
                    S.X > 0 ? (float) Math.Floor(P.X) + 1 - P.X :
                    S.X < 0 ? (float) Math.Ceiling(P.X) - 1 - P.X :
                    0,
                    S.Y > 0 ? (float) Math.Floor(P.Y) + 1 - P.Y :
                    S.Y < 0 ? (float) Math.Ceiling(P.Y) - 1 - P.Y :
                    0);
    
                if (Math.Abs(V.X) <= Math.Abs(D.X))
                {
                    D.X = V.X;
                    isCanMoveByX = false;
                }
    
                if (Math.Abs(V.Y) <= Math.Abs(D.Y))
                {
                    D.Y = V.Y;
                    isCanMoveByY = false;
                }
    
                if (M.X <= M.Y)
                {
                    M.X += T.X;
                    G.X += S.X;
                    if (isCanMoveByY)
                    {
                        D.Y = U.Y / U.X * D.X; // U.X / U.Y = D.X / D.Y => U.X * D.Y = U.Y * D.X
                    }
                }
                else
                {
                    M.Y += T.Y;
                    G.Y += S.Y;
                    if (isCanMoveByX)
                    {
                        D.X = U.X / U.Y * D.Y;
                    }
                }
    
                V -= D;
                P += D;
            }
        }
    }
    

    更新

    我从删除 GRID_CELL 上的冗余分区开始,然后注意到 M 计算中的错误。 有使用 Frac() 函数来回答这个问题,我提供了一个链接。我像 (1 - P % 1) 一样计算它,但这是 S > 0 的情况,如果 S

    更新 2

    应该还有

    Vector2 D = new Vector2(
        S.X > 0 ? (float) Math.Floor(P.X) + 1 - P.X :
        S.X < 0 ? (float) Math.Ceiling(P.X) - 1 - P.X :
        0,
        S.Y > 0 ? (float) Math.Floor(P.Y) + 1 - P.Y :
        S.Y < 0 ? (float) Math.Ceiling(P.Y) - 1 - P.Y :
        0);
    

    代替

    Vector2 D = new Vector2(
        S.X > 0 ? 1 - P.X % 1 : S.X < 0 ? P.X % 1 : 0,
        S.Y > 0 ? 1 - P.Y % 1 : S.Y < 0 ? P.Y % 1 : 0);
    

    因为如果 S

    【讨论】:

      猜你喜欢
      • 2017-05-08
      • 2014-08-30
      • 1970-01-01
      • 2014-09-16
      • 2021-11-18
      • 2020-07-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多