Any less ugly and more standard way of doing this?

Started by
48 comments, last by JoeJ 4 years, 9 months ago
24 minutes ago, Acosix said:

Your game world uses 2GB of RAM?

Which would be kind of a lot of it.

About class naming. Use /* */ at the start of the code file. Describe what is each class used for.

Another naming convention is to use // comments before each class and describe per-class what is it used for.

That's 2GB for an 800 km diameter planet at about a half meter resolution. It's procedural and uses an aggressive LOD system.

I've only been programming since 1981, but remarkably I've already learned how to comment code.

Advertisement
31 minutes ago, Acosix said:

About class naming. Use /* */ at the start of the code file. Describe what is each class used for.

Another naming convention is to use // comments before each class and describe per-class what is it used for.

 

As he stated, it was a small example code. So there is no need for documentation here. Only some comments for hard to understand code sections would have been nice ?

1 hour ago, Gnollrunner said:

Yes it's kind of complicated, but on the other hand I'm pretty happy with the performance, especially given I'm using an 8 year old computer, and it should get better as I make some improvements.

In the end, that is all that matters. You don't code to get a beauty price. Sure, I would favour clean and understandable code but that is not always easy to achieve. Sometimes, a high-performance code is simply ugly. If it is hidden inside a class and never need to be touched again. Who cares? However, for your real code, you should at least make comment about what you are doing. What also might help is to stop using one-liners, but you already did this more or less in the least version you posted.

The most important thing of all: Write a good test, that ensures that your code works as supposed and immediately fails if you make an invalid change. Also, use asserts and static_asserts (I love those) as much as possible.

 

Greetings

@Acosix, 2GB is not much for planetary data. Depending on the degree of realism, granularity and additional environmental etc. data this can be magnitudes more, which leads to out-of-core rendering and streaming of data. These data structures (quadtrees, octrees, etc.) exist to keep the complexity manageable and the volume under the threshold of "overwhelming" ?

-----------

I am way behind you guys with programming in general and these data structures in special, so i may totally miss the point. My naive question is: is it really necessary to go down to the smallest unit with the spacial data structure ? And wouldn't it be doable to slide in a layer between your voxels and the data they must access, separating the two things from each other ?

It sounds to me like there is so much focus on keeping the memory footprint low instead of finding an algorithmic solution.

But you've probably thought of this before and rejected it ...

From a naive kind of view I share @Green_Baron's opinion, just if you proceduraly generate your world what is totally fine, you don't want to keep it in RAM all the time but I geuss you already know that.

Keeping the memory footrprint low I would even renounce using inheritance at all and instead put as much code as possible into global static functions. Also allocate the whole tree as a continous block of memory so you arent forced to any byte paddings and at least use a byte based indicator flag for your chunks to save another 7 bytes per class. The performance gap shouldn't be noticeable I think because you exchange a v-table lookup for a switch-case jump instead.

Just my two cents ?

5 hours ago, Green_Baron said:

@Acosix, 2GB is not much for planetary data. Depending on the degree of realism, granularity and additional environmental etc. data this can be magnitudes more, which leads to out-of-core rendering and streaming of data. These data structures (quadtrees, octrees, etc.) exist to keep the complexity manageable and the volume under the threshold of "overwhelming" ?

-----------

I am way behind you guys with programming in general and these data structures in special, so i may totally miss the point. My naive question is: is it really necessary to go down to the smallest unit with the spacial data structure ? And wouldn't it be doable to slide in a layer between your voxels and the data they must access, separating the two things from each other ?

It sounds to me like there is so much focus on keeping the memory footprint low instead of finding an algorithmic solution.

But you've probably thought of this before and rejected it ...

What regards data structure, try using classes and see how it goes?

7 hours ago, Green_Baron said:

 

I am way behind you guys with programming in general and these data structures in special, so i may totally miss the point. My naive question is: is it really necessary to go down to the smallest unit with the spacial data structure ? And wouldn't it be doable to slide in a layer between your voxels and the data they must access, separating the two things from each other ?

You know procedural generation is kind of and  overloaded term.  You can of course generate terrain and other objects procedurally,  store it on disk as meshes, and deal with it like normal terrain. You can't really do a whole planet like that because of space requirements.  If you are using voxels you can also store you data on disk in some compact form like a list of values for the corer of the voxels.  I'll probably do store a small subset of my data like that later, for doing custom areas. But again storing truly large areas is going to be prohibitively expensive.  Currently everything I do is generated by functions. There is actually no data on disk at all. As you move around it uses the voxels to generate meshes at the correct LOD.

To do a whole planet like this requires a lot of voxels that are constantly changing.  There are different strategies for handling this. Some implementations have a tree of chunks where the chunk is just a 3D array.  However in my case the voxels I use are very explicit and the tree goes all the way down to the voxel level so that a chunk can be actually quite sparse.  For the actual implementation we have the voxels themselves. Then there are the walls of each voxel which are shared.  There are the edges of each wall which are also shared and finally there are the vertexes at the corners of each voxel, again shared.  Everything is an object.  There is also a reference counting system that keeps track of everything. My voxels are NOT EVEN SLIGHTLY what you'd call light weight.

However there are some advantages to all this complexity.  First I can build and update meshes very quickly and also re-chunk quickly.  A chunk is just a point in the voxel tree hierarchy and everything under it. So to re-chunk I grow or trim the voxel tree and move the chunk point up or down.   Also since voxel walls and edges are shared I don't have to go up and down the tree to build connected meshes.  When a mesh is built it's already in once piece.  I just copy/translate it to the GPU and since I only have to update chunks that change, that is really as small subset of the whole world assuming you aren't moving too fast. I also build normals which is a bit of a trick since they have to be correct across chunk borders.

In any case the upshot of all this is the speed and memory footprint of the voxel system are absolutely the most important thing.  Everyone talks about having cool fractal and other functions that generate stuff, but that part is relatively easy to change at will.  You still need an efficient way to go from your functions to your mesh, and it should have a near infinite LOD system if you want to do planets. Therefor this is where I've been putting most of my effort.

Thanks for the clarification, m8.

A lot of things cross my mind, the limitations you mean aren't totally clear to me and people do render earth-sized planets in real time with additional data streaming and so on, but not as voxels that constantly change afaik and not with the requirement to have it all in memory (including far side for example), which indeed is impractical.

I am sorry, i tried, but can't help ... *shrug*

28 minutes ago, Green_Baron said:

Thanks for the clarification, m8.

A lot of things cross my mind, the limitations you mean aren't totally clear to me and people do render earth-sized planets in real time with additional data streaming and so on, but not as voxels that constantly change afaik and not with the requirement to have it all in memory (including far side for example), which indeed is impractical.

I am sorry, i tried, but can't help ... *shrug*

You can render a planet perfectly well from afar.  The memory requirement is small as there isn't a lot of detail. Now if you zoom in it becomes a different story. There are several things at play.

First you see less of the planet so you can cull quite a bit.  That should take less memory. On the other hand you have to have more detail so that takes a lot more memory. If you look at some open world games you will see there is a lot of "fog". This is so you don't see too far because there is nothing loaded beyond a certain point. Also look at the disk space requirement for a typical large open world game. It's huge and you are talking about a surface area a fraction of the size of even a small planet. Streaming terrain at a resolution good enough for a open world game is going to take a lot of bandwidth. That might be possible but it's not what I'm shooting for. 

If you want to be able to stand on the top of a high mountain and see across a valley to the next mountain you have to do some fancy LODing.  If you want to be able to stand on the surface and zoom out to see the whole planet, or the other way around, you are going to put your LOD system to the test. Even if you have all that all working, that gets you the rendering, but it still doesn't alleviate the space requirements and you also need physics for a game.

Now take everything I just wrote and add in voxels. A lot of planet generation code just generates height-mapped terrain. That's great for a lot of stuff. You can generate some pretty pictures. But if you want to have underground areas, overhangs and more interesting terrain, it won't handle it on it's own. Voxels on the other hand can do that, but to use them on a planetary scale adds some extra complication. Think No man's sky, but the planets there are actually tiny as far as planets go. Also add in pathing, multiplayer and modifiable terrain and that's another level of complexity. Just go ask the guys who "were" making EverQuest next.

 

Well I don't like EverQuest Oblivion as I have already seen more than 10 games where there were beautiful greenery. But a very good such example to note-not for playing in this case, but for game development-is the first Far Cry. The level of detail there is insane...stealth in the tropical jungle forest on an island which has half-transparent sand water, with white sharks circling the multiple sea docks. The theory they took there to allow such memory and GPU overhead handling-was basically to realign the light system by populating more of the island by dense jungle forest, meaning less sun's lighting rays from any direction.

13 hours ago, Gnollrunner said:

That's 2GB for an 800 km diameter planet at about a half meter resolution. It's procedural and uses an aggressive LOD system.

I've only been programming since 1981, but remarkably I've already learned how to comment code.

I wasn't talking about commenting son...I just suggested the standard commenting style...you most probably know this as well, but it was worth noting.

13 hours ago, DerTroll said:

As he stated, it was a small example code. So there is no need for documentation here. Only some comments for hard to understand code sections would have been nice ?

Not quite. I would like a detailed commented explanation in the code to see what you think a class represents.

Three of your code examples:

In the first you should try data encapsulation.

In the third, use explicit data cast converting. You use it but not in every case. Also use smart pointers. Here is what I suggest for the voxels:


//Planet.h

#include "Voxel.h"
#include <utility>
//Include graphical library files here

class Planet
{
	private:
		std::unique_ptr<Voxel> building_blocks{nullptr};
};

//Planet.cpp

//Voxel.h

#include <array>
  
class Voxel
{
	private:
		int oct[8]{0};
	public:
		Voxel(int set1,int set2,int set3,int set4,int set5,int set6,int set7, int set8);
		Voxel(std::array<int, 8>& oct_arr);
};

//Voxel.cpp  

#include "Voxel.h"
  
Voxel::Voxel(int set1,int set2,int set3,int set4,int set5,int set6,int set7, int set8)
{
  	oct[1-1]=set1;
   	oct[2-1]=set2;
  	oct[3-1]=set3;
  	oct[4-1]=set4;
  	oct[5-1]=set5;
  	oct[6-1]=set6;
  	oct[7-1]=set7;
  	oct[8-1]=set8;
}
  
Voxel::Voxel(std::array<int, 8>& oct_arr)
{
	for(size_t iterator{ 1 };iterator <= 8; iterator += 1)
  	{
  		oct[iterator - 1] = oct_arr[iterator - 1];
  	}
}

 

@Gnollrunner, (Edit: i was ninja'd by @Acosix while saving so the direct address :-)) now you've underestimated me. I know all that. I am just trying to distract you from hardened views in the hope the long sought for flash of insight might come upon you ? Your problem should be solvable imo.

I have a LOD system (height map extrusion only) with adaptive LODing capable of rendering a planet (see my git rep orf_n, under Source/Applications/TerrainCDLOD, most of the LOD magic is in the vertex shader, and it is after P. Strugar's published CDLOD algorithm, you probably know it). But there i don't subdivide the spacial data structure (a quadtree) down the vertex but to a (for now pre-set) leaf node size of let's say 8*8 or 16*16, even 64*64. Depends. Node selection for rendering takes place every frame, based on view frustum and depth of view, so the actually rendered part is quite small (without graceful fog and celestial body curvature and occlusion culling which will be added in the future, maybe 2million triangles, framerate high (~2000/s) with basic shading. Currently, i am struggling with exactly the streaming part for my terrain tiles, that is why i am so interested in that. Theoretically the only limiting factor should be the hard disk (or network server or whatever is at the other end of the cable), and a little precalculation for the orbital overview, and maybe a transition between high orbit, low orbit and ground/flight fully LODed, but to load  a tile and build the quadtree takes only little time. But seamlessly zooming in and out shouldn't be much of a problem. All do that ?

I am aware that i can't compare this to your constantly changing voxels of a bubbling and boiling planet, but are you completely sure you cannot swap part of your terrain out, and do you really need any LOD level at any height, can't you really apply part of the above (or other) techniques with adaptations for your use case ? That sounds like a pretty hard restriction to me.

 

Edit: i have never played No Man's Sky, from what i read it has its flaws. But i know for example Orbiter (which renders real world planets from published height data) and Kerbal Space Program (small planets, like your size). And there are a whole lot of planet renderers, open or closed, out there. All these don't do voxels, so a dimension of difficulty is missing. There's the challenge ?

This topic is closed to new replies.

Advertisement