Making a Texture LOD system

Hello Community,

I need help with some theoretical stuff (or actual code if you are super nice :P)

I have a game which has a lot of terrain.

The terrain is using textures of real world satellite images.

I’ve given the “player” full movement control (think editor controls).

So the player can actually get super close or super far from the terrain.

So what I want to do is, when the player is close to the terrain, show a 2048 texture on it, and the more he gets far from it, lower the texture down to a max of 256.

I also need the same system to turn off the terrain component for terrains that are not visible.

Any ideas how to do this?

Thanks!

I won’t bet on it, since I am at work, but unity should do mipmapping by default.

1 Like

Mipmapping is the right keyword for textures and its turned on by default. It means that additional textures are generated with lower resolution and the gpu picks the right one depending on the distance. Without mipmapping texture minification (displaying the texture smaller than it actually is) would lead to horrible flickering.

For the visibility of terrain meshes google something like “frustum culling” to get some more information on that. That should also be done by default though.

1 Like

Thank you both for your help.

I’m not sure mipmapping is good enough for me, but I will test and get back to you.

About the terrain, I know from testing that if I’m not turning off the invisible terrains my self, then I’m getting big performance lose.

So I need to know how mange it myself.

Ok, just remembered why mipmapping is not good for me.

My problem is, all the textures used in the scene are loaded to memory and because its too much, unity crashes.

I already made a script to load and unload the texture from the terrain to avoid this, but I need my script to load the correct texture according to the distance the camera is from the terrain.

[bump]
Anyone?

First, you are going to have to generate the landscape on the fly. Terrain’s are really not going to work for you. They are big and bulky and just don’t fit the bill in your case.

So on top of satellite images for diffusion, you are going to need height maps.

You need 9 pieces of terrain that scale with distance to camera. You are going to have to have a build system that builds them according to the scales you need.

Next, you are going to have to make a texture system that builds that 2048x2048 map out of the pieces you get from download. So you need to familiarize yourself with the Texture2D. Also look up texture resizing. I remember there being a script for that someplace. (UnityCommunity, I think)

I don’t see why I can’t use terrains.
I’m currently using them, and what I’m doing is turning off the terrain component when I don’t need it, everything is working fine.
About the textures, I have my map already in different sizes.

My issue is how to know when to turn off terrain component or change texture.

You can get the cameras frustum planes with GeometryUtility.CalculateFrustumPlanes. then you can feed those planes in GeometryUtility.TestPlanesAABB together with a Bounds object, describing the AABB of your terrain. This method returns true if the given AABB is inside or intersecting the camera frustum. If it is not you can safely turn off the terrain-component. See here:

When to, or not to turn on or off terrain or geomtry or load maps is up to how you build it. You could say… I am so far from this terrain, so I download a big map and stick it there, or you could do the whole AABB bounding boxes thing. Either way, your going to have to sit down at some point and say: Here are my parameters.

LOD can be done various ways. mostly, it is distance to camera.

A typical LOD code:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TestBed : MonoBehaviour{
	public class LOD{
		public GameObject gameObject;
		public float maxDistance;
	};

	public LOD[] lods = new LOD[0];
	private int current = -1;

	void Start(){
		CheckLODs ();
	}

	void Update(){
		CheckLODs ();
	}

	void CheckLODs(){
		float dist = Vector3.Distance (Camera.main.transform.position, transform.position);
		
		int index = 0;
		while(lods[index].maxDistance > dist) index++;
		
		if (index != current) {
			current = index;
			foreach(LOD lod in lods) lod.gameObject.SetActive(false);
			if(index < lods.Length) lods[index].gameObject.SetActive(true);
		}
	}
}

Using something similar, you define things the way you want them. I can’t tell you how you want them done, you set the numbers and the way to go.

Thanks for trying to help.
I can see this code working for the texture LOD if I put it on each and every terrain, but wouldn’t that have really bad performance?
having so many Update() running?
And this still not covering terrains that are out of view, how can I check if a terrain is out of view so I can turn it off?

Read my previous post. You can calculate the frustum planes once per frame, the bounds of your terrainobject once for every terrainobject, and then in each update do the frustum test with TestPlanesAABB(…). If this test returns true you can run the texture-LoD-code provided by bigmisterb. There are no heavy calculations involved so that you shouldn’t be concerned about performance.