Hex grid on 3d terrain

Hi,

I’m new to the forums but i’ve been lurking for a long time, and this will be my first post so forgive me if this is in the wrong section. I’m going to begin work on a pretty major personal project this summer and so i’m trying to prepare by reading up and just compiling some notes. I’m fairly intermediate with Java but i have a lot of experience with C++

Anyway, i’m going to be making a hex grid based strategy game using 3d terrain; meaning its not 2d isometric, the plane is actually fully rendered 3d so you can rotate and zoom in on the map. The way i want to go about it is that i want the map to be natural looking and then “overlay” hex grid on top the terrain. I’m trying to avoid the blocky (hex shaped) terrain that is used when making 3d hex games; i dont want the terrain looking like Heroclix.

I suppose the closest example is Civilization V. The terrain is smooth/natural and the hex grid has been overlayed on top of that.

(i dont know what the rules of posting images are, so here is the link the image) http://cdn.steampowered.com/v/gfx/apps/8930/ss_84ee7ab3b0148a260359f8d5a78a2ab9033aa695.1920x1080.jpg?t=1338148097

I’m not really asking for code, im actually still at the very high level and just pondering ideas. Instead i want some suggestions. Is Java capable of doing something like that, or should i return to C++? If you were tasked with something like that, what would be your approach? In essence i just want people to toss me some ideas or thoughts, as i need somewhere to begin.

For the hexes i was thinking about using some sort of data structure, perhaps a linked list with 6 entries? Perhaps make them an object with various attributes such as the terrain type, altitude, etc. What do you guys think? I’d appreciate any and all thoughts, ideas or suggestions.

Thank you very much!

There’s nothing inherent to the problem that would make Java or C++ a more natural fit than the other. It’s all just a matter of which you’re more comfortable working with.

Civ V generates a different piece of terrain per hex, then has a rather fancy renderer that lets the terrain “bleed over” to neighboring hexes as well as smoothly transition between mountains and hills and whatnot. The hex grid overlaid on top also follows the height contours of the terrain. It’s no exaggeration to say that Firaxis undoubtedly sunk millions of dollars into the level of polish that went into the terrain renderer.

The code for it is almost certainly the least interesting part, probably just a lot of rendering passes using shaders, and a large library of varying terrain base tiles and fringes. Very straightforward, unlike Alpha Centauri which used a voxel terrain engine written in assembly.

thank you for the reply.

Hmm thats pretty interesting, I never thought about doing it like that. That is definitely something to keep in mind, thought it seems rather excessive and unrealistic in my situation. I wish i had millions of dollars :frowning:

Assuming i wanted more economical approach, do you think it would be possible to design the terrain (the entire map) first and then apply a hex overlay to that? So that way i wont have to deal with having a thousand different hex pieces. I mean my contours will likely be much more crude, but thats not my worry to be honest. However, since all the movement/attacking/etc will be constrained by the hexes, im wondering if overlaying the grid over a “prebuilt” terrain is feasible and possible.

Also, would you happen to know of any 3d hex based games aside from Civ5 that appear to do what im trying? Im trying to look around and draw some ideas…

Please forgive me if these sound like amateur questions. I’ve never actually worked with 3d rendering, i’ve only made 2d games before so i’m very new in this area.

you could render a texture with a hex grid on top of it.

thank you for the reply. These are some fantastic suggestions.

that actually seems rather straight forward to be honest. kind of ashamed i didnt think of that…

The only issue i can imagine arising from that would be that i would have to make sure the “actual” hexes (the ones the program uses) line up with the “rendered” outline. Doesnt SEEM difficult but of course what would i know, i’ve never worked with 3d graphics lol. I assume i would need to synchronize the actual hexes with the texture when the user rotates or zooms in on the map?

I know its too early to even consider this, but im trying to keep simplicity and modularity in mind; it would make for adding new content much easier.

please keep the ideas coming

lol…deep thought indeed

Texture splatting. Easily done with a limited number of textures in OpenGL 2 or even easier with an unlimited number of textures with OpenGL 3 using a texture array. Add a height map for mountains/whatever. Finally procedurally generate or sample a texture for the grid, and you have it all in one pass blazingly fast.

whoa very cool!

I think that will be very handy. Now i just have to read all i can about texture splatting. Any successful games/engines in java that use texture splatting i could check out?

Also the one thing i’m trying to wrap my head around is the hex grid. I’ve made a 2d hex grid game and that was easy since i just slapped on the grid and put a background. In this circumstance how can i impose a 2d hex grid on a 3d terrain? I’m not talking about the visual aspect of it, i mean the actual grid data structure. Would it be the same as a 2d hex game except now that background is 3d?

I think a 2d grid would be fine. You can rotate, zoom, pan, all that stuff.
Might get a bit confusing, but I doubt it.

Like I said, you have 3D terrain information, probably a height map. Just draw the grid with that information too.

I see. thanks ;D

I’m sure it will be more apparent as i begin work on my project. Since i’ve never worked with 3d before its hard for me to visualize and understand quickly, so i apologize. I guess my biggest confusion is, just because i’ve drawn a hex on the terrain, how does the engine itself know its a hex; how do i tell it that its a hex on a 3d object. Once i start working on my program then i’ll probably be able to state my question more effectively lol. But for know i suppose im good

Another quick question: Would this method allow me to apply visual effects on the hexes such as highlighting the selected hexes,etc?

For highlighting, if you have a 2D grid, you can easily do highlighting on a flat surface.
If you want the highlighting to go on the terrain, use the height map like theagentd said.

Civ V’s hex grid is perfectly regular, it’s just a flat map where the edges are painted straight on the terrain as if through a stencil, and the terrain tiles all have shapes chosen specifically so that this effect doesn’t look out of place. It’s doable in a fragment shader, just project the hex straight down on the terrain.

thank you very much for all the replies. As i begin work on my project i will bump this with more specific questions.

Before i begin, would any of you know of good tutorials, instructions, manuals, etc about things like Texture Splatting, Height Maps, etc? I’m reading a few now, but they’re not really that specific to java.

Remember that a hex-grid is nothing else than a square-grid with an offset applied to alternating columns or rows.

This might help you creating the datastructure.

Direct neighbours, used for logic: (the distances to all neighbours are equal!)


[ ][ ][ ][ ][ ]
[ ][o][o][ ][ ]
[ ][o][x][o][ ]
[ ][o][o][ ][ ]
[ ][ ][ ][ ][ ]

Alternating rows with offset, used for rendering:


[ ][ ][ ][ ][ ]
  [ ][o][o][ ][ ]
[ ][o][x][o][ ]
  [ ][o][o][ ][ ]
[ ][ ][ ][ ][ ]

A couple hex related functions (2D)…

private boolean hexIntersectsLine (int column, int row, int x1, int y1, int x2, int y2) {
		int px = column * spacingX;
		int py = row * spacingY;
		if (row % 2 == 0) px += offsetX;

		int dx = x2 - x1;
		int dy = y2 - y1;

		int x = px + width + 1;
		int y = py + spacingY;
		int side1 = (int)Math.signum(dx * (y - y1) - (x - x1) * dy);
		if (side1 == 0) return true;

		for (int i = 1; i < 6; i++) {
			switch (i) {
			case 1:
				x = px + width + 1;
				y = py + height - spacingY;
				break;
			case 2:
				x = px + width / 2;
				y = py;
				break;
			case 3:
				x = px - 1;
				y = py + height - spacingY;
				break;
			case 4:
				x = px - 1;
				y = py + spacingY;
				break;
			case 5:
				x = px + width / 2;
				y = py + height;
				break;
			}
			int turns = (int)Math.signum(dx * (y - y1) - (x - x1) * dy);
			if (turns == 0 || turns != side1) return true;
		}
		return false;
	}

	static public Direction getDirection (int x, int y, int targetX, int targetY) {
		float xDiff = x - targetX;
		float yDiff = y - targetY;
		if (y % 2 == 0) xDiff += 0.5f;
		if (targetY % 2 == 0) xDiff -= 0.5f;
		int index = (int)Math.round(MathUtils.atan2(yDiff, xDiff) / (MathUtils.PI / 3)) + 2;
		if (index < 0) index = 5;
		return Direction.values()[index];
	}
	
	public enum Direction {
		southeast, southwest, west, northwest, northeast, east,
	}

There are some instance fields in hexIntersectsLine for the offset and size of each hex.

Since we’re posting resources, here’s some other goodies:


http://www-cs-students.stanford.edu/~amitp/gameprog.html#hex

To add the grid, you could use a fragment shader. First sample the terrain, then sample the hex map, then blend the two together however you want (for e.g. additive blending). Ideally you’d use a seamless and transparent hex texture that wraps with GL_REPEAT. Then the grid will appear to “follow” the contours of your terrain, as if they were painted on. The toughest part would be getting the texcoords right for the hex map, so that it lines up with the game logic and repeats seamlessly. Highlighting a certain tile could also be done in this manner by either binding/sampling a different texture (e.g. hex_selected.png), or using the shader’s color attributes to filter the hex map, or what have you.

Aye, I’ve done this (hex with repeat, but simple 2D). I couldn’t get the art perfect so I made up for it in code…

public Point hexToPixel (int column, int row) {
	tempPoint.x = column * spacingX + width / 2;
	tempPoint.y = row * spacingY + height / 2;
	tempPoint.y -= Math.round(row / 3f); // Every third hex is one pixel short to fit 6 hexes in one 256 tall tile image.
	if (row % 2 == 0) tempPoint.x += offsetX;
	return tempPoint;
}

thank you guys so much. sorry i havent replied to this thread.

Unfortunately i havent even begun work on my project yet but i will sometime this week. Work, school and a few unexpected events have shifted my focus. Thank you so much for those resources. I cant tell you how much that helps!