- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试构建一个光线转换引擎。我已经成功地使用 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();
}
现在我正在尝试构建一个基于网络的 FPS(第一人称射击游戏)并坚持在 Canvas 上渲染墙壁纹理。
ctx.drawImage()
方法参数如下
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
但是 ctx.drawImage()
方法将图像绘制为一个没有 3D 效果的矩形,如 Wolfenstein 3D
我不知道该怎么做。
我应该使用 ctx.tranform()
吗?如果是,如何?如果不是,我该怎么办?
我正在寻找用于使用 2D 光线转换产生伪 3d 效果的数学。
一些伪3d游戏是Wolfenstein 3D Doom
我正在尝试构建类似 this 的东西
谢谢你:)
最佳答案
您映射(或不映射,视情况而定)纹理坐标的方式未按预期工作。
I am looking for the Maths used to produce pseudo 3d effect using 2D raycasting
Wikipedia Entry for Texture Mapping有一个很好的部分介绍了 Doom 如何执行纹理映射的特定数学。来自条目:
The Doom engine restricted the world to vertical walls and horizontal floors/ceilings, with a camera that could only rotate about the vertical axis. This meant the walls would be a constant depth coordinate along a vertical line and the floors/ceilings would have a constant depth along a horizontal line. A fast affine mapping could be used along those lines because it would be correct.
“快速仿射映射”只是纹理坐标的简单 2D 插值,对于您正在尝试的操作来说是一个合适的操作。 Doom 引擎的局限性还在于
Doom renders vertical and horizontal spans with affine texture mapping, and is therefore unable to draw ramped floors or slanted walls.
您的逻辑似乎不包含任何用于在各种坐标空间之间转换坐标的代码。您至少需要在给定的光线追踪坐标和纹理坐标空间之间应用变换。这通常涉及矩阵数学并且非常常见,也可以称为 Projection ,就像将点从一个空间/表面投影到另一个空间/表面一样。借助仿射变换,您可以避免使用矩阵,转而使用线性插值。
适用于您的变量的坐标方程(见上文)可能如下所示:
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 坐标。
main draw routine for W3D记录用于渲染游戏的光线跟踪和变换坐标的技术。即使您不熟悉 C/ASM,该代码也非常可读,并且是了解更多您感兴趣的主题的好方法。如需更多阅读,我建议在您选择的引擎中搜索“用于纹理映射的坐标矩阵变换”之类的内容,或搜索 GameDev SE site对于类似的。该文件的一个特定区域是从 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
> =
一本关于“数学”的好书是 this one - 我强烈推荐给任何想创造或改进这些技能的人。
更新:本质上,您会将图像中的像素(点)映射到矩形墙砖上的点,如光线追踪所报告的那样。
伪(ish)代码:
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
(例如,将点从中心平移到左上角)。
关于javascript - 如何在 HTML-Canvas 上渲染光线转换的墙壁纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56848054/
我目前在使用边界框使 sprite 显示为实体时遇到问题。碰撞与下面的代码一起工作得很好。 位置是主要角色在 map 上的位置。character2 是主角将与之发生碰撞的 18 x 28 Sprit
这个问题在这里已经有了答案: JavaScript: Collision detection (10 个回答) 10 个月前关闭。 检测 2 个物体(墙壁)碰撞的好方法。是的,不仅仅是检测,还有进一步
我正在制作一个 roguelike 游戏,但在编码方面我是初学者。我已经让我的角色移动了,我的墙壁和地板 Sprite ,但我的代码中有一些错误,允许角色穿过墙壁。 我用了 block_path在地板
我使用的代码只是取自一个示例,它确实为我的场景建了一堵墙: /** This loop builds a wall out of individual bricks. */ public vo
我已经尝试解决平滑播放器-墙壁-碰撞的问题,使播放器沿着墙壁滑动。 我试过以下: playerBox->move(); if (playerBox->intersects(wall)) { c
我是一名优秀的程序员,十分优秀!