Please support our sponsor:
Welcome To DirectX 4 VB! Multimedia Visual Basic at its best...




DirectXGraphics: Cubic Terrain Patches
Author: Jack Hoxley
Written: 10th May 2002
Contact: [Email]
Download: GR_Cubic.Zip (138kb)


Contents of this lesson
1. Introduction
2. The Cubic Equations


1. Introduction

Welcome to another extended DirectXGraphics article. This isn't going to be a tutorial as such, more of a covering-note for the downloadable source code.

I have a considerable interest in terrain modeling, and often read articles/white-papers on the subject. One area that crops up every so often is the use of quadratic/cubic/quartic/quintic patches to approximate an area of terrain. There are many advantages to this - the mathematical nature of the terrain makes it easy to implement LOD (Level Of Detail) algorithms, and it also provides nice results :-)

So, just for fun I decided to re-read several articles that I found and see if I could get it working in VB, and the fact that you're now reading this text shows that I managed to do it - and maybe you'd be interested in seeing how it all works!

The following 6 pictures show (in wireframe and solid forms) what the results are, the LOD is scalar, so the higher it is the smoother the terrain (but the more triangles / slower it gets).


Above and below: The lowest (0) possible setting


Above and Below: A low setting, but starting to look better!


Above and Below: A high resolution render, note very smooth :)


2. The Cubic Equations

The equations used to generate these "patches" are quite simple if you're good at math's, but if you're not familiar with parametric equations you'll need to do some research before continuing (I don't have the time to teach/explain them properly!)

First we take the simple linear equation: 
(A+B)=1
where A is the distance from the start (0.0 to 1.0) and B is the distance from the end (0.0 to 1.0). This basically expands to:
A + t(B-A)
with a little work.

We can then extend this to be "to the power n" - 2 (Quadratic), 3 (Cubic), 4 (Quartic), 5 (Quintic). When we raise it to one of these powers we need to multiply out the brackets, which gives us the polynomial to power n. For example:

(A+B)2 = A2 + 2AB + B2
(A+B)3 = A3 + 3A2B + 3AB2 + B3
(A+B)4 = A4 + 4A3B + 6A2B2 + 4AB3 + B4
(A+B)5 = A5 + 5A4B + 10A2B3 + 5AB4 + B5

I'm going to focus on the cubic equation, but you can easily work out the other versions if you really want them...

if we take A and B to be the distances along the line, we need to express them as one parameter (so we can get an f(t) formatted function). using the linear equation above:
(A+B)3 = 1     'cube-root both sides
(A+B) = 1       'cube root of 1 is still 1
B = 1-A          'rearrange for B

if we now substitute this into the main cubic equation:

A3 + 3A2(1-A) + 3A(1-A)2 + (1-A)3

don't simplify it yet, as all you'll do is prove that 1=1 or 0=0 :-)

to control our curve we're going to add a coefficient to each term of the equation and consider them to be "control points" - these are additional 3D points that will "guide" the curve accordingly. I will use lower case letters a, b, c, d (don't muddle these with A and B).

aA3 + b3A2(1-A) + c3A(1-A)2 + d(1-A)3

as it stands, with parameter A being in the range 0<=A<=1, control point 'a' is the start of the line (A=0.0), 'd' is the end of the line (A=1.0) and points 'b' and 'c' are just used to guide the curve (the curve wont actually pass through these points).

We can now expand these into the final parametric equations:

X(A) = axA3 + bx3A2(1-A) + cx3A(1-A)2 + dx(1-A)3
Y(A) = ayA3 + by3A2(1-A) + cy3A(1-A)2 + dy(1-A)3
Z(A) = azA3 + bz3A2(1-A) + cz3A(1-A)2 + dz(1-A)3

These equations will work perfectly for drawing a line between 'a' and 'd' influenced by 'c' and 'd'


An example of a cubic spline

Okay, we now need to expand this to cover a 2D patch, where we pass in an x and y value, and we get the "height" at the given point (this is the equation used to generate the meshes shown above).

(A+B)3•(C+D)3=1

basically, we just multiply the two curves, and we'll get the desired result!

(A3 + 3A2B + 3AB2 + B3)•(A3 + 3A2B + 3AB2 + B3)

I'll just jump to the full parametric equations, feel free to do the working-through if you want!

X(a,c) = Axa³c³ + Bx3a³c²(1-c) + Cx3a³c(1-c)² + Dxa³(1-c)³ + Ex3a²(1-a)c³ +
            Fx9a²(1-a)c²(1-c) + Gx9a²
(1-a)c(1-c)² + Hx3a²(1-a)(1-c)³ + Ix3a(1-a)²c³ + 
            Jx9a
(1-a)²c²(1-c) + Kx9a(1-a)²c(1-c)² + Lx3a(1-a)²(1-c)³ +
            Mx
(1-a)³c³ + Nx3(1-a)³c²(1-c) + Ox3(1-a)³c(1-c)² + Px(1-a)³(1-c)³       

Y
(a,c) = Aya³c³ + By3a³c²(1-c) + Cy3a³c(1-c)² + Dya³(1-c)³ + Ey3a²(1-a)c³ +
            Fy9a²(1-a)c²(1-c) + Gy9a²
(1-a)c(1-c)² + Hy3a²(1-a)(1-c)³ + Iy3a(1-a)²c³ + 
            Jy9a
(1-a)²c²(1-c) + Ky9a(1-a)²c(1-c)² + Ly3a(1-a)²(1-c)³ +
            M
y(1-a)³c³ + Ny3(1-a)³c²(1-c) + Oy3(1-a)³c(1-c)² + Py(1-a)³(1-c)³  

Z(a,c) = Aza³c³ + Bz3a³c²(1-c) + Cz3a³c(1-c)² + Dza³(1-c)³ + Ez3a²(1-a)c³ +
            Fz9a²(1-a)c²(1-c) + Gz9a²
(1-a)c(1-c)² + Hz3a²(1-a)(1-c)³ + Iz3a(1-a)²c³ + 
            Jz9a
(1-a)²c²(1-c) + Kz9a(1-a)²c(1-c)² + Lz3a(1-a)²(1-c)³ +
            M
z(1-a)³c³ + Nz3(1-a)³c²(1-c) + Oz3(1-a)³c(1-c)² + Pz(1-a)³(1-c)³ 

That's the math's behind the cubic-patch, you'll have to read through the source code in order to understand it fully.

As a final note, whilst all the source code is written by me, the math's/theory is based on the work featured in several articles on www.GameDev.Net (amongst other sites).

You can download the source code from the top of the page, or from the downloads page.

AMENDMENT: I've added an nth degree polynomial version for download, meaning you can test quadratic/quartic/quintic (or any other value for n). you can download it here (315kb)

DirectX 4 VB © 2000 Jack Hoxley. All rights reserved.
Reproduction of this site and it's contents, in whole or in part, is prohibited,
except where explicitly stated otherwise.
Design by Mateo
Contact Webmaster
This site is hosted by Exhedra Solutions, Inc., the parent company of RentACoder.com and PlanetSourceCode.com