How to create a Hexagon Grid?

edited April 2013 in Help request
I had no problem making an ordinary grid. I have no idea what would be the proper way. I am not sure if I can use configuration file due to non-rectangular shape. Or do I have to assemble the coordinates in code?


Thanks

Comments

  • edited April 2013
    Hi,

    Yes, as there's no concept of grid per se, you need to handle it yourself. This page is a good starting point if you're not familiar with the conversion between a square grid and an hex grid.

    However, if you only want to display hexagonal shapes, you have a few options:
      none
    • Use hex-shaped bitmap contained in a traditional rectangular bitmap with the overlap being transparent
    • Display actual hexagons using the orxDisplay_DrawMesh() function when doing custom rendering (look for custom rendering on this forum, this topic has been explained a few times)
    • Render you own tiles entirely via a custom pixel/fragment shader, which is the most optimal solution but also the most complexnone
  • edited April 2013
    if you want to go with fragment shader rendering,
    here is a good tutorial
    http://www.the2dgame.com/index?page=articles&ref=ART4
  • edited May 2013
    I am exited to show hexagon grid implemented in the shader. I will probably put it in some form on wiki. I am sure there are better ways to write it, but it is a good enough start for me. There are lots of resources on the web, but it is hard to find a functional example.

    I think the shader algorithm exposes internal grid structure well enough to use with tile maps, if needed.

    I really don't know if all that effort was worth it. However, I had fun figuring it out.

    One interesting side effect I noticed and don't know how to control is the scale of the map. The uneven size of the rectangle like 800x600 resulted in a skewed hexagon. I understand why, just don't know the options to take a better control over it. I had to set a perfect rectangle 596x596 to get the proper hexagon shape.

    I assume that I would have to implement exactly the same algorithm on C the side if I wan to map mouse coordinates to hex grid.

    I have considered trying to place PNG images with transparency, but I simply did not feel comfortable with the overlap. I felt that overlap would create unwanted side effects if I want to highlight the hexagon.

    I can't believe it. orx is so simple I am writing shaders for it :) And a week ago I did not know what it was.

    [Object]
    Graphic     = OnePixel
    Position   = (2., 2., 0.2)
    Scale       = (596., 596., 1)
    ShaderList  = HexShader
    
    [OnePixel]
    Texture = pixel
    
    [HexShader]
    ParamList = radius
    radius = 0.05
    Code = "
    bool sameSide(vec3 p1, vec3 p2, vec3 a, vec3 b) {
    	vec3 cp1 = cross(b-a, p1-a);
    	vec3 cp2 = cross(b-a, p2-a);
    	return dot(cp1, cp2) >= 0.0;
    }
    
    bool pointInTriangle(vec3 p, vec3 a, vec3 b, vec3 c) {
    	return sameSide(p,a, b,c) 
    		&& sameSide(p,b, a,c)
    		&& sameSide(p,c, a,b);
    }
    
    vec4 tileColor(float x, float y, float s, float h) {
    	return vec4(x * s, y * h, .7, 1.0); // red
    }
    
    void main()
    {
    	float PI = 3.14159265358979323846264;
    	float r = radius;
    	float h = 2.0 * r * sin(PI / 3.0); // PI / 3.0 is a 60 degree angle
    	float s = 3. / 2. * r;
    	vec3 p = gl_TexCoord[0].xyz; // current point
    
    	// aproximation or dirty grid coordinates
    	float gridX = floor(p.x / s);
    	float yOffset = mod(gridX, 2.0)*0.5*h;
    	float gridY = floor((p.y - yOffset) / h);
    	vec3 a = vec3(gridX * s, gridY * h + yOffset, 0.0); // top left corner of the top outside triangle
    	vec3 b = vec3(a.x + 0.5 * r, a.y, 0.0); // top right cornerof the top outside triangle
    	vec3 c = vec3(a.x, a.y + 0.5 * h, 0.0); // bottom point of the top outside triangle
    	if (pointInTriangle(p, a,b,c)) {
    		// outside top left corner
    		gl_FragColor = tileColor(gridX - 1., gridY - mod(gridX-1., 2.), s, h);
    	} else {
    		vec3 d = vec3(b.x, (gridY + 1.) * h + yOffset, 0.0);
    		vec3 e = vec3(a.x, d.y, 0.0);
    		if (pointInTriangle(p, c,d,e)) {
    			// outside bottom left corner
    			gl_FragColor = tileColor(gridX - 1., gridY + mod(gridX, 2.), s, h);
    		} else {
    			// main corner
    			gl_FragColor = tileColor(gridX, gridY, s, h);
    		}
    	}
    }
    "
    
  • edited May 2013
    Nice, I'm glad you got it working that fast. :)

    I'm also glad you appreciate your discovery of orx so far, and there's plenty more interesting stuff to discover. :)

    Speaking of which, if you want to span your shader over your full display (or a percentage of it), here's a trick that's very helpful, not only for this case, but also for all UI elements.
    [1P]; "Template" section for using the pixel graphic
    Graphic = @
    Texture = pixel
    Pivot = center
    
    [HexGround@1P]
    ParentCamera = MyCamera; Here's half of the trick, this object will automatically become a child of the specified camera and move with it
    UseParentSpace = both; Here we define that both scale and position will be relative to the camera (frustum) size
    Scale = 1; That means the object will be scale to cover the whole frustum
    Position = (0.5, 0.5, 1.0); Here we place the object in the middle of the camera, ie. centered, and the Z = 1 means the object will be completely in the background, at the end of the camera's frustum
    ShaderList = ...
    

    I think I have an idea on how to support any "size" without having any distortions for your grid. Would you mind sharing your texture (or maybe even better, your project?) with me so that I can give a try over the week end?
  • edited May 2013
    ok. I have posted the hexagon grid code as a barebones tutorial on wiki. C code is fully coordinated with shader code. In other words mouse correctly highlights the proper tile on the screen.

    http://orx-project.org/wiki/en/orx/tutorials/community/sergeig/hexagongrid

    it is easier to format text on wiki and I can freely update the content as I adjust it that's why it is there and not on the forum pages.

    The wiki page is a work in progress.
  • edited May 2013
    That's the best place for it.

    Tiny suggestion: I'd recommend using the resource system to define your assets locations.

    Right now you have:
    [Shader]
    textures = ../data/hexagonTiles/tile-blue.png # ../data/hexagonTiles/tile-red.png # ../data/hexagonTiles/tile-green.png # ../data/hexagonTiles/tile-brown.png # ../data/hexagonTiles/tile-yellow.png
    

    You could have:
    [Resource]
    Texture = ../data/hexagonTiles
    
    [Shader]
    textures = tile-blue.png # tile-red.png # tile-green.png # tile-brown.png # tile-yellow.png
    
  • edited May 2013
    nice!

    I just have two notes.

    1) try to avoid if/else in shaders, GPU are stream processors with big prefetch buffers, if will break the instruction stream, and will require the the GPU to flush and rebuild the buffer.
    You may have to rethink your algo, and maybe you cant avoid it.

    2) same for discard, if you cant avoid the discard, try to execute it ASAP.
Sign In or Register to comment.