我已经为doom/wolfenstein风格的光线投射器工作了一段时间。我实现了";地板光线投射";尽我所能,大致遵循一个著名的raycaster教程。它几乎起作用,但地砖似乎比它们应该的稍大,而且它们没有";"棒";,就像在中一样,它们似乎没有正确对齐,并且随着玩家的移动/旋转而轻微滑动。此外,随着FOV的增加,这种影响似乎会恶化。我不知道我的地板铸件哪里出了问题,所以我们非常感谢您的帮助。
这是发生故障的(糟糕的(gif图
这是我代码中最相关的部分:
void render(PVector pos, float dir) {
ArrayList<FloatList> dists = new ArrayList<FloatList>();
for (int i = 0; i < numColumns; i++) {
float curDir = atan((i - (numColumns/2.0)) / projectionDistance) + dir;
// FloatList because it returns a few pieces of data
FloatList curHit = cast(pos, curDir);
// normalize distances with cos
curHit.set(0, curHit.get(0) * cos(curDir - dir));
dists.add(curHit);
}
screen.beginDraw();
screen.background(50);
screen.fill(0, 30, 100);
screen.noStroke();
screen.rect(0, 0, screen.width, screen.height/2);
screen.loadPixels();
PImage floor = textures.get(4);
// DRAW FLOOR
for (int y = screen.height/2 + 1; y < screen.height; y++) {
float rowDistance = 0.5 * projectionDistance / ((float)y - (float)rY/2);
// leftmost and rightmost (on screen) floor positions
PVector left = PVector.fromAngle(dir - fov/2).mult(rowDistance).add(p.pos);
PVector right = PVector.fromAngle(dir + fov/2).mult(rowDistance).add(p.pos);
// current position on the floor
PVector curPos = left.copy();
PVector stepVec = right.sub(left).div(screen.width);
float b = constrain(map(rowDistance, 0, maxDist, 1, 0), 0, 1);
for (int x = 0; x < screen.width; x++) {
color sample = floor.get(floor((curPos.x - floor(curPos.x)) * floor.width), floor((curPos.y - floor(curPos.y)) * floor.height));
screen.pixels[x + y*screen.width] = color(red(sample) * b, green(sample) * b, blue(sample) * b);
curPos.add(stepVec);
}
}
updatePixels();
}
如果有人想查看完整的代码或有任何问题,请询问。
好吧,我似乎找到了一个"解决方案";。我会第一个承认我不明白为什么它有效,但它确实有效。根据我上面的评论,我注意到我的rowDistance
变量关闭了,这导致了所有的问题。在绝望中,我更改了FOV,然后对rowDistance
进行了硬编码,直到一切正常。我绘制了projectionDistance
和rowDistance
分子之间的比率。我注意到它完全符合一个按比例缩放的cos函数。经过一些简化,以下是我得出的公式:
float rowDistance = (rX / (4*sin(fov/2))) / ((float)y - (float)rY/2);
其中CCD_ 5是以像素为单位的屏幕宽度。
如果有人能直观地解释为什么这个公式有意义,请启发我。我希望这能帮助其他可能有这个问题的人。