Javascript 如何在HTML画布上渲染光线投射的墙纹理

Javascript 如何在HTML画布上渲染光线投射的墙纹理,javascript,canvas,frame-rate,raycasting,Javascript,Canvas,Frame Rate,Raycasting,我正在尝试建立一个光线投射引擎。我已经使用ctx.fillRect()成功地逐列渲染了场景,如下所示 我为上面的渲染编写的代码: 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 wh

我正在尝试建立一个光线投射引擎。我已经使用
ctx.fillRect()
成功地逐列渲染了场景,如下所示

我为上面的渲染编写的代码:

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();
}

但是
ctx.drawImage()
方法将图像绘制为一个矩形,没有类似的3D效果

我不知道怎么做

我应该使用
ctx.tranform()
?如果是,如何进行?如果没有,我该怎么办

我正在寻找使用2D光线投射产生伪3d效果的数学方法。

一些虚拟3d游戏是

我正试着建造一些类似的东西


谢谢:)贴图(或不贴图,视情况而定)纹理坐标的方式没有按预期工作

我正在寻找用于使用2D光线投射产生伪3d效果的数学

这本书有一个很好的章节,详细介绍了Doom如何执行纹理贴图。从条目:

厄运引擎将世界限制在垂直的墙壁和水平的地板/天花板上,相机只能绕垂直轴旋转。这意味着墙壁将沿垂直线保持恒定深度坐标,地板/天花板将沿水平线保持恒定深度。快速仿射映射可以沿着这些直线使用,因为它是正确的

“快速仿射贴图”只是纹理坐标的简单2D插值,对于您正在尝试的操作来说是合适的。厄运引擎的一个限制也是

Doom使用仿射纹理贴图渲染垂直和水平跨距,因此无法绘制斜楼板或斜墙

您的逻辑似乎不包含任何用于在各种坐标空间之间转换坐标的代码。您至少需要在给定的光线跟踪坐标和纹理坐标空间之间应用变换。这通常涉及矩阵数学,非常常见,也可以称为,如从一个空间/曲面投影点到另一个空间/曲面。使用仿射变换,可以避免使用矩阵而采用线性插值

适用于您的变量的坐标方程(见上文)可能如下所示:

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

where 0 <= *a* <= 1
在您的例子中,
A_x
是墙在世界空间中的位置
B_z
是焦距,焦距将为
1
A_z
是使用光线跟踪计算的距离。结果是表示到viewspace的平移的x或y坐标

这些文档介绍了用于光线跟踪和变换坐标以渲染游戏的技术。即使您不熟悉C/ASM,代码也非常可读,这是了解更多感兴趣主题的好方法。为了阅读更多的内容,我建议在您选择的引擎中搜索“纹理贴图的坐标矩阵变换”之类的内容,或者搜索类似的内容。 该文件的一个特定区域是从ln 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
> =
关于“数学”的一本好书是——我强烈推荐给任何想要创造或提高这些技能的人

更新: 从本质上讲,您将把图像中的像素(点)映射到矩形墙砖上的点上,正如光线跟踪报告的那样

伪(ish)-代码:

var image=getImage(someImage);//得到你想要的图像。确保在绘图之前完成加载
var iWidth=image.width,iHeight=image.height;
变量sX=0,sY=0;//图像的左上角。使用雪碧片等时进行调整

对于(var i=0;ii)已使用ctx.fillRect()成功地逐列渲染场景,如下所示显示此代码(全部)“但
ctx.drawImage()
将图像绘制为矩形,没有像Wolfenstein 3D那样的3D效果”,是的,与
ctx.fillRect()相同
@Shubhamrind请包括问题中的所有代码,不要只向github添加链接。我们需要一个如所述的链接,希望这会有所帮助,我不知道如何渲染墙纹理您检查了wolfenstein 3d的渲染效果了吗?高斯分布只是2d顶级摄影机场景的一部分,仅用于控制“3d”生成图像正确部分的相机。啊,这很公平。尽管如此,我认为应用空间变换的需求仍然非常现实。我根据OP示例添加了一些代码,演示了如何使用
drawImage
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.
> ========================
> =
> = 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); 
}