C# 如何修复我的3D光线投射算法,以获得玩家正在查看的块

C# 如何修复我的3D光线投射算法,以获得玩家正在查看的块,c#,math,game-physics,physics,raycasting,C#,Math,Game Physics,Physics,Raycasting,我计算玩家正在观看哪个块(基于体素的世界)的算法不正确。我已经把它从2D改编成3D。有时它会显示正确的块,但有时它会在应该返回的时候不返回任何内容,或者返回完全不同方向的内容,为什么会发生这种情况 public (Block, Box?) GetLookAtBlock(Vector3 pos, Vector3 look) { try { look = look.Normalized() * 4; float deltaX = Math.Abs(look.

我计算玩家正在观看哪个块(基于体素的世界)的算法不正确。我已经把它从2D改编成3D。有时它会显示正确的块,但有时它会在应该返回的时候不返回任何内容,或者返回完全不同方向的内容,为什么会发生这种情况

public (Block, Box?) GetLookAtBlock(Vector3 pos, Vector3 look) {
    try {
        look = look.Normalized() * 4;

        float deltaX = Math.Abs(look.Normalized().X);
        float deltaY = Math.Abs(look.Normalized().Y);
        float deltaZ = Math.Abs(look.Normalized().Z);

        int stepX, stepY, stepZ;
        float distX, distY, distZ;

        if (look.X < 0) {
            distX = (pos.X - SandboxMath.RoundDown(pos.X)) * deltaX;
            stepX = -1;
        } else {
            distX = (SandboxMath.RoundDown(pos.X) + 1 - pos.X) * deltaX;
            stepX = 1;
        }

        if (look.Y < 0) {
            distY = (pos.Y - SandboxMath.RoundDown(pos.Y)) * deltaY;
            stepY = -1;
        } else {
            distY = (SandboxMath.RoundDown(pos.Y) + 1 - pos.Y) * deltaY;
            stepY = 1;
        }

        if (look.Z < 0) {
            distZ = (pos.Z - SandboxMath.RoundDown(pos.Z)) * deltaZ;
            stepZ = -1;
        } else {
            distZ = (SandboxMath.RoundDown(pos.Z) + 1 - pos.Z) * deltaZ;
            stepZ = 1;
        }

        int endX = SandboxMath.RoundDown(pos.X + look.X);
        int endY = SandboxMath.RoundDown(pos.Y + look.Y);
        int endZ = SandboxMath.RoundDown(pos.Z + look.Z);

        int x = (int)pos.X;
        int y = (int)pos.Y;
        int z = (int)pos.Z;

        Block start = GetBlock(x, y, z);

        if (start != 0) {
            return (start, new Box(new Vector3(x, y, z), new Vector3(x + 1, y + 1, z + 1)));
        }

        while (x != endX && y != endY && z != endZ) {
            if (distX < distY) {
                if (distX < distZ) {
                    distX += deltaX;
                    x += stepX;
                } else {
                    distZ += deltaZ;
                    z += stepZ;
                }
            } else {
                if (distY < distZ) {
                    distY += deltaY;
                    y += stepY;
                } else {
                    distZ += deltaZ;
                    z += stepZ;
                }
            }

            Block b = GetBlock(x, y, z);
            if (b != 0) {
                return (b, new Box(new Vector3(x, y, z), new Vector3(x + 1, y + 1, z + 1)));
            }
        }

        return (0, null);
    } catch (IndexOutOfRangeException) {
        return (0, null);
    }
}
public(块,框?)GetLookAtBlock(矢量3位置,矢量3外观){
试一试{
look=look.Normalized()*4;
float deltaX=Math.Abs(look.Normalized().X);
float deltaY=Math.Abs(look.Normalized().Y);
float deltaZ=Math.Abs(look.Normalized().Z);
int stepX,stepY,stepZ;
浮动distX,distY,distZ;
如果(看X<0){
distX=(pos.X-SandboxMath.RoundDown(pos.X))*deltaX;
stepX=-1;
}否则{
distX=(SandboxMath.RoundDown(pos.X)+1-pos.X)*deltaX;
stepX=1;
}
如果(看起来Y<0){
distY=(位置Y-沙盒数学四舍五入(位置Y))*deltaY;
stepY=-1;
}否则{
距离=(沙盒数学四舍五入(位置Y)+1-位置Y)*三角洲;
stepY=1;
}
如果(看Z<0){
distZ=(pos.Z-SandboxMath.RoundDown(pos.Z))*deltaZ;
stepZ=-1;
}否则{
distZ=(SandboxMath.RoundDown(pos.Z)+1-pos.Z)*deltaZ;
stepZ=1;
}
int endX=SandboxMath.RoundDown(pos.X+look.X);
int endY=SandboxMath.RoundDown(pos.Y+look.Y);
int endZ=SandboxMath.RoundDown(pos.Z+look.Z);
int x=(int)pos.x;
int y=(int)pos.y;
int z=(int)pos.z;
块开始=获取块(x,y,z);
如果(开始!=0){
返回(开始,新框(新向量3(x,y,z),新向量3(x+1,y+1,z+1));
}
而(x!=endX&&y!=endY&&z!=endZ){
if(distX
您的DDA有两个问题,我可以从第一眼看到:

  • 仅当Z是长轴时工作

    所以,只有当你们在相机空间或有固定的相机在Z方向看

  • 你的三角洲很奇怪

    原因:

    我希望:

    delta? = abs(look.Normalized().?);
    
  • 我不使用C#编码,因此我没有信心修复您的代码,但这是我的C++模板,用于
    n
    -dimensionalDDA,因此只需根据它比较和修复您的代码即可

    模板类DDA
    {
    公众:
    int p0[n],p1[n],p[n];
    int d[n],s[n],c[n],ix;
    DDA(){};
    DDA(DDA&a){*this=a;}
    ~DDA(){};
    DDA*运算符=(常量DDA*a){*this=*a;返回this;}
    //DDA*运算符=(常量DDA&a){..复制…返回此;}
    void start()
    {
    int i;
    对于(ix=0,i=0;i0)s[i]=+1;
    
    如果(d[i]谢谢你,但是你能再解释一下代码吗?我不是专家(或任何接近专家的人)关于这个主题,我真的不太明白你的类模板中的每个变量是什么。谢谢,如果你不介意的话,我真的很感激你能完整地解释一下。凯,非常感谢,我现在已经试着实现了,但有时它似乎会跳过中间的一些块,这样它会在玩家实际使用的块后面返回一个块我在看…哦,我想这是因为,由于int计算,我实际上不是从我的相机所在的位置开始,而是从它所在的块的一角开始,它偏移了光线…你知道如何修复它吗?@VoxlDavid我重新编辑了答案,添加了一些来自评论和DDA亚像素偏移的内容…请删除oB引用评论。。。
    delta? = abs(look.Normalized().?);
    
    p(t) = p0 + t*(p1-p0);
    t = <0.0,1.0>
    
    dp = p1-p0
    D  = max (|dp.x|,|dp.y|,|dp.z|,...)
    p.x(i) = p0.x + (dp.x*i)/D
    p.y(i) = p0.y + (dp.y*i)/D
    p.z(i) = p0.z + (dp.z*i)/D
    ...
    i = { 0,1,...D }