Raycasting искажается на больших углах FOVJavascript

Форум по Javascript
Ответить Пред. темаСлед. тема
Anonymous
 Raycasting искажается на больших углах FOV

Сообщение Anonymous »

Я написал Raycaster в JavaScript после учебников Лодева. (https://lodev.org/cgtutor/raycasting.html)ски /узкие углы FOV, но на больших углах FOV объект идет на своего рода эллиптическом пути вокруг происхождения raycaster, а не вращается по кругу при вращении левого/правого. Теперь я уверен, что это не ожидается, и это выглядит удачным. См. Видео (извините, что я должен был донести до соответствующего размера для Stackoverflow):
< /p>
Вы можете ясно видеть, что стена проходит в эллиптической кривой вокруг игрока. На изображении я использую длину вектора направления 1 и плоский вектор длины 2.2 (давая нам большой FOV) < /p>
Я не могу найти никаких неисправностей в алгоритме, и используемая математика должна наиболее вероятно не производить такой результат. Для каждого луча мы должны двигаться в правильном направлении, добавив направление и плоские векторы, масштабированные по x координату камеры. Затем перенести перпендикулярные расстояния в плоскость камеры. < /P>
Есть идеи? 'T изменил алгоритм из исходного учебника. < /p>

Код: Выделить всё

let ZBuffer: { [key: number]: number } = {};
let width = Math.ceil(this.spacing);

this.ctx.save();
for (let column = 0; column < this.resolution; column++) {
// x-coordinate in camera space scaled from -1 to 1
let cameraX = (2 * column) / this.resolution - 1;

// get the ray direction vector
let rayDirX = player.position.dirX + player.position.planeX * cameraX;
let rayDirY = player.position.dirY + player.position.planeY * cameraX;

// which box of the map we're in
let mapX = Math.floor(player.position.x);
let mapY = Math.floor(player.position.y);

// length of ray from current position to next x or y-side
let sideDistX: number;
let sideDistY: number;

//length of ray from one x or y-side to next x or y-side
//these are derived as:
//deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX))
//deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY))
//which can be simplified to abs(|rayDir| / rayDirX) and abs(|rayDir| / rayDirY)
//where |rayDir| is the length of the vector (rayDirX, rayDirY). Its length,
//unlike (dirX, dirY) is not 1, however this does not matter, only the
//ratio between deltaDistX and deltaDistY matters, due to the way the DDA
//stepping further below works. So the values can be computed as below.
// Division through zero is prevented
let deltaDistX = Math.abs(1 / rayDirX);
let deltaDistY = Math.abs(1 / rayDirY);

// perpendicular wall distance
let perpWallDist: number;

// what direction to step in x or y-direction (either +1 or -1)
let stepX: number;
let stepY: number;

let hit: number = 0; // was there a wall hit?
let side: number; // was a NS or a EW wall hit? if x then side = 0, if y then side = 1

// calculate step and initial sideDist
if (rayDirX < 0) {
stepX = -1;
sideDistX = (player.position.x - mapX) * deltaDistX;
} else {
stepX = 1;
sideDistX = (mapX + 1.0 - player.position.x) * deltaDistX;
}

if (rayDirY < 0) {
stepY = -1;
sideDistY = (player.position.y - mapY) * deltaDistY;
} else {
stepY = 1;
sideDistY = (mapY + 1.0 - player.position.y) * deltaDistY;
}

// perform DDA
let range = this.range;
while (hit == 0 && range >= 0) {
// jump to next map square, either in x-direction, or in y-direction
if (sideDistX < sideDistY) {
sideDistX += deltaDistX;
mapX += stepX;
side = 0;
} else {
sideDistY += deltaDistY;
mapY += stepY;
side = 1;
}
// Check if ray has hit a wall
if (map.get(mapX, mapY) == 1) hit = 1;
range -= 1;
}
// Calculate distance projected on camera direction. This is the shortest distance from the point where the wall is
// hit to the camera plane. Euclidean to center camera plane would give fisheye effect!
// This can be computed as (mapX - posX + (1 - stepX) / 2) / rayDirX for side == 0, or same formula with Y
// for size == 1, but can be simplified to the code below thanks to how sideDist and deltaDist are computed:
// because they were left scaled to |rayDir|.  sideDist is the entire length of the ray above after the multiple
// steps, but we subtract deltaDist once because one step more into the wall was taken above.
if (side == 0) perpWallDist = sideDistX - deltaDistX;
else perpWallDist = sideDistY - deltaDistY;

// SET THE ZBUFFER FOR THE SPRITE CASTING
ZBuffer[column] = perpWallDist; //perpendicular distance is used

// Calculate height of line to draw on screen
let lineHeight: number = this.height / perpWallDist;

// calculate lowest and highest pixel to fill in current stripe
let drawStartY = -lineHeight / 2 + this.height / 2;
let drawEndY = lineHeight / 2 + this.height / 2;

let texture = map.wallTexture;

// calculate value of wallX
let wallX: number; // where exactly the wall was hit
if (side == 0) wallX = player.position.y + perpWallDist * rayDirY;
else wallX = player.position.x + perpWallDist * rayDirX;
wallX -= Math.floor(wallX);

// x coordinate on the texture
let texX = Math.floor(wallX * texture.width);
if (side == 0 && rayDirX > 0) texX = texture.width - texX - 1;
if (side == 1 && rayDirY < 0) texX = texture.width - texX - 1;

this.ctx.globalAlpha = 1;
if (hit) {
let left = Math.floor(column * this.spacing);
let wallHeight = drawEndY - drawStartY;

this.ctx.drawImage(
texture.image,
texX, // sx
0, // sy
1, // sw
texture.height, // sh
left, // dx
drawStartY, // dy - yes we go into minus here, it'll be ignored anyway
width, // dw
wallHeight // dh
);

// this is the shading of the texture - a sort of black overlay
this.ctx.fillStyle = `#000000`;
let alpha =
(perpWallDist +
// step.shading
0) /
this.lightRange -
map.light;
alpha = Math.min(alpha, 0.8);
if (side == 1) {
// give x and y sides different brightness
alpha = alpha * 2;
}
alpha = Math.min(alpha, 0.85);
// ensure walls are always at least a little bit visible - alpha 1 is all black
this.ctx.globalAlpha = alpha;
this.ctx.fillRect(left, drawStartY, width, wallHeight);
this.ctx.globalAlpha = 1;
}
}
Если кто -то хочет сыграть с полной версией, это на https://github.com/xtrinch/raycaster/tree/rewrite, может изменить длину плоского вектора в функции Fundspawnpoint < /code>

Подробнее здесь: https://stackoverflow.com/questions/794 ... fov-angles
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Рендеринг с использованием raycasting - текстура стены искажается при ограничении определенного размера [дубликат]
    Anonymous » » в форуме Python
    0 Ответы
    52 Просмотры
    Последнее сообщение Anonymous
  • Я пытаюсь внедрить теневой каскад в свой проект, но все, что я получаю, это странная карта тени с бесконечным FOV
    Anonymous » » в форуме C++
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous
  • Java Files.isWritable искажается при запуске от root
    Anonymous » » в форуме Linux
    0 Ответы
    14 Просмотры
    Последнее сообщение Anonymous
  • Загрузка PDF искажается запросами Python
    Anonymous » » в форуме Python
    0 Ответы
    36 Просмотры
    Последнее сообщение Anonymous
  • Номер порта «искажается» при импорте CSV в Excel 2010
    Anonymous » » в форуме Python
    0 Ответы
    13 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Javascript»