我正在使用光线投射方法(如Wolfenstein3D)实现一个假的3D渲染。我遵循永久的教程(https://permadi.com/1996/05/ray-casting-tutorial-table-of-contents/)
作为第一种观点,它似乎运作良好,但我正在努力解决一个问题,我不知道会发生什么。事实上,墙壁的边缘是互相交叉的,有时光线也没有探测到任何墙壁。

但情况并不总是如此。有时效果很好,这取决于球员的方向。

在用2D渲染场景之后,我可以看到光线确实没有探测到墙壁。但视方向而定,情况并不总是如此。

在上面的截图中,左边这个不工作,但是在右边这个是工作的。
这就是我如何检测墙壁,得到距离和Y轴
float getDistanceOnHorizontalGrid(float rayAngle, float playerPosX, float playerPosY)
{
float pointInRayY = playerPosY + (100 * sin(DEGREE_TO_RADIAN(rayAngle))); // Arbitrary Point to evaluate whether ray is facing up or down
float firstIntersectPointY;
float ya;
float xa;
if (pointInRayY <= playerPosY) // ray is facing up
{
firstIntersectPointY = floorf(playerPosY / WALL_SIZE) * (WALL_SIZE)-1;
ya = -WALL_SIZE;
xa = WALL_SIZE / tan(DEGREE_TO_RADIAN(rayAngle)) * -1;
}
else // ray is facing down
{
firstIntersectPointY = floorf(playerPosY / WALL_SIZE) * (WALL_SIZE)+WALL_SIZE;
ya = WALL_SIZE;
xa = WALL_SIZE / tan(DEGREE_TO_RADIAN(rayAngle));
}
float firstIntersectPointX = playerPosX - (playerPosY - firstIntersectPointY) / tan(DEGREE_TO_RADIAN(rayAngle));
float nextPointX = firstIntersectPointX;
float nextPointY = firstIntersectPointY;
for (int i = 0; i < MAP_HEIGHT; i++)
{
int toMapX = convertWorldToGridCoordinate(floor(nextPointX));
int toMapY = convertWorldToGridCoordinate(floor(nextPointY));
if (!(toMapX >= 0 && toMapX <= MAP_WIDTH - 1 && toMapY >= 0 && toMapY <= MAP_HEIGHT - 1))
{
return 0.0f;
}
if (map[toMapY][toMapX] == 1)
{
return abs(sqrt(((playerPosX - nextPointX) * (playerPosX - nextPointX)) + ((playerPosY - nextPointY) * (playerPosY - nextPointY))));
}
nextPointX += xa;
nextPointY += ya;
}
return 0.0f;
}X轴也是如此
float getDistanceOnverticalGrid(float rayAngle, float playerPosX, float playerPosY)
{
float pointInRayX = playerPosX + (100 * cos(DEGREE_TO_RADIAN(rayAngle))); // Arbitrary Point to evaluate whether ray is facing left or right
float firstIntersectX;
float firstIntersectY;
float xa;
float ya;
if (pointInRayX <= playerPosX) // ray facing left
{
firstIntersectX = floorf(playerPosX / WALL_SIZE) * (WALL_SIZE)-1;
xa = -WALL_SIZE;
ya = (WALL_SIZE * tan(DEGREE_TO_RADIAN(rayAngle))) * -1;
}
else
{
firstIntersectX = floorf(playerPosX / WALL_SIZE) * (WALL_SIZE)+WALL_SIZE;
ya = WALL_SIZE * tan(DEGREE_TO_RADIAN(rayAngle));
xa = WALL_SIZE;
}
firstIntersectY = playerPosY - (playerPosX - firstIntersectX) * tan(DEGREE_TO_RADIAN(rayAngle));
float nextPointX = firstIntersectX;
float nextPointY = firstIntersectY;
for (int i = 0; i < MAP_WIDTH; i++)
{
int toMapX = convertWorldToGridCoordinate(floorf(nextPointX));
int toMapY = convertWorldToGridCoordinate(floorf(nextPointY));
if (!(toMapX >= 0 && toMapX <= (MAP_WIDTH - 1) && toMapY >= 0 && toMapY <= (MAP_HEIGHT - 1)))
{
return 0.0f;
}
if (map[toMapY][toMapX] == 1)
{
return abs(sqrt(((playerPosX - nextPointX) * (playerPosX - nextPointX)) + ((playerPosY - nextPointY) * (playerPosY - nextPointY))));
}
nextPointX += xa;
nextPointY += ya;
}
return 0.0f;
}我一定做错了什么,但我不知道在哪里。谢谢你的帮助
更新
尽管把数值从1降下来仍然是必要的,但在计算中,所提到的BCT是正确的。在使loog更接近permadi的实现之后,完成以下操作
horizontalGrid = Math.floor(this.fPlayerY/this.TILE_SIZE)*this.TILE_SIZE + this.TILE_SIZE;他做到了:
horizontalGrid--;一开始我以为这和我所做的是一样的,但实际上没有。他后来降低了值的原因是因为这只是为了得到网格坐标。
为了解决我的问题,我从计算中删除了-1,并且只在寻找网格坐标时降低了值。
发布于 2022-04-22 09:49:22
我看了你发送的链接。似乎其中一个if块的价值很差:
这是教程代码:
// Ray is facing down
if (castArc > this.ANGLE0 && castArc < this.ANGLE180)
{
// truncuate then add to get the coordinate of the FIRST grid (horizontal
// wall) that is in front of the player (this is in pixel unit)
// ROUNDED DOWN
horizontalGrid = Math.floor(this.fPlayerY/this.TILE_SIZE)*this.TILE_SIZE + this.TILE_SIZE;这是你的代码:
if (pointInRayY <= playerPosY) // ray is facing up
{
firstIntersectPointY = floorf(playerPosY / WALL_SIZE) * (WALL_SIZE)-1;请注意,您的末尾是-1,而不是this.TILE_SIZE,在您的示例中,应该是WALL_SIZE
https://stackoverflow.com/questions/71966198
复制相似问题