- The Ultimate 3D Coding Tutorial (C) Ica /Hubris 1996,1997,1998
- Over 150k of pure sh...er, 3d coding power!
0 General Things
0.0 LICENSE AGREEMENT
3DICA PROGRAMMING TUTORIAL IS SUPPLIED AS-IS. THE AUTHOR DISCLAIMS ALL
WARRANTIES, EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, THE WARRANTIES
OF MERCHANTABILITY AND OF FITNESS FOR ANY PURPOSE. THE AUTHOR ASSUMES NO
LIABILITY FOR DAMAGE TO ANY LIVING / DEAD CREATURE OR EQUIPMENT, DIRECT
OR CONSEQUENTIAL, WHICH MAY RESULT FROM THE USE OF THE 3DICA PROGRAMMING
0.0.2 LIMITED WARRANTY
SATISFACTION GUARANTEE. If you are dissatisfied with this product you downloaded
from some F..ine BBS or the Internet, you may delete it at any time up
to 30 days after download and you will get your hard disk space (that was
occupied by the product) back. The space will be based on the space that
was occupied during the installation, with the cost of some bad sectors,
viruses and neat hidden files excluded. You must contact the author before
deleting the product.
(Used the readme.txt of Action Supercross as a basis)
The 3DICA Programming Tutorial is FREEWARE. This means, it can freely be
used and distributed as long as it is NOT CHANGED in any way. Of 3DICA,
one is not allowed to charge any fee without a written permission of the
author. The author is not liable of any damage caused by the source code
included in the package.
0.0.4 3dica careware - what does that mean?
If you have noticed how much work I have had making this tutorial and are
thinking about how to repay my efforts, I would appreciate any cash / other
nice things you could send. The people who send at least USD 5 (20FIM in
Finland), will get their names and some comment of their own published
in the next versions of 3dica. I reserve myself the right of not to publishing
sick, offensive or in some other way tasteless 'comments'.
Just to mention, Chem (Kaj Bjorklund) will get a third of all contributions.
Since version 2.1, Chem has been an active supporter of 3dica in three
ways: by proofreading every new version of the doc, by writing many chapters
of text, and by asking now and then unbelievably stupid questions ;D
Here's the address to which you can send your wallets / daddy's wallet
/ its contents:
0.1 The Authors, Greets, etc
My real name is Ilkka Pelkonen and I'm a 19-year-old c, (pascal), and assembly
coder. I live in Finland, near the capital city of Helsinki (30km to the
north). My hobbies include 3D coding, some cool games (Paybacktime2, Steel
Panthers, C&C, Warcraft 2, Screamer 2), writing 3dica, and jogging.
I'm studying computer science in the Helsinki
University of Technology (currently in first year), and I'll probably
concentrate on digital media. I'll join the Finnish Army in july 1998,
and my 'job' there being "a special duty for mathematically oriented men"
8-) I belong to the group Hubris, see a short overview below.
The best way to contact me is emailing to the address email@example.com,
so any comments or other discussion there. Please report any errors you
might find in the text.
My real name is Kaj Mikael Bjorklund (o with dots), and I'm a 18-year-old
c, pascal, and assembly coder. I live in Finland, Helsinki, 'Roihuvuori'
if it says something. Nice place. I'm mainly into programming (a real surprise
I can guess), but I have also tried to keep my physical condition up by
lifting weights. I go to Vuosaari Secondary High School (last year). After
matriculation exam I've planned to join Ica and (other ;) gurus (Tremor/Trauma,
Abyss/FC, Beta/5C, ...) in HUT. I'll join the Finnish Army in January 1999.
I've released a couple of players which no one (understandably) is using,
and made with my pals a game Rocket
Chase (which some ppl even play).
The best way to contact me is emailing to the address firstname.lastname@example.org.
You may check out http://www.pcuf.fi/~chem/,
too. Especially females are encouraged to email immediately ;)
0.1.3 Hubris Productions
First, you may want to check the Hubris
Productions Homepage (although it's quite nothing; built up in a couple
of hours just as a practice :)
The history of Hubris Productions:
February Bull (Tapio Vuorinen) and Slimey (Petri Tuohimaa) found
the group Dozer, Bull as an organizer/coder
March Override (Jouni Airaksinen) joins Dozer as a musician
October Zass (Jesse Lantinen) joins Dozer
Planning a demo 'Totally Oldish' (nothing was ever released, though
Zass and Slimey leave Dozer
February Bull and Override start coding a demo 'Rain'
April Override releases a tune "Deep Dreams"
May Ica (Ilkka Pelkonen) and Chem (Kaj Bjorklund) join in, Ica
as a 3D coder and secondary organizer, Chem as a music system coder
Dozer changes its name to Hubris (yeah!)
Ica releases v2.1 of his 3D coding tutorial 3DICA
June Acute (Aleksi Kallio) and Tweeker (Timo Makimattila) join
Hubris, Acute as a general stuff coder, Tweeker as a musician/graphician
July Ica releases v2.11 of 3DICA
September Chem releases first public version v1.0
of Hubris Module Player supporting SB2/Pro/16/GUS and MOD/S3M (DJGPP)
October Codger (Juha Leinonen) joins Hubris as a 3D modeller
Chem releases HMP v1.01
November Ica releases v2.2 of 3DICA this version describing widely
3D coding stuff from basic vector math to lighting effects, phong shading,
and BSP tree. The document is a great success
December Rondo (Lauri Tuovinen) joins Hubris as a musician
Chem releases HMP v1.06 with XM support. Many speed-requiring loops
have been translated into assembly and the player is now a tad bit faster
January Ica converts 3DICA into HTML and translates the whole
shit into English. Plenty of bugs have been fixed and some enhancements
have been done. The English and Finnish versions are now developed separately
March Ica releases 3DICA v2.21 (the first complete English
version). New subjects include inverse transformations, rotation about
an arbitrary vector, and B-Splines
0.1.4 Thanks for help
I list here the people who have somehow helped me with my own engine or
written themselves a chapter to 3dica. Thank you guys.
Kaj Bjorklund (Chem/Hubris)
Kaj is the official proofreader of 3dica. In addition, he has written about
linear interpolation, phong illumination, frameskip, texture mapping tricks,
gouraud, mip-mapping, convex polygons, bilinear filtering, and "real" phong.
He has also written the c source code included in the package.
Jonathan Castellanes (Loonix) Correcting grammatical and other errors
in the English version of the document (so blame him not me ;) ; general
Tapio Vuorinen (Bull/Hubris)
Henri Tuhkanen (Rodex/Static) Asm optimizing course, some
texture mapping tricks.
Jere Sanisalo Portals. You'll always find the newest version of
3dica at the homepage of Jere,
if hut.fi is down.
Timo Saarinen Perspective correction.
Sampsa Lehtonen (TexMex/Gigamess) Palette quantisizing.
Jukka Liimatta (Wog/Orange) Bilinear filtering.
Jari Komppa (Sol/Trauma) Median cut.
Altair Mental support ;D
The readers Informing about bugs that can always be found everywhere
Ilkka Pelkonen (Ica/Hubris) Everything else. :)
Ica (in no special order):
Beta /5C, TheJoker /Crusaders, Ripple /Inside, Tonic /Trauma, !Cube
/Trauma, Sol /Trauma, Wog /Orange, Case /Fuse, Friction /Morel Arts, Jokke
/Bad Karma, GREco /Oblivion, Mrz /Astroidea, Spector /Recreation, Zox /Storm,
Proton /Tehdas, Texmex /Gigamess, Zapmies, Cyberfish, Goblin, Venomix,
RaS, Mako, dAS, Whizzzzter (old gay ;), MiGbear, Sqrt(-1), JayLettu, Raster,
Harmless, Fobic, Midnight, Altair, Praetor, Absent, Adept, Gaffer, 3D-Zed
:), Loonix, RH, Janne Gronthal, Antti Haapakoski, Jussi Vainionpaa, Jukka
Keski-Oja, Otto Chrons, ..., *.Hubris, everyone at #coders, everyone who
think they ought to have been greeted :)
Haanpera bros & other RC people, Markku Ekblom, Antti Qvickstrom,
Sampsa Lehtonen, Antti Karjalainen, Ilkka Pelkonen, Tapio Vuorinen, Jere
Sanisalo, Joonas Pihlajamaa, Pekka Nurminen, Aki Puustinen, tAAt members,
Hubris members, mailing pals, other friends.
0.1.6 Thanks for support
Our heartfelt thanks to these people who have supported the development
of 3dica monetarily. Special thanks to the people whose names are marked
bold. Registered person's own comment in italic.
Joonas Pihlajamaa: Imuroi
lamertutti, imuroi lamertutti! BAD KARMA rulettaa!
JiMM: jeejee paasin greetzeihin ..
Juhana Venalainen: Ei millaan pahalla mutta hyvaa paivaa.
Ville Ruusutie: Some day I will conquer the world.
0.2 About the Document
0.2.1 Where can I get the newest version of 3dica?
The Official home page and distribution site of 3dica can be found at the
home page of the author in http://www.hut.fi/~ipelkone/.
The newest version can also always be found at Jere Sanisalo's home page
0.2.2 What has happened since the last version?
English version finally available!
The document has been converted into html.
The form of the 0 part has been changed
The linguistic form has been changed to less foolish :)
3D vocabulary improved (a lot)
Bilinear filtering described more accurately
Phong shading described a bit more cleverly :)
Rotation around an arbitrary vector added
A brief introduction to radians added
Palette quantisizing using median cut added (tnx Sol/Trauma)
Improved the Z-buffer chapter
Wrote some words about inverse transformations
0.2.3 Features to be added
Some topics, which will probably be described in some way in future versions:
Complex numbers (needed with fractals)
Bresenham line algorithm (for tmapping optimization)
Optimization tricks for 3D geometry
Suggest yorself new topics!
0.3 3D Terms etc.
At first, the co-ordinate system I'm using is as follows: x-axis from left
to right, y-axis from up to down, and z-axis points directly into the screen.
The coordinate system is so a right-handed one, which means two
1) The direction of the z-axis can be found with the first three fingers
of the right hand, by sticking thumb to the right and the following finger
downwards. The third finger shows now the direction of the z-axis (when
all fingers are perpendicular to each other).
And then 3D related terms.
2) Rotation about the axes is determined like this: when the thumb of the
right hand is pointing to the direction of an axis, the other fingers bend
to the positive rotating direction (that is, when you're rotating an object
about the z-axis to the positive direction, it rotates clockwise).
Additive rotation. Object matrices are reset every frame
and the rotation angles must be changed constantly to the objects rotate
constantly. (Brr.. don't use this way -- see cumulative rotation
Bilinear filtering. A technique that smoothens close-zoomed
Clipping. Cutting a polygon against another.
Complex polygon. A polygon that can cut itself.
Concave polygon. A polygon that has angles greater than 180
degrees, but is still solid.
Convex polygon. A polygon whose all angles are less than
180 degrees. Drawing one is as easy as drawing a triangle.
Cumulative rotation. Rotating in a way that object matrices
are reset only in the init part of the program. This means that if the
rotation angles stay constant, the object keeps rotating at a constant
speed. This is the Real Way of rotating; it ensures that objects rotate
about their own axes instead of the whole world's ones.
Face. A polygon on an object's surface. The corners of a
face are called vertices.
Keyframing. Having some key values and interpolating
between them to obtain a smooth movement between colors, rotation angles,
positions, etc. In 3D movement, this practically means having some orientations
of objects and/or camera saved and interpolating between them with quaternions
(below) and splines (below too :)
Matrix. Kind of a table of numbers, with help of which certain
complex mathematical operations are easier to perform. Matrices are used
in 3D transformations.
Mip-mapping. Of a texture, differently-sized and pre-filtered
bitmaps are kept in the memory. When drawing a polygon, a suitably-sized
mipmap is chosen depending on the size of the polygon. Like this, we get
a neat and good-looking filtering effect to texture mapping for free.
Origin. The center of a space; coordinates (0,0,0).
Palette quantisizing. Reducing the number of colors to fit
a palette as optimally as possible.
Quaternion interpolation. Using 4D space to interpolate object
orientations smoothly from one to another.
Scanline subdivision. Perspective correction is performed
only every 8th or 16th pixel and linear interpolation is used in the middle.
S-buffer. Segmented buffer or span-buffer or scanline Z-buffer.
Improved Z-buffer, where calculations are performed for scanlines instead
Sorting. Determining the drawing order of polygons so that
the farthest ones are drawn first and the closest ones last.
Spline. Given a desired amount of arbitrary points, a spline
is formed using certain formulas to go through or near all these points
keeping the spline as smooth as possible. Neat for camera location interpolation,
Subpixel. The position inside a pixel.
Subtexel. The position inside a texel (see bilinear filtering).
Texel. Texture element; the color of a point in a bitmap
(cf. pixel = picture element).
Vector. A line which has a constant length and direction,
but no determined location.
Vertex. A corner point of an object, to which one or more
faces are attached.
Vertex normal. The normal of a vertex :) the approximation
of which can be calculated by taking the average of the normals of every
face attached to the vertex.
Z-buffer. A sorting technique where points are sorted into
a screen-sized array to an order determined by the values of the points'
Z coordinates. Only the closest pixel is drawn.
A very general but still worth-to-know piece of advice to all questions:
USE YOUR WIT! Sure your code won't work, if not even the
SYNTAX is right!
Q: My 3D rotations which have been grabbed straight from the text
A: Are all the variables of right type? Glanced at the C source
Q: My texturemapper messes the screen up. I can't find any problems
A: Could be a rounding problem. Fixed:
putpixel( x, y, tmap[ u/65536+v/256) ] )
You've cleverly thought to optimize a bit: when v should be divided by
2^16 and multiplied by 2^8, you've just divided it by 2^8. The result is
wrong. Why? Now the upper 8 bits of the decimal part of your 16.16 fixed
point won't be cleared, and tmap regards them as u coordinates, so the
result is wrong. The right way is as follows:
putpixel( x, y, tmap[ u/65536+(v/65536)*256) ] )
putpixel( x, y, tmap[ word(u+v*256) ] )
The decimal parts of u and v mess each other up so misrepresenting the
result. The right way:
putpixel( x, y, tmap[ word(u)+word(v)*256) ] )
I myself had btw this problem and wondered for a long time why using
floats totally messed the routines up :I
Q: My flat polygon routine doesn't work.
A: Are the variables of right type? Do you use integer divide with floats
or vice versa? Can you really use fixed point? Do you remember to divide
by it at the end? Does your vertex sorting work?
Q: What are the terms AB, BC, and CA in the face listing of 3D-Studio's
asc format? (duh :)
A: They tell if a line is drawn or not in a wireframe figure.
Q: When should I use vertex normals, when face normals?
A: Use vertex normals with gouraud and phong shading, and face
normals with lambert flat shading.
0.5 Recommended References
As a great help and the Bible of graphics coding I use the glamorous book
Computer Graphics: Principles & Practice, 2nd Ed by Foley, Van
Dam, Feiner and Hughes, Addison-Wesley 1993. Other books and documents
are listed below.
0.6 A Quick Introduction to Radians
Radians are called the mystical angles all trigonometric functions
(sine, cosine, tangent, cotangent, ...) in mathematical code libraries
take as their parameters. What are they? Where did they come? Why
did they come? I'll not answer the two latter questions :) but I'll tell
how to use them in your apps.
Radian angles can be treated like any other angle by only remembering
that the degrees of a full circle (360 degrees) are 2*PI radians:
360 degrees = 2*PI = 6.28.. radians
Using this information, we derive a formula how to convert degrees to radians
and vice versa:
We can now calculate how much degrees is one radian:
x radians = (360 * x degrees)/2*PI = (180 * x degrees)/PI.
x degrees = (2*PI * x radians)/360 = (PI * x radians)/180.
1 radian = (1 degree)*180/PI = 57.295... degrees.
Now it should be quite clear. And remember: don't be afraid of using radians
-- they're as good an alternative as degrees, and at least as simple to
Back to the index