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)³ +
My(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)³ +
Mz(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)
|