[ ] Voxel Engine

Started by
9 comments, last by coderWalker 12 years, 11 months ago
I am making a game that utilizes a Voxel engine, that allows players to place and destroy blocks similar to Falling Sand Game however in 3d.

My Game:
moonrise.png

I am now at the point that I really need to be concerned with speed. I have been trying to code with it in mind the entire
time, however the game is now just too laggy.

The main problem causing it to be laggy is how I am rendering the chunks.
As you can see in the picture the game draws using Voxels with textures.

How the game loads and renders a chunk:
Loads the 16x16x16 array of blockID's from HDD in binary (~4kb)
Using 3 For loops (x,y,z) it checks every block to see where it does not have a block touching.
If blocks were positioned like this: [ ][ ][ ] only the 3 top, 3 bottom, and 2 side faces would be drawn.
When it finds that it needs to draw a face the face is added to 1 of 6 of that chunks draw Queues.
(I have 6 queues for each Chunk: top, bottom, left, etc) This is so that I can draw different sides with different lighting.
Once it is done processing the chunk it will not have to reprocess it again until it changes.
The Baked mesh data is then sent the GPU using the code pasted below, when drawing each frame.

Does anyone know of a way I can speed this up?

Basically I'm just loading the blocks, baking the mesh, then drawing.
Is this the best way to do this?

Would really like to hear opinions.
Thanks,
CoderWalker

Chunks code for drawing 1 side of its containing blocks:

//Send a Baked Chunks mesh to GPU
glColor4f(lightTop,lightTop,lightTop,1.0);
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D,texAtlus.texture );
glPushMatrix();
glTranslatef(x,y,z);
//Enable
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_INT, 0, &vertexTop[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &textureTop[0]);
//Draw
glDrawArrays(GL_QUADS, 0, vertexTop.size()/3);
//Disable
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();


Code to read a chunk from HDD to memory:

chunk* file::readChunk(signed int x,signed int y,signed int z)
{
std::stringstream name;
std::string temp;

chunk* newChunk;
ifstream fileStreamRead;
////Open File to load from
name.str(std::string());
name << "save/" << world0->name << "x" << x << "x" << y << "x" << z << ".txt";
temp = name.str();
fileStreamRead.open(temp.c_str(), ios::in|ios::binary);
if (fileStreamRead.is_open())
{
newChunk = new chunk(x,y,z);
////Make the 2 pointers
char *pStoreMemory;
char *pLoc;
////Allocate memory
pStoreMemory = new char [16*16*16];
pLoc = pStoreMemory;
////Copy memory to file
fileStreamRead.read(pStoreMemory,16*16*16);
////read needed data from memory
//if ((unsigned char)*pLoc != 48)
{
//newChunk->empty = false;
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
for (int k = 0; k < 16; k++)
{
newChunk->position[j][k] = (unsigned char)*pLoc;

// /!\ Add to watch Queue if block has potential to move
switch (*pLoc)
{
case steam:
case smoke:
case water1:
case water2:
case water3:
case water4:
case water5:
case lava1:
case lava2:
case lava3:
case lava4:
case lava5:
case oil1:
case oil2:
case oil3:
case oil4:
case oil5:
newChunk->liquidBufferAdd(i,j,k);
break;
}
pLoc++;
}
}
}
}
fileStreamRead.close();
delete[] pStoreMemory;
return newChunk;
}
else
{
//cout << "/!\\ Cannot open " << temp.c_str() << "\n";
newChunk = new chunk(x,y,z);
generateChunk(x,y,z,newChunk);
return newChunk;
}
}

If this post was helpful please +1 or like it !

Webstrand
Advertisement
Here's an easy one:

Using 3 For loops (x,y,z) it checks every block to see where it does not have a block touching.[/quote]

You should definitely multi-thread that (OpenMP is quite painless) or use a GPU language like OpenCL. That process sounds like it takes a lot of time.


#pragma omp parallel
{
#pragma omp for
for(int i = 1; i < size; ++i)
x = (y[i-1] + y[i+1])/2;
}


That loop would be scheduled up between all processors.

Edit: Also.. You could avoid some of those side checks entirely if you automatically eliminate one or three of them based on the direction you're looking (since they're all axis aligned). The logic to split that up might get annoying though. You could roll with a touching block function pointer that you re-assign based on the direction you're looking at in the beginning of each frame. Your code could stay pretty much the same in that case.

Edit: You should definitely build just one of those cubes with the three sides you can see and instance all of them instead of turning them into a mesh. Less buffer down-time.

Does anyone know of a way I can speed this up?


Step 1) Profile. Profile. Profile.
Step 2) act on results of profile.

Also; I assume you AREN'T rebuilding the stuff to draw every frame? Chances are most things are going to be the same between frames anyway so you might as well cache the results and only update when something significant happens such as a block changing or camera movement beyond a certain threshold. Fastest work = work not done after all.
That's what I mean by the term baking.
Basically I am creating the mesh and texture data ONLY when 1)the chunk is loaded 2) the chunk is changed.

So when the frame draws I'm just calling a draw routine in all the chunks that sends thier mesh and texture data to the GPU.

So basically the only way to speed this up would be multithread it?
I have actually tried that before, only problem is that when it creates the mesh or "bakes" it has to check adjacent chunks.
Meaning that 2 or more threads would be reading or writing the same section causing errors aka Seg Faults.
The only way to fix this is mutex's. But if only 1 thread can run at once, then defeates the purpose.
Out of the box solutions?

Below is the code that Creates the mesh for a Chunk:

How can I make this smaller, faster and better?
--Alot is repetitive just for diffrent directions.

void chunk::render()
{
//Clear arrays
vertexUp.clear();
vertexDown.clear();
vertexLeft.clear();
vertexRight.clear();
vertexTop.clear();
vertexBottom.clear();
textureUp.clear();
textureDown.clear();
textureLeft.clear();
textureRight.clear();
textureTop.clear();
textureBottom.clear();
vertex1.clear();
texture1.clear();

//Change chunks Absolute position to Array Coordinates
arrayPos.x = location.x+HALFCLIPDIST-world0->xOffset;
arrayPos.y = location.y+HALFCLIPDIST-world0->yOffset;
arrayPos.z = location.z+HALFCLIPDIST-world0->zOffset;
ref.x = world0->xOffset-location.x;
ref.y = world0->yOffset-location.y;
ref.z = world0->zOffset-location.z;

for (int x=0;x<16;x++)
{
for (int y=0;y<16;y++)
{
for (int z=0;z<16;z++)
{
if (position[x][y][z] != air)
{
switch (block[position[x][y][z]].draw)
{
case drawFullBlock:
renderAddBlock(x,y,z);
break;
case drawWithHeight:
renderAddLiquid(x,y,z);
break;
case drawTrans:
renderAddTransparent(x,y,z);
break;
}
}
}
}
}
}
void chunk::renderDraw(float x, float y, float z)
{
//render();
if (vertexTop.size()!=0)
{
//OpenGL Data
glColor4f(lightTop,lightTop,lightTop,1.0);
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D,texAtlus.texture );
glPushMatrix();
glTranslatef(x,y,z);
//Enable
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_INT, 0, &vertexTop[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &textureTop[0]);
//Draw
glDrawArrays(GL_QUADS, 0, vertexTop.size()/3);
//Disable
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
//
if (vertexBottom.size()!=0)
{
//OpenGL Data
glColor4f(lightBottom,lightBottom,lightBottom,1.0);
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D,texAtlus.texture );
glPushMatrix();
glTranslatef(x,y,z);
//Enable
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_INT, 0, &vertexBottom[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &textureBottom[0]);
//Draw
glDrawArrays(GL_QUADS, 0, vertexBottom.size()/3);
//Disable
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
//
if (vertexLeft.size()!=0)
{
//OpenGL Data
glColor4f(lightLeft,lightLeft,lightLeft,1.0);
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D,texAtlus.texture );
glPushMatrix();
glTranslatef(x,y,z);
//Enable
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_INT, 0, &vertexLeft[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &textureLeft[0]);
//Draw
glDrawArrays(GL_QUADS, 0, vertexLeft.size()/3);
//Disable
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
//
if (vertexRight.size()!=0)
{
//OpenGL Data
glColor4f(lightRight,lightRight,lightRight,1.0);
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D,texAtlus.texture );
glPushMatrix();
glTranslatef(x,y,z);
//Enable
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_INT, 0, &vertexRight[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &textureRight[0]);
//Draw
glDrawArrays(GL_QUADS, 0, vertexRight.size()/3);
//Disable
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
//
if (vertexUp.size()!=0)
{
//OpenGL Data
glColor4f(lightUp,lightUp,lightUp,1.0);
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D,texAtlus.texture );
glPushMatrix();
glTranslatef(x,y,z);
//Enable
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_INT, 0, &vertexUp[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &textureUp[0]);
//Draw
glDrawArrays(GL_QUADS, 0, vertexUp.size()/3);
//Disable
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
//
if (vertexDown.size()!=0)
{
//OpenGL Data
glColor4f(lightDown,lightDown,lightDown,1.0);
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D,texAtlus.texture );
glPushMatrix();
glTranslatef(x,y,z);
//Enable
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glVertexPointer(3, GL_INT, 0, &vertexDown[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &textureDown[0]);
//Draw
glDrawArrays(GL_QUADS, 0, vertexDown.size()/3);
//Disable
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
}
void chunk::renderDraw1(float x, float y, float z)
{
//render();
if (vertex1.size()!=0)
{
//OpenGL Data
glColor4f(lightTop,lightTop,lightTop,1.0);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D,texAtlus.texture );
glPushMatrix();
glTranslatef(x,y,z);
//Enable
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &vertex1[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &texture1[0]);
//Draw
glDrawArrays(GL_QUADS, 0, vertex1.size()/3);
//Disable
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
}
}
//Add vertex with directions
inline void chunk::renderAddVertexLeft(GLint x, GLint y, GLint z)
{
vertexLeft.push_back(x);
vertexLeft.push_back(y);
vertexLeft.push_back(z);
}
inline void chunk::renderAddVertexRight(GLint x, GLint y, GLint z)
{
vertexRight.push_back(x);
vertexRight.push_back(y);
vertexRight.push_back(z);
}
inline void chunk::renderAddVertexUp(GLint x, GLint y, GLint z)
{
vertexUp.push_back(x);
vertexUp.push_back(y);
vertexUp.push_back(z);
}
inline void chunk::renderAddVertexDown(GLint x, GLint y, GLint z)
{
vertexDown.push_back(x);
vertexDown.push_back(y);
vertexDown.push_back(z);
}
inline void chunk::renderAddVertexTop(GLint x, GLint y, GLint z)
{
vertexTop.push_back(x);
vertexTop.push_back(y);
vertexTop.push_back(z);
}
inline void chunk::renderAddVertexBottom(GLint x, GLint y, GLint z)
{
vertexBottom.push_back(x);
vertexBottom.push_back(y);
vertexBottom.push_back(z);
}
//Add texture with directions
inline void chunk::renderAddTextureLeft(GLfloat tx, GLfloat ty)
{
textureLeft.push_back(tx);
textureLeft.push_back(ty);
}
inline void chunk::renderAddTextureRight(GLfloat tx, GLfloat ty)
{
textureRight.push_back(tx);
textureRight.push_back(ty);
}
inline void chunk::renderAddTextureUp(GLfloat tx, GLfloat ty)
{
textureUp.push_back(tx);
textureUp.push_back(ty);
}
inline void chunk::renderAddTextureDown(GLfloat tx, GLfloat ty)
{
textureDown.push_back(tx);
textureDown.push_back(ty);
}
inline void chunk::renderAddTextureTop(GLfloat tx, GLfloat ty)
{
textureTop.push_back(tx);
textureTop.push_back(ty);
}
inline void chunk::renderAddTextureBottom(GLfloat tx, GLfloat ty)
{
textureBottom.push_back(tx);
textureBottom.push_back(ty);
}
//
inline void chunk::renderAddVertex1(GLfloat x, GLfloat y, GLfloat z)
{
vertex1.push_back(x);
vertex1.push_back(y);
vertex1.push_back(z);
}
inline void chunk::renderAddTexture1(GLfloat tx, GLfloat ty)
{
texture1.push_back(tx);
texture1.push_back(ty);
}
inline void chunk::renderAddBlock(int x,int y,int z)
{
//Calculate Texture Coordanates
GLfloat xMin = block[position[x][y][z]].xMin;
GLfloat xMax = block[position[x][y][z]].xMax;
GLfloat yMin = block[position[x][y][z]].yMin;
GLfloat yMax = block[position[x][y][z]].yMax;
//Left
if (x>0)
{
if (block[position[x-1][y][z]].hard==false)
{
renderAddVertexLeft(x,y,z);
renderAddVertexLeft(x,y,z+1);
renderAddVertexLeft(x,y+1,z+1);
renderAddVertexLeft(x,y+1,z);
renderAddTextureLeft(xMin,yMin);
renderAddTextureLeft(xMin,yMax);
renderAddTextureLeft(xMax,yMax);
renderAddTextureLeft(xMax,yMin);
}
}
else
{
if (world0->blockHard(15,y,z,arrayPos.x-1,arrayPos.y,arrayPos.z) == false)
{
renderAddVertexLeft(x,y,z);
renderAddVertexLeft(x,y,z+1);
renderAddVertexLeft(x,y+1,z+1);
renderAddVertexLeft(x,y+1,z);
renderAddTextureLeft(xMin,yMin);
renderAddTextureLeft(xMin,yMax);
renderAddTextureLeft(xMax,yMax);
renderAddTextureLeft(xMax,yMin);
}

}
//Right
if (x<15)
{
if (block[position[x+1][y][z]].hard==false)
{
renderAddVertexRight(x+1,y,z);
renderAddVertexRight(x+1,y,z+1);
renderAddVertexRight(x+1,y+1,z+1);
renderAddVertexRight(x+1,y+1,z);
renderAddTextureRight(xMin,yMin);
renderAddTextureRight(xMin,yMax);
renderAddTextureRight(xMax,yMax);
renderAddTextureRight(xMax,yMin);
}
}
else
{
if (world0->blockHard(0,y,z,arrayPos.x+1,arrayPos.y,arrayPos.z) == false)
{
renderAddVertexRight(x+1,y,z);
renderAddVertexRight(x+1,y,z+1);
renderAddVertexRight(x+1,y+1,z+1);
renderAddVertexRight(x+1,y+1,z);
renderAddTextureRight(xMin,yMin);
renderAddTextureRight(xMin,yMax);
renderAddTextureRight(xMax,yMax);
renderAddTextureRight(xMax,yMin);
}
}
//Up
if (y>0)
{
if (block[position[x][y-1][z]].hard==false)
{
renderAddVertexUp(x,y,z);
renderAddVertexUp(x,y,z+1);
renderAddVertexUp(x+1,y,z+1);
renderAddVertexUp(x+1,y,z);
renderAddTextureUp(xMin,yMin);
renderAddTextureUp(xMin,yMax);
renderAddTextureUp(xMax,yMax);
renderAddTextureUp(xMax,yMin);
}
}
else
{
if (world0->blockHard(x,15,z,arrayPos.x,arrayPos.y-1,arrayPos.z) == false)
{
renderAddVertexUp(x,y,z);
renderAddVertexUp(x,y,z+1);
renderAddVertexUp(x+1,y,z+1);
renderAddVertexUp(x+1,y,z);
renderAddTextureUp(xMin,yMin);
renderAddTextureUp(xMin,yMax);
renderAddTextureUp(xMax,yMax);
renderAddTextureUp(xMax,yMin);
}
}
//Down
if (y<15)
{
if (block[position[x][y+1][z]].hard == false)
{
renderAddVertexDown(x,y+1,z);
renderAddVertexDown(x,y+1,z+1);
renderAddVertexDown(x+1,y+1,z+1);
renderAddVertexDown(x+1,y+1,z);
renderAddTextureDown(xMin,yMin);
renderAddTextureDown(xMin,yMax);
renderAddTextureDown(xMax,yMax);
renderAddTextureDown(xMax,yMin);
}
}
else
{
if (world0->blockHard(x,0,z,arrayPos.x,arrayPos.y+1,arrayPos.z) == false)
{
renderAddVertexDown(x,y+1,z);
renderAddVertexDown(x,y+1,z+1);
renderAddVertexDown(x+1,y+1,z+1);
renderAddVertexDown(x+1,y+1,z);
renderAddTextureDown(xMin,yMin);
renderAddTextureDown(xMin,yMax);
renderAddTextureDown(xMax,yMax);
renderAddTextureDown(xMax,yMin);
}
}
//Bottom
if (z>0)
{
if (block[position[x][y][z-1]].hard == false)
{
renderAddVertexBottom(x+1,y,z);
renderAddVertexBottom(x+1,y+1,z);
renderAddVertexBottom(x,y+1,z);
renderAddVertexBottom(x,y,z);
renderAddTextureBottom(xMin,yMin+texOffset);
renderAddTextureBottom(xMin,yMax+texOffset);
renderAddTextureBottom(xMax,yMax+texOffset);
renderAddTextureBottom(xMax,yMin+texOffset);
}
}
else
{
if (world0->blockHard(x,y,15,arrayPos.x,arrayPos.y,arrayPos.z-1) == false)
{
renderAddVertexBottom(x+1,y,z);
renderAddVertexBottom(x+1,y+1,z);
renderAddVertexBottom(x,y+1,z);
renderAddVertexBottom(x,y,z);
renderAddTextureBottom(xMin,yMin+texOffset);
renderAddTextureBottom(xMin,yMax+texOffset);
renderAddTextureBottom(xMax,yMax+texOffset);
renderAddTextureBottom(xMax,yMin+texOffset);
}
}
//Top
if (z<15)
{
if (block[position[x][y][z+1]].hard==false)
{
renderAddVertexTop(x+1,y,z+1);
renderAddVertexTop(x+1,y+1,z+1);
renderAddVertexTop(x,y+1,z+1);
renderAddVertexTop(x,y,z+1);
renderAddTextureTop(xMin,yMin-texOffset);
renderAddTextureTop(xMin,yMax-texOffset);
renderAddTextureTop(xMax,yMax-texOffset);
renderAddTextureTop(xMax,yMin-texOffset);
}
}
else
{
if (world0->blockHard(x,y,0,arrayPos.x,arrayPos.y,arrayPos.z+1) == false)
{
renderAddVertexTop(x+1,y,z+1);
renderAddVertexTop(x+1,y+1,z+1);
renderAddVertexTop(x,y+1,z+1);
renderAddVertexTop(x,y,z+1);
renderAddTextureTop(xMin,yMin-texOffset);
renderAddTextureTop(xMin,yMax-texOffset);
renderAddTextureTop(xMax,yMax-texOffset);
renderAddTextureTop(xMax,yMin-texOffset);
}
}
}
inline void chunk::renderAddLiquid(int x,int y,int z)
{
//Calculate Texture Coordanates
GLfloat xMin = block[position[x][y][z]].xMin;
GLfloat xMax = block[position[x][y][z]].xMax;
GLfloat yMin = block[position[x][y][z]].yMin;
GLfloat yMax = block[position[x][y][z]].yMax;
GLfloat amnt = block[position[x][y][z]].amount/5.0f;
unsigned char thisBlock = position[x][y][z];
int thisBlockAmount = block[position[x][y][z]].amount;
//Left
if (x>0)
{
if (position[x-1][y][z]==air)
{
renderAddVertex1(x,y,z);
renderAddVertex1(x,y,z+amnt);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
else
{
GLfloat other = world0->getBlockAmount(x-1,y,z,arrayPos.x,arrayPos.y,arrayPos.z)/5.0f;
if ((other != amnt) && other != 0)
{
renderAddVertex1(x,y,z+other);
renderAddVertex1(x,y,z+amnt);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x,y+1,z+other);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
}
}
else
{
if (world0->getBlock(15,y,z,arrayPos.x-1,arrayPos.y,arrayPos.z) == air)
{
renderAddVertex1(x,y,z);
renderAddVertex1(x,y,z+amnt);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
else
{
GLfloat other = world0->getBlockAmount(15,y,z,arrayPos.x-1,arrayPos.y,arrayPos.z)/5.0f;
if ((other != amnt) && other != 0)
{
renderAddVertex1(x,y,z+other);
renderAddVertex1(x,y,z+amnt);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x,y+1,z+other);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
}
}
//Right
if (x<15)
{
if (position[x+1][y][z]==air)
{
renderAddVertex1(x+1,y,z);
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
else
{
GLfloat other = world0->getBlockAmount(x+1,y,z,arrayPos.x,arrayPos.y,arrayPos.z)/5.0f;
if ((other != amnt) && other != 0)
{
renderAddVertex1(x+1,y,z);
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
}
}
else
{
if (world0->getBlock(15,y,z,arrayPos.x+1,arrayPos.y,arrayPos.z) == air)
{
renderAddVertex1(x+1,y,z);
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
else
{
GLfloat other = world0->getBlockAmount(15,y,z,arrayPos.x+1,arrayPos.y,arrayPos.z)/5.0f;
if ((other != amnt) && other != 0)
{
renderAddVertex1(x+1,y,z);
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
}
}
//Up
if (y>0)
{
if (position[x][y-1][z]==air)
{
renderAddVertex1(x,y,z);
renderAddVertex1(x,y,z+amnt);
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
else
{
GLfloat other = world0->getBlockAmount(x,y-1,z,arrayPos.x,arrayPos.y,arrayPos.z)/5.0f;
if ((other != amnt) && other != 0)
{
renderAddVertex1(x,y,z);
renderAddVertex1(x,y,z+amnt);
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
}
}
else
{
if (world0->getBlock(x,15,z,arrayPos.x,arrayPos.y+1,arrayPos.z) == air)
{
renderAddVertex1(x,y,z);
renderAddVertex1(x,y,z+amnt);
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
else
{
GLfloat other = world0->getBlockAmount(x,15,z,arrayPos.x,arrayPos.y+1,arrayPos.z)/5.0f;
if ((other != amnt) && other != 0)
{
renderAddVertex1(x,y,z);
renderAddVertex1(x,y,z+amnt);
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
}
}
//Down
if (y<15)
{
if (position[x][y+1][z]==air)
{
renderAddVertex1(x,y+1,z);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
else
{
GLfloat other = world0->getBlockAmount(x,y+1,z,arrayPos.x,arrayPos.y,arrayPos.z)/5.0f;
if ((other != amnt) && other != 0)
{
renderAddVertex1(x,y+1,z);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
}
}
else
{
if (world0->getBlock(x,0,z,arrayPos.x,arrayPos.y-1,arrayPos.z) == air)
{
renderAddVertex1(x,y+1,z);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
else
{
GLfloat other = world0->getBlockAmount(x,0,z,arrayPos.x,arrayPos.y-1,arrayPos.z)/5.0f;
if ((other != amnt) && other != 0)
{
renderAddVertex1(x,y+1,z);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);
}
}
}
//Top
if (z<15)
{
if (block[position[x][y][z+1]].amount != 5 || position[x][y][z+1]==air)
{
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x,y,z+amnt);
renderAddTexture1(xMin,yMin-texOffset);
renderAddTexture1(xMin,yMax-texOffset);
renderAddTexture1(xMax,yMax-texOffset);
renderAddTexture1(xMax,yMin-texOffset);
}
}
else
{
if (world0->getBlockAmount(x,y,0,arrayPos.x,arrayPos.y,arrayPos.z+1) != 5 || world0->getBlock(x,y,0,arrayPos.x,arrayPos.y,arrayPos.z+1) == air )
{
renderAddVertex1(x+1,y,z+amnt);
renderAddVertex1(x+1,y+1,z+amnt);
renderAddVertex1(x,y+1,z+amnt);
renderAddVertex1(x,y,z+amnt);
renderAddTexture1(xMin,yMin-texOffset);
renderAddTexture1(xMin,yMax-texOffset);
renderAddTexture1(xMax,yMax-texOffset);
renderAddTexture1(xMax,yMin-texOffset);
}
}
//Bottom
if (z>0)
{
if (position[x][y][z-1] == thisBlock && block[position[x][y][z-1]].amount!=5)
{
renderAddVertex1(x+1,y,z);
renderAddVertex1(x+1,y+1,z);
renderAddVertex1(x,y+1,z);
renderAddVertex1(x,y,z);
renderAddTexture1(xMin,yMin+texOffset);
renderAddTexture1(xMin,yMax+texOffset);
renderAddTexture1(xMax,yMax+texOffset);
renderAddTexture1(xMax,yMin+texOffset);
}
}
else
{
if (world0->getBlockAmount(x,y,15,arrayPos.x,arrayPos.y,arrayPos.z-1) == thisBlock && block[world0->getBlock(x,y,15,arrayPos.x,arrayPos.y,arrayPos.z-1)].amount!=5)
{
renderAddVertex1(x+1,y,z);
renderAddVertex1(x+1,y+1,z);
renderAddVertex1(x,y+1,z);
renderAddVertex1(x,y,z);
renderAddTexture1(xMin,yMin+texOffset);
renderAddTexture1(xMin,yMax+texOffset);
renderAddTexture1(xMax,yMax+texOffset);
renderAddTexture1(xMax,yMin+texOffset);
}
}
}

inline void chunk::renderAddTransparent(int x,int y,int z)
{
//Calculate Texture Coordanates
GLfloat xMin = block[position[x][y][z]].xMin;
GLfloat xMax = block[position[x][y][z]].xMax;
GLfloat yMin = block[position[x][y][z]].yMin;
GLfloat yMax = block[position[x][y][z]].yMax;

//Left
renderAddVertex1(x,y,z);
renderAddVertex1(x,y,z+1);
renderAddVertex1(x,y+1,z+1);
renderAddVertex1(x,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);

//Right
renderAddVertex1(x+1,y,z);
renderAddVertex1(x+1,y,z+1);
renderAddVertex1(x+1,y+1,z+1);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);

//Up
renderAddVertex1(x,y,z);
renderAddVertex1(x,y,z+1);
renderAddVertex1(x+1,y,z+1);
renderAddVertex1(x+1,y,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);

//Down
renderAddVertex1(x,y+1,z);
renderAddVertex1(x,y+1,z+1);
renderAddVertex1(x+1,y+1,z+1);
renderAddVertex1(x+1,y+1,z);
renderAddTexture1(xMin,yMin);
renderAddTexture1(xMin,yMax);
renderAddTexture1(xMax,yMax);
renderAddTexture1(xMax,yMin);

//Bottom
renderAddVertex1(x+1,y,z);
renderAddVertex1(x+1,y+1,z);
renderAddVertex1(x,y+1,z);
renderAddVertex1(x,y,z);
renderAddTexture1(xMin,yMin+texOffset);
renderAddTexture1(xMin,yMax+texOffset);
renderAddTexture1(xMax,yMax+texOffset);
renderAddTexture1(xMax,yMin+texOffset);

//Top
renderAddVertex1(x+1,y,z+1);
renderAddVertex1(x+1,y+1,z+1);
renderAddVertex1(x,y+1,z+1);
renderAddVertex1(x,y,z+1);
renderAddTexture1(xMin,yMin-texOffset);
renderAddTexture1(xMin,yMax-texOffset);
renderAddTexture1(xMax,yMax-texOffset);
renderAddTexture1(xMax,yMin-texOffset);
}
If this post was helpful please +1 or like it !

Webstrand
Is the code just too over-whelming?
If this post was helpful please +1 or like it !

Webstrand
Before you can hope to speed it up, or get advice on speeding it up, you're going to need to use a profiler and actually tell us what's slow

Is it the GPU or CPU that's the bottleneck? Is there too much GPU work going on every frame? Is the game slow, even when no block updating is being done? Or is it just frames that need to update the baked meshes slow?

Get some profilers (for both GPU and CPU), and identify the actual bottlenecks. Only then can you hope to figure out how to eliminate those pieces or make them faster

Meaning that 2 or more threads would be reading or writing the same section causing errors aka Seg Faults.


That's not a SegFault. Yes, making that for loop parallel would be a bad idea, because of all the vector pushing. But nothing should keep you from at least processing the chunks in parallel, as they all seem to have their own vectors anyway.

You fail to mention WHAT is slow. Are your fps too low? Does loading take to long? Processing of chunks? Without knowing which part of an application is causing the slow downs it is really pointless to optimize anything and just hope to accidentally change the right thing. For low fps you should ask yourself: how much geometry do I try to render? How many state changes and draw calls am I using (hint about a huge b**tload more than necessary which may or may not be filtered by the driver). If nothing of that is the obviously problem you can try using VBOs instead of vertex arrays.

As for the code... well, it's code. Without context.

-What is block and position?

-What's the point of the calculations before that part?

-Why is the function called render and is it executed every single frame?

-Why is there so much pointlessly redundant code and setup in every single if-block? None of them has any reason to contain more than 4 lines.

-All the copy/pasted Add-functions seem to achieve the opposite of what functions are good for (reduce redundancy and copy/pasting) by not passing the vector as parameter.

-Code that really would benefit from these seperate functions is an endless copy/paste orgy (why isn't AddTop able to figure out which vertices to add on its own instead of painfully passing them one by one?)

Texture atlases are used to minimize the amount of texture binding, yet you happily call bindTexture 6 times per chunk, which in MC terms is almost 4000 times per frame when there is no reason to call it more than once per frame.

Edit: You should definitely build just one of those cubes with the three sides you can see and instance all of them instead of turning them into a mesh. Less buffer down-time.[/quote

It's funny everybody always points out how you can never see more than 3 sides of a cube, but fails to mention a concept to exploit it that wouldn't require either constant or at least significantly more updating of vertex buffers.

So let's first decide that we definitely do NOT want to update every frame, just because a shifted perspective means we might now see tops or bottoms previously unseen. That means we always have to draw at least 4 sides. Further more, for chunks directly in the line with the one the player is in, you can't skip the sides, because depending on the position either one could be visible, meaning you can only skip a single side (the one facing away). For the chunk the player is in, no side can be skipped at all.

So let's compare ignoring that and trying to use it assuming 25x25 chunks (seems to be what MC uses for far view distance):

Ignoring backfaces:
-When crossing a chunk border you load and update 25 chunks (loaded over the memory previously used by the 25 chunks that became invisible). You're done.

Exploiting backfaces (no top/bottom):
-When crossing a chunk border you load 25 chunks (again with the memory of the now useless chunks)
-You update the 25 chunks previously in line with the player chunk (which can now hide one more face per block)
-You update the 25 now in line with the player chunk (which can only hide the one facing away)
-You update the 25 you just loaded (which can also hide 2 faces)

Essentially you trade in rendering a few faces less (which is fast) for 3 times more updating (which usually hurts a lot). Unless polycount really turns out the issue, I'd stay far away from that.
f@dzhttp://festini.device-zero.de
That's not a SegFault. Yes, making that for loop parallel would be a bad idea, because of all the vector pushing. But nothing should keep you from at least processing the chunks in parallel, as they all seem to have their own vectors anyway.

You fail to mention WHAT is slow. Are your fps too low? Does loading take to long? Processing of chunks? Without knowing which part of an application is causing the slow downs it is really pointless to optimize anything and just hope to accidentally change the right thing. For low fps you should ask yourself: how much geometry do I try to render? How many state changes and draw calls am I using (hint about a huge b**tload more than necessary which may or may not be filtered by the driver). If nothing of that is the obviously problem you can try using VBOs instead of vertex arrays.

[color="#006400"]When the player stays in the same Chunk the FPS are fine >60. It only uses ~10% of my Geforce 8800GT to render the frames, so not bad at all.
The problem is when the player moves to another chunk.
The game slows because it's having to render all of those new chunks 11^3 chunks with (16x16x16 blocks each) for now. Goal would be 25.

As for the code... well, it's code. Without context.

-What is block and position?

[color="#006400"]Position is a 3d array (16x16x16) containing all the block ID's.
Block is a 1d array containing the texcoords, fluid amount, draw type, etc

Here is all the data Block contains:

//Generate Block Data
for (int y=0;y<4;y+=1)
{
for (int x=0;x<16;x++)
{
block[x+(y*16)].xMin = tsMax(x)+0.0001f;
block[x+(y*16)].xMax = tsMin(x)-0.0001f;
block[x+(y*16)].yMin = tsMin(y*3)+texOffset-0.0001f;
block[x+(y*16)].yMax = tsMax(y*3)+texOffset+0.0001f;
block[x+(y*16)].draw = drawFullBlock;
block[x+(y*16)].reacts = false;
block[x+(y*16)].flammable = false;
block[x+(y*16)].hard = true;
block[x+(y*16)].group = static_cast<objBlock>(x+(y*16));
block[x+(y*16)].amount = 0;
}
}
//Fix Multiple Size Blocks
block[water2].xMin = block[water1].xMin;
block[water2].xMax =block[water1].xMax;
block[water2].yMin = block[water1].yMin;
block[water2].yMax =block[water1].yMax;
block[water3].xMin = block[water1].xMin;
block[water3].xMax =block[water1].xMax;
block[water3].yMin = block[water1].yMin;
block[water3].yMax =block[water1].yMax;
block[water4].xMin = block[water1].xMin;
block[water4].xMax =block[water1].xMax;
block[water4].yMin = block[water1].yMin;
block[water4].yMax =block[water1].yMax;
block[water5].xMin = block[water1].xMin;
block[water5].xMax =block[water1].xMax;
block[water5].yMin = block[water1].yMin;
block[water5].yMax =block[water1].yMax;

block[lava2].xMin = block[lava1].xMin;
block[lava2].xMax =block[lava1].xMax;
block[lava2].yMin = block[lava1].yMin;
block[lava2].yMax =block[lava1].yMax;
block[lava3].xMin = block[lava1].xMin;
block[lava3].xMax =block[lava1].xMax;
block[lava3].yMin = block[lava1].yMin;
block[lava3].yMax =block[lava1].yMax;
block[lava4].xMin = block[lava1].xMin;
block[lava4].xMax =block[lava1].xMax;
block[lava4].yMin = block[lava1].yMin;
block[lava4].yMax =block[lava1].yMax;
block[lava5].xMin = block[lava1].xMin;
block[lava5].xMax =block[lava1].xMax;
block[lava5].yMin = block[lava1].yMin;
block[lava5].yMax =block[lava1].yMax;

block[oil2].xMin = block[oil1].xMin;
block[oil2].xMax =block[oil1].xMax;
block[oil2].yMin = block[oil1].yMin;
block[oil2].yMax =block[oil1].yMax;
block[oil3].xMin = block[oil1].xMin;
block[oil3].xMax =block[oil1].xMax;
block[oil3].yMin = block[oil1].yMin;
block[oil3].yMax =block[oil1].yMax;
block[oil4].xMin = block[oil1].xMin;
block[oil4].xMax =block[oil1].xMax;
block[oil4].yMin = block[oil1].yMin;
block[oil4].yMax =block[oil1].yMax;
block[oil5].xMin = block[oil1].xMin;
block[oil5].xMax =block[oil1].xMax;
block[oil5].yMin = block[oil1].yMin;
block[oil5].yMax =block[oil1].yMax;


//Set Special Property - Draw
block[glass].draw = drawTrans;
block[ocean].draw = drawWithHeight;
block[ice].draw = drawTrans;
block[smoke].draw = drawTrans;
block[steam].draw = drawTrans;
block[air].draw = drawTrans;
block[water1].draw = drawWithHeight;
block[water2].draw = drawWithHeight;
block[water3].draw = drawWithHeight;
block[water4].draw = drawWithHeight;
block[water5].draw = drawWithHeight;
block[oil1].draw = drawWithHeight;
block[oil2].draw = drawWithHeight;
block[oil3].draw = drawWithHeight;
block[oil4].draw = drawWithHeight;
block[oil5].draw = drawWithHeight;
block[lava1].draw = drawWithHeight;
block[lava2].draw = drawWithHeight;
block[lava3].draw = drawWithHeight;
block[lava4].draw = drawWithHeight;
block[lava5].draw = drawWithHeight;
//Set Special Property - Reacts
block[sand].reacts = true;
block[fire].reacts = true;
block[tree].reacts = true;
block[wood].reacts = true;
block[coal].reacts = true;
block[ocean].reacts = true;
block[coal].reacts = true;
block[ice].reacts = true;
block[steam].reacts = true;
block[smoke].reacts = true;
block[water1].reacts = true;
block[water2].reacts = true;
block[water3].reacts = true;
block[water4].reacts = true;
block[water5].reacts = true;
block[oil1].reacts = true;
block[oil2].reacts = true;
block[oil3].reacts = true;
block[oil4].reacts = true;
block[oil5].reacts = true;
block[lava1].reacts = true;
block[lava2].reacts = true;
block[lava3].reacts = true;
block[lava4].reacts = true;
block[lava5].reacts = true;
//Set Special Property - Flammable
block[wood].flammable=true;
block[tree].flammable=true;
//Set Special Property - Hard
block[water1].hard = false;
block[lava1].hard = false;
block[oil1].hard = false;
block[water2].hard = false;
block[lava2].hard = false;
block[oil2].hard = false;
block[water3].hard = false;
block[lava3].hard = false;
block[oil3].hard = false;
block[water4].hard = false;
block[lava4].hard = false;
block[oil4].hard = false;
block[water5].hard = false;
block[lava5].hard = false;
block[oil5].hard = false;
block[ocean].hard = false;
block[air].hard = false;
//Set Special Property - amount
block[water1].amount = 1;
block[water2].amount = 2;
block[water3].amount = 3;
block[water4].amount = 4;
block[water5].amount = 5;
block[lava1].amount = 1;
block[lava2].amount = 2;
block[lava3].amount = 3;
block[lava4].amount = 4;
block[lava5].amount = 5;
block[oil1].amount = 1;
block[oil2].amount = 2;
block[oil3].amount = 3;
block[oil4].amount = 4;
block[oil5].amount = 5;
block[air].amount = 0;
block[ocean].amount = 5;
//Set Special Property - amount
block[water1].group = water5;
block[water2].group = water5;
block[water3].group = water5;
block[water4].group = water5;
block[water5].group = water5;
block[lava1].group = lava5;
block[lava2].group = lava5;
block[lava3].group = lava5;
block[lava4].group = lava5;
block[lava5].group = lava5;
block[oil1].group = oil5;
block[oil2].group = oil5;
block[oil3].group = oil5;
block[oil4].group = oil5;
block[oil5].group = oil5;


-What's the point of the calculations before that part?

-Why is the function called render and is it executed every single frame?

[color="#006400"]Render is just a name I came up with, what It does is makes the draw data from the blockID array.
It is only called Once (when the chunk laods), then later when the chunk is modified.
Meaning Chunk load time takes a bit, however helps a ton when drawing.

-Why is there so much pointlessly redundant code and setup in every single if-block? None of them has any reason to contain more than 4 lines.

[color="#006400"]I origonally had just a addVertex() function meaning I would have to specify the verts.
I have the diffrent buffers so I can just glColor() before drawing each side for *lighting.
However this is a very poor method as each block can not have it's own light values.
Should I just have one array per Chunk?
You can send Verts, and texCoords using ClientSide, can you send lighting information?
Or is there a way to have the blocks that emit light (lava, fire) ?

-All the copy/pasted Add-functions seem to achieve the opposite of what functions are good for (reduce redundancy and copy/pasting) by not passing the vector as parameter.

[color="#006400"]If thier decalred as inline, will it take the same amount of time as now even if I pass the queue as a parameter?
However if I switch to one queue per chunk, then this is not even needed.

-Code that really would benefit from these seperate functions is an endless copy/paste orgy (why isn't AddTop able to figure out which vertices to add on its own instead of painfully passing them one by one?)
[color="#006400"]Again use to be an old function just addVertex()
[color="#006400"]However if I switch to one queue per chunk, then this is not even needed.
Arn't orgys a good thing? j/k

Texture atlases are used to minimize the amount of texture binding, yet you happily call bindTexture 6 times per chunk, which in MC terms is almost 4000 times per frame when there is no reason to call it more than once per frame.
[color="#006400"]Thanks a ton for noticing that!

Edit: You should definitely build just one of those cubes with the three sides you can see and instance all of them instead of turning them into a mesh. Less buffer down-time.[/quote

It's funny everybody always points out how you can never see more than 3 sides of a cube, but fails to mention a concept to exploit it that wouldn't require either constant or at least significantly more updating of vertex buffers.
[color="#006400"]Considering the verticies are only modified once this really isn't needed. I mean it barely uses the GPU now.
If I wanted I could even save alot of time and also send the normals to the GPU, however with my clipping routine it may not be worth-it.

So let's first decide that we definitely do NOT want to update every frame, just because a shifted perspective means we might now see tops or bottoms previously unseen. That means we always have to draw at least 4 sides. Further more, for chunks directly in the line with the one the player is in, you can't skip the sides, because depending on the position either one could be visible, meaning you can only skip a single side (the one facing away). For the chunk the player is in, no side can be skipped at all.

[color="#006400"]Chunks do not need to be redone at all unless modified.
So no calculation at all is needed. Just passing the drawData to the GPU.

So let's compare ignoring that and trying to use it assuming 25x25 chunks (seems to be what MC uses for far view distance):

Ignoring backfaces:
-When crossing a chunk border you load and update 25 chunks (loaded over the memory previously used by the 25 chunks that became invisible). You're done.
[color="#006400"]were good here.

Exploiting backfaces (no top/bottom):
-When crossing a chunk border you load 25 chunks (again with the memory of the now useless chunks)
-You update the 25 chunks previously in line with the player chunk (which can now hide one more face per block)
-You update the 25 now in line with the player chunk (which can only hide the one facing away)
-You update the 25 you just loaded (which can also hide 2 faces)

Essentially you trade in rendering a few faces less (which is fast) for 3 times more updating (which usually hurts a lot). Unless polycount really turns out the issue, I'd stay far away from that.
[color="#006400"]Yea, poly count is definetly the least of my worries.

I just realized this really is kinda hard to explain and a picture wouldn't really do it either.
I have the game online, all you have to do is make an account really quick
The game is on this page: http://webstrand.comoj.com/betatesting.php
invide code: bl0ck
0 not o!

Thanks for all the points so far!
If this post was helpful please +1 or like it !

Webstrand
Also the reason for some checking position, and some checking using world0 is that:
When calling world0 it checks to make sure the coordinates are in the correct chunk, and position is direct access to the correct data with no validation.

Basically World sets the target to find which chunk pointer and which position in that chunk to use.

void world::setTarget(float x, float y, float z, signed int xChunkOffset, signed int yChunkOffset, signed int zChunkOffset)
{
//Sets the target of other functions
//tmpOffset (Chunk in Map)
//tmpPoint (Block in Chunk)

//Save origonals
tmpInitOffset.x=xChunkOffset;
tmpInitOffset.y=yChunkOffset;
tmpInitOffset.z=zChunkOffset;
tmpInitPoint.x = x;
tmpInitPoint.y = y;
tmpInitPoint.z = z;

//Get full offset in blocks not chunks
x-=(xChunkOffset*16);
y-=(yChunkOffset*16);
z-=(zChunkOffset*16);
//Round to closest Block
tmpPoint.z=align(z);
tmpPoint.y=align(y);
tmpPoint.x=align(x);
//Get X Chunk
tmpOffset.x=0;
while (tmpPoint.x>=16)
{
tmpPoint.x-=16;
tmpOffset.x+=1;
}
while (tmpPoint.x<0)
{
tmpPoint.x+=16;
tmpOffset.x-=1;
}
//Get Y Chunk
tmpOffset.y=0;
while (tmpPoint.y>=16)
{
tmpPoint.y-=16;
tmpOffset.y+=1;
}
while (tmpPoint.y<0)
{
tmpPoint.y+=16;
tmpOffset.y-=1;
}
//Get Z Chunk
tmpOffset.z=0;
while (tmpPoint.z>=16)
{
tmpPoint.z-=16;
tmpOffset.z+=1;
}
while (tmpPoint.z<0)
{
tmpPoint.z+=16;
tmpOffset.z-=1;
}
//Apply the Offsets
tmpOffset.x+=HALFCLIPDIST;
tmpOffset.y+=HALFCLIPDIST;
tmpOffset.z+=HALFCLIPDIST;
return;
}

Then returns weither or not it is hard

return block[Chunk[xChunkOffset][yChunkOffset][zChunkOffset]->position[x][y][z]].hard;


Would there be a faster way to calculate the target without all this time consuming code with While statements?
If this post was helpful please +1 or like it !

Webstrand
[color="#006400"]
The game slows because it's having to render all of those new chunks 11^3 chunks with (16x16x16 blocks each) for now. Goal would be 25.


So your visible world is 11 chunks in each direction? Why would you "render" them all (are we talking actual rendering or just the function misnamed "render") when only 11^2 chunks have been loaded? The only affected chunks are the loaded ones and their neighbors (which can usually also be only 11^2 chunks).
f@dzhttp://festini.device-zero.de

This topic is closed to new replies.

Advertisement