Math 根据墙的旋转角度感知贴花的宽度
我正在使用JavaScript画布从头开始创建一个光线投射游戏 挑战的一部分(对我来说)是用随机图像(图片)装饰墙壁。我已经实现了墙壁、地板、天花板和精灵的绘制。 在绘制墙时,我为每个Math 根据墙的旋转角度感知贴花的宽度,math,graphics,geometry,raycasting,perspective,Math,Graphics,Geometry,Raycasting,Perspective,我正在使用JavaScript画布从头开始创建一个光线投射游戏 挑战的一部分(对我来说)是用随机图像(图片)装饰墙壁。我已经实现了墙壁、地板、天花板和精灵的绘制。 在绘制墙时,我为每个x(描绘屏幕坐标)存储到墙的距离(Z-BUFFER)、墙的高度(H-BUFFER)以及底层二维网格中像素的实际坐标(grid\u BUFFER) 我在墙上绘制贴花(图片)的方法如下(在确定理论上可以看到的贴花列表后): 计算贴标位置的距离(位置定义为位于观察者的网格顶点中间) 屏幕坐标屏幕X是根据从栅格坐标到屏幕
x
(描绘屏幕坐标)存储到墙的距离(Z-BUFFER
)、墙的高度(H-BUFFER
)以及底层二维网格中像素的实际坐标(grid\u BUFFER
)
我在墙上绘制贴花(图片)的方法如下(在确定理论上可以看到的贴花列表后):
- 计算贴标位置的距离(位置定义为位于观察者的网格顶点中间)
- 屏幕坐标
是根据从栅格坐标到屏幕坐标的转换矩阵计算的。这是正确的:屏幕X
让贴花屏幕x=数学地板((RAYCAST.SCREEN_WIDTH/2)*(1+CAMERA.transformX/CAMERA.transformDepth))代码>
- 然后我检索相关贴花的图像数据,并获取其宽度和高度
- 根据距离和观察角度,我计算出贴花的感知宽度。这就是真正的问题所在,因为我发现我计算的宽度并不完全准确
- 有了所有这些信息,就可以很容易地计算左右屏幕坐标-绘制贴花的起始位置和结束位置,使用
H-BUFFER
计算高度因子,使用GRID\u BUFFER
仅在属于此贴花的网格上绘制
我看到了宽度计算,即如果播放器方向与贴花面向空间的方向不相反,贴花将从播放器方向向量旋转一个角度(示例):
或者,如果播放器方向与贴花方向正好相反,则此角度为0°(示例):
我的第一种方法是使用反向播放器方向和贴花朝向方向的点积,从而获得向量之间的角度余弦,并将其用作减少感知宽度的一个因素:
let CosA = PLAYER.dir.mirror().dot(decal.facingDir);
let widthScale = CosA * (CAMERA.transformDepth / decal.distance);
此解决方案的问题是,当垂直时,因子为0且不绘制贴花,但当使用透视绘制墙时,情况不应如此。于是我开始即兴创作。我定义了CAMERA.minPerspective
因子,如下所示。视野(FOV)为70°
我的直觉是(因为我缺乏透视和几何学知识,唉),对于小角度,因子应该保持为1。对于接近90°的角度,应该有一些最小的因素,以便贴花保持可见。所以我带来了这个“改进”代码:
这种方法的效果要好得多,但也有一些缺陷。从视觉上看,对于角度0-50°,折减系数太大。这可以观察到,如果我使用这样的宽度贴花,他们应该涵盖整个网格表面。(见下图;楼梯左侧下方的墙可见,贴花应覆盖整个网格,但不覆盖,因为系数太小)
我已经搜索了Stack Overflow和Web的其他部分,寻找更好的解决方案,因为我的几何知识似乎也阻止我识别出正确的解决方案,如果它们不在这个上下文中
所以,请。在计算感知宽度时,可能存在确定性解决方案,无需再次使用光线投射相位,也无需使用我能够存储在光线投射相位中的信息。虽然在代码示例中使用JavaScript,但我认为这个问题不是针对任何编程语言的。< P>我找到了一种解决方案,它保留(甚至改善)问题中的方法的简单性和时间复杂度。
- 我在贴花定义中添加了两点-
leftDrawStart
和
rightStartDraw
。这些在贴花点很容易计算
实例化,基于真实精灵(贴花)宽度和定义
网格(块)大小的。在进行这个计算时,我从摄像机透视图(不是网格坐标)考虑 LeftRoxStuts。< /LI>
- 渲染贴花时,我使用变换矩阵(如下面的代码示例所述)计算
leftDrawStart
和rightStartDraw
的屏幕坐标,这些坐标来自它们的网格坐标:
- 我区分计算出的绝对值
drawStartX
和draundx
,以及它们的调整,以便它们符合屏幕边界,或者如果完全脱离屏幕,则从功能返回
- 最后,甚至不需要贴花的感知宽度,因为纹理位置可以通过使用当前绘制<代码>条纹代码>-绝对绘制开始和绝对绘制结束-绝对绘制开始之间的差值比率来计算:
与在光线投射步骤中加入贴花投射的方法相比,该方法完全准确且速度更快。hmm这听起来像是光线投射与3D渲染引擎的结合。。。这很奇怪,但速度很快。然而,这恰恰导致了这样的问题。我会以不同的方式来做,并以与墙相同的方式渲染“贴花”图像。。。但是,为此,您需要将其存储为与墙纹理相同的分辨率/大小,并将其用作精灵(不渲染边界空间),以便混合或其他测试。。。
CAMERA.minPerspective = Math.cos(Math.radians((90 + this.FOV) / 2));
let CosA = PLAYER.dir.mirror().dot(decal.facingDir);
let FACTOR = Math.min(1, CosA + CAMERA.minPerspective);
FACTOR = Math.max(FACTOR, CAMERA.minPerspective);
let widthScale = FACTOR * (CAMERA.transformDepth / decal.distance);
transform(spritePos) {
let invDet = 1.0 / (CAMERA.dir.x * PLAYER.dir.y - PLAYER.dir.x * CAMERA.dir.y);
CAMERA.transformX = invDet * (PLAYER.dir.y * spritePos.x - PLAYER.dir.x * spritePos.y);
CAMERA.transformDepth = invDet * (-CAMERA.dir.y * spritePos.x + CAMERA.dir.x * spritePos.y);
}
let texX = (((stripe - drawStartX_abs) / (drawEndX_abs - drawStartX_abs)) * imageData.width) | 0;