132 lines
7.6 KiB
Markdown
132 lines
7.6 KiB
Markdown
---
|
|
title: Michael Abrash's Graphics Programming Black Book, Special Edition
|
|
author: Michael Abrash
|
|
date: '1997-07-01'
|
|
isbn: '1576101746'
|
|
publisher: The Coriolis Group
|
|
category: 'Web and Software Development: Game Development,Web and Software Development:
|
|
Graphics and Multimedia Development'
|
|
chapter: '70'
|
|
pages: 1291-1293
|
|
---
|
|
|
|
From the beginning, Quake was conceived as a client-server app,
|
|
specifically so that it would be possible to have persistent servers
|
|
always running on the Internet, independent of whether anyone was
|
|
playing on them at any particular time, as a step toward the long-term
|
|
goal of persistent worlds. Also, client-server architectures tend to be
|
|
more flexible and robust than peer-to-peer, and it is much easier to
|
|
have players come and go at will with client-server. Quake is
|
|
client-server from the ground up, and even in single-player mode,
|
|
messages are passed through buffers between the client code and the
|
|
server code; it's quite likely that the client and server would have
|
|
been two processes, in fact, were it not for the need to support DOS.
|
|
Client-server turned out to be the right decision, because Quake's
|
|
ability to support persistent, come-and-go-as-you-please Internet
|
|
servers with up to 16 people has been instrumental in the game's high
|
|
visibility in the press, and its lasting popularity.
|
|
|
|
However, client-server is not without a cost, because, in its pure form,
|
|
latency for clients consists of the round trip from the client to the
|
|
server and back. (In Quake, orientation changes instantly on the client,
|
|
short-circuiting the trip to the server, but all other events, such as
|
|
motion and firing, must make the round trip before they happen on the
|
|
client.) In peer-to-peer games, maximum latency can be just the cost of
|
|
the one-way trip, because each client is running a simulation of the
|
|
game, and each peer sees its own actions instantly. What all this means
|
|
is that latency is the downside of client-server, but in many other
|
|
respects client-server is very attractive. So the big task with
|
|
client-server is to reduce latency.
|
|
|
|
As of the release of QTest1, the first and last prerelease of Quake,
|
|
John had smoothed net play considerably by actually keeping the client's
|
|
virtual time a bit earlier than the time of the last server packet, and
|
|
interpolating events between the last two packets to the client's
|
|
virtual time. This meant that events didn't snap to whatever packet had
|
|
arrived last, and got rid of considerable jerking and stuttering.
|
|
Unfortunately, it actually increased latency, because of the retarding
|
|
of time needed to make the interpolation possible. This illustrates a
|
|
common tradeoff, which is that reduced latency often makes for rougher
|
|
play.
|
|
|
|
> 
|
|
> Reduced latency also often makes for more frustrating play. It's
|
|
> actually not hard to reduce the latency perceived by the player, but
|
|
> many of the approaches that reduce latency introduce the potential for
|
|
> paradoxes that can be quite distracting and annoying. For example, a
|
|
> player may see a rocket go by, and think they've dodged it, only to find
|
|
> themselves exploding a second later as the difference of opinion between
|
|
> his simulation and the other simulation is resolved to his detriment.
|
|
|
|
Worse, QTest1 was prone to frequent hitching over all but the best
|
|
connections, because it was built around reliable packet delivery (TCP)
|
|
provided by the operating system. Whenever a packet didn't arrive, there
|
|
was a long pause waiting for the retransmission. After QTest1, John
|
|
realized that this was a fundamentally wrong assumption, and changed the
|
|
code to use unreliable packet delivery (UDP), sending the relevant
|
|
portion of the full state every time (possible only because the PVS can
|
|
be used to cull most events in a level), and letting the game logic
|
|
itself deal with packets that didn't arrive. A reliable sideband was
|
|
used as well, but only for events like scores, not for gameplay state.
|
|
However, this was a good example of Carmack's Law: John did not rewrite
|
|
the net code to reflect this new fundamental assumption, and wound up
|
|
with 8,000 lines of messy code that took right up until Quake shipped to
|
|
debug. For QuakeWorld, John did rewrite the net code from scratch around
|
|
the assumption of unreliable packet delivery, and it wound up as just
|
|
1,500 lines of clean, bug-free code.
|
|
|
|
In the long run, it's cheaper to rewrite than to patch and modify!
|
|
|
|
So as of shipping Quake, multiplayer performance was quite smooth, but
|
|
latency was still a major issue, often in the 250 to 400 ms range for
|
|
modem players. QuakeWorld attacked this in two ways. First, it reduced
|
|
latency by around 50 to 100 ms with a server change. The Quake server
|
|
runs 10 or 20 times a second, batching up inputs in between ticks, and
|
|
sending out results after the tick. By contrast, QuakeWorld servers run
|
|
immediately whenever a client sends input, knocking up to 50 or 100 ms
|
|
off response time, although at the cost of a greater server processing
|
|
load. (A similar anti-latency idea that wasn't implemented in QuakeWorld
|
|
is having a separate thread that can send input off to the server as
|
|
soon as it happens, instead of incurring up to a frame of latency.)
|
|
|
|
The second way in which QuakeWorld attacks latency is by not
|
|
interpolating. The player is actually predicted well ahead of the latest
|
|
server packet (after all, the client has all the information needed to
|
|
move the player, unless an outside force intervenes), giving very
|
|
responsive control. The rest of the world is drawn as of the latest
|
|
server packet; this is jerkier than Quake, again showing that smoothness
|
|
is often a tradeoff for latency. The player's prediction may, of course,
|
|
result in a minor paradox; for example, if an explosion turns out to
|
|
have knocked the player sideways, the player's location may suddenly
|
|
jump without warning as the server packet arrives with the correct
|
|
location. In the latest version of QuakeWorld, the other players are
|
|
predicted as well, with consequently more frequent paradoxes, but
|
|
smoother, more convincing motion. Platforms and doors are still not
|
|
predicted, and consequently are still pretty jerky. It is, of course,
|
|
possible to predict more and more objects into the future; it's a
|
|
tradeoff of smoothness and perceived low latency for the frustration of
|
|
paradoxes—and that's the way it's going to stay until most people are
|
|
connected to the Internet by something better than modems.
|
|
|
|
#### Quake 2 {#Heading20}
|
|
|
|
I can't talk in detail about Quake 2 as a game, but I can describe some
|
|
interesting technology features. The Quake 2 rendering engine isn't
|
|
going to change that much from Quake; the improvements are largely in
|
|
areas such as physics, gameplay, artwork, and overall design. The most
|
|
interesting graphics change is in the preprocessing, where John has
|
|
added support for radiosity lighting; that is, the ability to put a
|
|
light source into the world and have the light bounced around the world
|
|
realistically. This is sometimes terrific—it makes for great glowing
|
|
light around lava and hanging light panels—but in other cases it's less
|
|
spectacular than the effects that designers can get by placing lots of
|
|
direct-illumination light sources in a room, so the two methods can be
|
|
used as needed. Also, radiosity is *very* computationally expensive,
|
|
approximately as expensive as BSPing. Most of the radiosity demos I've
|
|
seen have been in one or two rooms, and the order of the problem goes up
|
|
tremendously on whole Quake levels. Here's another case where the PVS is
|
|
essential; without it, radiosity processing time would be
|
|
O(polygons^2^), but with the PVS it's
|
|
O(polygons\*average\_potentially\_visible\_polygons), which is over an
|
|
order of magnitude less (and increases approximately linearly, rather
|
|
than as a squared function, with greater-level complexity).
|