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?
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
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);
}
}
}
"
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?
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.
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.
Comments
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
here is a good tutorial
http://www.the2dgame.com/index?page=articles&ref=ART4
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.
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.
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?
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.
Tiny suggestion: I'd recommend using the resource system to define your assets locations.
Right now you have:
You could have:
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.