Raycaster,寻找更有效的地板/天花板光线投射

2024-01-31

大多数对光线投射感兴趣的人可能都知道 Lodev 和 Permadi 教程:https://lodev.org/cgtutor/raycasting2.html https://lodev.org/cgtutor/raycasting2.html

https://permadi.com/1996/05/ray-casting-tutorial-11/ https://permadi.com/1996/05/ray-casting-tutorial-11/

起初,我实现了所谓的“垂直地板/天花板”光线投射,它继续逐列绘制墙壁例程,它只是在墙壁完成后才开始绘制地板,这是优化的思维,但算法本身非常非常慢。

所以我尝试了 Lodev 的“水平地板/天花板”光线投射,效果非常明显,而且速度加快了。 一切都会好起来的,但是这个算法,尽管速度很快,却在填充上浪费了性能 整个屏幕包括地板和天花板,然后绘制墙壁。

我想优化该功能,因此地板和天花板将在绘制墙壁后绘制,并且仅填充空白空间。

也许解决方案是在墙壁铸造期间记住空白,然后创建包含 x、y 坐标的数组,因此在地板和天花板铸造期间我们已经知道在哪里绘制..您觉得怎么样。您是否知道更好的方法,也许是一些提示、学习资源、算法?提前致谢...

附:我用鼠标环顾四周,所以地平线在变化。

我正在 Windows 上进行开发,但我正在将我的代码移植到更快的 Amigas,使用 m68k 060/080 cpu,RTG 为 320x240x32 或 640x480x32.. 到目前为止,我得到了很好的结果.. 所以尝试尽我所能地优化 az。

下面是我的一些测试和进展...

PC AMIGA(赢得阿联酋)

https://www.youtube.com/watch?v=hcFBPfDYZig https://www.youtube.com/watch?v=hcFBPfDYZig

AMIGA,V600 080/78 Mhz - 320x240x32 无纹理(质量抱歉)

https://www.youtube.com/watch?v=6dv46hT1A_Y https://www.youtube.com/watch?v=6dv46hT1A_Y


由于问题与任何语言无关,我从Javascript的角度来回答。 我还实施了所谓的“垂直地板/天花板”技术。 但不是每个像素绘制像素ctx.drawImage() I use putImageData.

首先,我从要使用临时画布渲染的图块中获取数据:

var tempCanvas = document.createElement('canvas');
var tempCtx = tempCanvas.getContext('2d');

tempCanvas.width = 64;
tempCanvas.height = 64;

var wallsSprite = new Image();

wallsSprite.onload = function () {
  tempCtx.drawImage(wallsSprite, 0, 128, 64, 64, 0, 0, 64, 64);
  floorData = tempCtx.getImageData(0, 0, 64, 64);

  tempCtx.drawImage(wallsSprite, 0, 192, 64, 64, 0, 0, 64, 64);
  ceilData = tempCtx.getImageData(0, 0, 64, 64);
}

wallsSprite.src = "./walls_2.png";

我创建一个空的 imageData:

var floorSprite = this.ctx.createImageData(600, 400);

然后我进行“垂直地板/天花板”光线投射:

 //we check if the wall reaches the bottom of the canvas
 // this.wallToBorder = (400 - wallHeight) / 2;
        
 if (this.wallToBorder > 0) {
    
 // we calculate how many pixels we have from bottom of wall to border of canvas
 var pixelsToBottom = Math.floor(this.wallToBorder);
    
 //we calculate the distance between the first pixel at the bottom of the wall and the player eyes (canvas.height / 2) 
 var pixelRowHeight = 200 - pixelsToBottom;
         
 // then we loop through every pixels until we reach the border of the canvas  
    
 for (let i = pixelRowHeight; i < 200; i += 1) {
    
   // we calculate the straight distance between the player and the pixel
      var directDistFloor = (this.screenDist * 200) / (Math.floor(i));
    
   // we calculate it's real world distance with the angle relative to the player
      var realDistance = (directDistFloor / Math.cos(this.angleR));
    
   // we calculate it's real world coordinates with the player angle
      this.floorPointx = this.player.x + Math.cos(this.angle) * realDistance / (this.screenDist / 100);
    this.floorPointy = this.player.y + Math.sin(this.angle) * realDistance / (this.screenDist / 100);
    
    // we map the texture
            var textY = Math.floor(this.floorPointx % 64);
            var textX = Math.floor(this.floorPointy % 64);

    // we modify floorSprite array:
            if (floorData && ceilData) {
    
              floorSprite.data[(this.index * 4) + (i + 200) * 4 * 600] = floorData.data[textY * 4 * 64 + textX * 4]
              floorSprite.data[(this.index * 4) + (i + 200) * 4 * 600 + 1] = floorData.data[textY * 4 * 64 + textX * 4 + 1]
              floorSprite.data[(this.index * 4) + (i + 200) * 4 * 600 + 2] = floorData.data[textY * 4 * 64 + textX * 4 + 2]
              floorSprite.data[(this.index * 4) + (i + 200) * 4 * 600 + 3] = 255;
    
              floorSprite.data[(this.index * 4) + (200 - i) * 4 * 600] = ceilData.data[textY * 4 * 64 + textX * 4]
              floorSprite.data[(this.index * 4) + (200 - i) * 4 * 600 + 1] = ceilData.data[textY * 4 * 64 + textX * 4 + 1]
              floorSprite.data[(this.index * 4) + (200 - i) * 4 * 600 + 2] = ceilData.data[textY * 4 * 64 + textX * 4 + 2]
              floorSprite.data[(this.index * 4) + (200 - i) * 4 * 600 + 3] = 255;
            }
          }
        }
      }
    }

最后我们在渲染墙壁之前绘制地板和天花板:

this.ctx.putImageData(floorSprite, 0, 0);

结果非常快,因为:

  • 我们不需要计算天花板纹理坐标,因为我们从地板坐标中推导出它们。
  • 我们每个循环只绘制一次天花板/地板,而不是每个像素绘制一次。
  • 仅重绘可见的像素,因此不会wastes performance on filling up the whole screen with floor and ceiling, and after that it draws walls.

也许可以通过混合来优化horizontal raysting and putImageData将游戏速度与墙壁/天花板渲染或不进行几乎相同。

这是结果 https://i.ibb.co/Sw4jPHK/ezgif-com-gif-maker.gif

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Raycaster,寻找更有效的地板/天花板光线投射 的相关文章

  • Graphics2D:在白色上绘制黑色?

    我确信这是一个非常愚蠢的问题 但我找不到答案 我对 Java2D API 没有经验 我正在尝试创建一个图像并将其写入 GIF 或 PNG 并且我希望它在白色背景上使用黑色笔 如果我不设置任何颜色 我会得到黑底白字 如果我使用 setPain
  • 2D 弹跳公式无法正常工作

    我是 Unity 的新手 我正在尝试创建一个弹跳球 所以我做了很多关于弹跳相关物理的研究 我找到了一个公式 Formula 2 V dot N N V 其中 V 是速度矢量 N 是球弹跳表面的法线 这是我的脚本 using UnityEng
  • 如何在plotly 3D曲面图中标记区域?

    我使用plotly从xyz数据创建3D高程剖面图 它与以下代码配合得很好 import plotly graph objects as go import pandas as pd import numpy as np Read data
  • Direct3D 中的矩阵多阶

    关于在 Direct3D 中乘法矩阵以获得结果 我收到了两个相互矛盾的答案 教程确实规定从左到右相乘 这很好 但这不是我想象的方式 这是一个例子 OpenGL 从上到下阅读 GLRotatef 90 0f GLTranslatef 20 0
  • 仅使用本机库的 C# 简单游戏

    我可以找到一组java 2D 游戏教程 http zetcode com tutorials javagamestutorial and 安卓游戏教程 http obviam net index php table of contents
  • OpenGL Z 偏置(多边形偏移)限制

    我有两个共面的多边形 我尝试做 glEnable GL POLYGON OFFSET FILL glPolygonOffset 0 1 并期望其中一个明显 位于 另一个之上 这种情况直到大约 70 75 个单位之外 近剪裁平面为 1 远剪裁
  • 在 Three.js 中将贝塞尔曲线转换为平面道路

    我试图根据之前计算得到的一些贝塞尔曲线在 Three js 中绘制一条弯曲的道路 问题是我找不到转换曲线序列的方法 一条从上一条曲线的末尾开始 到一个曲面 我有一个 3D 场景 其中有一些汽车 一条用飞机创建的道路 并且绘制了即将到来的道路
  • 在 JPanel 与 JComponent 中绘图

    我需要一些帮助来理解为什么 JComponent 与 JPanel 中的绘图工作方式不同 import java awt Color import java awt Graphics import java awt Graphics2D i
  • 用均匀的彩色表面替换颜色点

    这是我的数据和当前的绘图 require ggplot2 a rep c 2 5 10 15 20 30 40 50 75 100 each 7 b rep c 0 001 0 005 0 01 0 05 0 5 5 50 10 c c T
  • 一次性渲染阴影

    考虑到阴影投射的成本 我想知道对于动态定位的静态对象 例如 程序城市 是否有一个功能或可能 实验性的方法可以在 Three js 中仅渲染一次阴影贴图 甚至在 webgl 中 因此 结果可以在静态对象的下一帧中免费使用 仅当物体移动时才会进
  • 如何在pdf中导出一对一的JTable[重复]

    这个问题在这里已经有答案了 可能的重复 为什么 JTable 标题没有出现在图像中 https stackoverflow com questions 7369814 why does the jtable header not appea
  • Three.js 光线投射器可以与组相交吗?

    我想知道我的光线投射器是否正在查看我已加载的 OBJ 由于从 Cinema4D 导出的方式 我相信 OBJ 是一个具有 3 个子级的 THREE Group 而不是 THREE Object 我可以更改我的 raycaster 代码行来查找
  • 判断一个点是否在多面体内部

    我试图确定某个特定点是否位于多面体内部 在我当前的实现中 我正在研究的方法采用我们正在寻找多面体面的数组 在本例中为三角形 但稍后可能是其他多边形 的点 我一直在尝试根据这里找到的信息进行工作 http softsurfer com Arc
  • Unity3D:在 AA 解析后绘制粒子以提高性能

    我正在尝试评估 MSAA 对 Unity 中含有大量粒子的场景的影响 为此 我需要 使用 8x MSAA 绘制场景中的所有非粒子对象 使用上一个通道中解析的深度缓冲区来渲染所有 将非遮挡粒子系统转移到较小的渲染目标上 将 2 的颜色缓冲区与
  • C++ Irrlicht 程序未链接:“未定义对‘__imp_createDevice’的引用”

    我的 Irrlicht 程序无法链接 我使用的编译器是g Code include
  • 将大块位图转换为 3 维位图

    Problem 我需要这个大量的数据作为输入 对于基于C的arduino 这是上面示例中所需格式的大量数据 const byte bitmap 8 8 0xFF 0x81 0x81 0x81 0x81 0x81 0x81 0xFF 0x81
  • 简单的线框格式?

    我正在寻找一种用于线框模型的简单文件格式 我知道 VRML u3D 等 但这些对于我的需求来说似乎很重要 我的标准是 必须有明确的规格 要么是开放的 要么是非常完善 记录的 我只需要 想要 简单的模型 顶点和边 我不想处理面孔或物体 如果格
  • 合并空间上接近的路径/线段的算法

    我正在寻找一种用于街道地图制图概括的几何算法 名称 在我的地图数据中 我有许多路径 点的有序列表 由线段连接 这些路径彼此靠近且几乎平行 我如何 1 识别这些 相邻路径 即如何找到比某个阈值更接近的路径 以及 2 将它们合并成一条路径 即如
  • Paper.js 中的事件处理程序

    我是 Paper js 的新手 在阅读教程时我对事件系统感到好奇 这就是事件处理中描述的方式tutorial http paperjs org tutorials interaction mouse tool events var path
  • 更改 3D 图形颜色 (matplotlib)

    我使用以下代码在 matplotlib 中绘制了 3D 图形 Previously defines lists of data to plot fig plt figure ax fig add subplot 111 projection

随机推荐