GameBanana shows no ads to members. Sign up now!
Ads keep us online. Without them, we wouldn't exist. We don't have paywalls or sell mods - we never will. But every month we have large bills and running ads is our only way to cover them. Please consider unblocking us. Thank you from GameBanana <3

Better view bobbing

A Tutorial for Half-Life

Updates

Version 1.2 7mo
  • Improvement Using a better technique as opposed to 3 V_CalcBob functions
  • Removal Cleanup of some needless things
  • Addition Some additional explanations

Bring back HL WON view bobbing + add your own!

1. Better view bobbing

If you're old enough to remember HL WON, you may remember that before version 1.1.x.x, there was a view bob that was more than just forward and backward.

NOTE:
Do NOT replace your vanilla Half-Life client.dll. I repeat, DO NOT do this. This tutorial is meant for custom mods. Thank you. :)


In this tutorial, we'll bring that back, and make it even better. 
So, let's get started!

Open Visual Studio or whatever IDE you use, and in cl_dll, find view.cpp.
Scroll down to line 490, at the function V_CalcNormalRefdef.

This function's mission is to do a couple of things.
  1. Grab player's view (position and angles)
  2. Grab player's viewmodel
  3. If it's in water, either raise or lower the view
  4. Calculate the view bob, the roll and similar
  5. Apply the calculated variables
  6. Smooth out the view, in multiplayer, when on trains and lifts
It does more than that, but for you, the 4th part is what's important.

In the end of the tutorial, we'll have something like this:


1.1. Enabling HL WON view bobbing

Firstly, we need to bring back the old view bobbing.
Go to line 664, and paste this:
// Enables old HL WON view bobbing
VectorCopy( view->angles, view->curstate.angles );

Compile the client DLL, and copy it to your mod. If you launch it, you'll see that our old view bobbing is back! However, it looks a bit cheesy, doesn't it?

Before we make our own view bobbing, we gotta understand the variables behind this stuff first.

Essentially, there's a cycle behind all of this. That cycle represents some angle, and the view bobbing variables are sines and cosines of that angle.

The variable "view" is actually our viewmodel clientside entity. So its angles and origin can be different than the player's 'camera'. I'll show you later how to manipulate the camera itself, but for now, let's stick to the viewmodel.

Let's take a look at view's most important variables.

Entity state 'curstate' -> angles, origin etc. received from the server
Vector 'origin' -> position
Vector 'angles' -> angles

These entity states are essentially structures that are used for entity packets sent to the client, by the server. Modifying these on the client side, once they are received, we can easily manipulate our view.
You may find it similar to the PEV structure, as it contains origin, angles, skin, solid, effects, and so on.

Changing curstate's values means changing the current view. So, let's do a little experiment.
Let's change some of the variables.

1.2. Messing with the view bob further

Add the following code right under line 658 (which is view->origin[2] += bob):
view->origin[1] += 2 * bob;

It looks very weird in-game, but, what we essentially did here was shifting the viewmodel's origin on the Y axis depending on the bob. Let's remove that line.

Instead, let's see right above:
for ( i = 0; i < 3; i++ )
{
view->origin[ i ] += bob * 0.4 * pparams->forward[ i ];
}

Let's change pparams->forward to pparams->right.

So far, we've moved our origin in world coordinates. However, pparams' vectors are local (up, forward, right).

Now, this is all nice, but what if you want to bob it right and up, kinda like the view bob in Doom, Far Cry 1, HL2 etc.? In the form of an infinity shape, basically.

The plan is to have two waves, one for up, and the other one for right.
So, replace that for loop with the following two:
for ( i = 0; i < 3; i++ )
{
view->origin[ i ] += bob * 0.4 * pparams->right[ i ];
view->origin[ i ] += bob * 0.4 * pparams->up[ i ];
}

However, our viewmodel is moving diagonally now. :/
Let's fix this.

1.3. Separate bobs for each direction

We are still using only one wave, which is the bob variable. If we want to have different cycles for right and up, we need to somehow modify the V_CalcBob function, since that is the function that calculates the current value for the bob.

'bob' is the variable that changes over time, and it behaves like a wave. As it goes up'n'down over time, your viewmodel will go forward-backward.

If we have, say, bob_up and bob_right, planning for each to have a separate frequency, we could use a V_CalcBobUp and V_CalcBobRight, but this is a WRONG approach.
Right now, if we called the same V_CalcBob for them, the bobs themselves would be the same. This is why we are going to modify V_CalcBob, to allow us to handle multiple different cycles.

Notice the static variables inside V_CalcBob:
float V_CalcBob ( struct ref_params_s *pparams )
{
static double bobtime;
static float bob;
float cycle;
static float lasttime;
vec3_t vel;

This is pretty much the source of the problem. Since the variables are static, they will "remember" their values after the function ends, and when we call V_CalcBob again for another variable, it's gonna treat it like it's the same one. In other words, V_CalcBob was designed for only one cycle.

We will modify V_CalcBob in a way that we will send bobtime, bob and lasttime as parameters. The bob parameter will be an output parameter for our wave/cycle. Also, the function will no longer return a float. Instead, it'll be a void.

The function will start like this:
void V_CalcBob ( struct ref_params_s *pparams, float freqmod, calcBobMode_t mode, double &bobtime, float &bob, float &lasttime )
{
float cycle;
vec3_t vel;

Since V_CalcBob will now support cos, sin and their square variants, I added a calcBobMode_t variable as a parameter. Let's add an enum for that above the function:
enum calcBobMode_t
{
VB_COS,
VB_SIN,
VB_COS2,
VB_SIN2
};

Now, on the end of V_CalcBob, write the following:
	bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value;

if ( mode == VB_SIN )
bob = bob * 0.3 + bob * 0.7 * sin( cycle );
else if ( mode == VB_COS )
bob = bob * 0.3 + bob * 0.7 * cos( cycle );
else if ( mode == VB_SIN2 )
bob = bob * 0.3 + bob * 0.7 * sin( cycle ) * sin( cycle );
else if ( mode == VB_COS2 )
bob = bob * 0.3 + bob * 0.7 * cos( cycle ) * cos( cycle );

bob = V_min( bob, 4 );
bob = V_max( bob, -7 );
//return bob;

}

Since the function is now a void, it can't return the bob. But, because bob is now a parameter by reference, we don't have to worry about returning anything.

You've also noticed the 'freqmod' parameter. This is what we will use to have different frequencies for the separated view bob variables.

The entire V_CalcBob function now looks like this:
void V_CalcBob ( struct ref_params_s *pparams, float freqmod, calcBobMode_t mode, double &bobtime, float &bob, float &lasttime )
{
float cycle;
vec3_t vel;

if ( pparams->onground == -1 ||
pparams->time == lasttime )
{
// just use old value
return;// bob;
}

lasttime = pparams->time;

bobtime += pparams->frametime * freqmod;
cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value;
cycle /= cl_bobcycle->value;

if ( cycle < cl_bobup->value )
{
cycle = M_PI * cycle / cl_bobup->value;
}
else
{
cycle = M_PI + M_PI * ( cycle - cl_bobup->value )/( 1.0 - cl_bobup->value );
}

// bob is proportional to simulated velocity in the xy plane
// (don't count Z, or jumping messes it up)
VectorCopy( pparams->simvel, vel );
vel[2] = 0;

bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value;

if ( mode == VB_SIN )
bob = bob * 0.3 + bob * 0.7 * sin( cycle );
else if ( mode == VB_COS )
bob = bob * 0.3 + bob * 0.7 * cos( cycle );
else if ( mode == VB_SIN2 )
bob = bob * 0.3 + bob * 0.7 * sin( cycle ) * sin( cycle );
else if ( mode == VB_COS2 )
bob = bob * 0.3 + bob * 0.7 * cos( cycle ) * cos( cycle );

bob = V_min( bob, 4 );
bob = V_max( bob, -7 );
//return bob;
}

1.4. Using bobs with multiple directions

V_CalcNormalRefdef now must be changed.
Somewhere in that function, bob gets assigned to V_CalcBob, but since we changed V_CalcBob to a void, it will result in a compiler error.
Other than that, inside V_CalcNormalRefDef, we'll also have to declare 3 bobtimes and 3 lasttimes, since they used to be static variables in the old V_CalcBob.

Let's begin, at the start of V_CalcNormalRefdef:
void V_CalcNormalRefdef ( struct ref_params_s *pparams )
{
cl_entity_t *ent, *view;
int i;
vec3_t angles;
float bobRight = 0, bobUp = 0, bobForward = 0, waterOffset;
static viewinterp_t ViewInterp;

static float oldz = 0;
static float lasttime;

static double bobtimes[ 3 ] = { 0,0,0 };
static float lasttimes[ 3 ] = { 0,0,0 };

vec3_t camAngles, camForward, camRight, camUp;
cl_entity_t *pwater;

bobRight, bobUp and bobForward will be our bob variables, if that's not obvious.

Go to the line where you see bob = V_CalcBob(... and replace it with this:
// transform the view offset by the model's matrix to get the offset from
// model origin for the view
V_CalcBob( pparams, 0.75f, VB_SIN, bobtimes[0], bobRight, lasttimes[0] ); // right
V_CalcBob( pparams, 1.50f, VB_SIN, bobtimes[1], bobUp, lasttimes[1] ); // up
V_CalcBob( pparams, 1.00f, VB_SIN, bobtimes[2], bobForward, lasttimes[2] ); // forward

So now you can see how this is actually going to work. We have an array for bobtimes and lasttimes. We could have an array for bobs as well, but this works too.
When V_CalcBob does its thing, it's gonna update bobtimes, lasttimes and all 3 of the bobs separately, instead of treating them as one thing.

Let's update the for loop that applies the bobbing:
for ( i = 0; i < 3; i++ )
{
view->origin[i] += bobRight * 0.5 * pparams->right[i];
view->origin[i] += bobUp * 0.25 * pparams->up[i];
view->origin[i] += bobForward * 0.125 * pparams->forward[i];
}
And that's about it. The rest is tweaking these values.
So, we now got an idea how to manipulate the viewmodel angles. But what about the player's view camera?

1.5. View 'camera' swaying

The answer lies in the pparams structure. Precisely, pparams->viewangles.
So, let's go to this line:
// throw in a little tilt.
view->angles[YAW]   -= bob * 0.8;
view->angles[ROLL]  -= bob * 0.8;
view->angles[PITCH] -= bob * 0.8;
Instead of bob, let's write bobRight, bobUp and bobRight respectively.
view->angles[YAW]   -= bobRight * 0.8;
view->angles[ROLL] -= bobUp * 0.8;
view->angles[PITCH] -= bobRight * 1.2;
However, this isn't actually the view camera. The variable view is actually used for the viewmodel.

To control our actual viewing camera, you can add this right under:
pparams->viewangles[ROLL]  += bobRight * 0.15;
pparams->viewangles[PITCH] += bobRight * 0.55;
In-game, you'll get a small up'n'down leaning when you move. It'd be like if you moved your mouse slowly back and forth.
I generally wouldn't recommend you to manipulate the view camera, unless you want to cause headaches and motion sickness for your players.

This is pretty much the end of the tutorial. If you weren't able to follow along, there's a GitHub repository containing all the source code of this tutorial. Alternatively, ask me in the comments if you need help.

Keep in mind, however, that you can do so much more than just this. We could add linear interpolation, we could push the weapon naturally up and down if we jumped. We could have a different view sway underwater, and we could make it sway quicker depending on the speed at which the player moves. Hell, you can even try to do what Move In! does, a free aim!

Here's a small example of what you can do:

It is up to you, for now, to play around, and discover how some of that is done.
I'll very likely write a part 2 of the tutorial, where I'll talk more about the maths of view bobbing (nothing complicated), and how to achieve certain effects from that GIF up there.

All source code and compiled binaries can be found at the GitHub repo here.

Happy coding. :)
Sign up to access this!
1-10 of 20
1
Pages
  • 1
  • 2
Go to page:
  • Admer456 avatar
    Admer456 username pic Joined 6y ago
    Gone. :3
    26,334 points Ranked 197th
    32 medals 2 legendary 5 rare
    • Submitted 30 Tutorials Medal icon
    • Returned 5000 times Medal icon
    • Submitted 15 Tutorials Medal icon
    • Returned 1000 times Medal icon
    • Reached 50 subscribers Medal icon
    • Received thanks 50 times Medal icon
    1mo
    URL to post:
  • JvLvs avatar
    JvLvs Joined 8mo ago
    Offline
    6mo
    thanks . it helped me a lot
    Bananite
    URL to post:
  • Atzimoova avatar
    Atzimoova Joined 2y ago
    Offline
    680 points Ranked 44,062nd
    5 medals 1 rare
    • Returned 1000 times Medal icon
    • One month a member Medal icon
    • Returned 100 times Medal icon
    • 6 months a member Medal icon
    • 1 year a member Medal icon
    7mo
    could you compile it with that jumping thing? 
    time wasting twat.
    URL to post:
  • LiZou Mapper avatar
    LiZou Mapper username pic Joined 3y ago
    Stopped !
    154 points Ranked 62,642nd
    14 medals 1 rare
    • Submitted 20 Maps Medal icon
    • Submitted 5 Maps Medal icon
    • One month a member Medal icon
    • 6 months a member Medal icon
    • Received thanks 5 times Medal icon
    • Returned 100 times Medal icon
    7mo
    incredible

    but you can make it in AMX :D  
    Mapper - Design Level GoldSrc
    URL to post:
  • PancakeNinja avatar
    PancakeNinja Joined 2y ago
    Offline
    716 points Ranked 43,684th
    5 medals 1 rare
    • Returned 1000 times Medal icon
    • One month a member Medal icon
    • 6 months a member Medal icon
    • 1 year a member Medal icon
    • Returned 100 times Medal icon
    7mo
    Hello, I'm not a programmer so I tried to download the "firstmod" folder. I placed the folder in C:\Program Files (x86)\Steam\steamapps\common\Half-Life and I couldn't get it to work. There could be an issue here with the fact I'm also using this mod: https://gamebanana.com/skins/174124
    I really would like to be able to use your mod, if you could help explain to me what is causing the problem and how to fix it I would greatly appreciate it :)
    Bananite
    URL to post:
  • Admer456 avatar
    Admer456 username pic Joined 6y ago
    Gone. :3
    26,334 points Ranked 197th
    32 medals 2 legendary 5 rare
    • Submitted 30 Tutorials Medal icon
    • Returned 5000 times Medal icon
    • Submitted 15 Tutorials Medal icon
    • Returned 1000 times Medal icon
    • Reached 50 subscribers Medal icon
    • Received thanks 50 times Medal icon
    8mo
    Considering a bunch of people requested compiled binaries, I made something for everyone who asked for them:

    https://github.com/Admer456/halflife-adm-tutorials/releases

    It comes in the form of a mod. So all you gotta do is put the "firstmod" folder into Steam/steamapps/Half-Life/ and you can try it out.
    DO NOT overwrite the vanilla Half-Life DLLs. UNDER ANY CIRCUMSTANCES.
    • Win x 3
    • Helpful x 1
    • Epic win x 2
    • Agree x 1
    • Interesting x 1
    • Thanks x 2
    URL to post:
  • Hey, can you make a version for brutal half life beta 2, compress it and upload it there? Also, please teach me how to compile the client.dll file? It look so cool but i don't know how to do it (i'm dumb at coding)

    Bananite
    URL to post:
  • Kayf - Poc avatar
    Kayf - Poc username pic Joined 3y ago
    Offline
    1,296 points Ranked 23,053rd
    13 medals 1 legendary 1 rare
    • Returned 5000 times Medal icon
    • Returned 1000 times Medal icon
    • One month a member Medal icon
    • Thanked 5 submitters Medal icon
    • Submission featured Medal icon
    • Submitted 10 Skins Medal icon
    1y
    Can you upload this in rar or zip? I am too stupid for this coding and all those things.
    • Agree x 4
    Фанни Рашн Гай! avatar
    Mantra
    Фанни Рашн Гай!
    URL to post:
  • Can you upload the compiled one you used in the last gif?
    Eph. 4:31-32 | 1 Cor. 15:1-4
    URL to post:
  • AleKK avatar
    AleKK username pic Joined 4y ago
    Planning
    10,507 points Ranked 605th
    17 medals 2 legendary 1 rare
    • 2017 Top Contributor Medal icon
    • Returned 5000 times Medal icon
    • Returned 1000 times Medal icon
    • One month a member Medal icon
    • Returned 100 times Medal icon
    • Submission featured Medal icon
    1y
    I remember seeing some mods and addons with custom weapon-bobbing, but never actually saw any tutorials on how to do it

    It looks pretty good here, keep it up! We need more people who aren't afraid of experimenting
    • Agree x 1
    Duty is the greatest gift!
    URL to post:

Embed

Share banner
Image URL
HTML embed code
BB embed code
Markdown embed code

Credits

Key Authors
Admer456 avatar
Admer456 username pic Joined 6y ago
Gone. :3
26,334 points Ranked 197th
32 medals 2 legendary 5 rare
  • Submitted 30 Tutorials Medal icon
  • Returned 5000 times Medal icon
  • Submitted 15 Tutorials Medal icon
  • Returned 1000 times Medal icon
  • Reached 50 subscribers Medal icon
  • Received thanks 50 times Medal icon
Writer
Special Thanks
Shepard62700FR
Shepard62700FR Joined 12y ago
Offline
887 points Ranked 42,248th
6 medals 1 rare
  • 6 years a member Medal icon
  • One month a member Medal icon
  • 6 months a member Medal icon
  • 1 year a member Medal icon
  • 2 years a member Medal icon
  • 4 years a member Medal icon
How to enable HL WON bobbing

Submitter

Admer456 avatar
Admer456 username pic Joined 6y ago
Gone. :3
26,334 points Ranked 197th
32 medals 2 legendary 5 rare
  • Submitted 30 Tutorials Medal icon
  • Returned 5000 times Medal icon
  • Submitted 15 Tutorials Medal icon
  • Returned 1000 times Medal icon
  • Reached 50 subscribers Medal icon
  • Received thanks 50 times Medal icon
Admer456 avatar
Admer456

Creator
Sign up to access this!
Sign up to access this!
Sign up to access this!

Game

Sign up to access this!

Category

Details

Difficulty Level
Intermediate

Attributes

Share

  • Share on Reddit
  • Share on Twitter
  • Share on Facebook
  • Best of the Banana
    Featured on Jun 29 2019
  • Best of Yesterday
    Featured on Jun 28 2019
  • Today's Pick
    Featured on Jun 27 2019
  • 36
  • 13.7k
  • 69
  • 1y
  • 7mo
  • 7mo

More from Submitter

WiPs by Submitter

More Programming Tutorials