Making a terrain using L3DT
From Leadwerks Developer Wiki
Contents |
Introduction
This tutorial will show how to make a terrain suitable for Leadwerks Engine
using the free L3DT Large 3D Terrain Generator tool.
Install L3DT
L3DT is terrain creation tool which can be downloaded for free
from http://www.bundysoft.com/L3DT/downloads
After you've downloaded and installed terragen,
Start the program and this is what you should get.
Background
In Leadwerks Engine there are several ways to present a terrain. In this
tutorial we will concentrate on using a height-map together with an alpha-map
where the RGB and Alpha values defines where 4 layers of texture should be painted.
So we need
- A heightmap
- An RGBA alphamap
- 4 textures including normalmapping, one for each layer
L3DT materials
If you bring up the Material Manager you will find a list of different
materials. Here is the place to add your own materials.
Each material consist of one or more diffuse textures together with it's normal map.
So if you want to use your own textures while working with L3DT this is the place
to either edit an existing material or create a new one.
For this tutorial we will use existing materials though.
L3DT Climates
You may assign different climates to a terrain in L3DT. A Climate is a collection
of Land Types together with settings telling where each Land Type will be painted on the terrain.
A Land Type is a collection of one or several Materials.
If you bring up the 'Climate Manager' you can see all Climates. This is the place to
create your own climates or edit existing ones.
As we only want 4 land types (Leadwerks support of Alphamap layers permits 4 layers) we will
make an new climate to be sure that we only use 4 Land Types and 4 textures.
Fortunately there is already a climate that has exactly 4 Land Types. We can copy that climate
to get a start. In the Climate Manager, copy the climate 'Spring Mars (FA)' and give the copy
some nice name as 'Leadwerks tutorial' or whatever.
Good. Now we have a climate with exactly 4 land types. One Land Type for each Alpha-map channel
Red, Green and Blue channels and one for the transparency channel.
We don't need to bother about which textures the climate uses. The important thing is that
is uses 4 land types.
One important thing we must do is to set the color for each land type. For each land type, double
click and in the 'General' tab change the color
- Make 'Flatland' red
- Make 'Rocky ground' green
- Make 'Rock slope' blue
- Make 'Cliff face' black
That's all that we need for getting a correct Alpha-map out from our terrain.
Generate the terrain
Time to create a terrain. Click on new map and select 'Design/inflate' which will
produce a random terrain (If you want to build from scratch select Design/inflate (blank)).
- Set X = Y = 16
- Horiz. scale(m) = 1
This will give a reasonable big terrain. Feel free to text other combinations.
In next dialog please select our new climate 'Leadwerks tutorial' as Default climate.
Change any other parameters at your desire. For this tutorial I left them at their default positions
Next dialog is the 'Calculation queue'. Mark all check-boxes.
Water flooding
I desired to have a water level at 0. Test with other settings.
Then I left the Water-table modeling values at their default values.
Attributes
Nothing much to add here. Accept and go on.
Normal mapping
Same here. Accept and go on.
Light mapping
Here you may chane the sun direction and elevation. You may also draw the Sun/ambient ratio slider to the left to get softer shadows.
Here I prefer to disable water effect or else the water tends to be to blue.
You can leave the texture settings as they are as we are not going to use the
produced terrain texture image anyway.
Next just sit down and watch L3DT working.
L3DT output
L3DT produces a bunch of maps. We are going to use 3 of them. </div>
Heightfield
This is our heightmap.
Let's export it. Press Ctrl+E and select PNG as File format and save as 'terrain_hm.png'
in your application directory or somewhere else where you keep you stuff.
Attributes map
This is our alpha-map. Save it as 'terrain_am.png'.
Before saving click on Options, then double click on
'ColourMapped(bool)' so it becomes true.
Terrain Normals
This is our normal-map. Save it as 'terraindot3.png'
Save
This concludes what's needed in L3DT. Save your work and close L3DT.
Implementing the terrain using LEO
To check how the terrain looks we must write an application to show it.
This application shows the terrain, has a sky (see my Making a sky using Terragen tutorial)
and a spectator that can walk around in the terrain.
Using Visual Studio create a new Win32 Console empty project and give it some nice name.
Add the leo.cpp file to the project and also in Additional Include Directories enter the
path to your CPP directorys.
Add a new file Test.cpp to the project and copy following code to that file.
You can also check LEO - Visual Studio 2008 Setup for instructions on how to create a LEO project with Visual Studio
This code is for LE 2.23
#include "leo.h" using namespace LEO ; #pragma warning( disable : 4996 ) // === PROGRAM ENTRY ==== int main(int argc, char **argv) { const float HEIGHT_SCALE = 132 ; const float SPECTATOR_LENGTH = 1.8f ; #define START_X 64 #define START_Z 64 bool debugPhysics = false ; bool debugGravity = false ; // ================== INIT ==================== Engine engine( "LEO testing terrain",800,600); Engine::SetFilters(); // ================== WORLD ==================== // create and init world World world( CREATENOW ) ; world.Set(); World::SetCollisions(1,1) ; World::SetAmbientLight( Vec3(0) ); // ================== TERRAIN ================= Terrain terrain( 1024 ); terrain.SetType( SLIDINGCOLLISION); terrain.SetScale( Vec3(1,HEIGHT_SCALE,1) ); terrain.LoadHeightmap( "abstract::terrain_hm.raw" ); terrain.LoadAlphamap ( "abstract::terrain_am.dds" ); terrain.SetTexture( Texture("abstract::grass.dds") , 0, 0 ) ; terrain.SetTexture( Texture("abstract::grassdot3.dds") , 1, 0 ) ; terrain.SetTextureMappingMode( HORIZONTAL, 0 ) ; terrain.SetTextureScale( 12, 0 ) ; terrain.SetTexture( Texture("abstract::stone.dds") , 0, 1 ) ; terrain.SetTexture( Texture("abstract::stonedot3.dds") , 1, 1 ) ; terrain.SetTextureMappingMode( HORIZONTAL, 1 ) ; terrain.SetTextureScale( 12, 1 ) ; terrain.SetTexture( Texture("abstract::dirt.dds") , 0, 2 ) ; terrain.SetTexture( Texture("abstract::dirtdot3.dds") , 1, 2 ) ; terrain.SetTextureMappingMode( HORIZONTAL, 2 ) ; terrain.SetTextureScale( 6, 2 ) ; terrain.SetTexture( Texture("abstract::mud.dds") , 0, 3 ) ; terrain.SetTexture( Texture("abstract::muddot3.dds") , 1, 3 ) ; terrain.SetTextureMappingMode( HORIZONTAL, 3 ) ; terrain.SetTextureScale( 14, 3 ) ; terrain.UpdateNormals() ; // ================== SKY ===================== // create and init sky World sky( CREATENOW ) ; Material skymat( "abstract::sky.mat" ); Cube skybox( CREATENOW ) ; skybox.Flip() ; skybox.Paint( skymat ); skybox.SetPosition( Vec3(0) ) ; skybox.SetScale( Vec3(100) ) ; // create and init camera for sky Camera skycam( CREATENOW ) ; skycam.SetClearMode( BUFFER_DEPTH); // light sky.Set() ; World::SetAmbientLight( Vec3(1) ); // ================== SPECTATOR ================ // create a spectactor world.Set(); BodySphere spec(1); spec.SetGravityMode(false); spec.SetMass(1) ; spec.SetDamping(1,0); spec.SetType( SLIDINGCOLLISION ); spec.SetSweptCollision(); // inital position ; TVec3 specposition = Vec3( START_X, terrain.GetElevation(START_X, START_Z)+4*SPECTATOR_LENGTH, START_Z ); TVec3 specforce = Vec3(0) ; spec.SetPosition( specposition ) ; // ================== CAMERA ================ // create and init camera for world Camera cam( CREATENOW ) ; cam.SetClearMode( BUFFER_DEPTH ); cam.SetRange(0.1f,1000); flt camspeed = 10.0f; TVec3 camrotation = Vec3(0) ; TVec3 camposition = specposition ; cam.SetPosition( camposition ); cam.SetRotation( camrotation ); // ================== MOUSE ================ flt mx=0.0f, my=0.0f; int SX = Engine::GetWidth(); int SY = Engine::GetHeight(); int CX = SX/2; int CY = SY/2; Mouse::Hide(); Mouse::Move(CX,CY); // ================== LIGHT ===================== DirectionalLight dirLight(CREATENOW) ; flt lightRotX = 0 ; dirLight.SetRotation( lightRotX, 0, 0 ); // ================== GO! ================ // keep on until user hits ESC or terminates the window while ( !Keyboard::IsHit() && !Engine::IsTerminated()) { if ( !Engine::IsSuspended() ) { // --- Keyboard --- if ( Keyboard::IsHit(KEY_P)) Engine::SetDebugPhysics(debugPhysics=!debugPhysics); if ( Keyboard::IsHit(KEY_G)) spec.SetGravityMode (debugGravity=!debugGravity); // --- Mouse --- mx=Curve( static_cast<flt>(Mouse::GetX()-CX),mx,4.0f/Engine::GetSpeed()); my=Curve( static_cast<flt>(Mouse::GetY()-CY),my,4.0f/Engine::GetSpeed()); Mouse::Move(CX,CY); // --- Camera --- camrotation = cam.GetRotation() ; camrotation.X += my*0.25f; camrotation.Y -= mx*0.25f; cam.SetRotation( camrotation ); // --- Spectator --- specforce = Vec3( (Keyboard::IsDown(KEY_D)-Keyboard::IsDown(KEY_A))*camspeed*Engine::GetSpeed(), (Keyboard::IsDown(KEY_Q)-Keyboard::IsDown(KEY_E))*camspeed*Engine::GetSpeed(), (Keyboard::IsDown(KEY_W)-Keyboard::IsDown(KEY_S))*camspeed*Engine::GetSpeed()); specforce = TFormVector( specforce, cam, 0 ) ; spec.AddForce( specforce, GLOBAL ); specposition = spec.GetPosition(GLOBAL); camposition = cam.GetPosition(); cam.SetPosition(Vec3( Curve(specposition.X,camposition.X,4.0f/Engine::GetSpeed()), Curve(specposition.Y,camposition.Y,4.0f/Engine::GetSpeed()), Curve(specposition.Z,camposition.Z,4.0f/Engine::GetSpeed()))); // --- Sky --- // rotate sky camera in same direction as main camera and render sky skycam.SetRotation( camrotation ); sky.Set(); World::Render(); // --- World --- // Render world world.Set(); World::Update(); World::Render(); // --- Some screen info Draw::Text( 0, 0, "FPS %f", Engine::GetFPS()) ; Draw::Text( 0, 20, "%d polys", Engine::GetTrisRendered()); Draw::Text( 0, 40, "Position %0.2f %0.2f %0.2f", specposition.X, specposition.Y, specposition.Z); Draw::Text( 0, 60, "P = Debug physics" ) ; Draw::Text( 0, 80, "G = Enable gravity" ) ; // --- Update screen --- Engine::Flip(); } } // ================== DONE! ============= return engine.Free(); }
Before compiling be sure to set Linker Output File to the same directory as where your
terrain images are. You also needs the Shader directory copied there, or
at least the 'skybox.frag', 'skybox.vert', 'terrain.vert' and 'terrain.frag'
Compile and check that you have no errors.
Before running you must set the Debugging Working Directory to $(TargetDir), at least
if you are going to run the program from Visual Studio.
Go ahead and run the program by hitting Ctrl+F5.
The result should look something like this if you used my textures.
Textures
If you want to use my textures you can get them here
Thanks for your time and good luck.
--Rstralberg 07:54, 9 July 2008 (MST)
