Как визуализировать лучистые текстуры стен на HTML-холсте - PullRequest
1 голос
/ 02 июля 2019

Я пытаюсь построить движок лучевого вещания.я успешно отрисовал колонку сцены, используя ctx.fillRect() следующим образом.

canvas-raycasting.png

демо код

код, который я написал для вышеупомянутого рендера:

var scene = [];// this contains distance of wall from player for an perticular ray 
var points = [];// this contains point at which ray hits the wall 

/*
i have a Raycaster class which does all math required for ray casting and returns 
an object which contains two arrays 
1 > scene : array of numbers representing distance of wall from player.
2 > points : contains objects of type { x , y } representing point where ray hits the wall.
*/

var data = raycaster.cast(wall);
/* 
raycaster : instance of Raycaster class , 
walls : array of boundries constains object of type { x1 , y1 , x2 , y2 } where 
(x1,y1) represent start point ,
(x2,y2) represent end point.
*/
scene = data.scene; 

var scene_width = 800;
var scene_height = 400; 
var w = scene_width / scene.length;
for(var i=0;i<scene.length;++i){
    var c = scene[i] == Infinity ? 500 : scene[i] ;

    var s = map(c,0,500,255,0);// how dark/bright the wall should be 
    var h = map(c,0,500,scene_height,10); // relative height of wall (farther the smaller)

    ctx.beginPath();
    ctx.fillStyle = 'rgb('+s+','+s+','+s+')';
    ctx.fillRect(i*w,200-h*0.5,w+1,h);
    ctx.closePath();
}

Теперь я пытаюсь создать веб-интерфейс FPS (шутер от первого лица) и привязан к рендерингу текстур на холсте,

ctx.drawImage() Метод принимает аргументы следующим образом:

void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

ctx.drawImage_arguments

, но метод ctx.drawImage() рисует изображение в виде прямоугольника без3D-эффект, такой как Wolfenstein 3D

Я понятия не имею, как это сделать.

я должен использовать ctx.tranform()?если да, то как?если нет, что мне делать?

Я ищу математики, используемые для создания псевдо-3D-эффекта с использованием 2D-лучевой передачи.

некоторые псевдо3д игры Wolfenstein 3D Doom

Я пытаюсь построить что-то вроде this

СПАСИБО:)

1 Ответ

0 голосов
/ 02 июля 2019

То, как вы отображаете (или нет, в зависимости от обстоятельств) координаты текстуры, работает не так, как задумано.

Я ищу математику, используемую для создания псевдо-3D-эффекта с использованием 2D-лучевого вещания

Запись в Википедии для наложения текстур содержит хороший раздел с описанием того, как Doom выполняет наложение текстур. Из записи:

Движок Doom ограничил мир вертикальными стенами и горизонтальными полами / потолками с камерой, которая могла вращаться только вокруг вертикальной оси. Это означало, что стены будут иметь постоянную глубину по вертикальной линии, а полы / потолки будут иметь постоянную глубину по горизонтальной линии. Быстрое аффинное отображение может быть использовано по этим направлениям, потому что это будет правильно.

«Быстрое аффинное отображение» - это просто простая 2D-интерполяция координат текстуры, и она будет подходящей операцией для того, что вы пытаетесь. Ограничением Doom было также то, что

Doom визуализирует вертикальные и горизонтальные пролеты с аффинным наложением текстур и поэтому не может рисовать наклонные полы или наклонные стены.

Не похоже, что ваша логика содержит какой-либо код для преобразования координат между различными координатными пространствами. Вам нужно будет применить преобразования между заданными координатами трассировки лучей и координатными пространствами текстуры как минимум. Это обычно включает в себя матричную математику и является очень распространенным и может также упоминаться как Проекция , как при проецировании точек из одного пространства / поверхности в другое. С помощью аффинных преобразований вы можете избежать использования матриц в пользу линейной интерполяции.

Уравнение координат для этого, адаптированного к вашим переменным (см. Выше), может выглядеть следующим образом:

u = (1 - a) * wallStart + a * wallEnd

where 0 <= *a* <= 1

В качестве альтернативы, вы можете использовать Weak Perspective projection , так как большая часть данных уже рассчитана. Снова из википедии:

To determine which screen x-coordinate corresponds to a point at

A_x_,A_z_
multiply the point coordinates by:

B_x = A_x * B_z / A_z
where

B_x
is the screen x coordinate
A_x
is the model x coordinate
B_z
is the focal length—the axial distance from the camera center *to the image plane*
A_z
is the subject distance.
Because the camera is in 3D, the same works for the screen y-coordinate, substituting y for x in the above diagram and equation.

В вашем случае A_x - это местоположение стены в мировом пространстве. B_z - это фокусное расстояние, которое будет 1. A_z - это расстояние, которое вы рассчитали, используя трассировку лучей. Результатом является координата x или y, представляющая перевод в область просмотра.

Процедура основного рисования для W3D документирует методы, используемые для трассировки лучей и преобразования координат при рендеринге игры. Код вполне читабелен, даже если вы не знакомы с C / ASM, и это отличный способ узнать больше о ваших интересных темах. Для дальнейшего чтения я бы предложил выполнить поиск в выбранном вами движке для таких вещей, как «матричное преобразование координат для наложения текстур», или поищите на сайте GameDev SE аналогичные. Конкретная область этого файла, на которую нужно установить ноль, - это раздел, начинающийся с 267:

> ========================
> =
> = TransformTile
> =
> = Takes paramaters:
> =   tx,ty     : tile the object is centered in
> =
> = globals:
> =   viewx,viewy       : point of view
> =   viewcos,viewsin   : sin/cos of viewangle
> =   scale     : conversion from global value to screen value
> =
> = sets:
> =   screenx,transx,transy,screenheight: projected edge location and size
> =
> = Returns true if the tile is withing getting distance
> =

Великолепная книга по "математике" - это эта - я очень рекомендую ее всем, кто хочет создать или улучшить эти навыки.

Обновление: По сути, вы будете отображать пиксели (точки) изображения на точки на вашей прямоугольной настенной плитке, как показано трассировкой лучей.

Псевдо (МОГ) -кода:

var image = getImage(someImage); // get the image however you want. make sure it finishes loading before drawing
var iWidth = image.width, iHeight = image.height;
var sX = 0, sY = 0; // top-left corner of image. Adjust when using e.g., sprite sheets

for(var i=0;i<scene.length;++i){
    var c = scene[i] == Infinity ? 500 : scene[i];

    var s = map(c,0,500,255,0);// how dark/bright the wall should be 
    var h = map(c,0,500,scene_height,10); // relative height of wall (farther the smaller)
    var wX = i*w, wY = 200 - h * 0.5;
    var wWidth = w + 1, wHeight = h;
//... render the rectangle shape
    /* we are using the same image, but we are scaling it to the size of the rectangle
     and placing it at the same location as the wall. 

    */
    var u, v, uW, vH; // texture x- and y- values and sizes. compute these.

    ctx.drawImage(image, sX, sY, iWidth, iHeight, u, v, uW, vH); 
}

Поскольку я не знаком с вашим кодом, выполняющим трассировку лучей, его систему координат и т. Д., Вам может потребоваться дополнительная настройка значений для wX, wY, wWidth и wHeight (например, , переведите точки из центра в верхний левый угол).

...