🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Major graphics overhaul

Published September 22, 2019
Advertisement

Dev. update: Major graphics overhaul

Over the past few weeks, Close Quarters received a cosmetic makeover:

beforeafter2.thumb.png.49532a27c3b3b9a11ae9a46faec8376f.png

See the “before” version live (networking disabled).
See the “after” version live.

I think it’s a major improvement! In this post, I discuss some of the details, technical and otherwise, of this major change.

The need for better graphics

My original graphics philosophy for Close Quarters was minimalism: simple, smooth graphics that provide the player with only the information that affects gameplay.

However, as time went by, I began to see the simple graphics as a detriment rather than a positive. Some people whom I showed the game were immediately dismissive because it “has no graphics”, so I began to fear that the vector graphics would give the impression that the game is a low-effort product and repel casual players. I also began to become more sensitive to the lack of visual variation (environments that consist only of line segments have no visual theme and all look alike). Hence, I decided to revamp the rendering engine to support textured polygons and other embellishments.

Graphic design principles

The paramount principle I wanted to maintain from the original graphics was clarity. I found inspiration in architectural and urban designs, for example:

planning-layout-sq.jpg

The desire for clarity influenced several choices:

I decided that all traversable space should feature very light and subtle textures so that players, projectiles, and effects (which were originally all designed for a white background) still stand out. See, for example, the following two textures:

texture-floor-tiles-250x250tiny.jpg.040bb674e4a95b34e35d6c9e7f3771cb.jpg testtilesbright.jpg.3d51588d06dd87103fd13f0fde3b3fbe.jpg

The original choice (left) has too many lines and details and is too dark, so it obscures bullets and other gameplay elements passing over it. Hence, I replaced it with the less complex and lighter texture on the right.

Similarly, I decided that solid polygons should generally have much darker colours so that they are easily distinguishable from traversable space.

I also increased the rendering size of projectiles so that they are more apparent against a textured background.

Finding resources

Finding textures subtle enough not to interfere with clarity isn’t easy. The two most useful resources I found were Subtle Patterns by Toptal and SketchUp Texture Club, both of which offer textures for free.

Rendering system

The internal workings of the new rendering system can be summarised as follows:

1. Upon the loading of the map, all polygons are triangulated individually.
2. Memory is then allocated for a number of arrays, one for each layer/texture. Enough memory is allocated so that each of these arrays could contain all the integer indices of every triangle bearing the corresponding texture.
2. The triangles are then added to the spatial partitioning system. This system is a grid, and each cell ultimately contains a list of the indices of the triangles that intersect it.
3. At run-time, the spatial partitioning system is queried with the axis-aligned bounding box of the player’s view, whereupon it adds the indices of all visible triangles to the aforementioned arrays, taking care not to allow triangles that span multiple grid cells from having their indices added to the relevant array multiple times.
4. These arrays (or, rather, the triangles whose indices are contained therein) are then rendered sequentially via a batching system that copies 5,000 vertices to the GPU at a time.

Rendering shadows

The most interesting aspect of the new graphics system is probably the soft shadows, which give everything a sense of volume. The shadows were also the aspect most time-consuming to produce (primarily because Close Quarters supports three graphics APIs, namely OpenGL, WebGL 1.0, and WebGL 2.0, and each one has its own idiosyncrasies).

I decided that the map designer should manually plot shadow polygons. Though tedious, this allows for some depth effects that would be difficult to achieve if the shadows were generated programmatically because the game stores only very basic height information for each polygon.

To render the shadows, I first render the shadow polygons in view in solid black to an offscreen, transparent framebuffer. I later render the content of that buffer to the screen using a one-pass blur fragment shader and a low alpha value:


precision mediump float;
varying vec4 vcolor;
varying vec2 vtexcoords;
uniform sampler2D texture;

const float blurinc = 0.002;

void main()
{
	vec4 c0 = texture2D( texture, vtexcoords + vec2( -blurinc, -blurinc ) ) * 0.0625;
	vec4 c1 = texture2D( texture, vtexcoords + vec2( 0.0, -blurinc ) ) * 0.125;
	vec4 c2 = texture2D( texture, vtexcoords + vec2( blurinc, -blurinc ) ) * 0.0625;

	vec4 c3 = texture2D( texture, vtexcoords + vec2( -blurinc, 0.0 ) ) * 0.125;
	vec4 c4 = texture2D( texture, vtexcoords + vec2( 0.0, 0.0 ) ) * 0.25;
	vec4 c5 = texture2D( texture, vtexcoords + vec2( blurinc, 0.0 ) ) * 0.125;

	vec4 c6 = texture2D( texture, vtexcoords + vec2( -blurinc, blurinc ) ) * 0.0625;
	vec4 c7 = texture2D( texture, vtexcoords + vec2( 0.0, blurinc ) ) * 0.125;
	vec4 c8 = texture2D( texture, vtexcoords + vec2( blurinc, blurinc ) ) * 0.0625;

	gl_FragColor = vcolor * ( c0 + c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 );
}

Usually, a Gaussian blur would be done in two passes because that would allow for each pixel to be rendered via N+N texture samples instead of N*N samples. In my case, my blur kernel is only 3x3 in size, so the difference between a one-pass blur and two-pass blur would only be the difference between nine and six samples, and the gain made by using the two-pass approach might be negated by the need for an additional framebuffer and the fact that I would be rendering twice.

One thing that is important to realise for anyone attempting to replicate this approach to rendering shadows is that the offscreen buffer should support multisampling. Otherwise, the shadow polygon’s edges will “snap” to the nearest pixel and therefore appear to “dance” very slightly as the view scrolls around. As WebGL 1.0 does not support multisampled framebuffers, this undesirable effect can currently be seen in Close Quarters when played using Microsoft Edge, which does not support WebGL 2.0.

Also note that a similar soft shadow effect can be achieved without relying on a blur shader. Once the shadows are rendered with solid black into the offscreen buffer, the offscreen buffer can then be rendered to the backbuffer a dozen or so times with a very low alpha value and slightly offset in a circular pattern, resulting in blurred edges. The advantage of this approach is code simplicity, but I found its performance erratic in WebGL (sometimes it would have no discernible performance impact and other times it would cause the frame rate to drop from 60 to about 45).

New gameplay possibilities

While this “makeover” is mainly cosmetic, it does open new possibilities regarding gameplay mechanics. Firstly, the addition of shadows makes it easier to represent depth, so by carefully crafting the environment, it is now possible to create spaces that appear higher than others:

depth.png.d5f071d605c4628993cd2813f20c0767.png
Longer shadows on the right building suggest greater height.

Moving into such spaces could cause the player’s view to zoom out slightly, giving an advantage in terms of seeing distance.

Secondly, top-level overlays can provide concealment, a mechanic that exists in the game surviv.io. Currently, such concealment is possible under treetops in Close Quarters:

trees.png.fc9b13e6ce77d5790b35586d8a71bc28.png

Going forward

Of course, there is still much room for graphical improvements. Some elements, such as the explosions, looked good when paired with the old, simple graphics, but now look too basic, so I will have to make an effort to restore congruence across all the different visual elements. Also, the additional rendering seems to be having some side effects on Web Audio such that a crackling noise can now be heard in some clips – an issue that could be related to JavaScript’s lack of multithreading and will need to be explored.

0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement