Tutorial: Advanced Terrain Creation Last edited 3 months ago2024-09-01 20:06:46 UTC

Advanced Terrain Creation

Mmm, landscape :3Mmm, landscape :3
Terrain is one of the more challenging things in GoldSrc mapping. There are many ways to make terrain, and not just with terrain generators, but by hand. It sounds complicated, but making terrain by hand is actually kind of easy if you know how to do it. I won't show how to use a terrain generator, since they probably don't need a guide how simple they are.

Combining certain methods, you can get a landscape such as this:
ts_untergrundts_untergrund
In this tutorial I will show certain methods and how to combine them.

Triangular Prisms

User posted image
User posted image
Let's start with a method which is fairly easy to understand.
It's similar to Source's displacements.

Triangular prisms (a.k.a. wedges) are a popular way of adding terrain into your map. A triangular prism is basically a 3D shape which, when looked from above, looks like a triangle.
Let's see how to create terrain with triangular prisms:

1. Create a brush like this:
User posted image
2. Cut it diagonally:
User posted image
3. Disable the Texture Lock:
User posted image
This is important for texturing. If you don't turn it off, the textures will 'stick' to the brushes and the terrain will have seams everywhere.

4. Texture the top faces:
User posted image
5. Make copies of the 2 brushes, forming a grid:
User posted image
This is why I told you to disable the texture lock, otherwise it would look like this:
User posted image
6. Manipulate the vertexes in the top view: (with the Vertex Manipulation tool, of course)
User posted image
Now you can select the middle vertices and in the front or side view, you can pull them down. You can either nudge them with the arrow keys, or click and drag them.
User posted image
Hint
Sometimes, you'll end up with this:
User posted image
The triangle seems to be too "thin". Usually, you can retriangulate the part by either deleting the few brushes and aligning them, or you can rotate them by 90° and align the vertices:
User posted image
What's after 6th step has two variations:

Variant 1

7. Now let's do the walls.
Repeat the same process, and make it like this:
User posted image
8. Raise the vertexes upwards:
User posted image
Variant 2

7. Create a wall and cut it like this:
User posted image
8. Copy it and align it to the floor:
User posted image
9. Copy it vertically:
User posted image
10. Do the same for the other side:
User posted image
11. Give it a shape:
User posted image
This was done by selecting a line of vertices in the front view, and then I pushed them away from the centre.

12. Simply apply the textures, and give the shape some more variation:
User posted image

Tip
When some faces are stretched like this:
User posted image
Open the Texture Application tool, select the faces, and tick World:
User posted image
If some faces don't align properly like here:
User posted image
Then pick one face that aligned correctly:
User posted image
Press Shift+F6:
User posted image
And left-click the other faces which should've obeyed, so you can force their orientation:
User posted image
Sometimes, setting it to World won't work, so you'll have to set the "parent" face to Face.
Final step:
Press Alt+P.
User posted image
This will usually happen to some faces that are invisible in-game.
It's usually caused by vertex manipulation, and sometimes improper usage of the texturing tool.
Texture axis perpendicular to face
Here's a quick explanation of it.
User posted image
The white frames represent the projection planes, and the arrows represent the normals. This is perfectly fine. If the face is parallel to the projection plane, it's not stretched.
User posted image
In this scenario, we rotate the projection plane by 90° and thus it becomes perpendicular to the face. Actually, the projection was copied from the top face. This causes infinite stretching and a "Bad surface extents" error when compiling, as well as the "Texture axis perpendicular to face" error in the map editor.
You should not make the cliffs too detailed, otherwise you'll hit the clipnode limit pretty quickly (32 767). There are 3 clipnodes generated per face, so be careful.
Alternatively, you can use the -nohull2 parameter in CSG, so you'll end up saving a third of your clipnodes.
Basically, hull2 is for big monsters. Counter-Strike 1.6 doesn't have any monsters except the hostages.

This method can have a few tricks. If you've followed Variant 2 of this method, then you can do this:
User posted image
You can essentially use your triangular prisms for not just the wall, but also the floor which is on that wall.
User posted image
With some smoothing, triangular prism terrain like this is surely a delight.

Tetrahedra

While this method is very messy for the 2D views, it's really useful in a lot of situations.
Let's see how to create tetrahedrons and how to make something with them.

1. Create a cube and cut it diagonally:
User posted image
2. Pull these 3 vertices up:
User posted image
User posted image
3. Apply a texture, disable texture locking, and clone the tetrahedron pair:
User posted image
You'll mostly use the 3 top vertices. Those vertices will define that visible, textured face you see in-game.
But there's a 4th one. (highlighted in red)
User posted image
Consider it as a "root" vertice. If the root vertice is sticking out like this:
User posted image
... then it's concave. It's simply inside-out. So you should always look out for this.

Now, when do we sometimes use tetrahedra instead of prisms?
With tetrahedra, it's impossible to get the "face not planar" error.
A tetrahedron is made of triangles, while a triangular prism is made out of two triangles, and three squares.
Those squares' planes get bent if you're not careful:
User posted image
You could triangulate it via Ctrl+F, but it could lead to problems later on since it's not easily reversible.

4. Clone it into walls and the ceiling:
User posted image
5. Shape it like a cave with the VM tool:
User posted image
User posted image
6. Copy the segments and twist it a bit more:
User posted image
User posted image
As you can see, there are 512 brushes.
In theory, that should be 1536 clipnodes (1024 with -nohull2). This is why you have to be careful with such terrain.

And another reason is VIS. It can take VIS a LONG time to process a map of this complexity.

We could've used regular, old wedges for this part, but it wouldn't be ideal for the following part.

7. Copy the whole part and rotate it 90°:
User posted image
8. Copy a few segments and align the vertices in the top view:
User posted image
These vertices are now aligned on the XY plane, but now we need to align them vertically as well.
User posted image
Now you can polish the brushwork a little bit, and texture it.
User posted image

Cave entrance/exit (combining tetrahedra and triangular prisms)

In this example, we'll use a cliff made out of triangular prisms, and a cave made out of tetrahedra.

1. Start off by preparing the cliff and cave mesh
User posted image
User posted image
(note: never do it this detailed, it's just for the sake of this example)

One end is on the bottom, and the other end is on the top.
User posted image
2. Go to one of the ends, hide everything except this:
User posted image
3. "Open" the wall with the VM tool (without deleting any brushes)
User posted image
That step is usually done by selecting one half of the brushes (e.g. left half) and dragging the vertices, effectively un-welding them.

Since the cave mesh end is about 256 units away from the wall, we should copy it a couple of times otherwise there would be stretching.

4. Copy the cave segments close to the wall
User posted image
To quickly connect the two segments, mirror this one horizontally.

5. In the Vertex Manipulation tool, connect the vertices of the cave to the wall.

For J.A.C.K. users: Select the vertices in the 3D view, and nudge them in the 2D views. If the 2D views are too messy, you can use the blue camera in the 2D views to help you. Wherever the 3D camera is at, it will show up in the 2D views. Just navigate to the point where you want to move your vertices and you'll see where to move the verts in the 2D view.
For VHE users: on my end, it will always select just one vertice unless you enable auto-select IIRC, therefore I suggest you to drag a selection box in the Top view and then drag the vertices around. Sledge selects 'bundled' vertices just fine like J.A.C.K.
User posted image
.

6. Repeat the same for the other end
User posted image
Potential encounters
However, it doesn't look too great.
User posted image
In this case, delete these brushes:
User posted image
Connect these:
User posted image
User posted image
Add some brushes to cover it up (and texture it):
User posted image
I told you not to do it this detailed because of a good reason:
User posted image
(0fps FTW)

It's a mess of wpolys. And VIS would take a lot of time if they were all world brushes.

However, if you really want to, or have to use a lot of triangles, here's a tip: scale all the textures to larger values like 4 or 8, and use a detail texture and downscale it. That way you'll prevent a part of BSP subdivision, although lightmaps will be more low-res (texture scale affects lightmap scales on faces).
User posted image
The cave, on the other hand, was subdivided nicely:
User posted image
Combining tetrahedra with triangular prisms was used in ts_untergrund to make a hole going through a cliff.
User posted image

Toward Gearbox-style terrain

Quads 4 life!

Creating cliffs with a relatively small number of brushes

User posted image
You start with a "base".
User posted image
After that, add a few big cubes and start cutting them:
User posted image
User posted image
Sledge has a really useful feature in its Clipping Tool. Its clipping plane can be defined by 3 points, not just 2.
Click the edges and connect each edge:
User posted image
User posted image
Basically, once you select two edges, press Ctrl+F.

If you return to the Select mode and the lines get removed, check this:
User posted image
And repeat it for all of the brushes except the left-most and right-most ones:
User posted image
Now, this is a more complex part:

Connect the edges like this:
User posted image
And then merge these two:
User posted image
With this one:
User posted image
Do the same for the other end.
And then select the edge vertices:
User posted image
And move them:
User posted image
Lastly, make sure to do some minor corrections and then press Ctrl+Alt+T if needed (if you end up with the "face not planar" error). If you aren't using J.A.C.K., you can always select the brush with that non-planar face, and use Ctrl+F to cut the face into 2 triangles, thus making it planar.
And then, we have the texturing part. All of the faces should have a common projection plane, so you can either turn on "World" alignment, or use the "Apply (all + copy axes)" mode.
User posted image
User posted image
After that, you can keep adding more geometry this way:
User posted image
The end result will look something like this:
User posted image
However, there's a problem:
User posted image
User posted image
If you would leave these to be world brushes, the compiled map would be messy. It's sort of messy as it is, but that's one of the compromises with GoldSRC terrian.
This is why you should convert these brushes to func_detail.
User posted image
Don't forget to cover them with CLIP brushes, of course. We'd rather not want too many clipnodes or funky geometry that can make other players get stuck.
You will, of course, encounter errors while trying to do this:
User posted image
The brush looks completely fine, but it's really not fine.
User posted image
Let's take a closer look:
User posted image
This is where we need to retriangulate our brush. It's fairly simple and it's done in the VM tool.
User posted image
Make these lines:
User posted image
User posted image
And then merge two vertices to make the brush look like this:
User posted image
After that, you have to pull the middle vertice:
User posted image
If you scroll up, you would remember that the diagonal line was going from the bottom left to the top right corner.
So, we only need to make it the opposite.
Pull the middle vertice to the bottom-right corner:
User posted image
If you get the "Point off the face plane" error, I suggest you to move some vertices.
In the end, you'll save many brushes:
User posted image
56 brushes (not counting the 2 clip brushes)

Imagine how many brushes it would take if you did that with tetrahedrons only.
Tetrahedrons surely give you lots of freedom when you're working on the shape, but that produces a lot of brushes.

Terrain without the VM tool

This might be the least messiest method for the 2D views. So far, we've mainly used the Clipping tool and the Vertex Manipulation tool for the brushwork. Now let's limit ourselves to not using the VM tool at all.

Firstly, let's disable the texture lock.

Now, create a cuboid like this:
User posted image
Clone it above:
User posted image
Click the cuboid multiple times in the 2D view until the skewing mode shows up:
User posted image
And skew it a little bit. Repeat the two steps until you get to a certain height or a shape.
User posted image
Now group this entire segment, and clone it sideways.
User posted image
Select one segment and skew it in a different 2D view.
User posted image
User posted image
Lastly, you can skew it again in the Top view.
You can easily make ground this way too.

Just don't overdetail it.
User posted image
This takes a lot to compile and it wouldn't make much of a difference compared to something more low-poly.
Effectively the same thing can always be achieved with less.

Gearbox-style

User posted image
When first playing through Opposing Force, the terrain just amazed me. If you're looking for the terrain style that looks so late 90's, look no further. But beware, funky geometry awaits after you compile it.

One approach to this style of terrain is via layers.
User posted image
First layer.
User posted image
User posted image
Second layer.
User posted image
Third layer.
User posted image
Fourth layer.
User posted image
Fifth layer. (optional, also it doesn't have to be in this very order)
User posted image
Let's do this on another example.

1. Place down the floor brushes
User posted image
Let's give them a twist. You can either skew them with the Select tool or the Vertex Manipulation tool.
User posted image
User posted image
2. Start adding the wall segments.

If you simply started adding walls and skewing them, you'd get this:
User posted image
It looks boring...
Start off by placing this block.
User posted image
Cut it and turn it into this.
User posted image
This is where the magic happens.
After this point, a lot of people could do something wrongly in the VM tool and get a "Face not planar" error.
However, a way to prevent it is to prepare the brush for further operations.

Since these two are relatively simple, only 2 edges needed to be moved.
User posted image
Now, select the following vertices and move them up:
User posted image
After that, select the bottom vertices and move them sideways:
User posted image
We can go one step further and move the vertices in the middle.
User posted image
We're not finished with this wall segment yet, as it has to be complete.
You can clone one brush and keep skewing it downwards and inwards.

In the end, you'll get a rock like this:
User posted image
You may cut the rock to later merge it into one brush. (I'd rather not do that, though)
User posted image
At this point, you might become worried about the off-grid vertices. It won't be too much of a problem. In the final phase we'll convert a lot of things into func_detail and cover what's needed in CLIP brushes.

For now, let's save this rock for later. It's part of the 5th layer.
Let's focus on the 1st layer.
User posted image
Remember. Always prepare the brushes:
User posted image
(top view - this is to preserve facial planarity)

That's better. We'll start by lowering these vertices:
User posted image
And then we can move the vertices to form this:
User posted image
For some variety, we can nudge some segments closer to the road.
User posted image
Additionally, raise some segments:
User posted image
First you do a smooth curve, then the 'pinches'.
User posted image
You've probably noticed by now that the front view is never really used due to the mess. I've done all my vertex manipulations in the top and side view. That's at least in this situation. Sometimes you won't use the top view, sometimes you won't use the side view.

We'll repeat the same for the other side.
User posted image
Holes
In case you get a hole like this:
User posted image
Extend the ground to close it, or move the cliff.
User posted image
I'm extending all the segments in order to preserve the planarity, because the ground will be slanted.
User posted image
Now we'll make a rock.

3. Create a block, and rotate it:
User posted image
And just cut it up:
User posted image
User posted image
After some more adjustments, we get the final result.
User posted image
4. Optimise.

Back in the day, if you had terrain like that, you would've had to go through very long compile times. Maps compiled for hours and some took days. Even if you've got a decent PC with a fast CPU, it doesn't mean you shouldn't bother optimising the map. Remember, a lot of people still use (old) laptops and old desktop PCs. I've got a relatively decent PC, but before that one, I had a 2007 Fujitsu laptop.

So, let's begin.

Since I've raised my ground in a specific way:
User posted image
I can do the following:

Hide everything but the road.
Copy the road on both sides and apply the NULL texture.
User posted image
And align it to the cliffs while they're unhidden. You can hide them again and place sky brushes.
User posted image
Time for func_detail.
User posted image
The ground -> detail level 1
The cliffs -> detail level 2
The rocks -> detail level 3

If you're familiar with BSP face clipping, this means that you can control it even further. If not, well, I'll explain.
Level 1 can clip level 2 and 3, while level 2 can't clip level 1, but can clip 3. Level 3 can't clip level 1 and 2, but gets clipped by them.
User posted image
If you look closely, the parts where the rock touches the cliff are cut. This is because I've set all the func_details to the same detail level (1).

If we follow the image I posted above, however:
User posted image
You can see that we managed to save some wpoly as the rock doesn't cut the cliff, and the cliff doesn't cut the ground.
Additionally, to save on clipnodes, you can turn the rocks into passable func_details and add some CLIP brushes.
User posted image
Good half-morning. :v
There's one thing to keep in mind, though. You can't always use func_detail for all things. It will lead to huge areas being rendered at once and that means lag. It does sound hard to believe for GoldSrc, but even with a GTX 1080 Ti, the game can drop from 400fps to 40fps if certain things are going on.
So you'll sometimes have to make a compromise.

Also, if you func_detail too much terrain, it will lead to a bigger clipnode count. So be careful. Clipnodes are one of the biggest threats to terrain in GoldSrc.
You might hit the clipnode limit pretty quickly (32 767). There are 3 clipnodes generated per face (one for each hull except hull0, the visual hull), so be careful.

Alternatively, you can use the -nohull2 parameter in CSG, so you'll end up saving a third of your clipnodes.
Basically, hull2 is for big monsters. Counter-Strike 1.6 doesn't have any monsters except the hostages, so compiling with -nohull2 shouldn't cause any issues. Hull1 and hull3 are for standing and crouching players respectively.

Tips & Tricks

Flow
User posted image
Look at the marked brushes. There's something bad.
User posted image
This one ruins the terrain because there's a noticeable line on it.

To fix this, mirror it horizontally in the Top view:
User posted image
And align the vertices:
User posted image
This improves the flow of the terrain by a bit. It looks smoother this way and it looks more natural.
Grouping
User posted image
It's a good idea to group the segments because it becomes easier to work with.
When you want to select more specific parts, just turn on Ignore Grouping and turn it off when you're done.
Smoothing
User posted image
This is a blocky corner.
We need smooth ones. Select these:
User posted image
Shape them into this:
User posted image
If you smooth every corner, you can have really nice results.
User posted image
User posted image
Let's see how I actually did the smoothing.
We'll perform this on a low-poly mesh.
User posted image
Grab the corner vertices in the Top view and pull them:
User posted image
If you come across this kind of segment:
User posted image
Rotate it by 90°. In J.A.C.K. you can press Ctrl+R to rotate it 90°.
User posted image
We've finished one part of the smoothing:
User posted image
Now, make the grid smaller by one step, and start smoothing it even more:
User posted image
User posted image
Now, we grab either the ceiling or the floor. Let's start with the ceiling:
User posted image
And pull!
User posted image
Do the same with the other edges.
User posted image
After this, you can either do the same thing with the floor.
If you want to save time, you can just copy the finished half.
User posted image
And then mirror it:
User posted image
Then spend some time fine-tuning the mesh:
User posted image
It doesn't always have to be terrain, though.

Take the bottom half:
User posted image
And then wrap another segment around it:
User posted image
And then make a heart shape out of it:
User posted image
You can decorate your indoors this way. It would surely make a nice addition.
You don't necessarily need to make a heart shape. You could also shape it like a lake:
User posted image
Or maybe a ball. Anything is possible.
Blend textures and large textures
User posted image
The lake up there doesn't look too natural, so I decided to give it a blend texture.
I basically went up and took 3 screenshots of it.
One with the gravel texture, one with the mud texture, and the last one which is covered in water, so I know how to blend the first two.
User posted image
This is starting to look more like Source.
However, be careful with 512x512 blend textures, as you can easily make a huge WAD file, and produce more wpolys (assuming you downscaled the texture). Another limit to take into account is AllocBlock.

Another method would be making 4 textures, 512x512 each. However, that would require a strict grid of triangular prisms, which you can only raise up and down. (actually, not entirely true)
User posted image
Here are the source BMPs.
In a map, it would look like this:
User posted image
The 'strict grid' I was talking about actually doesn't have to be completely followed.
User posted image
Moving vertices in the top view here will cause seams:
User posted image
However, since J.A.C.K. has a UV lock (sometimes doesn't work as intended), this problem can be partially avoided, if we move the vertices in a single direction.
User posted image
User posted image
As mentioned, sometimes it does not work as intended, so I suggest you to avoid using this.
User posted image
If you have faces that share the same texture, and share the same angle, chances are that CSG is going to merge them, like it did in this example. So, you don't have to worry too much if you've got a lot of faces like those in the editor.
On the other hand, BSP cuts some of those faces. CSG merges, BSP cuts.

Either way, out of the potential 128 wpoly or more, only about 97 faces got compiled in my case.

If you wish to use a texture with dimensions like 1024x256, 2048x128 etc., be warned:
User posted image
In OpenGL, power-of-two textures will be rendered properly, but NPOT textures won't. Instead, they will be rescaled: 1024x256 to 256x256, 2048x128 to 128x128, which will make them look horribly stretched horizontally. So yeah, 96x96 will be 64x64, 48x48 will be 32x32 etc. In Software mode they are rendered exactly as they are.
Terrain density
In most situations, you will want a constant terrain density in your map.
What does this mean, however?

With the first method, triangular prisms, when you're making that first brush, you have to define what dimensions you want to use.
Basically, I made a 64x64x16 block, and cut it into two wedges. These first two dimensions are what matter. If it's 64x64, it means there will be a relatively high terrain density. If you're going for a very open area, you'll want something bigger (less dense) like 128x128, 256x256 or even 512x512 if it's far away.

But nothing prevents you from using a dynamic density. ts_untergrund is the prime example of that. Some parts of the terrain consist of 128x128 pieces, some are 320x224, and a lot of the parts are off the 'strict grid'. This basically means that you can have detailed terrain that's in the nearby playable area, and low-poly terrain in the far away area, which is sometimes good.
SOLIDHINT
Here we have a nice little cliff:
User posted image
From experience, we know that we will get messy cuts with terrain like this.
User posted image
We can actually 'tell' the compiler how exactly it should cut that geometry. We do that by using the SOLIDHINT tool texture.
So, after we replace the backfaces with SOLIDHINT (typically textured with NULL or BEVEL), we're gonna get this:
User posted image
In this scenario, it decreased the wpolys by roughly 40%. Your mileage may vary, but it'll certainly be significant.

In the end

I hope this helped you out at least a bit on terrain in GoldSrc.
It's one of those things that I was fascinated with, when I started mapping.
You could expect me to write a part 2 of this tutorial one day. The first part already took long enough and it's long enough by itself. The next part will focus on certain situations and some extra things I haven't mentioned in this tutorial.

Just remember, watch your r_speeds and keep your compile times reasonable. You can always make it look better with less.

You can find source files (JMF & WAD) here.

Happy mapping!

1 Comment

Commented 4 years ago2020-02-10 16:03:29 UTC Comment #102536
Wow. Nice work, Admer :crowbar: This will certainly help me with my future mountainous map projects.

Happy mapping on GoldSrc.

You must log in to post a comment. You can login or register a new account.