Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
September 19, 2017
arrowPress Releases






If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 

One Month Polish: Taking a Game from Ugly to Pretty As A Non-Artist

by Solomon Lutze on 06/01/17 09:55:00 am   Featured Blogs

2 comments Share on Twitter    RSS

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

I am bad at making visuals, so I spent this month trying to make my game-in-progress JELLYBEAM (which you can play here) pretty. I spent as little time as possible on the actual mechanics, and focused instead on making it look nicer and nicer wherever possible.

This writeup isn't intended to be a step-by-step guide to recreating all the effects used in the JELLYBEAM demo, nor is it meant to be a comprehensive overview of those effects. Instead, I'm aiming to identify what effects I used and what they let me accomplish. My goal is to give other developers who aren't familiar with visual effects an idea of what tools are available to them to look into further.

Moreover, I want to point out to those developers who, like me, have a difficult time envisioning a polished end product, how unnecessary that detailed final vision is for the purpose of making your work more attractive. I had an idea of what I wanted this game to feel like, and at each step I identified something existing that I could improve and made that improvement. If it brought it closer to the feeling I was seeking, I kept it; otherwise, I tried again. If lack of a detailed vision of a finished product keeps you from trying to improve your game or art, I recommend identifying something that feels lacking, or which hints at but doesn't quite achieve a nice effect, and working at improving that aspect only. Move on when you feel you've made a true improvement. Repeat this a few times. See if you don't feel like the result is better than the original. Here is what JELLYBEAM looked like at the start of the month:

The blue sphere in the middle is our player, trailing a set of spheres behind it using a simple particle system to show where it's been. The sphere darting around the player is our enemy - our player can grapple the enemy and spin around it, though there's very little visual effect showcasing this. 

This gif also showcases the first visual optimization I made: adding a pulsing light to the enemy. The pulsing light consists of a simple Unity point light with a script that modifies its intensity over a given period of time:

```
    public float flickerTime = 1.0f;  // time it takes to go from min to max intensity
    public float initialIntensity = 1.0f; // minimum intensity
    public float targetIntensity = 2.0f; // maximum intensity
    float t = 0f;
    Light light;

    // Use this for initialization
    void Start () {
        light = GetComponent<Light> ();  // assign the light component to a reusable variable
    }

    void Update() {
        light.intensity = Mathf.Lerp(initialIntensity, targetIntensity, t); // set intensity to t * 100% between initial and target intensity;
        t +=  Time.deltaTime / flickerTime ; // increase t
        if (t > 1.0f) // we have completed an intensity cycle
        {
            float temp = targetIntensity; // switch initial and target intensity
            targetIntensity = initialIntensity;
            initialIntensity = temp;
            t = 0.0f; // reset t
        }
    }    

```

Lerp is doing most of the heavy lifting here; it takes a start and end number, as well as a number _t_ between 0 and 1. When t is 0, it returns the start number; when t is 1, it returns the end number. You can smoothly update t, as we're doing here, to get gradual increases in a number. Adding time.deltaTime divided by our flickerSpeed ensures t reaches 1 after `flickerSpeed` seconds.

This light works, but it's a bit flat. To give me more control and make the light a bit more intense, as well as to reduce reliance on true light sources, I decided to add some bloom.

Bloom, which is a part of the standard Unity PostProcessing stack, essentially gives you the ability to define a brightness threshold beyond which surfaces will begin to glow. To use it, you'll need to:
 -download the Unity PostProcessing stack from the Unity Store (for free)
 -create a new post-processing profile (right click in project -> create -> Post-Processing Profile)
 -define and enable bloom on the profile (check the unity docs for more information) 
 -Add the Post-Processing Behavior component to your scene's camera and reference your new post-processing profile on it
 
 Here are the settings I used for my bloom effect:
 

 
To get objects to glow once you've added bloom, you'll need to make their materials emissive. I gave my enemies an emissive material to give them way too much glow:

And then toned it down some:

What works best for you will depend on the style you're going for and the specific content of your game, so mess with it some. I advise setting a low gamma threshold and high emission on your materials so you can be sure it's all hooked up correctly, and then scale it back a lot.

For my next step, I decided to replace the spheres following my jellyfish with some tentacles - a jellyfish with no tentacles can hardly be said to be a proper jellyfish at all. To do this, I used Unity's LineRenderer component.

LineRenderers are pretty simple components: you give them a list of points, and they draw a line between those points. My initial plan for was to create child objects on my jellyfish that each had a LineRenderer component and a Tentacle script that controlled it. The Tentacle script held an array of points; initialized to create a line behind the player. Each FixedUpdate, the Tentacle script pushed its current position onto the front of that array, like a queue. That array was then passed to the LineRenderer as its positions. The result, with three tentacles, looked like this:

At this point the ball was looking kind of silly, so I decided to make a simple bell shape in Blender to act as my jellyfish bell. I don't intend for this to be a Blender tutorial, so I'll just say that everything I did was done by deleting and scaling vertices and using the extrude tool - those few things will get you very far, and if you run through a couple half-hour blender tutorials on YouTube you'll have all the tools you need to make something like this:

To give the impression of bioluminescence I made the bell material slightly transparent and a bit emissive, then attached another pulsing light to it. Technically that light is between the jellyfish and the camera - I just manipulated the distance until I liked how it looked.

After that, I spent a lot of time trying to get the tentacles to look good with a standard mesh shader before realizing that all of the documentation and StackOverflow responses I'd read on the matter were correct - particle shaders look way better on line renderers than any other kind of shader:

You've probably noticed at this point that our jelly gains some spin from swinging around the enemy, but doesn't have any innately and freezes while swinging around enemies. I decided that the effect I wanted was to have the tentacles constantly spinning at a speed proportional to the jellyfish's overall velocity.

This required some hacking - the jellyfish's rigidbody (physics component) has to allow some rotation to get the physical effect I want. First, I nested the bell mesh under an empty object called ForwardFacing (itself nested under the main player object, which has the rigidbody attached to it) and nested the tentacles under the bell object:

Then, I created a ForwardOrient script that does two things: forces itself and all its children to always face the direction the object is moving in, and applies a rotation to itself and its children along its forward-facing axis based on velocity:

```
public class ForwardOrient : MonoBehaviour {

    public float spinSpeedMult = 40.0f; // how quickly the object spins; higher mult = faster spin
    private Quaternion previousRot; // track last given rotation in case we aren't moving
    protected float t = 0;

    // Use this for initialization
    void Start () {
        previousRot = transform.rotation; // initialize previousRot so it's never null
    }
    
    // Update is called once per frame
    protected void Update () {
        Vector3 velocity = GetComponentInParent<Rigidbody>().velocity;
        if (!velocity.magnitude.Equals(0.0f)) { // if we are moving at all, our rotation should be the direction we're looking at
            previousRot = Quaternion.LookRotation(Vector3.Normalize(GetComponentInParent<Rigidbody>().velocity));
            transform.rotation = previousRot;
        }  else { // if we aren't moving, our rotation should be the last rotation we had
            transform.rotation = previousRot;
        }
        t += Time.deltaTime * GetComponentInParent<Rigidbody>().velocity.magnitude * spinSpeedMult; // deltaTime is multiplied by velocity magnitude times a given mult
        t = Mathf.Repeat(t, 360.0f); // when t is increased beyond 360, subtract 360 from it
        transform.Rotate(Vector3.forward * t); // now that we're-facing 'forward', rotate us around the forward axis
    }
```

Starting to look like a jelly! The next step was to visit the color section in the LineRenderer to set the colors over time. I had it fade from a blue-grey to white, and also had it become transparent at the tip to give the tentacles a more ethereal feel. After adding 2 more tentacles and shortening them a bit, this was the result:

By this point it was starting to look a little strange without an actual grapple beam, so I decided to add that. When I changed my jellyfish tentacles to fade out I lost the light-beading effect where tentacles overlapped, so I wanted to reproduce that here. To get the effect I wanted, I added:

-A single LineRenderer that drew a line between the player and the enemy using a script called GrappleBeam;
-Two additional LineRenderers that drew oscillating lines around the center line (I called these GrappleBeamOuter);
-An empty GrappleBeamParent component to decide when to draw/destroy these beams

The GrappleBeam script is simple enough; it takes the player position and the enemy position and passes those points to the LineRenderer component. 

The GrappleBeamOuter script is maybe the most conceptually complicated single component I made for this project, and there's a little much to get into for this post. The solution had a few parts:

-Create a sequence of points between the player and the enemy stored in terms of their local position - that is, position relative to their parent object, on the player
-Have the parent object constantly face the enemy, so the locally-positioned points are always drawn towards the enemy
-Give those points a curve by adding a sine offset to them
-Convert the points into worldspace and give the converted points to the LineRenderer to draw

This effect was pretty complicated to implement, and maybe more work than I should have given it in a one-month polish, but I am happy with how it turned out:

Next up was the background. My drawing isn't as strong as my programming so I opted not to draw any backgrounds. Instead, I attached a few particle systems to the camera (which already had a script that caused it to follow the player). I placed each of the particle systems at different distances behind the player so that they'd create a parallax effect and give a sense of depth. 

I wasn't immediately in love with this, but without a clear sense of how to improve it, I decided to try something else and come back to backgrounds later. The next obvious thing to me was to clean up our enemies, which are more or less exactly the Blender's default torus shape. I gave them some tentacles of their own and tweaked their material's color and emissiveness to adjust their bloom. Now they looked like this:

The tentacles help give an impression of speed, but we can do better. I decided to create a script that scales an object based on velocity, so that it is slightly longer along its forward axis and narrower along its other axes, with the exact variation depending on how fast the object is moving. I tweaked the numbers until I got a little bit of change - enough to be noticeable but not enough to be weird:

I liked this effect enough to apply it to my player as well.

Satisfied with enemies for now, I returned to backgrounds, which took some more experimentation to get right. Eventually the solution I settled on was:

-give the particles very wide spawn radiuses, but limit their motion towards/away from the camera; this allowed me to give the different particles more distinct layers
-make all particles less intense, to give a feeling of murky water between them and to make them look less like stars in the night
-make particles in the background larger, longer-lived, and slower-blinking, to offer a sense of scale, suggesting huge and sluggish things in the distance 

There's no real game to speak of here yet, and even the art is far from perfect, but I don't think it's controversial to say that the game now looks much better than it did at the start of the month. Again, the main thing I want to communicate is that I didn't start this month with a clear mental image of what the game would look like. Instead, after each change I looked at what I had, found something missing, or something that could be improved, or something hinted at but not yet present, and changed it accordingly as best I could. If something was too tricky I did what I could and moved on, and if I didn't know what the right solution was for a problem I left it and came back later.

If you're looking to improve the way a project looks but don't consider yourself an artistic person, the lessons I want to leave you with are: Don't be intimidated by skills you think you don't have. Don't be discouraged if you don't know exactly what you want it to look like. Don't assume that because you're "not an artist" you can't make a judgment about whether changes you've made improve your work or not. (And absolutely, ABSOLUTELY, don't feel like this process is beyond you if something in this guide didn't make sense or felt beyond your abilities - I didn't know how to do any of these work I talk about in this post a month ago.) 

Just make small changes to the things that feel like they need it the most. If the changes are bad, try again. If they are good, repeat this process. I think after a few of these cycles your work will feel more alive and beautiful, and the polishing process will feel like a much more doable task.


Related Jobs

DigitalFish, Inc.
DigitalFish, Inc. — San Mateo, California, United States
[09.18.17]

Software Engineer - Mechanical Learning
DigitalFish, Inc.
DigitalFish, Inc. — Mountain View, California, United States
[09.18.17]

Software Engineer - AR/VR
DigitalFish, Inc.
DigitalFish, Inc. — Mountain View, California, United States
[09.18.17]

Senior Software Engineer - Unity/VR
Insomniac Games
Insomniac Games — Burbank, California, United States
[09.15.17]

Mid to Sr Gameplay Programmer





Loading Comments

loader image