[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-6394":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":15,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":18,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":23,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":33,"readmeContent":34,"aiSummary":35,"trendingCount":16,"starSnapshotCount":16,"syncStatus":36,"lastSyncTime":37,"discoverSource":38},6394,"VoxelSpace","s-macke\u002FVoxelSpace","s-macke","Terrain rendering algorithm in less than 20 lines of code","https:\u002F\u002Fs-macke.github.io\u002FVoxelSpace\u002FVoxelSpace.html",null,"C",6753,293,107,5,0,35,3,69.41,"MIT License",false,"master",true,[25,26,27,28,29,30,31,32],"3d-engine","comanche","game-comanche","rendering-algorithms","rendering-engine","voxel","voxel-engine","voxel-space-engine","2026-06-12 04:00:28","# Voxel Space\n\n![web demonstration](images\u002Fwebdemo.gif)\n\n# **[Web Demo of the Voxel Space Engine][project demo]**\n\n## History\n\nLet us go back to the year 1992. The CPUs were 1000 times slower than today and the acceleration via a GPU was unknown or unaffordable. 3D games were calculated exclusively on the CPU and the rendering engine rendered filled polygons with a single color.\n\n![Game Gunship 2000 in 1991](images\u002Fgunship2000-1991.gif)\n*Game Gunship 2000 published by MicroProse in 1991*\n\nIt was during that year [NovaLogic](http:\u002F\u002Fwww.novalogic.com\u002F) published the game [Comanche](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FComanche_(video_game_series)).\n\n![Game Comanche in 1992](images\u002Fcomanche-1992.gif)\n*Game Comanche published by NovaLogic in 1992*\n\nThe graphics were breathtaking for the time being and in my opinion 3 years ahead of its time. You see many more details such as textures on mountains and valleys, and for the first time a neat shading and even shadows. Sure, it's pixelated, but all games in those years were pixelated.\n\n## Render algorithm\n\n[Comanche](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FComanche_(video_game_series)) uses a technique called [Voxel Space](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FVoxel_Space), which is based on the same ideas like [ray casting](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FRay_casting). Hence the Voxel Space engine is a 2.5D engine, it doesn't have all the levels of freedom that a regular 3D engine offers.\n\n### Height map and color map\n\nThe easiest way to represent a terrain is through a height map and color map. For the game Comanche a 1024 \\* 1024 one byte height map and a 1024 \\* 1024 one byte color map is used which you can download on this site. These maps are periodic:\n\n![periodic map](images\u002Fperiodicmap.gif)\n\nSuch maps limit the terrain to \"one height per position on the map\" - Complex geometries such as buildings or trees are not possible to represent. However, a great advantage of the colormap is, that it already contains the shading and shadows. The Voxel Space engine just takes the color and doesn't have to compute illumination during the render process.\n\n### Basic algorithm\nFor a 3D engine the rendering algorithm is amazingly simple. The Voxel Space engine rasters the height and color map and draws vertical lines. The following figure demonstrate this technique.\n\n![Line by line](images\u002Flinebyline.gif)\n\n * Clear Screen.\n * To guarantee occlusion start from the back and render to the front. This is called painter algorithm.\n * Determine the line on the map, which corresponds to the same optical distance from the observer. Consider the field of view and the [perspective projection](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002F3D_projection) (Objects are smaller farther away)\n * Raster the line so that it matches the number of columns of the screen.\n * Retrieve the height and color from the 2D maps corresponding of the segment of the line.\n * Perform the [perspective projection](https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002F3D_projection) for the height coordinate.\n * Draw a vertical line with the corresponding color with the height retrieved from the perspective projection.\n\nThe core algorithm contains in its simplest form only a few lines of code (python syntax):\n\n```python\ndef Render(p, height, horizon, scale_height, distance, screen_width, screen_height):\n    # Draw from back to the front (high z coordinate to low z coordinate)\n    for z in range(distance, 1, -1):\n        # Find line on map. This calculation corresponds to a field of view of 90°\n        pleft  = Point(-z + p.x, -z + p.y)\n        pright = Point( z + p.x, -z + p.y)\n        # segment the line\n        dx = (pright.x - pleft.x) \u002F screen_width\n        # Raster line and draw a vertical line for each segment\n        for i in range(0, screen_width):\n            height_on_screen = (height - heightmap[pleft.x, pleft.y]) \u002F z * scale_height. + horizon\n            DrawVerticalLine(i, height_on_screen, screen_height, colormap[pleft.x, pleft.y])\n            pleft.x += dx\n\n# Call the render function with the camera parameters:\n# position, height, horizon line position,\n# scaling factor for the height, the largest distance, \n# screen width and the screen height parameter\nRender( Point(0, 0), 50, 120, 120, 300, 800, 600 )\n```\n\n### Add rotation\n\nWith the algorithm above we can only view to the north. A different angle needs a few more lines of code to rotate the coordinates.\n\n![rotation](images\u002Frotate.gif)\n\n```python\ndef Render(p, phi, height, horizon, scale_height, distance, screen_width, screen_height):\n    # precalculate viewing angle parameters\n    var sinphi = math.sin(phi);\n    var cosphi = math.cos(phi);\n\n    # Draw from back to the front (high z coordinate to low z coordinate)\n    for z in range(distance, 1, -1):\n\n        # Find line on map. This calculation corresponds to a field of view of 90°\n        pleft = Point(\n            (-cosphi*z - sinphi*z) + p.x,\n            ( sinphi*z - cosphi*z) + p.y)\n        pright = Point(\n            ( cosphi*z - sinphi*z) + p.x,\n            (-sinphi*z - cosphi*z) + p.y)\n        \n        # segment the line\n        dx = (pright.x - pleft.x) \u002F screen_width\n        dy = (pright.y - pleft.y) \u002F screen_width\n\n        # Raster line and draw a vertical line for each segment\n        for i in range(0, screen_width):\n            height_on_screen = (height - heightmap[pleft.x, pleft.y]) \u002F z * scale_height. + horizon\n            DrawVerticalLine(i, height_on_screen, screen_height, colormap[pleft.x, pleft.y])\n            pleft.x += dx\n            pleft.y += dy\n\n# Call the render function with the camera parameters:\n# position, viewing angle, height, horizon line position, \n# scaling factor for the height, the largest distance, \n# screen width and the screen height parameter\nRender( Point(0, 0), 0, 50, 120, 120, 300, 800, 600 )\n```\n\n### More performance\n\nThere are of course a lot of tricks to achieve higher performance.\n\n* Instead of drawing from back to the front we can draw from front to back. The advantage is, the we don't have to draw lines to the bottom of the screen every time because of occlusion. However, to guarantee occlusion we need an additional y-buffer. For every column, the highest y position is stored. Because we are drawing from the front to back, the visible part of the next line can only be larger then the highest line previously drawn.\n* Level of Detail. Render more details in front but less details far away. \n\n![front to back rendering](images\u002Ffronttoback.gif)\n\n```python\ndef Render(p, phi, height, horizon, scale_height, distance, screen_width, screen_height):\n    # precalculate viewing angle parameters\n    var sinphi = math.sin(phi);\n    var cosphi = math.cos(phi);\n    \n    # initialize visibility array. Y position for each column on screen \n    ybuffer = np.zeros(screen_width)\n    for i in range(0, screen_width):\n        ybuffer[i] = screen_height\n\n    # Draw from front to the back (low z coordinate to high z coordinate)\n    dz = 1.\n    z = 1.\n    while z \u003C distance\n        # Find line on map. This calculation corresponds to a field of view of 90°\n        pleft = Point(\n            (-cosphi*z - sinphi*z) + p.x,\n            ( sinphi*z - cosphi*z) + p.y)\n        pright = Point(\n            ( cosphi*z - sinphi*z) + p.x,\n            (-sinphi*z - cosphi*z) + p.y)\n\n        # segment the line\n        dx = (pright.x - pleft.x) \u002F screen_width\n        dy = (pright.y - pleft.y) \u002F screen_width\n\n        # Raster line and draw a vertical line for each segment\n        for i in range(0, screen_width):\n            height_on_screen = (height - heightmap[pleft.x, pleft.y]) \u002F z * scale_height. + horizon\n            DrawVerticalLine(i, height_on_screen, ybuffer[i], colormap[pleft.x, pleft.y])\n            if height_on_screen \u003C ybuffer[i]:\n                ybuffer[i] = height_on_screen\n            pleft.x += dx\n            pleft.y += dy\n\n        # Go to next line and increase step size when you are far away\n        z += dz\n        dz += 0.2\n\n# Call the render function with the camera parameters:\n# position, viewing angle, height, horizon line position, \n# scaling factor for the height, the largest distance, \n# screen width and the screen height parameter\nRender( Point(0, 0), 0, 50, 120, 120, 300, 800, 600 )\n```\n\n## Links\n\n[Web Project demo][project demo] page\n\n[Voxel terrain engine - an introduction](https:\u002F\u002Fweb.archive.org\u002Fweb\u002F20131113094653\u002Fhttp:\u002F\u002Fwww.codermind.com\u002Farticles\u002FVoxel-terrain-engine-building-the-terrain.html)\n\n[Personal website](http:\u002F\u002Fwww.simulationcorner.net)\n\n\n\n## Maps\n[color](maps\u002FC1W.png),\n[height](maps\u002FD1.png)\n\n![C1W.png](images\u002Fthumbnails\u002FC1W.png)\n![D1.png](images\u002Fthumbnails\u002FD1.png)\n\n[color](maps\u002FC2W.png),\n[height](maps\u002FD2.png)\n\n![C2W.png](images\u002Fthumbnails\u002FC2W.png)\n![D2.png](images\u002Fthumbnails\u002FD2.png)\n\n[color](maps\u002FC3.png),\n[height](maps\u002FD3.png)\n\n![C3.png](images\u002Fthumbnails\u002FC3.png)\n![D3.png](images\u002Fthumbnails\u002FD3.png)\n\n[color](maps\u002FC4.png),\n[height](maps\u002FD4.png)\n\n![C4.png](images\u002Fthumbnails\u002FC4.png)\n![D4.png](images\u002Fthumbnails\u002FD4.png)\n\n[color](maps\u002FC5W.png),\n[height](maps\u002FD5.png)\n\n![C5W.png](images\u002Fthumbnails\u002FC5W.png)\n![D5.png](images\u002Fthumbnails\u002FD5.png)\n\n[color](maps\u002FC6W.png),\n[height](maps\u002FD6.png)\n\n![C6W.png](images\u002Fthumbnails\u002FC6W.png)\n![D6.png](images\u002Fthumbnails\u002FD6.png)\n\n[color](maps\u002FC7W.png),\n[height](maps\u002FD7.png)\n\n![C7W.png](images\u002Fthumbnails\u002FC7W.png)\n![D7.png](images\u002Fthumbnails\u002FD7.png)\n\n[color](maps\u002FC8.png),\n[height](maps\u002FD6.png)\n\n![C8.png](images\u002Fthumbnails\u002FC8.png)\n![D6.png](images\u002Fthumbnails\u002FD6.png)\n\n[color](maps\u002FC9W.png),\n[height](maps\u002FD9.png)\n\n![C9W.png](images\u002Fthumbnails\u002FC9W.png)\n![D9.png](images\u002Fthumbnails\u002FD9.png)\n\n[color](maps\u002FC10W.png),\n[height](maps\u002FD10.png)\n\n![C10W.png](images\u002Fthumbnails\u002FC10W.png)\n![D10.png](images\u002Fthumbnails\u002FD10.png)\n\n[color](maps\u002FC11W.png),\n[height](maps\u002FD11.png)\n\n![C11W.png](images\u002Fthumbnails\u002FC11W.png)\n![D11.png](images\u002Fthumbnails\u002FD11.png)\n\n[color](maps\u002FC12W.png),\n[height](maps\u002FD11.png)\n\n![C12W.png](images\u002Fthumbnails\u002FC12W.png)\n![D11.png](images\u002Fthumbnails\u002FD11.png)\n\n[color](maps\u002FC13.png),\n[height](maps\u002FD13.png)\n\n![C13.png](images\u002Fthumbnails\u002FC13.png)\n![D13.png](images\u002Fthumbnails\u002FD13.png)\n\n[color](maps\u002FC14.png),\n[height](maps\u002FD14.png)\n\n![C14.png](images\u002Fthumbnails\u002FC14.png)\n![D14.png](images\u002Fthumbnails\u002FD14.png)\n\n[color](maps\u002FC14W.png),\n[height](maps\u002FD14.png)\n\n![C14W.png](images\u002Fthumbnails\u002FC14W.png)\n![D14.png](images\u002Fthumbnails\u002FD14.png)\n\n[color](maps\u002FC15.png),\n[height](maps\u002FD15.png)\n\n![C15.png](images\u002Fthumbnails\u002FC15.png)\n![D15.png](images\u002Fthumbnails\u002FD15.png)\n\n[color](maps\u002FC16W.png),\n[height](maps\u002FD16.png)\n\n![C16W.png](images\u002Fthumbnails\u002FC16W.png)\n![D16.png](images\u002Fthumbnails\u002FD16.png)\n\n[color](maps\u002FC17W.png),\n[height](maps\u002FD17.png)\n\n![C17W.png](images\u002Fthumbnails\u002FC17W.png)\n![D17.png](images\u002Fthumbnails\u002FD17.png)\n\n[color](maps\u002FC18W.png),\n[height](maps\u002FD18.png)\n\n![C18W.png](images\u002Fthumbnails\u002FC18W.png)\n![D18.png](images\u002Fthumbnails\u002FD18.png)\n\n[color](maps\u002FC19W.png),\n[height](maps\u002FD19.png)\n\n![C19W.png](images\u002Fthumbnails\u002FC19W.png)\n![D19.png](images\u002Fthumbnails\u002FD19.png)\n\n[color](maps\u002FC20W.png),\n[height](maps\u002FD20.png)\n\n![C20W.png](images\u002Fthumbnails\u002FC20W.png)\n![D20.png](images\u002Fthumbnails\u002FD20.png)\n\n[color](maps\u002FC21.png),\n[height](maps\u002FD21.png)\n\n![C21.png](images\u002Fthumbnails\u002FC21.png)\n![D21.png](images\u002Fthumbnails\u002FD21.png)\n\n[color](maps\u002FC22W.png),\n[height](maps\u002FD22.png)\n\n![C22W.png](images\u002Fthumbnails\u002FC22W.png)\n![D22.png](images\u002Fthumbnails\u002FD22.png)\n\n[color](maps\u002FC23W.png),\n[height](maps\u002FD21.png)\n\n![C23W.png](images\u002Fthumbnails\u002FC23W.png)\n![D21.png](images\u002Fthumbnails\u002FD21.png)\n\n[color](maps\u002FC24W.png),\n[height](maps\u002FD24.png)\n\n![C24W.png](images\u002Fthumbnails\u002FC24W.png)\n![D24.png](images\u002Fthumbnails\u002FD24.png)\n\n[color](maps\u002FC25W.png),\n[height](maps\u002FD25.png)\n\n![C25W.png](images\u002Fthumbnails\u002FC25W.png)\n![D25.png](images\u002Fthumbnails\u002FD25.png)\n\n[color](maps\u002FC26W.png),\n[height](maps\u002FD18.png)\n\n![C26W.png](images\u002Fthumbnails\u002FC26W.png)\n![D18.png](images\u002Fthumbnails\u002FD18.png)\n\n[color](maps\u002FC27W.png),\n[height](maps\u002FD15.png)\n\n![C27W.png](images\u002Fthumbnails\u002FC27W.png)\n![D15.png](images\u002Fthumbnails\u002FD15.png)\n\n[color](maps\u002FC28W.png),\n[height](maps\u002FD25.png)\n\n![C28W.png](images\u002Fthumbnails\u002FC28W.png)\n![D25.png](images\u002Fthumbnails\u002FD25.png)\n\n[color](maps\u002FC29W.png),\n[height](maps\u002FD16.png)\n\n![C29W.png](images\u002Fthumbnails\u002FC29W.png)\n![D16.png](images\u002Fthumbnails\u002FD16.png)\n\n## License\n\nThe software part of the repository is under the MIT license. Please read the license file for more information. Please keep in mind, that the Voxel Space technology might be still [patented](https:\u002F\u002Fpatents.justia.com\u002Fassignee\u002Fnovalogic-inc) in some countries. The color and height maps are reverse engineered from the game Comanche and are therefore excluded from the license.\n\n[project demo]: https:\u002F\u002Fs-macke.github.io\u002FVoxelSpace\u002FVoxelSpace.html\n","VoxelSpace 是一个基于 C 语言的地形渲染算法，核心代码仅用不到20行实现。该项目复现了1992年游戏《Comanche》所使用的Voxel Space技术，这是一种介于2D和3D之间的渲染方法，能够高效地生成具有纹理、阴影效果的地形图像，特别适合在计算资源有限的情况下创建逼真的环境视图。它通过高度图和颜色图来表示地形，并采用简单的线性扫描方式结合透视投影原理完成渲染过程，无需复杂的光照计算即可达到良好的视觉效果。此项目非常适合对复古游戏开发或低性能设备上的图形渲染感兴趣的技术人员学习与研究。",2,"2026-06-11 03:06:49","top_language"]