ROAM implementation for terrain lod (C# help)

Hello,

After searching alot on this one i believe the attached C++ project is the most simple roam implementation that i can atleast understand what is going on in there. However, as i lack on c# knowledge, can any c# guru help me convert the recursive tesselation part of the code?
Also, the code uses openGL, i would also need some help on how to use the final vertex and triangle information with Unity mesh.

Thanks for any help.

447998–15576–$63aa0b6b2cf2.rar (372 KB)

Maybe you’ve already gotten help with this, but I think this would probably be more at home in the Collaboration forum. Also, unless someone’s feeling really generous, I’m guessing you’ll probably have to hire someone if you want this done (or at least offer a skills trade or something).

Agreed; if you’re not willing to pay/trade for someone’s time doing the work, you need to do (as much as you can of) the work yourself, asking specific questions where you get stuck.

I have a 95% complete ROAM implementation in Unity knocking around somewhere, but I don’t know how useful you’d find it; the remaining 5% of work it needs is to diagnose some bugs in the very part of the code you’re asking for help with… The good news is, getting Unity to understand the vertex and triangle information is trivial, since all Unity needs, at minimum, is a list of verts and a list of indices into the verts array. Depending on what you want to do with the resulting Mesh, though, you’ll probably also want to supply vertex normals and probably UV coordinates too.

Well, i ask for a simple lod terrain algorythm which is floating everywhere on the internet to be converted to c# and unity. Thing is, this i ask for only learning purposes because my main goal is using what i learnt with a spherical planet surface indeed.

Anyways, i cant afford to pay for someones valuable time yet.

Laurie: Can you please direct me to where your %95 implementation is? I searched everywhere without a chance.

You ask only for learning purposes? GREAT! This is a great learning experience! Dabble a bit into C++ and C# syntax and try porting it! You’ll be 32874289374% better off getting that little bit of an introduction to these great languages than having someone do it for you! (you know, fishing, teaching men to fish, yaddi yaddi yadda)

Eh, anytime i ask for some help about slightly advanced stuff which is over my head. Such a dork pops up and tells me to put some effort on it.
Dear dork, I WOULDNT ASK FOR HELP IF I COULD DO IT MYSELF! appearently i didnt make myself clear; I am not asking you to write my code, im asking (NOT) you to help convert this function into c#, (im not experienced with c# as i only known it since using unity.)

void Patch::RecursTessellate( TriTreeNode *tri,
							 int leftX,  int leftY,
							 int rightX, int rightY,
							 int apexX,  int apexY,
							 int node )
{
	float TriVariance;
	int centerX = (leftX + rightX)>>1; // Compute X coordinate of center of Hypotenuse
	int centerY = (leftY + rightY)>>1; // Compute Y coord...

	if ( node < (1<<VARIANCE_DEPTH) )
	{
		// Extremely slow distance metric (sqrt is used).
		// Replace this with a faster one!
		float distance = 1.0f + sqrtf( SQR((float)centerX - gViewPosition[0]) +
									   SQR((float)centerY - gViewPosition[2]) );
		
		// Egads!  A division too?  What's this world coming to!
		// This should also be replaced with a faster operation.
		TriVariance = ((float)m_CurrentVariance[node] * MAP_SIZE * 2)/distance;	// Take both distance and variance into consideration
	}

	if ( (node >= (1<<VARIANCE_DEPTH)) ||	// IF we do not have variance info for this node, then we must have gotten here by splitting, so continue down to the lowest level.
		 (TriVariance > gFrameVariance))	// OR if we are not below the variance tree, test for variance.
	{
		Split(tri);														// Split this triangle.
		
		if (tri->LeftChild 											// If this triangle was split, try to split it's children as well.
			((abs(leftX - rightX) >= 3) || (abs(leftY - rightY) >= 3)))	// Tessellate all the way down to one vertex per height field entry
		{
			RecursTessellate( tri->LeftChild,   apexX,  apexY, leftX, leftY, centerX, centerY,    node<<1  );
			RecursTessellate( tri->RightChild, rightX, rightY, apexX, apexY, centerX, centerY, 1+(node<<1) );
		}
	}
}

If you will not contribute even a constructive sentence, why do you even bother to come up here and post that dumb, idiotic comment???
Worst thing is, you dont even know what im talking about but just shouting around like an idiot!
Oh what the hell.

Aubergine, take a deep breath and calm down. The implication of your first post was that you had attached a complete C++ implementation of ROAM which you were hoping someone would convert into C# for you, and the responses have been in that spirit. I hadn’t looked at the RAR file you attached but, doing so now, I see my assumption about its content was correct. If all you need is help with that one function, it would have been clearer to post just that in the first place :slight_smile:

Having looked through the code you’ve now posted, it seems relatively straight forward. What part of the C# conversion do you need help with? If you can explain where you’re stuck, we can offer specific guidance.

With only a general, undirected request for help the usual response on these forum is usually to go ahead and try on your own and post the resulting code, with questions about the parts you couldn’t work out. Such responses aren’t intended to be ‘dorky’ or un-constructive; rather, they are intended to help you learn by doing. Sometimes, just making an attempt at a difficult problem, even if that attempt doesn’t result in a working solution, can be very instructive – and that often allows you to ask much more specific questions that people can quickly and easily answer.

most of that code actually converts 1:1 right as it is, what changes is that → becomes . as C# does not have different operators for by value and by ref accesses.

the other thing that changes is that it is TriTreeNode tri in the function call (so no * as there are no pointers, all is by ref in C# unless its a struct) and naturally not Patch::xxxx but just RecursTessellate within the class Patch

I hope that helps, should be all that requires any change in here.

In the first post i mentioned help about recursive tesselate function and using the final vertex and triangle information with unity.
Next time i will write such with bold uppercase letters.

Anyways thanks for the help, if ill succeed, ill share it, if not, ill ask again.

I don’t see a problem there, sorry.
This might not be obvious, but this function is in no way related to the mesh at all, it neither touches nor generates any tri or vertex at all, so there is no such thing you can need help on in relation to this function.

Split potentially is related to it and whats potentially also is related to it is the TriTreeNode which indicates that it holds at least triangle data.

Portation of mesh code is rather straight forward too you work with index buffers etc in Unity too when using the Mesh class (thats how you generate any kind of mesh, from cubes to complex terrains)
The only difference / important thing to keep in mind is the vertex - triangle restriction you need to keep in mind. A single mesh can’t have more than 64k tris / vertices. That being said, a roam with that muchdata would have a massive performance hit as consequence.

What you at worst will have to fight though and whats not portable, is if the tritreenode holds a pointer into an array (index or vertex buffer) because such memory pointers are impossible in .NET

This function recursively divides the main patch node (or the one needed in that case) into child tristrips which is a class holding the vertexdata as well as tri indice data. Check the whole archive i posted above if you are interested in.

split function does the actual math of checking if any edge of the quad is suitable for a new child triangle and creates the necessary middle vertex if the edge needs it.

EDIT: Obviously you dont see the mesh generation part in those functions.

Offcourse it uses a pointer to an array.

Well, i understand maybe not all but most of the c++ code there, just have no idea at all about how it might be written in c#.
Forexample, after you mentioned, just a minute ago i found out size_t can be represented as sizeof in c#.

As for the EDIT: My posting was only in relation to the recursive tesselation and your comment on it in relation to meshes.
There are naturally other classes but as mentioned, index arrays etc transport nearly 1 : 1 into the unity mesh class as you can see on the script reference for Mesh as it uses a index array for the triangles and the same array style as both 3D APIs for the vertex data.
So if you understood what the C++ code does, transporting it to unity will be a piece of cake :slight_smile:

Pointer to an array is no problem, thats the same as an array object in C#. But pointer to explicit array offsets would be a problem, cause there is no pointer arithmetic in C#

size_t is actually just and alias for int and it can hold all kind of data in there, though the common consense is to put in sizes of objects - classes - structs in such variables (which in all C based languages come from sizeof, including C# so it will transfer directly)

The main work the porting will take is caching variables and right code structures so you don’t get killed by the garbage collector which unhappily is one of the largest possible troublemakers.

Looking forward to see what you come up with :smile:

Okay, mostly converted the mesh and roam classes to c#
before i can continue further, i need to construct the base cube. But the direction of vertices is different in this guys opengl implementation and unitys.

below is the opengl vertices and triangles for a basic cube, but it doesnt work in unity. Anybody can see why?

		const int CUBE_VERTICES = 8;
		const int CUBE_TRIANGLES = 12;
		float[] fCube = new float[CUBE_VERTICES*3]{-0.57735f, 0.57735f, 0.57735f, 0.57735f, 0.57735f, 0.57735f, 0.57735f, -0.57735f, 0.57735f, -0.57735f, -0.57735f, 0.57735f, -0.57735f, 0.57735f, -0.57735f, 0.57735f, 0.57735f, -0.57735f, 0.57735f, -0.57735f, -0.57735f, -0.57735f, -0.57735f, -0.57735f};
		int[] nCube = new int[CUBE_TRIANGLES*3]{ 1, 0, 3, 3, 2, 1, 5, 6, 7, 7, 4, 5, 0, 1, 5, 5, 4, 0, 3, 7, 6, 6, 2, 3, 0, 4, 7, 7, 3, 0, 1, 2, 6, 6, 5, 1};
		
		for(int i = 0; i < fCube.Length; i+=3) {
			verticesN[i].x = fCube[i];
			verticesN[i].y = fCube[i+1];
			verticesN[i].z = fCube[i+2];
			//verticesN[i] = Spherical (vertices[i], 2.0F);
		}
		m.Clear();
		m.vertices = verticesN;
		m.triangles = nCube;
		m.RecalculateNormals();

Another question:
How can i extend unity vector3 class? Any simple example please? Not necessary for this one, but it would be nice to know.

Well, I’ve had issues converting my outside meshes into Unity in that the Y axis was flipped from the two systems, so that may be something going on here. Maybe try decomposing the cube down to a single face and you can track the numbers going in/out and you can figure out where the math messes up (or if the math doesn’t mess up, how the resultant values differs from what the Unity engine works with)

Regarding extending Vector3, since it’s a struct you can’t inherit from it. You’d have to roll your own. But you can always attach implicit operators to seamlessly convert the Vector3 to your custom class.

public struct MyCustomVector
{
	public float X;
	public float Y;
	public float Z;

	public MyCustomVector(x, y, z)....
	public MyCustomVector(Vector3 source).... //if you want to do it with a constructor

	public static implicit operator MyCustomVector(Vector3 source)
	{
		return new MyCustomVector(source.x, source.y, source.z);
	}

	public static implicit operator Vector3(MyCustomVector source)
	{
		return new Vector3(source.X, source.Y, source.Z);
	}
}


Vector3 source = new Vector3(0, 1, 2);
MyCustomVector customVector = source;
source = customVector;