Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

29. June 2016

 

Welcome to a new tutorial series here on GameFromScratch.com where we will be looking at core concepts of game programming.  This includes data structures, design patterns and algorithms commonly used in game development.  We start the series off with Finite State Machines.

 

There is an HD video version of this tutorial available here and embedded below.

 

What is a Finite State Machine?

 

A Finite State Machine (or FSM for short) is one of those concepts that sounds much scarier than it actually is.  In the simplest form it’s a datatype that can have only one value (state) from a finite selection of values(states).  The easiest way is to understand the finite state machine is to look at a real world example.

 

trafficLight

 

Yep, a traffic light is a perfect example of a FSM, or at least, the logic controlling it is.  Consider the three possible states this particular traffic light can be in.  At any given point (assuming I suppose the power is working...) the light will be one of three states, red, yellow or green.  It can never been more than one of those states at a time, it’s always red or yellow or green.  These are the two keep concepts of a finite state machine.  There are a finite number of states ( 3 in this case ) and only one is true or active at a time.

 

It’s a very simple concept, but extremely useful in game development.

 

What are FSMs Used For?

 

In game development, one of the most common uses for finite state machines is artificial intelligence.  Consider the example of PacMan’s ghosts.  A state machine can be used to control how they behave.  A ghost may have one of several different operating modes for example waiting to be released, hunting, hunted and dead.  The state machine is what is used to drive the ghost’s actions and to switch between states.  You will find AI examples absolutely loaded with state machines, often with some fuzzy logic controlling the transition between states to give a layer of unpredictability to your characters.

AI isn’t the only place of course, think of all the different things in a game that are related, there are multiple different states they can be in, but only one can be active at a time.  Game states are a very common example, where you break your game up into a series of states, for example Loading, Main Menu, Playing, High Score, Exiting.  Many game engines ( one such example is Phaser ) split your game up into a series of states.  The ultimate controller of these states is a finite state machine.  A sequential UI ( think of a sequence of dialogs controlled by next/back buttons ) can also be implemented using FSMs.  They are also commonly used to control elements in a games world.  Consider a game with a weather system, be it day or night cycles or season cycles like Spring, Summer, etc...  these would most likely be controlled via FSMs.

 

Implementing a Finite State Machine

 

The example we are going to use here is to implement a traffic light via FSM.  At it’s core the data is going to be stored in an enum, a natural fit for state machines, but stack based or array based options are also viable.  This example is not only going to switch the traffic lights periodically, it’s also going to implement callbacks so the world at large can interact with the light.  This example is implemented using C#, but should be easily adapted to most modern programming languages.

 

using System;

namespace GameFromScratchDemo
{

    public class TrafficLight{
        // This enum represents the three possible values our state machine can 
        be
        public enum States { Green, Yellow, Red };    
        // This is the amount of time for the timer to wait before changing 
        between states
        private const int LIGHT_DURATION = 5000;

        // An actual instance of our enum.
        private States _state;

        // The timer object that is going to be used to switch between states 
        private System.Threading.Timer _timer;

        // This function is called by the timer when it's time for a light to 
        change
        public void lightChanged(){
            System.Console.WriteLine("Light Changed");
            
            //  For each state, move to the next appropriate state.  I.e, red 
            becomes green, etc. 
            switch(_state){
                case States.Green:
                _state = States.Yellow;
                break;

                case States.Yellow:
                _state = States.Red;
                break;

                case States.Red:
                _state = States.Green;
                break;
            }

            // Reset our timer, so this will all happen again and again
            _timer.Change(LIGHT_DURATION,System.Threading.Timeout.Infinite);

            // Call our event.  This is used to communicate with the outside 
            world that our state change occured
            onStateChange(_state);
        }

        // In our constructor we simply set out default state (green) and 
        create/start our timer
        public TrafficLight() {
            _state = States.Green;
            System.Console.WriteLine("Light Created with initial Green state");

            _timer = new System.Threading.Timer( _ => lightChanged(), null, 
            LIGHT_DURATION,
                System.Threading.Timeout.Infinite);
        }

        // these two work together to provide the callback functionality
        // Implementing callback is going to differ greatly from langauge to 
        language
        public delegate void StateChangedResult(States newState);
        public event StateChangedResult onStateChange;
    }

    // Our actual program.  Simply create a traffic light instance
    // Register a callback that will simply print the current state returned 
    when the light state changes
    // And finally wait for the user to hit enter before ending the program
    public class Program
    {
        public static void Main(string[] args)
        {
            TrafficLight light = new TrafficLight();
            light.onStateChange += (TrafficLight.States state) => { Console.
            WriteLine(state); };
            Console.ReadLine();
        }
       
    }
}

The example is pretty well documented in the code above.  Essentially we are creating a class TrafficLight that can internally have one of three states Green, Yellow or Red.  It also implements a timer that switches between those states.  To make the code actually useful, it also implements a callback system so code external to the TrafficLight can interact with it as a black box.  The callback will be passed the current state value every time the light changes.

 

This is obviously a simple example of a state machine but the same basic premise remains regardless to complexity.  It is a very useful data structure for organizing code, especially the flow of logic.  Coupled with callbacks, it is also a great way of keeping systems decoupled as much as possible.

 

The Video

Programming, Design , ,

29. June 2016

 

Another week another Unity patch, this one version 5.3.5P6.  In addition to the usual spate of bug fixes, this patch includes several improvements to audio functionality, a bump to Oculus 1.5 and has been updated to work with XCode 8 for iOS builds.

The full release details:

Improvements
  • Audio: Added ability to transition AudioMixer snapshots by scaled and unscaled time.
  • Audio: Added virtualization of audio effects. For audio sources that are virtual because they have been culled due to low audibility or priority, attached effect components or spatializers are now also bypassed in order to save CPU use. The new behaviour is on by default, but can be turned off in the audio project settings.
  • Audio: Audio clip waveform preview now displays the actual format used for compression when the default format isn’t available on a certain platform.
  • Audio: Audio clips with the "Streaming" load type are no longer preloaded. This is done to reduce the number of open file handles in scenes referencing a large number of streamed clips. The behaviour is not affected except for a slight increase in playback delay of this type of audio clips.
  • Audio: Fixed audio clip waveform preview rendering sync issues after import, and improved the way the waveforms are being rendered to be more dynamic and reveal more detail.
  • Audio: Moved Preload Audio Data to the platform-specific settings section. The previous location was confusing as it was shown grayed-out in the inspector with a checkmark that depended on all overrides.
  • Audio: SystemInfo now includes supportsAudio info.
  • iOS: Update Build and Run to work with Xcode 8
  • VR: Updated to Oculus Version 1.5.
Fixes
  • (786827) - Animation: Fixed rotation values set in inspector restricted to [0,360] degrees when recording animation.
  • (800268) - Animation: Fixed animation event firing twice when controller is set by a script and an instantaneous transition is trigger in the same frame.
  • (778887) - Animation: Fixed crash when changing playable controller in animator in game mode.
  • (740603) - Audio: "Failed to initialize spatializer" warning message no longer appears when Spatializer Plugin is set to "None".
  • (758064) - Audio: Audio Profiler no longer shows "wrong" information when using Spatialization.
  • (632169) - Audio: AudioMixer.GetFloat() and SetFloat() now work without needing to restart Unity.
  • (782248) - Audio: AudioSource: Fixed issue whereby Doppler Level didn't work when used with custom spatializer plugins.
  • (772946) - Audio: Fixed case of component effect appearing disabled on play and becoming enabled again after pressing pause and then play.
  • (763036) - Audio: Fixed case of Unity crashing when the Disable Audio option was selected in Project Settings.
  • (784887) - Audio: Fixed crash when disabling component which uses OnAudioFilterRead.
  • (none) - Audio: Fixed handling of default DSP buffer size. Previously, once the buffer size was changed to something other than Default latency, changing it back to Default latency had no effect.
  • (781566) - Audio: Fixed issue where AudioListener with two custom scripts crashed when reinitializing the sound system.
  • (775328) - Audio: Fixed issue where the Audio Lowpass Frequency curve moved in the wrong direction in the AudioSource curve view.
  • (771825) - Audio: Fixed issue whereby adding an effect in the mixer with bypass effects enabled didn't rechain the component effect back properly.
  • (none) - Audio: Fixed issue whereby the memory profiler did not report AudioClip memory correctly. The memory allocated by AudioClips was wrongly accumulated under AudioManager.
  • (760985) - Audio: Fixed mixer reverb effects getting cut off early in standalone builds.
  • (718344) - Audio: Fixed random mixup between internal direct and reverb signal connections which could cause AudioSources to interfere and become silent under certain conditions.
  • (731177) - Audio: Large numbers of streaming audio clips no longer cause crashes in batch mode.
  • (732854) - Audio: Low Pass Filter now works on Audio Listener.
  • (715257) - Audio: Microphone.IsRecording(null) no longer returning true even when no devices were available.
  • (none) - Audio: Native audio plugin SDK: Fixed dspbuffersize having a value of 0 when default buffer size settings are selected.
  • (none) - Audio: Preloaded sounds now allow calling GetData in Start().
  • (none) - Audio: Project browser now updates after a change has been applied in the AudioImporterInspector.
  • (none) - Audio: Sounds marked as Play On Awake are now shown in Audio profiler.
  • (806648) - Editor: Fixed activate license failure if user switch user before activation.
  • (804864) - Editor: Fixed an issue causing unnecessary script compilation, and improved compilation error handling
  • (804139) - Editor: fixed an issue where custom windows could be removed when encountering errors in user editor scripts.
  • (802014) - IL2CPP: Fixed a crash that can occur during XML serialization with the .NET 2.0 profile.
  • (800496) - IL2CPP: Fixed a crash which can occur during the iteration of enum values cast as a list of System.Object values.
  • (804767) - IL2CPP: Corrected the packing for some C# struct definitions with explicit layout.
  • (805846) - IL2CPP: Fixed try/catch handling when filter type includes generic parameters.
  • (794660, 790555, 737693) OpenGLES: Fixed crash and reflection probes corruption on A9 chipsets (OpenGLES2.0).
  • (799560) - Windows Store: Fixed a crash which happened when serializing objects which have the first field be an array or a list on .NET scripting backend.
  • (805830) - Windows Store: Fixed a memory leak which leaked ~5 KB of memory per frame.
  • (804163) - Windows Store: Fixed an issue which sometimes caused "The referenced script on this Behaviour is missing!" after unloading unused assets while maintaining indirect references on the MonoBehaviours on .NET scripting backend.
  • (775624) - Windows Store: Fixed manifest generation for StoreLogo, when only scale-100 image is available.
  • (767548) - Windows Store: Load first scene after Unity splash screen is over.
  • (786277) - Windows Store: NetworkTransport.ConnectEndPoint will work correctly on UWP (required by secure sockets), note this function will not work on older Windows Store SDKs.

The patch is available for download here.

GameDev News

29. June 2016

 

Lumberyard is Amazon’s new game engine based on a forked version of CryEngine.  I did a short hands-on video of Lumberyard shortly after it was released if you want more information.  Earlier this month Amazon announced the upcoming release of Lumberyard 1.3, announcing that it would have VR support among other features.  Well that release date is now here, at least in Beta form.  This release brings with it over 130 features, improvements and fixes including some serious graphicalvolumetric_fog enhancements.  The two major features of this release are HDR support and the aforementioned VR support (currently Oculus Rift and HTC Vive).  There were several other graphical updates to the engine, including:

  • Volumetric Fog: We increased the temporal stability of volumetric fog, reduced the presence of flickering artifacts, and improved fog’s overall performance.
  • Motion Blur: To give a higher degree of control over the motion blur effect, we added a weighting algorithm to improve the visual quality of silhouettes and added a shutter speed control like those you find in a real-world camera.
  • Height Mapped Ambient Occlusion: This new feature generates ambient occlusion per pixel from a terrain height map, which brings out subtle details and depth cues in terrain that would have been previously unseen.
  • Depth of Field: We implemented a new depth of field technique that reduces edge-bleeding artifacts and utilizes fewer GPU resources.
  • Emittance: We have replaced glow with a physical-based model of emittance. This allows you to model glowing objects as proper citizens of a physically accurate world of lighting and materials. We have changed lighting calculations to properly account for emittance, and we provided a way to automatically convert older content to use the new emittance property.

On the mobile graphics side, we have improved iOS rendering performance by an average of 15%, which is a significant jump considering our mobile renderer is already leveraging Metal and GMEM to maximize performance. We also added adaptive and scalable texture compression (ATSC), which is useful for managing bandwidth, memory footprint, and power, all of which are important for low-power, mobile devices.

Finally, if you are a graphics programmer like me, then you are just as concerned about profiling and performance as pretty pixels. So one last thing I want to highlight is the integrated graphics profiler. You can now display all sorts of mission-critical performance stats in real-time, including detailed CPU and GPU timings per frame, per pipeline stage, per sub-system. You will also find many useful graphics counters like to draw call counts, shader counts, triangle, and vertices count. These run-time stats nicely complement capture-based analysis tools like RenderDoc and Lumberyard’s Driller logging system.

You can read the announcement blog here while the more detailed release notes are available here.

GameDev News

28. June 2016

 

Corona is a popular Lua powered mobile focused game engine, which just saw a new major release.  Major features of this release include Spine animation support and support for high DPI screens on both Windows and Mac.  There are several other new features however including:

Core and cross-platform features
Corona Simulator
  • High resolution screen support for macOS (retina) and Windows screens (DPI Awareness).
  • Console improvements.
  • Updates to file handling for opening projects, including opening directories and dragging files to the Corona Simulator icon to open projects.
  • native.showAlert() improvements on Windows.
  • The Corona Simulator now warns you if a plugin is required and needs configuration within build.settings.
  • You now get warnings in the Corona Simulator when there is a file name mismatch due to case sensitivity.
Android
  • Multi-Dex support.
  • Improvements to Android 6.x permission handling.
  • Support for Android Studio builds for Enterprise.
  • Videos can now be loaded from all Corona-defined directories.
  • Updated libpng to version 1.2.56.
  • Fixed an issue involving Java-based plugins and applications exiting.
  • Improvements around licensing support.
iOS
  • In-app purchase API store.purchase() can now take a table of item strings or a single item string, just like the similar API for other purchasing platforms.
  • New lines handled correctly in display.newText().
  • Improved rendering of large text objects.
  • Camera fill can now be invalidated more than once per frame.
macOS
  • Added support for system.setIdleTimer().
  • Improved handling of full screen apps.
  • Improved handling of native objects when resizing desktop builds.
  • Improved rendering of large text objects.
  • native.newTextBox() objects now support the “began” phase.
  • You can now control the window’s title bar for desktop builds.
  • Support for high resolution retina displays.
  • Added the ability to show and hide the mouse using native.setProperty().
tvOS
  • Support for On-Demand Resources.
  • Remote handling improvements including “relativeTouch”.
  • Improved rendering of large text objects.
Windows Phone 8 / Windows 10 Mobile
  • Added Visual Studio 2015 and .NET 4.6 support to CoronaCards for Windows Phone.
Windows Desktop
  • Easier to run Corona from the command line.
  • Added support for surround sound audio (5.1 and 7.1).
  • Support for high resolution screens with “DPI awareness”.
  • Added the ability to show and hide the mouse using native.setProperty().
  • Computers with touch screens will now show a virtual keyboard when you interact with native.newTextField() and native.newTextBox().
  • Better formatting for Corona Simulator error messages.

This release is available for download here.

GameDev News

28. June 2016

 

There is a new release of the Defold Game Engine, version 1.2.84.  WebView is now available on mobile platforms with certain limitations.  This release also includes improved sound on mobile devices with better call and battery management.  Among the other fixes are:

Engine

  • DEF-1674 - Added: WebView support on iOS and Android
  • DEF-1691 - Added: sound.is_phone_call_active() available on mobile devices
  • DEF-1857 - Changed: render.predicate now accepts hashes as well as strings
  • DEF-1914 - Fixed: Support for setting HTTPS URIs as resource.uri
  • DEF-1709 - Fixed: IAP callback did not run after opening a minimized app via the home screen on Android
  • DEF-1940 - Fixed: Some purchases using test accounts on Android resulted in error
  • DEF-1918 - Fixed: Stack problem on Android devices < 4.3
  • DEF-1920 - Fixed: Bundle dialogs for iOS and Android now remember the field entry data
  • DEF-1924 - Fixed: Android IAP dialog was shown multiple times if changing device orientation
  • DEF-1937 - Fixed: dmloader.js would sometimes try to load the same archive files multiple times
  • DEF-1825 - Fixed: Crash when on_message functions tried to return data
  • DEF-1278 - Fixed: Android implementation of sound.is_music_playing() now works correctly

Service

  • Updates of access token management. It is now possible to revoke access tokens.

Web

  • API documentation for render has been updated
  • An "Examples project" is now available
  • Return values has been clarified in API docs
  • API documentation has been added for WebView

If you are interested in learning more about the Defold Engine be sure to watch this video.  We also have a tutorial series in development here on GameFromScratch.com.

GameDev News

Month List

Popular Comments

Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

12. September 2013

 

So after finishing up my ongoing Blender tutorial series, I intend to take a closer look at LibGDX and hopefully launch a new tutorial series.  This however presented a bit of a challenge to me.  You see, although I have experience with Java, it’s pretty out of date.  Since the release of C#, I’ve done very little work in Java other than some dabbling here and there.  So my knowledge is certainly out of date.  For example, when I last seriously programmed in Java Annotations ( ie @Override ) didn’t exist and the language didn’t yet have generics.

 

Obviously I need to get up to speed with modern Java before I start writing some truly embarrassing code.  This however presented a terrible problem for me.  Most texts are either targeted towards complete beginners or are more advanced and targeted at a very specific domain or technology.  The beginners texts make me want to scratch my eyeballs out, as after a decade of working in C#, and a few years of working in Java before that, reading about what a class is, or what a private variable does is a little…  behind me.  On the other hand, the little tidbits of information I need ( about what’s new ) are buried in these descriptions. 

 

I’ve been looking for an ideal book and I haven’t found one.  Something along the lines of Effective C++ or JavaScript: The Good Parts would be absolutely ideal.  Both of those books present best practices for experienced programmers in the modern usage of each language.  Both are incredible reads and will change the way you program.  Sadly, I haven’t found a Java equivalent yet.  There are a couple books I’ve tried.

 

The first was Java: The Good Parts.  By the title, I was really expecting something like the JavaScript book I mentioned earlier.  I will say, I do recommend this book, but it really isn’t what I am looking for.  The author Jim Waldo has been at Sun ( er, Oracle ) a very long time and has a deep insight into the Java language and how it evolved.  It answers a lot of the “why the hell did they do this???” questions you might have about various language features.  That said, the target audience seems a bit confused, at times covering brutally simple tasks in detail, like it was aimed at a beginner.  Then jumping into a topic at a more advanced level.  Basically this means I have to read through a lot of stuff I already know quite well.   I don’t regret reading it though, again, it gave some pretty good insight behind the curtain of language development.

 

Then I went with Learning Java 4th Edition as it was one of the most up to date releases ( July 2013 ), was reasonably well reviewed on Amazon and Safari and seemed to be partitioned nicely into beginner and more advanced topics.  At the end of the day, I guess I am resolved to have to go through all the beginner stuff to pick up what’s changed.  Oh well I guess.

 

So, to any of you Java developers out there… are there any books along the lines of what I am looking for?  A text that focused on writing modern Java code.  That illustrate what parts of the language are cruft and what various best practices are?  A text aimed at a non-beginner?  If there is a book you recommend, I would love to hear it!.

Programming ,

11. September 2013

 

Now we are going to export our texture so we can edit it in an external image editor.

 

First in the image editor, make sure Mode is set to View.  ( We changed it to paint in the last section ).

 

In UV Window, Select Image-> Save As Image

image

 

Pick a filename and location and then click Save As Image:

image

 

Now we can export the UV layout to help us with the painting.

 

In 3D View, switch to edit mode and select All ( A ).

In the UV window select the UV menu, then Export UV Layout:

image

 

Once again, pick a directory and location for the saved image file.  I personally went with ReferenceImages5UVLayout.png.

 

Now load your exported texture file in your image editor of choice.  You have the option of registering a program that will be opened by Blender automatically if you prefer, then you can simply select Image->Edit Externally.  For now we will simply open it manually.

 

In this case I am going to use the GIMP as the editor.  The GIMP is a freely available 2D graphics package.

 

Here is our texture loaded in GIMP. 

image

 

Now let’s load the UV Layout.  In the GIMP select File->Open As Layers

image

 

Select the file you saved the UV layout to.  Now it should appear like so in GIMP:

image

 

Now we draw the additional texture details on our texture.  Just be certain you have the right layer selected when you edit:

 

image

 

Drawing textures is an art in and of itself that I can’t cover here.  Frankly, I am not very good at it either.  Now I add some graphical details to the image and end up with something like this:

 

Untitled 3 2 (6)

 

… yeah, I’m no artist!  Don’t worry though, in sprite sheet form it will look just fine.  Just make sure when you export the image from your image editor, the reference layer ( the wireframe ) isn’t visible.

 

Once you are done editing your texture, assuming you didn’t change the location or filename, in the UV/Image Editor window, simply select Image->Reload Image or press Alt + R.  If you did change the file name, instead select Image->Replace.  Keep in mind you also have to change the texture name in the Texture panel if you renamed it.

 

image

 

As a 3D model though, it could certainly use a bit of work.  It’s a matter of adding more details to the texture, as well as implementing normal maps to give it some depth, something we will hopefully talk about later.  You can also greatly improve rendering with various texturing modes ( specular, bump, etc ) which only will work within Blender.  ( Wont work when exported to a game engine ).  This is also something we will hopefully talk about in more detail later.  Texturing adds a hell of a lot to your models quality, so it’s certainly a skill you should take some time to develop ( unlike me! Smile )

 

image

 

 

Tips

Often you will find yourself working in the UV Window and wanting to figure out just what @#$@$#ing Polygons you are working on.  Fortunately there is an easy way to do this.  In the UV window, make sure you are in View ( as opposed to Paint ) mode.  Then click the Keep UV and edit mode mesh selection in sync icon:

image

 

Now you can select stuff in the UV window:

image

And in the 3D View, the corresponding items will be selected.

image

 

 

Another thing you might have noticed is how incredibly annoying the layout is to paint on.  The UVs are set how Blender thinks they fit best, not necisarrily how you think they should be arranged to paint on.  You can however move the UVs however you want.  Unfortunately every single time you Unwrap again, the UV layout changes you have made will be reset.

 

Say for example we want to paint our cockpit in it’s natural direction.  We could then move the cockpit UVs into a position that is more appropriate to painting ( using G(rab), R(otate) and S(cale) like normal 3D editing ).  Like I’ve done here by moving them to the right and rotating 90 degrees:

image

 

This will be a great deal easier to paint.  Unfortunately if we go to 3D View and choose Unwrap:

image

 

Well, that’s annoying!  Fortunately there is a solution.  If you want to have a custom UV layout, you need to “Pin” them in place.  Then when the model is Unwrapped again, Blender knows where to put it.

 

Select the outermost two vertices and press P to pin them in place.  The selected value will turn red(ish) when selected, like so:

image

 

Now the next time you Unwrap the texture, these UVs will be pinned in place.  Of course, you could just select and Pin all vertices in place, but you are greatly handicapping Blender’s ability to deal with UV map changes.  Keep in mind too that adding a Seam will automatically cause an Unwrap. 

 

Final tip.  Notice the ugly line across the tail of the plane?

image

What causes this?  It’s the texture seem.  Basically make sure the edges of your textures where you cut a seam have a matching seamless colouring on both sides, or you will end up with an ugly artefact like this.  A few seconds with a Blur brush would solve this problem.

 

The astute eyed may also notice that the text is mirrored on the mirrored half of the model:

image

 

This is a side effect of using the mirrored modifier.  You’ve got a few options here.  1 – apply the modifier, to form a single mesh and texture each side manually ( nah! ).  2- Switch to a symmetric number like 808  3- live with it.  I’ve chosen 3.

 

Next up we will look at animation.


Click here for the Next Part

 

Art , ,

9. September 2013

 

First, let me start by saying this step is completely optional!  Blender has integrated texture painting functionality, but if you prefer to work entirely in a 2D application like GIMP or Photoshop, that is completely your option.  That said, Blender’s painting abilities are pretty solid and are a great way to block in colours rapidly. 

 

You enter Texture Painting mode the same way you enter Object or Edit mode, in 3D view.  Just pull down the mode dropdown and select Texture Paint.

image

 

Once in Texture Paint mode, hit T to open up the Tools panel.

 

Clicking the Brush icon allows you to select between the various brushes:

image

 

While the controls right below the brush allow you to select the active color, set the brush strength, radius and blending mode ( as in colour blending ):

image

 

 

There is a ton more functionality in there, such as painting with a texture pattern, changing brush stroke styles, etc… but we will just be using the painting tools to block in our basic colours.  Most jets have a grey on grey camouflage colour and that’s what we are going to go with here. 

 

Let’s start with our base color, from the colour picker, select a light grey colour.  Then set the radius to a large value and keep strength at 1 ( full ).  Like so:

image

 

Now you should see a very large circle over the cursor in 3D View.  This represents the radius of the brush.  Left clicking will paint with the current brush:

image

 

Now, let’s look at something rather cool.  As you paint in the 3D View, it will automatically update in the UV window:

image

 

Even cooler, you can paint in the UV window and it will update in the 3D view.  To paint in 2D in the UV window, simply click the Mode dropdown at the bottom of the UV/Image Editor window and select Paint.

image

 

Now you can paint in the UV window!  Keep in mind though, colour and brush selections are still done from the Tools panel of the 3D view.

 

Now I am just going to paint the entire Jet in our light grey colour.  Keep in mind you will have to rotate and zoom the camera around to get in every nook and cranny while painting.  Fortunately you can easily see from the UV windows if you missed a spot.  You of course could just paint in the 2D layer, but then you don’t get nice crisp edges in the texture map.

 

Here is the fully painted jet:

image

 

Next I simply vary the grey-ness of the brush and randomly layer colours to get a gray on gray camo pattern.  I then pick a slightly darker gray and colour in the cockpit area.

 

image

 

That’s it for painting in Blender.  Next up we will finish the details of our texture in an external 2D graphics package.


Click here for the Next Part

 

Art , ,

6. September 2013

 

This one is short and sweet.  Until this point, we haven't actually applied a texture to our model, we’ve instead been using a reference grid image.  We can re-use the same image file as our texture.

First in the Properties window, we click the Textures tab:

image

 

Next we create a new texture, simply click New

image

 

Now we drop down the Type dialog and select Image or Movie:

image

 

Now click the Browse Image button:

image

 

Now select our reference image:

image

 

Now scroll down to the mapping section and select Coordinates, then pick UV

image

 

Pull down Map and select our UVMap:

image

 

Your texture is now applied.  If you render (F12), you should see:

image


Click here for the Next Part

 

Art ,

6. September 2013

 

As I mentioned in the prior tutorial section creating a UVMap is basically like wielding a pair of virtual scissors to cut your 3D object up so it can be smushed flat.  As we saw earlier, the default unwrap map is pretty, subpar:

 

Default unwrap:

default

 

Let’s start cutting things up.  First we will default the wings.  In 3D view, make sure you are in Edit mode and Edge selection, then select the edges at the base of the wing, like so:

image

 

Now we want to mark the selected as a seam.  Press CTRL + E to bring up the Edge menu, and select Mark Seam.

image

 

Or you could use the button in the Tools panel of 3D View:

image

 

Both options do exactly the same thing.  Once the seem is marked it will appear as red:

image

 

Now you can see the result of marking a seam.  In 3D view, select all edges ( A ) and take a look at the UV window:

image

 

We now have a completely separate collection of UVs ( called a UV island ).  I still wouldn’t want to paint over these UVs yet, so we have a bit more work to do.  In order to be able to flatten the wing even more, lets mark another set of seams, like below:

image

 

Now look what happened to the UVs

image

 

That is certainly much easier to paint over!  Of course, you could have split the wing top and bottom easy enough but each additional seam makes painting a bit trickier.

 

Remember the textured view of our jet from the previous tutorial:

badUVs

Instead of a checkerboard texture on the wing, you just got a white blotch.  Now that we marked the wing seams, look at the result:

image

 

MUCH better!  Ultimately our goal is to make the entire jet have a checkered texture like that.  The process is exactly the same, just keep marking seems in the model until the UV layout makes sense.  Let’s repeat the same process on the back wing and then the tail.  If you make a mistake, you can simply Clear Seam on the selected seam.  To completely undo your changes, select all edges and do CTRL+E –> Clear Seam and you are back to default.

 

I marked the following seams on the back tail and wing:

image

 

 

Resulting in this UV layout:

image

 

And in our rendered view:

image

 

Next lets cut the jet in half vertically.  Select the continuous loop all the way around the jet, it will meet up with the wing cut:

Front:

image

 

Back:

image

 

Highlighted:

image

 

You want a continous edge around the entire jet that will cut it between top and bottom.  Once selected, mark the seam.

image

 

Now mark the area surrounding the air intake:

image

 

This however results in an unwanted seam, shown below marked in green:

image

 

Select those edges and then select Clear Seam.

 

Now we have:

image

 

And the following UV layout:

image

 

Keep in mind, Blender automatically sets the positions, so yours might be a bit different layout wise.

 

Finally, lets seperate the cockpit away from the fusalage:

image

 

The cockpit:

image

 

And finally, the tail:

image

 

And now our fully UV mapped model:

image

As you can see, the texture pattern flows pretty well over our image.  There are portions where we might get into a bit of trouble but they aren't areas where we are going to need details, so we should be good to go!

 

 

Well, that sucked, there has to be an easier way!

 

Yeah, actually, there is.  Blender has something called a Smart UV Project.  To use it, in 3D View, in edit mode, select all, then press U.  In the resulting menu select Smart UV Project:

 

image

 

Then a dialog will appear:

image

 

As I understand it, Smart UV looks at your model and separates UVs based on the angle between shapes.  So for example, since the wing essentially meets the fusalage at 90 degrees, it will easily be split into it’s own UV group.  Play around with the angle limit until you get a grouping you like.  Here is the result at 66 degrees.

 

image

 

Not ideal, but certainly a hell of a lot easier!

 

 

We only touched on a very small bit of what you can do with UVmaps.  Just keep in mind, if you add another seam ( and thus generate another Unwrap ), the positions will be reset.  Otherwise you can scale, turn, relocated, etc… UV coordinates to your hearts content.  If you don't want them to be scaled again, you can Pin (p) a UV in place.

 

Selection Options

 

You may find that you want to select Polygons from the UV layout screen.  By default it’s setup that what you select in the 3D view will be selected in the UV view, but it’s possible to do the opposite.

You need to click the “Keep UV and edit mode mesh selection in sync” button.

image

 

Now making a selection ( such as using the B)ox select mode ) in the UV window:

image

 

Will select the corresponding polygons in the 3D view:

image


Click here for the Next Part

 

Art ,

Month List

Popular Comments