Okay, I think I caught a little of that from your thread that you posted earlier, not 100% sure the best way to implement that, did you follow any tutorials at all or any examples?
Nope, just used my experience from past projects ive done that required async to be used. Ill post more of my code later, i have to go on a ENVS 10 trip to a nature center.
Much appreciated sir, we’re starting to hit deadlines on this project and not entirely sure our best way to go about this part.
We’re hoping to finish up the render to be efficient enough that you can blockpick (which I’m going to throw my hand at implementing tonight) and delete /add blocks in
Thanks, look forward to seeing what you mean!
EDIT: also just figured I’d back up why we have such bad computers, it’s a high school, though next week I’ll be outta there after I finish at least a basic version of this game. Actually plan on continuing it after
EDIT #2: Attempted our hand at implementing Threading… God that did not end well…
If you want to see our miserable attempt you can just uncomment a couple things but to be honest most of it was so bad we just didn’t even save it commented
I’m really curious to see how you went about doing the “toRemove” and “toAdd” Queue’s and such!
Okay so I’ve now tried my attempt at threading again, this time with a little more success.
I got so far as to realize that I’m having issues with doing the rebuilding of the chunks inside the subthread. The issue however is that if I queue the loading to be in the main thread, that defeats the purpose of even having the subthread as all of that loading will just end of being done in the main thread anyway…
If you want to see my code, I’m not sure what would be best to post:
https://github.com/Kyrluckechuck/EndOfYearProj/tree/ThreadedBranch
The outside loading is being done insdie of the BackgroundProcessing class for reference, the rest of the chunkupdating is being done in the ChunkManager class.
Anyone with any ideas in regards to doing the asynchronous chunk loading or if they have a way of doing chunkloading in a way that it won’t slow down my game (in another thread is the only way I can think of) please post! Help would be much appreciated as I only have a couple days left!
Thank you in advance!
Okay so i removed my ready queue completely, just pooped it out of my code.
I am keeping the remove queue though.
Here is my chunk loading based on camera position thread. (dont mind the slopiness, i always clean up my code after i finalize it.)
Thread th = new Thread(new Runnable(){
public void run(){
while (Camera.instance == null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
while (Game.isRunning()){
List<Chunkv2> chss = new ArrayList<>();
int camx = (int)Camera.instance.getPosition().x;
int camz = (int)Camera.instance.getPosition().z;
for (int[] point : MathUtil.getRadialCoords(radius)){
int tx = (camx < 0 ? ((camx + 1) / Chunkv2.X_MAX) - 1 : camx / Chunkv2.X_MAX)+point[0];
int tz = (camz < 0 ? ((camz + 1) / Chunkv2.Z_MAX) - 1 : camz / Chunkv2.Z_MAX)+point[1];
chss.add(getChunk2(tx, tz, true).build());
}
for (Chunkv2 old : getChunks()){
if (!chss.contains(old)){
delete.add(old);
}
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
}
}
});
th.start();
then i recently switched to only local face render checks, and ended up speeding up my calculations of faces to render by around 23ms. This is the face calcualation, like i said before its messy and i dont give a hoot about it being messy atm. Too busy with physics summer class to spend too much time making it look neat when i just want it working atm.
public static int X_MAX = 16, Z_MAX = 16;
public static int Y_MAX = 120;
private short[][][] ids = new short[Y_MAX][X_MAX][Z_MAX];
//LATER in a method...
List<float[]> vertexs = new ArrayList<>();
List<float[]> norms = new ArrayList<>();
List<float[]> texs = new ArrayList<>();
for (short y = 0; y < Y_MAX; y++)
for (short xx = 0; xx < X_MAX; xx++)
for (short zz = 0; zz < Z_MAX; zz++) {
//TODO: just check internal faces.
if (y == 0 || ids[y-1][xx][zz] == 0)
Cuboidv2.generate(ids[y][xx][zz], (x * X_MAX) + xx, y, (z * Z_MAX) + zz, vertexs, norms, texs, BlockFace.DOWN);
if (y == this.Y_MAX-1 || ids[y+1][xx][zz] == 0)
Cuboidv2.generate(ids[y][xx][zz], (x * X_MAX) + xx, y, (z * Z_MAX) + zz, vertexs, norms, texs, BlockFace.UP);
if (xx == 0 || ids[y][xx-1][zz] == 0)
Cuboidv2.generate(ids[y][xx][zz], (x * X_MAX) + xx, y, (z * Z_MAX) + zz, vertexs, norms, texs, BlockFace.WEST);
if (xx == this.X_MAX-1 || ids[y][xx+1][zz] == 0)
Cuboidv2.generate(ids[y][xx][zz], (x * X_MAX) + xx, y, (z * Z_MAX) + zz, vertexs, norms, texs, BlockFace.EAST);
if (zz == 0 || ids[y][xx][zz-1] == 0)
Cuboidv2.generate(ids[y][xx][zz], (x * X_MAX) + xx, y, (z * Z_MAX) + zz, vertexs, norms, texs, BlockFace.SOUTH);
if (zz == this.Z_MAX-1 || ids[y][xx][zz+1] == 0)
Cuboidv2.generate(ids[y][xx][zz], (x * X_MAX) + xx, y, (z * Z_MAX) + zz, vertexs, norms, texs, BlockFace.NORTH);
}
}
then this is for drawing, note that it only runs the draw method whence the chunk has been built by the above method. Im using display lists with va’s inside, might switch to vao’s with attrib pointers though.
this.drawID = GL11.glGenLists(1);
GL11.glNewList(drawID, GL11.GL_COMPILE);
/* BUILD */
/* ENABLE */
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
/* ADD BUFFERS */
glNormalPointer(0, normals);
GL11.glTexCoordPointer(2, 0, texcoords);//(3, GL_FLOAT, 0, colors1);
glVertexPointer(3, 0, verticies);
/* DRAW */
glDrawArrays(GL11.GL_QUADS, 0, this.drawcount);
/* DISABLE */
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
GL11.glEndList();
Then to render i just call the draw list. quite simple, all relies on the “do only when done” system now.
This below is what i have in my chunk manager when calling renderchunks.
Chunkv2 remove;
while ((remove = delete.poll()) != null){
loaded.remove(remove);
}
for (Chunkv2 chun : getChunks()) {
chun.draw();
chun.render();
}
And my MathUtils class which i use for calculating radial chunks near camera,(horrid way of doing what im doing but hell it works atm.)
public static int[][] getRadialCoords(int radius){
/*
LOGIC
(x*x) + (y*y) = radius*radius
x = radius * cos(theta)
y = radius * sin(theta)
*/
List<int[]> points = new ArrayList<>();
for (int r = 0; r <= radius; r++){
for (int theta = 0; theta < 360; theta++){
int x = (int) (r * Math.cos( theta ));
int y = (int) (r * Math.sin( theta ));
if (!isPointInList(points, new int[]{x,y})){
points.add(new int[]{x,y});
}
}
}
return points.toArray(new int[points.size()][]);
}
private static boolean isPointInList(List<int[]> list, int[] point){
for (int[] si : list){
if (si[0] == point[0] && si[1] == point[1]){
return true;
}
}
return false;
}
All in all loads up new chunks near instantly(37ms max from finding chunk doesnt exist to having it rendered), i cant move the camera fast enough to get past the loading chunks anymore. Longest part in my code atm is generating the values in the chunk. I really need to clean this code up badly the more i look at it. but i’m super busy, so if anyone is going to come on here and just be like face to the desk to the max then just please don’t waste your time! -.-
Main thing here thats good is the simplex algo i’m using for the different values but it takes roughly 78ms to generate a chunk terrain caves and all the other goodies, roughly 20,000 cuboids.
protected static short[][][] generateSolid(int x, int z){
short[][][] solidBlocks = new short[Chunkv2.Y_MAX][Chunkv2.X_MAX][Chunkv2.Z_MAX];
for (short xx = 0; xx < Chunkv2.X_MAX; xx++) {
for (short zz = 0; zz < Chunkv2.X_MAX; zz++) {
short maxHeight = (short) (85 + (int) ((World.terrain.getNoise(xx + (x * Chunkv2.X_MAX), (z * Chunkv2.X_MAX) + zz) * 25)));
for (short y = 0; y < maxHeight; y++) {
if (y == 0)
solidBlocks[Math.min(y, Chunkv2.Y_MAX)][xx][zz] = 5;
else if (y == maxHeight-1)
solidBlocks[Math.min(y, Chunkv2.Y_MAX)][xx][zz] = 1;
else if (World.cavePossibility.getNoise((xx + (x * Chunkv2.X_MAX))/100, ((z * Chunkv2.X_MAX) + zz)/100) >= 0 && y < maxHeight-13){
if (World.caves.getNoise(xx + (x * Chunkv2.X_MAX), (z * Chunkv2.X_MAX) + zz, y) >= 0)
solidBlocks[Math.min(y, Chunkv2.Y_MAX)][xx][zz] = 3;
else
solidBlocks[Math.min(y, Chunkv2.Y_MAX)][xx][zz] = 0;
} else {
solidBlocks[Math.min(y, Chunkv2.Y_MAX)][xx][zz] = 2;
}
}
}
}
return solidBlocks;
}
MAIN TODO ON ALL MY CODE IS OPTIMIZE IT AND CLEAN IT UP THANKS!
Thanks! Uber helpful, I’ll take a look at your face rendering method in an hour!
Do you mind if I ask how you implemented threading?
Well for simple tasks i use http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html but for main threads like RenderingThread and MeshCalculationThread and PhysicsEngineThread i just use Threads. Everyonce in a while ill make my own sub thread async task system.
Okay so starting to realize I’m way over my head here.
After talking with a couple people in the tech industry, I’ve come across the realization that it’s never good to have multiple classes accessing the OpenGL stream. So in short, the rendering must be done in the main class or only in one class.
At first I attempted to use the Executor Service style, but that didn’t turn out well. All I ended up doing there was implementing a way for chunks to save ASYNC when you make block changes (previously it didn’t save your changes to the world).
So, now realizing I very likely won’t be able to offset my calculations needed for rendering, it brings up a new question I’m unable to answer and was hoping someone might have an idea: How could I render ONLY the blocks I am able to see? Or just render enough blocks, not excess. (Currently I’m rendering all blocks next to air within the 9 chunk’s square around me. (my current chunk and the 8 surrounding chunks, which is about 4000 blocks rendered per chunk in a 16x16x64 world (generated using a SimplexNoise))
The second question then;
And what would be a good method of implementing the loading of the new chunks as I move into another chunk (assuming it always has the 9 square chunks in memory)?
Sorry if I’m too vague, but this is really starting to drive me nuts, everything I try is just making the game run even slower!
Hi
Accessing OpenGL from multiple threads is possible but there is no guarantee that it works reliably everywhere. The rendering can be done in multiple classes as long as they don’t try to make the OpenGL context current on several threads. Call all your rendering methods directly or indirectly in GameLoop.render() or Screen.worldRender() and it will work.
Are you sure that the bottlenecks are those computations? Do you plan to use view frustum culling in order to render only the blocks you have a chance to see?