Well, as you probably figured by the title, I am doing like everyone else, creating a minecrafty clone.
My reasons are simple, I wan't to learn 3d programming and I don't know squat about modelling etc.
So cubes are the easy way to go, besides finding textures is no problem either.
But I have managed to render about 3k cubes at once without dropping below 50 fps, I am using Display.sync 60.
This is my display list:
displayList = glGenLists(1);
glNewList(displayList, GL_COMPILE);
{
/* 6 faces */
ResourceManager.getManager().getTexture(frontTexture).bind();
glBegin(GL_QUADS);
{
//front face
glNormal3f(0f, 0f, 1f);
glTexCoord2f(0f, 1f);
glVertex3f(1f, 0f, 0f); //1
glTexCoord2f(1f, 1f);
glVertex3f(0f, 0f, 0f); // 2
glTexCoord2f(1f, 0f);
glVertex3f(0f, 1f, 0f); // 3
glTexCoord2f(0f, 0f);
glVertex3f(1f, 1f, 0f); // 4
}
glEnd();
ResourceManager.getManager().getTexture(backTexture).bind();
glBegin(GL_QUADS);
{
//right face
glNormal3f(0f, 0f, -1f);
glTexCoord2f(0f, 1f);
glVertex3f(0f, 0f, 1f); //1
glTexCoord2f(1f, 1f);
glVertex3f(1f, 0f, 1f); // 2
glTexCoord2f(1f, 0f);
glVertex3f(1f, 1f, 1f); // 3
glTexCoord2f(0f, 0f);
glVertex3f(0f, 1f, 1f); // 4
}
glEnd();
ResourceManager.getManager().getTexture(topTexture).bind();
glBegin(GL_QUADS);
{
//top face
glNormal3f(0f, -1f, 0f);
glTexCoord2f(0f, 1f);
glVertex3f(1f, 1f, 0f); //1
glTexCoord2f(1f, 1f);
glVertex3f(0f, 1f, 0f); // 2
glTexCoord2f(1f, 0f);
glVertex3f(0f, 1f, 1f); // 3
glTexCoord2f(0f, 0f);
glVertex3f(1f, 1f, 1f); // 4
}
glEnd();
ResourceManager.getManager().getTexture(bottomTexture).bind();
glBegin(GL_QUADS);
{
//bottom face
glNormal3f(0f, 1f, 0f);
glTexCoord2f(0f, 1f);
glVertex3f(1f, 0f, 1f); //1
glTexCoord2f(1f, 1f);
glVertex3f(0f, 0f, 1f); // 2
glTexCoord2f(1f, 0f);
glVertex3f(0f, 0f, 0f); // 3
glTexCoord2f(0f, 0f);
glVertex3f(1f, 0f, 0f); // 4
}
glEnd();
ResourceManager.getManager().getTexture(leftTexture).bind();
glBegin(GL_QUADS);
{
//left face
glNormal3f(-1f, 0f, 0f);
glTexCoord2f(0f, 1f);
glVertex3f(1f, 0f, 1f); //1
glTexCoord2f(1f, 1f);
glVertex3f(1f, 0f, 0f); // 2
glTexCoord2f(1f, 0f);
glVertex3f(1f, 1f, 0f); // 3
glTexCoord2f(0f, 0f);
glVertex3f(1f, 1f, 1f); // 4
}
glEnd();
ResourceManager.getManager().getTexture(rightTexture).bind();
glBegin(GL_QUADS);
{
//right face
glNormal3f(1f, 0f, 0f);
glTexCoord2f(0f, 1f);
glVertex3f(0f, 0f, 0f); //1
glTexCoord2f(1f, 1f);
glVertex3f(0f, 0f, 1f); // 2
glTexCoord2f(1f, 0f);
glVertex3f(0f, 1f, 1f); // 3
glTexCoord2f(0f, 0f);
glVertex3f(0f, 1f, 0f); // 4
}
glEnd();
}
glEndList();
As you can see I am rendering each face and giving them an unique texture.
The first thing that comes in mind is the fact that for each square rendered there is a display list, and lets say for example I am going to render 3000 blocks. Then there will be atleast 3000 display lists in the world, I don't think that is a performance decrease but rather a memory hogger. (And thus knowing this I am at the moment thinking of a better way to handle this issue).
This is how I create my cubes.
This is how I draw them:
public void render() {
if (selected == 1) {
glColor3f(1f, 0f, 0f);
draw();
selected = -1;
return;
}
glColor3f(1f, 1f, 1f);
draw();
}
public void draw() {
glCallList(displayList);
}
It is really not that big of a deal, but I am just leaving it here for pointers.
This is how they are parsed in my render loop
/**
* Apply Blocks
*/
glPushMatrix();
{
glEnable(GL_TEXTURE_2D);
glScalef(0.5f, 0.5f, 0.5f);
renderBlocks();
}
glPopMatrix();
public void renderBlocks() {
for (Block b : WorldManager.getWorld().
getRegionForCoordinates(
(int) gameCamera.position.x,
(int) gameCamera.position.y,
(int) gameCamera.position.z).getBlocks()) {
if (b.isTransparent()) {
transpBlocks.add(b);
continue;
}
glPushMatrix();
{
glTranslatef(b.position.x, b.position.y, b.position.z);
((Renderable) b).render();
}
glPopMatrix();
}
//glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
for (Block b : transpBlocks) {
glPushMatrix();
{
glTranslatef(b.position.x, b.position.y, b.position.z);
((Renderable) b).render();
}
glPopMatrix();
}
//glEnable(GL_DEPTH_TEST);
if (cullBack && !glIsEnabled(GL_CULL_FACE)) {
glEnable(GL_CULL_FACE);
}
transpBlocks.clear();
}
Alright and this is my region class, I know it's only sketchy.
public class Region {
private HashMap<Vector3f, Block> blocks = new HashMap<Vector3f, Block>();
private int regionX, regionY, regionZ;
public Region(int regionX, int regionY, int regionZ) {
this.regionX = regionX;
this.regionY = regionY;
this.regionZ = regionZ;
}
public void addBlock(int x, int y, int z, Block b) {
if (x >= 128 || y >= 128 || z >= 128
|| x < 0 || y < 0 || z < 0) {
return;
}
removeBlock(x, y, z);
blocks.put(new Vector3f(x, y, z), b);
}
public boolean hasBlockAt(int x, int y, int z) {
for (Object oKey : blocks.keySet().toArray()) {
if (((Vector3f) oKey).x == x
&& ((Vector3f) oKey).y == y
&& ((Vector3f) oKey).z == z) {
return true;
}
}
return false;
}
public void removeBlock(int x, int y, int z) {
if (x >= 128 || y >= 128 || z >= 128
|| x < 0 || y < 0 || z < 0) {
return;
}
for (Object oKey : blocks.keySet().toArray()) {
if (((Vector3f) oKey).x == x
&& ((Vector3f) oKey).y == y
&& ((Vector3f) oKey).z == z) {
blocks.remove(oKey);
return;
}
}
}
public Block getBlock(int x, int y, int z) {
if (x >= 128 || y >= 128 || z >= 128
|| x < 0 || y < 0 || z < 0) {
return null;
}
for (Object oKey : blocks.keySet().toArray()) {
if (((Vector3f) oKey).x == x
&& ((Vector3f) oKey).y == y
&& ((Vector3f) oKey).z == z) {
return blocks.get(oKey);
}
}
return null;
}
public Block[] getBlocks() {
Block[] b = new Block[getTotalBlocks()];
return blocks.values().toArray(b);
}
public int getTotalBlocks() {
return blocks.size();
}
}
Now you got all the information.
And here is my computer specs:
AMD Phenom II X6 1100T 3.3GHz
ATI Radeon 5700
As you can see I have quite the powerful equipment, the display card isn't the best in the world, but it works.
In my opinion I should be able to render over 100k blocks without lagg. But again when I come to about 5000 > I start getting low fps.
So my question then becomes, how should I deal with rendering all these block? I am not asking for some specific code, but rather asking for a guideline or some tips.