C# 如何修复我的3D光线投射算法,以获得玩家正在查看的块
我计算玩家正在观看哪个块(基于体素的世界)的算法不正确。我已经把它从2D改编成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.
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有两个问题,我可以从第一眼看到:
delta? = abs(look.Normalized().?);
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 }