 |
Feedback
If you've got any feedback, suggestions, or bugs to report regarding the Collective website, go here!
Feedback (302)
|
|
|
|
 |
 |
recent articles
NPC and Item Placement Theory
17/03/05 11:35pm PST
Non-Player Character (NPC) and item placement can influence both
the gameflow and immersion of a level. This article aims to give some
pointers on how to properly place them.
- Hugh 'Hugh' Lloyd
|
|
Got Props?
13/03/05 08:32am PST
A common problem in HL2 mapping is props not showing up in game. This article explains why and offers solutions.
- Jeff 'Yesukai' Pritchard
|
|
Simulating Randomness
18/12/04 11:29pm PST
This article focuses on how to properly simulate random events
that should occur at a certain average frequency, or within a certain
probability per period of time.
- Skyler 'Zipster' York
|
|
Your world in HL2
06/12/04 12:17am PST
This article gives tips and advice to anyone wanting to make custom photorealistic textures to be used in Half-Life 2.
- Oksid
|
|
Hiding in Shadow
21/08/04 01:11pm PDT
Describes how to create a function that has monsters disregard
you if you are hiding in a certain level of "darkness," which can be set
from within map properties.
- Anders [Wolf] Jenbo (NoBody)
|
|
Bump Mapping in Half-Life
08/08/04 11:58am PDT
Details a method of achieving real-time bump mapping in Half-Life, and provides an implementation of the algorithm.
- Francis 'DeathWish' Woodhouse
|
|
Real-Time "TRON 2.0" Glow For Low-Spec Hardware
19/06/04 02:06pm PDT
A sequel to the original "Real-Time 'TRON 2.0' Glow" article,
this describes how to implement real-time glow that works on low-spec
graphics cards.
- Francis 'DeathWish' Woodhouse
|
|
Hitboxes and Code
05/06/04 06:25pm PDT
How do I make only one part of a monster take damage? Learn about
the relationship between model hitboxes and what you can do with them
in a characters code.
- Jonathan 'Teh_Freak' Smith
|
|
|
|
|
 |
 |
In the client.dll source code, there's a file called StudoModelRenderer.cpp. It handles the drawing of all the .mdl models in the game.
Each time the engine wants to draw a model, it calls the function StudioDrawModel.
This function then works out where the model is, where all the bones of
its skeleton should go, whether there are any special effects that need
applying, and finally draws it.
Needless to say, having access to all this code gives us a great opportunity to do special effects!
For this article, I'll be looking at something simple - scaling. I added the following code at the very end of StudioSetupTransform (a function in StudioModelRenderer.cpp which decides where the model will be drawn on the screen):
if (m_pCurrentEntity->curstate.scale != 0) { int j; for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { (*m_protationmatrix)[i][j] *= m_pCurrentEntity->curstate.scale; } } } |
|
That's
it. Add this code, compile, and you've finished! To test it, you just
need to make a monster in Worldcraft, turn off Smartedit and give it a
"scale" setting of 2.0 (double size) or 0.5 (half size), or whatever.
So, how does this actually work? m_pCurrentEntity->curstate
is the current state of the entity we're supposed to be drawing. The
"scale" variable is one of the properties that make up that state. (I
didn't create it - it's been there all along, although previously it was
only used by sprites. I'm using it here because having a pre-existing
variable makes the example nice and simple. And it seems sensible to
reuse it for such a similar purpose.)
So, that's the simple stuff out of the way. What are these "for" loops doing? Multiplying up the numbers in m_protationmatrix.
To
understand that, we need to talk a little bit about matrices. Yeah,
matrices - the seemingly pointless things you hated (or, for the younger
audience, will hate) in maths lessons. Well, this is the moment where you get to learn what matrices are actually for!
A matrix is a rectangular grid of numbers. m_protationmatrix
is a matrix with 4 columns and 3 rows, and its 12 numbers are used to
define exactly where a model will appear on the screen. Don't let the
name fool you: it can express all sorts of transformations, not just a
rotation. It comes in two parts:
a b c x d e f y g h i z
Numbers
in the first three columns are used to scale, rotate and/or skew the
model. (I'll explain how in a minute.) Numbers in the right-hand column
simply define where the model is in 3d space.
In the StudioSetupTransform function, there's a good example of how the last column can be used - the very first and very last things it does.
void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) { //...some variables... vec3_t modelpos;
VectorCopy( m_pCurrentEntity->origin, modelpos ); //...the rest of the function... (*m_protationmatrix)[0][3] = modelpos[0]; (*m_protationmatrix)[1][3] = modelpos[1]; (*m_protationmatrix)[2][3] = modelpos[2]; } |
|
As I hope you can see, this code first saves the entity's origin into the modelpos vector, and at the end, copies that vector directly into the last column of the matrix. Yes, it really is that simple to use.
Sadly, the same isn't true of the other three columns. To understand how those work, let's talk about matrices.
Here's how you multiply a 3-by-3 matrix by a 3d vector, to produce a new 3d vector:[a b c] [x] [?] [d e f] * [y] = [?] [g h i] [z] [?] 1) Take the top line of the first matrix: [a b c]
2) Multiply the first number in that line by the first number in the vector, multiply the second by the second, and so on. [ax by cz]
3) Add up the results, and write the answer as the first entry in the result vector.[ax+by+cz] [ ? ] [ ? ] Then,
repeat this process for the second row of the matrix, and put the
result in as the second entry in the result vector. And then do the same
for the third.[a b c] [x] [ax+by+cz] [d e f] * [y] = [dx+ey+fz] [g h i] [z] [gx+hy+iz] With
me still? Once you get your head around it, you'll hopefully realise
that the idea of a matrix is actually quite simple: it's like a recipe.
Our ingredients are x, y and z from the vector; the matrix is telling us
how much of each ingredient we need to stir into a given part of the
result.
So for example, with a matrix like this...
[1 0 0] [1 0 0] [1 0 0]
...each
line says "stir in 100% of the vector's x value, and 0% of the other
two values". Let's see how that works on a vector containing a bunch of
random numbers:[1 0 0] [453] [1*453 + 0*7 + 0*99] [453] [1 0 0] * [ 7] = [1*453 + 0*7 + 0*99] = [453] [1 0 0] [ 99] [1*453 + 0*7 + 0*99] [453] Since the three lines in the matrix were the same, we got the same answer for each entry in the result. Now, here's a related one:
[1 0 0] [0 1 0] [0 0 1]
Here,
the first line says "use 100% of x, and nothing else". The second line
says "use 100% of y, and nothing else". The third line says "use 100% of
z, and nothing else".
Guess what the result is -[1 0 0] [453] [1*453 + 0*7 + 0*99] [453] [0 1 0] * [ 7] = [0*453 + 1*7 + 0*99] = [ 7] [0 0 1] [ 99] [0*453 + 0*7 + 1*99] [ 99] No change at all! This "no change" matrix is known as the "identity" matrix.
Ok. How about if we wanted to rearrange the components of a vector? (don't ask me why...)[0 1 0] [453] [0*453 + 1*7 + 0*99] [ 7] [0 0 1] * [ 7] = [0*453 + 0*7 + 1*99] = [ 99] [1 0 0] [ 99] [1*453 + 0*7 + 0*99] [453] Or making a vector longer, without changing its direction?[2 0 0] [453] [2*453 + 0*7 + 0*99] [906] [0 2 0] * [ 7] = [0*453 + 2*7 + 0*99] = [ 14] [0 0 2] [ 99] [0*453 + 0*7 + 2*99] [198] If
you've been paying attention, that last one should have made you
remember the beginning. By scaling up each of the components in a
matrix, we scale up each value in the result.
So, two pages
later, we finally get to see why the scaling code works. Half-Life
supplies me with a matrix, I multiply each entry by the scale factor,
and as a result, when the model gets drawn, each bit is scaled up! (note
that the scaling will be relative to its origin - which for most
monsters is at its feet, but not for all).
I hope this was helpful. I'll go into more interesting effects in a future article - assuming people are interested... |
 |
article created on Fri Feb 28, 2003 / 10:13am PST
this item has been viewed 4445 times
|
[Half-Life / coding]
|
|
Only registered users can post comments. Have you registered yet?
user comments
displaying comments of normal or higher rating
1. |
Michiel "MuzzleFlash" Breddels
Tue Mar 04, 2003 / 02:08am PST
|
|
|
Nice, this can do great things. lol, a huge baby headcrab, lol or a very tiny Gonarch (Big Momma)
Let me guess, there's NO WAY we can use this in normal HL maps. Is this only possible in Spirit???
MuzzleFlash |
|
2. |
Daniel 'Lord Booga' Koppes
Tue Mar 04, 2003 / 03:42am PST
|
|
|
If you do the modification he mentioned, it's possible in any mod (other than normal HL etc) |
|
3. |
Laurie Cheers
Tue Mar 04, 2003 / 05:59am PST
|
|
|
Yeah, it's really easy to add it. Also, note that the changes are client-side, so you don't even have to provide a new hl.dll. |
|
4. |
Skyler 'Zipster' York
Tue Mar 04, 2003 / 08:30am PST
|
|
|
I think it's worth pointing out
that this effect only affects the rendered model, and not it's physical
size. Don't want people to get confused  |
|
5. |
Eddy 'Cobra' Loughton
Tue Mar 04, 2003 / 09:20am PST
|
|
|
Nice job
Probably a good
idea for the higher-profile SP episode creators to include this in their
episodes, nice to see some different scientists and Barneys. Gives the
impression of a different model  |
|
6. |
Chris 'autolycus' Bokitch
Tue Mar 04, 2003 / 09:58am PST
|
|
|
Would it be possible to increase
different aspects of the scale? For example, increase the x scale to
make a tall skinny scientist, or the y and z scales to make a fat
barney... basically, to squash or stretch a model. |
|
7. |
Francis 'DeathWish' Woodhouse
Tue Mar 04, 2003 / 10:50am PST
|
|
|
This article should've been called "Scaling Models and Multiplying a 3x4 by a 3x1 Matrix" 
Good
article, well-written. Perhaps I should supplement the matrices bit
with an article specifically focussing on matrices and their math, and
their applications in transformations... |
|
8. |
Marc 'Delete_Me' Henry
Tue Mar 04, 2003 / 12:57pm PST
|
|
|
Elaborating on what Zip said; I
tried this on a Spirit 1.0 Launch map I was originally desiging. The
scale only effects the rendered picture of the model, and not the
hitboxes nor events like where bullets appear from (well, maybe the
latter, I forget). Headcrab of doom would have been fun... |
|
9. |
Skyler 'Zipster' York
Tue Mar 04, 2003 / 03:21pm PST
|
|
|
How's the texture scaling affected on the larger models? |
|
10. |
Patrick 'ComCray' Kanne
Tue Mar 04, 2003 / 03:42pm PST
|
|
|
dynamically adjusting x, y and/or z
scales? Hmm.. am I the onlyone considering storylines involving certain
mind-altering substances? castaneda meets freeman? |
|
11. |
Laurie Cheers
Tue Mar 04, 2003 / 04:18pm PST
|
|
|
Fear and Loathing in Black Mesa Research Facility?  |
|
12. |
Brian 'Fletch' Thomas
Tue Mar 04, 2003 / 07:12pm PST
|
|
|
mmmm SOHL dream sequences.... army
of tiny scientists gets attacked by headcrab'o'doom, huge barney comes
and saves the day. zoom out of Barney sleeping in a room as aliens run
by his room slaughtering folk. oh the joys of scripted sequences. |
|
14. |
Dorian "DD" Gorski
Wed Mar 05, 2003 / 02:17am PST
|
|
|
I'm confused on how the matrix 3 x
3 matrix represents scale, rotation, and scew. I mean, isn't it just a
representation of a vector? This is pretty sad considering I'm taking
linear algebra and we're past mid terms yet I have an 'A'. One of those
here's this, do that classes I suppose.
The code above appears to multiply all elements of the matrix, not just the diagonal of the matrix. |
|
15. |
Daniel 'Lord Booga' Koppes
Wed Mar 05, 2003 / 03:58am PST
|
|
|
I think in this example, it doesn't, it just represents x, y, and z of a 3D vector.
I suck at this kind of math at the moment, don't mind me if I'm horribly wrong  |
|
16. |
Skyler 'Zipster' York
Wed Mar 05, 2003 / 08:17am PST
|
|
|
Matrices are simply a fancy way to
organize numbers and systems of equations. A matrix representation of a
vector is nice because, in matrix form, it can take on the mathematical
properties and behaviors of a matrix and thus can operate on other
matrices which represent other vectors or systems of equations. All of
this is going on right here in this article.
Mathematic
operations with matrices on other scalars or matrices is well-defined,
so all you really have to do is "work backwards" from these operations
to determine which elements in the original transformation matrix (the
3x3) correspond to which changes in the final vector. Matrix
transformation are done primarily by multiplying them together, so if
you want to keep a value, multiplying it by 1 works great. On the same
token, if you want to eliminate a value, you use a 0.
This is
where the trick comes in. You know that any given any element in the
final vector is really a sum of several sub-multiplications of the
original matrix operands. This means that you can't have all zero
factors, because that would get rid of everything, however at the same
time, you can't have all 1 factors, because that would keep everything.
Working backwards, we find that multiplying by the identity matrix,
which consists of 1's down the main diagonal, maintains the original
vector. If these numbers down the diagonal aren't 1, then they scale, as demonstrated.
In
effect, you are multiplying the entire matrices, however the zero
factors eliminate everything but what you want. That's why it appears
you are only multiplying down the diagonal, because zero destroys
everything else.
When in doubt, expand the math. Make a really big matrix and plug in the actual equations into each element. comment modified on Wed Mar 05, 2003 / 08:19am PST |
|
17. |
Francis 'DeathWish' Woodhouse
Wed Mar 05, 2003 / 08:31am PST
|
|
|
I shall supplement what Zipster has said above.
Vector as matrix (one column, three rows):
[x] [y] [z]
Vector
transpose as matrix (don't worry about this, just here for the people
who'll lynch me if I don't mention it) (three columns, one row):
[x][y][z]
(Normally
matrices are represented with just big square brackets around either
end of the whole thing, not with square brackets around each element.
I'll use brackets around each element to make things easier to read.)
A
3x3 matrix can be used to do rotations and scaling. However, a 4x4
matrix is normally used for full transformations, with the vector having
a 4th component added (the 'w' component, set to 1). If you don't want
to have a 'w' component in the vector, then a four-column three-row
matrix can be used to represent transformations. However, as
demonstrated above, a 3x3 matrix is only required for rotations and
scaling.
I hope that made sense. |
|
18. |
Laurie Cheers
Wed Mar 05, 2003 / 09:43am PST
|
|
|
Ok. A 3x3 rotation matrix looks something like this:[cos(angle) -sin(angle) 0] [sin(angle) cos(angle) 0] [ 0 0 1] This example rotates around the Z axis, but you can use it for any axis by just switching the rows and columns around.
A simple worked example - rotating a vector by 90 degrees... sin 90 = 1 cos 90 = 0[0 -1 0] [453] [0*453 + -1*7 + 0*99] [ -7] [1 0 0] * [ 7] = [1*453 + 0*7 + 0*99] = [453] [0 0 1] [ 99] [0*453 + 0*7 + 1*99] [ 99] The
really useful thing about matrices is that by multiplying them
together, you automatically combine their effects. So if you take two
rotation matrices and multiply them together, you get a single matrix
that performs both rotations - just as if you'd multiplied a vector by
one, then by the other.
And yes, my code scales up every part of
the matrix, not just the leading diagonal. (sorry I wasn't clear about
that). That's simply the way you scale up a matrix - you need to scale
up every component. (Think about scaling up the one above, for instance.
If you scale up the leading diagonal, you'll only affect the 1 at the
bottom right - so you'll only scale up the Z axis.)
From a
Half-Life programming point of view, you don't really need to know the
details. You can construct a rotation matrix by simply calling the AngleMatrix function in studio_util.cpp. To multiply two matrices together, you can use the ConcatTransforms function. And to apply a matrix to a vector, you can use VectorTransform. comment modified on Wed Mar 05, 2003 / 10:11am PST |
|
19. |
Masahiro Sakuta
Sat Nov 15, 2003 / 05:21am PST
|
|
|
This technique doesn't work
properly in software mode. Model itself never scales, but attachment
points seem to move relative to scale. Anyone have an idea why and how
to deal with it? |
|
20. |
Anders [Wolf] Jenbo (NoBody)
Tue Jun 15, 2004 / 04:02pm PDT
|
|
|
just wanted to point out that thers a } to mutch in the code posted here in the artical  nice worke thow |
|
|
|
|
 |