Search code examples
iosswiftmetal

Endless scrolling over a 3d map


I have some experience with Metal and quite a bit with Unity and am familiar with setting up meshes, buffers, and the backing data for drawing; but not so much the math/shader side. What I'm struggling with is how to get an endless scrolling world. So if I pan far to the right side I can see the left side and keep going.

The application of this would be a seamless terrain that a player could scroll in any direction forever and have it just wrap.

I don't want to duplicate everything on draw and offset it, that seems horrendously inefficient. I am hoping for a way to either use some magic matrix math or some sort of shader to get things wrapping/drawing where they should when panning the map. I've searched all over for some sort of guide or explanation of how to get this working but haven't come up with anything.

I know a lot of old (dos) games did this somehow, is it still possible? Is there a reason why it seems the industry has migrated away from this type of scrolling (bounding to edges vs wrapping)?


Solution

  • I have created a simple example demonstrating what you're looking for (I think).

    The basic idea of it is that you draw the map in a repeating grid, using the drawPrimitives(type:vertexStart:vertexCount:instanceCount:) method on MTLRenderCommandEncoder. As the instance count you want to pass in the number of identical maps you want to draw, extending it as far as needed to not see where it ends. In my example I used a simple 5x5 grid.

    To not have the user see the edge of the map, we're gonna calculate their position modulo 1 (or whatever size your map is):

    func didDrag(dx: CGFloat, dy: CGFloat) {
        // Move user position on drag, adding 1 to not get below 0
        x += Float(dx) * draggingSpeed + 1
        z += Float(dy) * draggingSpeed + 1
        
        x.formTruncatingRemainder(dividingBy: 1)
        z.formTruncatingRemainder(dividingBy: 1)
    }
    

    This is how it looks: