Hey all!
I’m working on a kind of 3D room rendering data structure, but I’m having trouble with a couple of points.
First and foremost, here’s a couple of screenshots from the actual engine running:
An example room:
From inside the room:
A room is made up of segments. A segment can be defined as a 1 x 1 tile that extends upwards by an arbitrary amount to form a hollow 3D cuboid.
Every time you add a segment next to another, their two adjoining faces are removed (not rendered) to form a larger interior space, until you create an entire room, as explained in the following diagram:
Up to this point, my data structure would define each segment as simply having an X, Y, Z position, a floor height and a ceiling height. The inner wall height is naturally the difference between the upper ceiling Y and lower floor Y.
Here’s where things get a little more complicated :S
Adjacent floors can be different heights (as can ceilings). This raises the problem where you need to fill in the ‘gap’ between floors. This can be neatly explained in the following diagram:
The data structure gets a little more complex now. I’ve reduced the need to do runtime processing of these ‘step’ values by pre-computing them. For each segment in the entire map, I calculate the difference in floor height between each segment, and for each face (north, east, south and west). This allows each segment edge to drop down to a unique height from its other edges.
If the adjacent floor is higher, it gets ignored since that higher floor will do the processing for that edge anyway.
So, here’s where I’m having trouble.
I’m doing all of the tile rendering in immediate mode - so I have a Segment object that looks a bit like this in code:
public class Segment {
private float x, y, z; // the segment's position, where Y is the floor's position
private float height; // the height of the segment
private float ceilingY; // for convenience, set as y + height
// the values that define how much lower this segment's neighbouring floors are
private float lowerDropNorth, lowerDropEast, lowerDropSouth, lowerDropWest;
// flags to enable or disable drawing of each side wall
private boolean drawNorth, drawEast, drawSouth, drawWest;
// flags to enable or disable drawing of the lower step edges
private boolean drawStepN, drawStepE, drawStepS, drawStepE;
public Segment() { }
public void render()
{
// draw inner walls
if (drawNorth)
{
glBegin(GL_QUADS);
// vertex definitions...
glEnd();
}
if (drawSouth)
{
glBegin(GL_QUADS);
// vertex definitions...
glEnd();
}
if (drawEast)
{
glBegin(GL_QUADS);
// vertex definitions...
glEnd();
}
if (drawWest)
{
glBegin(GL_QUADS);
// vertex definitions...
glEnd();
}
// draw step edges
f (drawStepNorth)
{
glBegin(GL_QUADS);
// vertex definitions...
glEnd();
}
if (drawStepSouth)
{
glBegin(GL_QUADS);
// vertex definitions...
glEnd();
}
if (drawStepEast)
{
glBegin(GL_QUADS);
// vertex definitions...
glEnd();
}
if (drawStepWest)
{
glBegin(GL_QUADS);
// vertex definitions...
glEnd();
}
}
}
This seems massively inefficient to me. Even with frustum and manual distance culling, this doesn’t really seem to be an efficient way of rendering each segment’s required faces. Or is it?
I figured that having each Segment’s data pre-processed (position, step size etc.) would be beneficial since nothing is ever going to move once its created (static geometry), but I can’t seem to think of a more appropriate way of rendering it.
I’d greatly appreciate feedback from anyone else who might have experience with these things!
Thanks!