Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
16. October 2014

 

GameFromScratch has a long running “A closer look at” series of articles that take a deep dive into a particular game engine.  Hopefully by the end, you the reader will have an idea if this engine is the right fit for you or not.logo

 

Today we are looking at the Urho3D engine, a game engine that somehow flew below my radar for a very long time.  It started life as Bofh3D but apparently was renamed after a tyrannical fish king ( seriously… and thus the fish in the logo to your right! ) According to Google Translate, Urho is Finnish for “Brave”, while 3D… I hope you know that one by this point!  The 3D is a bit of a misnomer though, as like many modern 3D engines, there is a 2D component as well, so you can just as easily make 2D games if that’s what you want to do.

 

Let’s start straight away with their own description:

 

Urho3D is a lightweight, cross-platform 2D and 3D game engine implemented in C++ and released under the MIT license. Greatly inspired by OGRE and Horde3D.

 

Features

  • Direct3D9 or OpenGL rendering (Shader Model 2, OpenGL 2.0 or OpenGL ES 2.0 required as minimum)
  • HLSL or GLSL shaders + caching of HLSL bytecode
  • Configurable rendering pipeline. Default implementations for forward, light pre-pass and deferred rendering
  • Component based scene model
  • Skeletal (with hardware skinning), vertex morph and node animation
  • Automatic instancing on SM3 capable hardware
  • Point, spot and directional lights
  • Shadow mapping for all light types; cascaded shadow maps for directional lights
  • Particle rendering
  • Geomipmapped terrain
  • Static and skinned decals
  • Auxiliary view rendering (reflections etc.)
  • Geometry, material & animation LOD
  • Software rasterized occlusion culling
  • Post-processing
  • HDR renderingv1.31
  • 2D sprites and particles that integrate into the 3D scenev1.31
  • Task-based multithreading
  • Hierarchical performance profiler
  • Scene and object load/save in binary and XML format
  • Keyframe animation of object attributesnew
  • Background loading of resourcesnew
  • Keyboard, mouse, joystick and touch input (if available)
  • Cross-platform support using SDL 2.0 (currently runs on Windows, Linux, Mac OS X, Android, iOS, and Raspberry Piv1.3)
  • Physics using Bullet
  • 2D physics using Box2Dnew
  • Scripting using AngelScript
  • Alternative script interface using Luav1.3 or LuaJITv1.31 (on Windows, Linux, Mac OS X, Android, and Raspberry Pi)
  • Networking using kNet + possibility to make HTTP requestsv1.3
  • Pathfinding using Recast/Detourv1.23
  • Image loading using stb_image + DDS / KTX / PVR compressed texture support
  • 2D and “3D” audio playback, Ogg Vorbis support using stb_vorbis + WAV format support
  • TrueType font rendering using FreeType, AngelCode bitmap fonts are also supported
  • Unicode string support
  • Inbuilt UI system
  • Scene editor and UI-layout editor implemented in script with undo & redo capabilities
  • Model/scene/animation/material import from formats supported by Open Asset Import Library
  • Alternative model/animation import from OGRE mesh.xml and skeleton.xml files
  • Supported build tools and IDEs: Visual Studio, Xcode, Eclipse, CodeBlocks, GCC, LLVM/Clang, MinGW-W64
  • Supports both 32-bit and 64-bitv1.3 build
  • Build as single external libraryv1.3 (can be linked against statically or dynamically)

 

The line greatly inspired by Ogre3D seems incredibly accurate to me.  On my initial explorations, that is what it most reminded me of, and that is certainly not an insult.  My nutshell description of Urho3D is:

 

A cross platform, open source, C++ based, Lua and AngelScript scripted game engine that runs on Windows, Mac and Linux and can target all those plus iOS, Android and Raspberry Pi.

 

So the question remains, what’s the developer experience like?  Well, let’s find out!

 

The Source Code

 

Being open source, Urho3D is available on Github.

image

 

I only took a quick browse through the actual code but from what I saw, it’s clean and well written in a modern C++ style.  The project is laid out intuitively, the engine and platforms nicely decoupled and things are pretty much where you would expect them to be.  The code is fairly sparsely commented, but the things that need to be commented, are.  We will touch on the documentation a bit later on.

 

Getting Started

 

Getting started is pretty simple.  Download the source code archive, extract it and use CMake to build the project files for your platform of choice.  I was up and running in a matter of minutes, however I already had all of the required development tools installed and configured.  If you’ve never used CMake before you may be in for a bit of a fight and if something goes wrong, CMake starts to feel strangely like black magic.  For me though, it mostly just worked.  A warning though, download the master branch!  The version linked of their main page is outdated to the point that the documentation doesn’t actually work.  They really should update the official release version so that it matches their getting started manual!

 

Once unzipped, Urho3D looks something like this:

image

 

Simply run the sh or bat file appropriate to your platform and you are good to go.  One thing to be aware of up front, Urho3D has samples in both AngelScript and C++, but by default the C++ projects aren’t created by cmake.  If you want them, when calling the script, add –DURHO3D_SAMPLES=1.  Additionally, Lua support isn’t added out of the box, if you want Lua support as –DURHO3D_LUA=1.

 

So for example, to get started on Windows using Visual Studio 2013, with Lua and C++ sample support, run:

cmake_vs2013.bat –DURHO3D_SAMPLES=1 –DURHO3D_LUA=1

Now if you go into the Build directory, you will see Visual Studio ( or XCode, or Makefile, whatever you chose ) projects.

 

image

 

Simply open Urho3D.sln in Visual Studio and you are done.

 

Samples Samples and More Samples

 

This is one area where Urho3D is well represented.  There are a number of included samples, written in both AngelScript and C++.  Here they are:

 

image

 

For C++, each sample is a project within your solution.  In the case of AngelScript however, each is simply a script file to be run.  Once you’ve built the Engine, you should have a tool named Urho3DPlayer ( or Urho3DPlayer_d if you built for debug ).  This is a command line utility, simply run it and pass in the path to a script to run.  The scripts are located under the Bin folder in the directory /Data/Scripts.

image

 

They are the sample examples as the C++, except of course implemented as AngelScript.

From the command line, in the bin folder, running:

Urho3DPlayer Data\Scripts\11_Physics.as

Will then load and run the script:

image

 

It’s worth noting, I also used the –w switch to run the player in Windowed mode so I could take a screen shot.  Hit ESC to exit.  Oh and Urho3D has annoying behavior of grabbing your mouse cursor, don’t worry when you lose your mouse cursor ( even Windowed ), exit with ESC or alt-tab away and you get your cursor back.  I hate really hate when windowed applications take complete control of my mouse!

 

The code in the samples is well documented, and they cover a wide variety of topics.  This is most likely going to be your primary learning source for getting up to speed quick.

 

To get an idea of a Urho3D application’s structure, let’s take a look at one of the samples, 03_Sprites.  When run, it will do this (except in motion that is):

 

image

 

Now let’s take a look at the corresponding AngelScript and C++ sources.

 

03_Sprites.as

 

// Moving sprites example.
// This sample demonstrates:
//     - Adding Sprite elements to the UI
//     - Storing custom data (sprite velocity) inside UI elements
//     - Handling frame update events in which the sprites are moved

#include "Scripts/Utilities/Sample.as"

// Number of sprites to draw
const uint NUM_SPRITES = 100;

Array<Sprite@> sprites;

void Start()
{
    // Execute the common startup for samples
    SampleStart();

    // Create the sprites to the user interface
    CreateSprites();

    // Hook up to the frame update events
    SubscribeToEvents();
}

void CreateSprites()
{
    // Get rendering window size as floats
    float width = graphics.width;
    float height = graphics.height;

    // Get the Urho3D fish texture
    Texture2D@ decalTex = cache.GetResource("Texture2D", "Textures/UrhoDecal.dds");

    for (uint i = 0; i < NUM_SPRITES; ++i)
    {
        // Create a new sprite, set it to use the texture
        Sprite@ sprite = Sprite();
        sprite.texture = decalTex;

        // The UI root element is as big as the rendering window, set random position within it
        sprite.position = Vector2(Random() * width, Random() * height);

        // Set sprite size & hotspot in its center
        sprite.size = IntVector2(128, 128);
        sprite.hotSpot = IntVector2(64, 64);

        // Set random rotation in degrees and random scale
        sprite.rotation = Random() * 360.0f;
        sprite.SetScale(Random(1.0f) + 0.5f);

        // Set random color and additive blending mode
        sprite.color = Color(Random(0.5f) + 0.5f, Random(0.5f) + 0.5f, Random(0.5f) + 0.5f);
        sprite.blendMode = BLEND_ADD;

        // Add as a child of the root UI element
        ui.root.AddChild(sprite);

        // Store sprite's velocity as a custom variable
        sprite.vars["Velocity"] = Vector2(Random(200.0f) - 100.0f, Random(200.0f) - 100.0f);

        // Store sprites to our own container for easy movement update iteration
        sprites.Push(sprite);
    }
}

void MoveSprites(float timeStep)
{
    float width = graphics.width;
    float height = graphics.height;

    // Go through all sprites
    for (uint i = 0; i < sprites.length; ++i)
    {
        Sprite@ sprite = sprites[i];

        // Rotate
        float newRot = sprite.rotation + timeStep * 30.0f;
        sprite.rotation = newRot;

        // Move, wrap around rendering window edges
        Vector2 newPos = sprite.position + sprite.vars["Velocity"].GetVector2() * timeStep;
        if (newPos.x < 0.0f)
            newPos.x += width;
        if (newPos.x >= width)
            newPos.x -= width;
        if (newPos.y < 0.0f)
            newPos.y += height;
        if (newPos.y >= height)
            newPos.y -= height;
        sprite.position = newPos;
    }
}

void SubscribeToEvents()
{
    // Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent("Update", "HandleUpdate");
}

void HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    // Take the frame time step, which is stored as a float
    float timeStep = eventData["TimeStep"].GetFloat();

    // Move sprites, scale movement with time step
    MoveSprites(timeStep);
}

// Create XML patch instructions for screen joystick layout specific to this sample app
String patchInstructions =
        "<patch>" +
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" +
        "        <attribute name=\"Is Visible\" value=\"false\" />" +
        "    </add>" +
        "</patch>";

 

And now the C++ versions:

Sprite.h

#pragma once

#include "Sample.h"

/// Moving sprites example.
/// This sample demonstrates:
///     - Adding Sprite elements to the UI
///     - Storing custom data (sprite velocity) inside UI elements
///     - Handling frame update events in which the sprites are moved
class Sprites : public Sample
{
    // Enable type information.
    OBJECT(Sprites);

public:
    /// Construct.
    Sprites(Context* context);

    /// Setup after engine initialization and before running the main loop.
    virtual void Start();

protected:
    /// Return XML patch instructions for screen joystick layout for a specific sample app, if any.
    virtual String GetScreenJoystickPatchString() const { return
        "<patch>"
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">"
        "        <attribute name=\"Is Visible\" value=\"false\" />"
        "    </add>"
        "</patch>";
    }

private:
    /// Construct the sprites.
    void CreateSprites();
    /// Move the sprites using the delta time step given.
    void MoveSprites(float timeStep);
    /// Subscribe to application-wide logic update events.
    void SubscribeToEvents();
    /// Handle the logic update event.
    void HandleUpdate(StringHash eventType, VariantMap& eventData);

    /// Vector to store the sprites for iterating through them.
    Vector<SharedPtr<Sprite> > sprites_;
};

 

Sprite.cpp

#include "CoreEvents.h"
#include "Engine.h"
#include "Graphics.h"
#include "ResourceCache.h"
#include "Sprite.h"
#include "Texture2D.h"
#include "UI.h"

#include "Sprites.h"

#include "DebugNew.h"

// Number of sprites to draw
static const unsigned NUM_SPRITES = 100;

// Custom variable identifier for storing sprite velocity within the UI element
static const StringHash VAR_VELOCITY("Velocity");

DEFINE_APPLICATION_MAIN(Sprites)

Sprites::Sprites(Context* context) :
    Sample(context)
{
}

void Sprites::Start()
{
    // Execute base class startup
    Sample::Start();

    // Create the sprites to the user interface
    CreateSprites();

    // Hook up to the frame update events
    SubscribeToEvents();
}

void Sprites::CreateSprites()
{
    ResourceCache* cache = GetSubsystem<ResourceCache>();
    Graphics* graphics = GetSubsystem<Graphics>();
    UI* ui = GetSubsystem<UI>();

    // Get rendering window size as floats
    float width = (float)graphics->GetWidth();
    float height = (float)graphics->GetHeight();

    // Get the Urho3D fish texture
    Texture2D* decalTex = cache->GetResource<Texture2D>("Textures/UrhoDecal.dds");

    for (unsigned i = 0; i < NUM_SPRITES; ++i)
    {
        // Create a new sprite, set it to use the texture
        SharedPtr<Sprite> sprite(new Sprite(context_));
        sprite->SetTexture(decalTex);

        // The UI root element is as big as the rendering window, set random position within it
        sprite->SetPosition(Vector2(Random() * width, Random() * height));

        // Set sprite size & hotspot in its center
        sprite->SetSize(IntVector2(128, 128));
        sprite->SetHotSpot(IntVector2(64, 64));

        // Set random rotation in degrees and random scale
        sprite->SetRotation(Random() * 360.0f);
        sprite->SetScale(Random(1.0f) + 0.5f);

        // Set random color and additive blending mode
        sprite->SetColor(Color(Random(0.5f) + 0.5f, Random(0.5f) + 0.5f, Random(0.5f) + 0.5f));
        sprite->SetBlendMode(BLEND_ADD);

        // Add as a child of the root UI element
        ui->GetRoot()->AddChild(sprite);

        // Store sprite's velocity as a custom variable
        sprite->SetVar(VAR_VELOCITY, Vector2(Random(200.0f) - 100.0f, Random(200.0f) - 100.0f));

        // Store sprites to our own container for easy movement update iteration
        sprites_.Push(sprite);
    }
}

void Sprites::MoveSprites(float timeStep)
{
    Graphics* graphics = GetSubsystem<Graphics>();
    float width = (float)graphics->GetWidth();
    float height = (float)graphics->GetHeight();

    // Go through all sprites
    for (unsigned i = 0; i < sprites_.Size(); ++i)
    {
        Sprite* sprite = sprites_[i];

        // Rotate
        float newRot = sprite->GetRotation() + timeStep * 30.0f;
        sprite->SetRotation(newRot);
        
        // Move, wrap around rendering window edges
        Vector2 newPos = sprite->GetPosition() + sprite->GetVar(VAR_VELOCITY).GetVector2() * timeStep;
        if (newPos.x_ < 0.0f)
            newPos.x_ += width;
        if (newPos.x_ >= width)
            newPos.x_ -= width;
        if (newPos.y_ < 0.0f)
            newPos.y_ += height;
        if (newPos.y_ >= height)
            newPos.y_ -= height;
        sprite->SetPosition(newPos);
    }
}

void Sprites::SubscribeToEvents()
{
    // Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent(E_UPDATE, HANDLER(Sprites, HandleUpdate));
}

void Sprites::HandleUpdate(StringHash eventType, VariantMap& eventData)
{
    using namespace Update;

    // Take the frame time step, which is stored as a float
    float timeStep = eventData[P_TIMESTEP].GetFloat();
    
    // Move sprites, scale movement with time step
    MoveSprites(timeStep);
}

 

EDIT: And the Lua example as well:

03_Sprites.lua

-- Moving sprites example.
-- This sample demonstrates:
--     - Adding Sprite elements to the UI
--     - Storing custom data (sprite velocity) inside UI elements
--     - Handling frame update events in which the sprites are moved

require "LuaScripts/Utilities/Sample"

local numSprites = 100
local sprites = {}

-- Custom variable identifier for storing sprite velocity within the UI element
local VAR_VELOCITY = StringHash("Velocity")

function Start()
    -- Execute the common startup for samples
    SampleStart()

    -- Create the sprites to the user interface
    CreateSprites()

    -- Hook up to the frame update events
    SubscribeToEvents()
end

function CreateSprites()
    local decalTex = cache:GetResource("Texture2D", "Textures/UrhoDecal.dds")

    local width = graphics.width
    local height = graphics.height

    for i = 1, numSprites do
        -- Create a new sprite, set it to use the texture
        local sprite = Sprite:new()
        sprite.texture = decalTex
        sprite:SetFullImageRect()

        -- The UI root element is as big as the rendering window, set random position within it
        sprite.position = Vector2(Random(width), Random(height))

        -- Set sprite size & hotspot in its center
        sprite:SetSize(128, 128)
        sprite.hotSpot = IntVector2(64, 64)

        -- Set random rotation in degrees and random scale
        sprite.rotation = Random(360.0)
        sprite.scale = Vector2(1.0, 1.0) * (Random(1.0) + 0.5)

        -- Set random color and additive blending mode
        sprite:SetColor(Color(Random(0.5) + 0.5, Random(0.5) + 0.5, Random(0.5) + 0.5, 1.0))
        sprite.blendMode = BLEND_ADD

        -- Add as a child of the root UI element
        ui.root:AddChild(sprite)

        -- Store sprite's velocity as a custom variable
        sprite:SetVar(VAR_VELOCITY, Variant(Vector2(Random(200.0) - 100.0, Random(200.0) - 100.0)))

        table.insert(sprites, sprite)
    end
end

function SubscribeToEvents()
    -- Subscribe HandleUpdate() function for processing update events
    SubscribeToEvent("Update", "HandleUpdate")
end

function MoveSprites(timeStep)
    local width = graphics.width
    local height = graphics.height

    for i = 1, numSprites do
        local sprite = sprites[i]
        sprite.rotation = sprite.rotation + timeStep * 30

        local newPos = sprite.position
        newPos = newPos + sprite:GetVar(VAR_VELOCITY):GetVector2() * timeStep

        if newPos.x >= width then
            newPos.x = newPos.x - width
        elseif newPos.x < 0 then
            newPos.x = newPos.x + width
        end
        if newPos.y >= height then
            newPos.y = newPos.y - height
        elseif newPos.y < 0 then
            newPos.y = newPos.y + height
        end
        sprite.position = newPos
    end
end

function HandleUpdate(eventType, eventData)
    local timeStep = eventData:GetFloat("TimeStep")

    MoveSprites(timeStep)
end

-- Create XML patch instructions for screen joystick layout specific to this sample app
function GetScreenJoystickPatchString()
    return
        "<patch>" ..
        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" ..
        "        <attribute name=\"Is Visible\" value=\"false\" />" ..
        "    </add>" ..
        "</patch>"
end

 

As you can see, the code is clean enough and well enough documented to learn from. Unfortunately there aren't equivalent Lua examples right now.

EDIT: Ok, my bad.  Fortunately there are in fact Lua examples as well!  They were just very well hidden in the /Bin/Data/LuaScript folder.

 

Hello World

 

Urho3D commits a common sin and one that drives me absolutely nuts with game engines.  It’s Hello World, in fact, all of it’s C++ examples are built over a “Sample” class.  This means when the reader wants to start from scratch on their own project, they have to tear through the base class to figure out what goes into a core application.  I get why they do this, so they can focus on the feature they want to show, but at least one example should be as complete as possible with no underlying class to build on.  Fortunately I have done this for you.  The following is basically the “minimum usable” Urho3D application:

 

TestMain.h

#pragma once

#include "Application.h"


using namespace Urho3D;

class TestMain : public Urho3D::Application {
   OBJECT(TestMain);

public:
   TestMain(Urho3D::Context*);

   virtual void Setup();
   virtual void Start();
   virtual void Stop() {}

private:
   void onKeyDown(StringHash,  VariantMap&);

};

 

TestMain.cpp

#include "TestMain.h"
#include "Engine.h"
#include "Graphics.h"
#include "Input.h"
#include "InputEvents.h"
#include "ResourceCache.h"
#include "UI.h"
#include "Font.h"
#include "Text.h"

using namespace Urho3D;

DEFINE_APPLICATION_MAIN(TestMain)

TestMain::TestMain(Urho3D::Context* context) : Application(context){
}

void TestMain::Setup(){
   engineParameters_["FullScreen"] = false;
}

void TestMain::Start(){
   SubscribeToEvent(E_KEYDOWN, HANDLER(TestMain,onKeyDown));

   SharedPtr<Text> text(new Text(context_));
   text->SetText("Hello Cruel World!");
   text->SetColor(Color::WHITE);
   text->SetFont(GetSubsystem<ResourceCache>()->GetResource<Font>("Fonts/BlueHighway.ttf"), 42);
   text->SetHorizontalAlignment(HA_CENTER);
   text->SetVerticalAlignment(VA_CENTER);

   GetSubsystem<UI>()->GetRoot()->AddChild(text);
}

void TestMain::onKeyDown(StringHash event, VariantMap& data){
   engine_->Exit();
}

 

It creates a windowed Hello World application, displays the text “Hello Cruel World” in white, centered to the screen and waits for any key to be pressed before exiting.

While basic, it should give you some idea how Urho3D works.  There are times, like when trying to figure out parameters engineParameters takes that you really wish for better reference documentation, but it was fairly simple to get things up and running.  I did have a bit of a struggle with life cycle, when I tried to put more logic into Setup() instead of Start() but otherwise things mostly worked how I expected.   Speaking of documentation…

 

The Documentation

 

So what’s the documentation like?  It’s split in to two parts, the documentation that has been written covering the various aspects, tasks and systems in Urho3D.  There is also an auto generated class reference. You can read the documentation here.

 

As you can see, most of the major systems are covered:

image

 

The documentation is well written in clear English, and for the most part covers what you would expect it to.  For an open source project I have to say, the overall documentation level is very good.  The only area I was somewhat let down by was the reference material.

 

There is an automatically generated class reference available:

image

But the details are pretty sparse:

image

 

So, for example, if you are hunting down say… what audio formats are supported, this information can be a bit hard to find and may result in you having to jump into the source code.  I do wish there was more implementation specific details in the reference materials.

 

Perhaps I am nit picking at this point…  working so much in Java lately, JavaDoc has really spoiled me.

 

In summary, the documentation is solid, great in fact for an open source project.  I would however appreciate more detail in the reference material.

 

Tools

 

Part of what makes an engine and engine is the tooling it supports.  Urho3D is no exception.  We already mentioned Urho3DPlayer, but there are several other tools, one of which is actually run in the player.  There is a full blown 3D level editor:

image

 

The editor enables you to create and edit several node types:

image

 

And provides context appropriate property editing:

image

 

It’s not going to win any beauty pageants, but it is a full functioning 3D world editor written entirely in AngelScript.  So if it doesn’t have functionality you want, simply add it.  The code is all available in the Bin\Data\Scripts\Editor folder:

image

 

With full code access, you should easily be able to extend the editor to fit whatever type of game you are looking at creating.

 

In addition to the editor, there are a number of other tools.  There is AssetImporter from the Assimp project, for importing 3D assets.  There is also a tool for importing Ogre3D assets.  PackageTool, for pulling your assets all together, a shader compiler, lightmap generator and more.

 

Summary

 

Urho3D is an impressive, well documented, cross platform game engine with clean accessible code and a ton of examples.  There are of course some negatives too.  The tools aren’t nearly as polished as you see in many commercial engines, the reference material could be a bit more extensive and the community isn’t huge.  I can’t speak to performance as I never dove in that deeply.  Is it worth checking out for your own game project?  Well, if control and open source are important to you and you like C++, AngelScript and/or Lua, I would most certainly give it a look. 

 

What do you think, does Urdo3D look interesting to you?  Would you like to see more in depth tutorials from GameFromScratch.com?  Let me know!

Programming


1. October 2014

 

Version 5 of the CopperCube engine was just released.  In their own words, CopperCube is:

 

CopperCube is an editor for creating 3D apps, games and 3D websites. Import or create your 3D models, set camera controllers, materials, behaviors, click 'publish' and your app is ready. Create everything from simple model viewers to full 3D games. As WebGL websites, Flash .swfs, Mac OS, Windows, or Android apps. You can do all this without programming.

 

 

The following are the release notes of the new features in Version 5:

 

  • Terrain support

The editor now includes a way to create and edit terrain. There is also a terrain generator, completely with trees and grass. Terrain can be drawn with height painting tools directly in the editor, textures can be painted quickly with automatic texture blending into the terrain. There are also tools for placing grass and bushes, and for distributing meshes automatically over the terrain.
terrain support terrain rendering

  • Physics engine
    It can be switched on for the Windows and Mac OS X target in the publishing settings. There is also a new behavior available named 'Move object by physics engine' for making objects behave, collide and move like objects in the real world. Objects with the 'Collide when moved' behavior will also collide against those then and be able to move them, roll them over etc. There is also a way to react when an object collides with the world, for example to play sounds, and a way to manually apply forces to objects using scripting.
    physics simulation
  • Video Playback in 2D and 3D
    The professional version of CopperCube now includes an action to play back videos on the Windows .exe, WebGL and Flash target. Videos can be played back in 2D and 3D (like on any 3D object in a scene), it is possible to influence playback with actions (play/stop/pause) and to react when the video playback has been finished or playback failed.
    video playback
  • Network communcation
    You can now easily do HTTP requests on all targets, in order to exchange data with game multiplayer servers, PHP/MySQL database backends, or whatever you like to. This feature is available as new JavaScript function named ccbDoHTTPRequest(), but there is also an action for doing this without programming for download from the website. This feature doesn't directly provide multiplayer support for your games, but it is now possible to build this yourself on top of this.
  • Added iOS 8 WebGL support
    Apps created with CopperCube and the WebGL target now also run on Apple devices (iPhone, iPad, ...) with iOS 8.
    running on iphone and ipad
  • Shader programming
    You can create and add your own materials and shaders during runtime now using the JavaScript API. In the documentation, you will find a few examples showing you how to start. Note that this is nothing simple, and not for beginners. You need to know shader programming in order to use this feature.
    shader programming
  • Animation blending
    CopperCube now blends animations when switching between them. It is automatically enabled, but can be turned off or adjusted for every animated model manually in the editor or via script. This also means that you don't need to create perfect animation loops anymore. The engine will now automatically blend non-fitting animation loops together so that they look nice.
  • Attaching nodes to animated meshes
    This is useful for example to let characters carry weapons in their hands, to switch them dynamically, change how they look like, or for example to even attach particle systems to moving parts of an animation. Use the command "Modify Selection -> Attach node to animated joint..." for this.
    attaching to animations
  • Directional light
    This is useful for simulating light sources from a very far distance, like for simulating the sun. Directional light can now be used just as the already supported point lights both with the light mapper as well for dynamic lighting.
    directional light
  • Procedurally generated trees
    There is a new scene node type available which generates a tree (a 3d model of a plant) based on user specified parameters. It is possible to create all kind of tree types from it, be it for example a full grown pine or a dead desert bush. This feature is beta, and not very user friendly yet, but planned to be improved in future versions.
    generated trees
  • Faster Lightmapper, with Mac OS X support
    The built-in lightmapper has been rewritten and is now much faster. Additionally, it now also works with shadows on the Mac OS X version of the editor, wich previsously only produced results with diffuse lighting only.
    lightmapper of coppercube
  • Optimized WebGL performance and compatibility
    Not only did we squeeze all these features into a tiny, 180KB .js file, we also improved the performance again by about 20% in certain areas, and improved compatibility with mobile and/or touch enabled WebGL capable browsers such as Chrome for Android.
  • Custom Icons for Windows Apps
    There is now a new option to select an icon for the windows target. Note that embedding the icon in your app might slow down the publishing process by a few seconds, depending on your operating system. (This feature is not supported in the Mac OS X version of CopperCube)
  • Manual Commands for the AI
    Use the function ccbAICommand() for this, so you can send any "Game actor with Health" to a specific location, command it to attack something, or similar.
  • 15 new prefabs
    15 new prefabs added: 2 new animated characters (a soldier; a sleep walker), 2 weapons to be attached to animated characters: a shotgun and a pistol, 11 high quality, low poly prefabs created by Efe: a classic car, a bicycle, an armchair, an ancient statue, a book, a nightstand, a flowerpot, a lamp, two tables, a television.
    prefabs
...and many other changes:

 

  • There is now a new command for converting a static mesh to an animated mesh (without animation). This is useful for ditributing huge amounts of static meshes over the terrain without much memory usage, since instances of animated meshes share their data and are culled more efficiently.
  • New, better looking examples come preinstalled with CopperCube now.
  • The 'object controlled by keyboard' behavior now has a more fine tuned animation playback system
  • The 'object controlled by keyboard' behavior now has the option to 'pause' after jumping, making the jumping feature look more like in some platform games.
  • The gravity value is now set per scene, in the root object of the scene.
  • Jumping in all behaviors is much nicer and more physically correct now. But this also means that you might have to adjust your jump settings in existing projects when upgrading to CopperCube 5.
  • Game AI movement is more smoother now
  • Scripting changes: New functions:
    • ccbCreateMaterial()
    • ccbSetShaderConstant()
    • ccbAICommand()
    • ccbSetPhysicsVelocity()
    The following functions are now also available in the editor:
    • ccbGetCollisionPointOfWorldWithLine()
    • ccbDoesLineCollideWithBoundingBoxOfSceneNode()
    Changed behavior:
    • ccbEndProgram() now closes the window in WebGL and Flash
  • When cloning nodes in the editor, also children will now get unique names and ids, and relinked with the behavior of the parent
  • 3D Editor change: When changing the parent child relation of a node, the position of the node is tried to be kept at the old position
  • 3D Editor change: When moving an object which is the child of a rotated parent object, movement will still move into the direction the arrows are pointing
  • When right-clicking onto a texture in the texture browser, there is now a command to save the texture as file to disk.
  • It's possible to use the mouse wheel in the prefabs window
  • Removed feature: It is no longer possible to target Flash players older than version 11
  • When switching the perspective, orthogonal views now place the camera more nicely.
  • The path tool new works a bit nicer when adding new path nodes.
  • Lots of updates to the documentation.

 

A trial version is available for both Windows and Mac.

News


16. September 2014

 

Searching for and finding 3D models on the internet can be a daunting task.  There are hundreds of sites with free 3D models, but the quality varies massively and it’s a laborious task separating the wheat from the chaff.  If only there was a search engine for this!  Well, now there is.

 

Enter Yobi3D.com.  Literally a search engine for 3D models:

 

image

 

Simply enter a search term and it brings you thumbnailed search results:

image

 

Pick a search result and a 3D WebGL viewer pops up.  ( or your iPad that doesn’t support WebGL crashes! ).

 

image 

 

From here you can orbit and zoom the model.  Of course you can also navigate to the source using the link at the bottom.

 

One immediately obvious question, how do you filter results?  If you are a Blender user, you probably don’t want Max files for example.  There is a way to do this, but unfortunately it’s clunky.  In the search box add “AND extension:filetype” like:

image

And it will return only Blender results.

 

 

Very cool new tool and I hope them well.  There are a few things I would really like to see to make this even better.

  • metadata in the search results.  File type, vertex count, etc. 
  • textures if available
  • animations if available
  • license model released under
  • less clunky UI for specifying model format.

 

Hopefully we will see improvements over time.  All told though, already a very useful tool for people looking for 3D models.

News


23. July 2014

 

In Part One we looked at the basics of working with the Three.js graphics library.  We got as far as creating a camera and a textured 3D object.  Now is the true test of ease of use… getting a 3D model exported from Blender and displayed in our browser.  HTML libraries face an even bigger burden, as their access to the local file system isn’t as seamless as most other games.  Simply opening up an FBX or DAE file isn’t an option.  Let’s take a look at how ThreeJS works around this issues.

 

 

First’s thing first, I needed a Blender Blend file to work with.  This actually lead me down this road, resulting in a post about taking a Blend file from the web and making it game ready.  Anyways, I did.  I started with this file, merged the geometry, UV mapped it, and baked the Blender materials to a single texture map.  I am not entirely sure if I can share the resulting file or not, so you may have to provide your own Blender file or follow the linked tutorial to generate one of your own.

 

Anyways, this is what we are starting with…

image 

 

Let’s see how close we can get with Three.js.

 

The first obvious question is… how the hell do we get this model in to Three.JS from Blender?

Well, the answer is a plugin.  Follow the installation direction, however in my case the path was wrong.  For Blender 2.71, my actual plugin directory is C:\Program Files\Blender Foundation\Blender\2.71\scripts\addons\io_mesh_threejs.

 

There is one very critical thing to be aware of here… when downloading the files from Github, be certain to download the RAW format:

image

 

This particular mistake caused me a bit of pain, don’t make the same mistake!

 

Once you’ve copied each of these three files, configure the plugin in Blender.  If Blender is running, restart it.

Now select File->User Preferences:

image

 

In the resulting dialog select Addons, then in the search box type “three”.  If it installed correctly it will show on the right.  Click the checkbox to enable the plugin.

image

 

Now if you check the File->Export menu, you should see Three.js as an option.

image

 

When exporting you can clearly see there are a ton of options:

image

 

The options I selected above is for just exporting the mesh and materials.  No animation data, lights, cameras, etc… Scaling and Flip YZ all depend on the orientation of your game engine.

 

This exporter creates a JSON js like this one:

 

{

	"metadata" :
	{
		"formatVersion" : 3.1,
		"generatedBy"   : "Blender 2.7 Exporter",
		"vertices"      : 8,
		"faces"         : 6,
		"normals"       : 2,
		"colors"        : 0,
		"uvs"           : [24],
		"materials"     : 1,
		"morphTargets"  : 0,
		"bones"         : 0
	},

	"scale" : 1.000000,

	"materials" : [	{
		"DbgColor" : 15658734,
		"DbgIndex" : 0,
		"DbgName" : "Material",
		"blending" : "NormalBlending",
		"colorAmbient" : [0.6400000190734865, 0.6400000190734865, 0.6400000190734865],
		"colorDiffuse" : [0.6400000190734865, 0.6400000190734865, 0.6400000190734865],
		"colorEmissive" : [0.0, 0.0, 0.0],
		"colorSpecular" : [0.5, 0.5, 0.5],
		"depthTest" : true,
		"depthWrite" : true,
		"mapDiffuse" : "crate.jpg",
		"mapDiffuseWrap" : ["repeat", "repeat"],
		"shading" : "Lambert",
		"specularCoef" : 50,
		"transparency" : 1.0,
		"transparent" : false,
		"vertexColors" : false
	}],

	"vertices" : [1,-1,0,1,0,1,-1,0,0,0,-1,0,1,0,0,0,1,1,-1,1,0,0,0,0],

	"morphTargets" : [],

	"normals" : [0.577349,0.577349,0.577349,0.577349,0.577349,-0.577349],

	"colors" : [],

	"uvs" : [[0.988679,0.99767,0.988677,0.016243,0.007251,0.016244,0.007252,0.
	997671,0.989755,0.017099,0.989755,0.998526,0.008328,0.998526,0.008328,0.017099,
	0.990714,0.989755,0.009287,0.989755,0.009286,0.008328,0.990713,0.008328,0.
	000516,0.993662,0.981943,0.993661,0.981942,0.012235,0.000516,0.012235,0.987766,
	0.997568,0.987766,0.016141,0.006339,0.016141,0.006339,0.997568,0.986807,0.
	986807,0.986807,0.005381,0.00538,0.00538,0.00538,0.986807]],

	"faces" : [43,0,3,2,1,0,0,1,2,3,0,0,1,1,43,4,7,6,5,0,4,5,6,7,0,0,1,1,43,0,4,5,1,
	0,8,9,10,11,0,0,1,1,43,1,2,6,5,0,12,13,14,15,1,1,1,1,43,2,3,7,6,0,16,17,18,19,1,
	0,0,1,43,3,0,4,7,0,20,21,22,23,0,0,0,0],

	"bones" : [],

	"skinIndices" : [],

	"skinWeights" : [],

  "animations" : []


}

 

In theory things should just work, but since when did gamedev give a damn about theory?  Suffice to say I ran into a bit of a problem fully documented here.  The bug actually had nothing to do with Three.js, it was actually caused by my IDE WebStorm.

 

Anyways… once I figured out the problem, the code to load a model was extremely straightforward:

 

///<reference path="./three.d.ts"/>

class ThreeJSTest {
    renderer:THREE.WebGLRenderer;
    scene:THREE.Scene;
    camera:THREE.Camera;

    constructor() {
        this.renderer = new THREE.WebGLRenderer({ alpha: true });

        this.renderer.setSize(500, 500);
        this.renderer.setClearColor(0xFFFFFF, 1);

        document.getElementById('content').appendChild(this.renderer.domElement);

        this.scene = new THREE.Scene();

        this.camera = new THREE.PerspectiveCamera(75
            , 1
            , 0.1, 1000);

        this.camera.position = new THREE.Vector3(10, 0, 10);
        this.camera.lookAt(new THREE.Vector3(0, 0, 0));


        // New code begins below
        // Create a loader to load in the JSON file
        var modelLoader = new THREE.JSONLoader();

        // Call the load method, passing in the name of our generated JSON file
        // and a callback for when loadign is complete.
        // Not fat arrow typescript call for proper thisification.  AKA, we want 
        this to be this, not that
        // or something else completely
        modelLoader.load("robot.jsm", (geometry,materials) => {
            // create a mesh using the passed in geometry and textures
            var mesh = new THREE.SkinnedMesh(geometry,new THREE.MeshFaceMaterial(
                       materials));
            mesh.position.x = 0; mesh.position.y = mesh.position.z = 0;
            // add it to the scene
            this.scene.add(mesh);
        });

        this.scene.add(new THREE.AmbientLight(new THREE.Color(0.9,0.9,0.9).
                       getHex()));
        this.renderer.render(this.scene, this.camera);
    }

    render() {
        requestAnimationFrame(() => this.render());
        this.renderer.render(this.scene, this.camera);
    }

    start() {
        this.render();
    }
}

window.onload = () => {
    var three = new ThreeJSTest();
    three.start();
};

 

And when you run it:

image

 

Mission accomplished!  The astute reader may notice the file was renamed robot.jsm.  That was to work around the problem I mentioned earlier.

 

 

 

This isn’t actually the only option for loading 3D models into Three.js, there are actually a series of loaders available as a separate download from the Github site.  It is however certainly the easiest one!  The next few steps took me two full days to fight my way through!  Some of the blame is on TypeScript, some is on me and of course, CORS reared it ugly head as well.  Oh, and to add to the fun, a recent change in Three.js introduced an error in the version of ColladaLoader.js I downloaded. This was one of those trials that Google was no help with, so hopefully this guide will help others in the future.  Anyways… on with the adventure!

 

We are actually about to run smack into two different problems with using a Three.js plugin.  The first one is TypeScript related.  You see, the ColladaLoader plugin is not a core part of Three.js.  In JavaScript, this is no big deal.  In TypeScript however, big deal.  You see, until now we have been relying on the generated .d.ts file from StrictlyTyped for defining all of the types in Three.js from JavaScript in their corresponding TypeScript form.  However, since this is a plugin and not a core part of Three.js, this means the d.ts file has no idea how ColladaLoader works.

 

Ultimately this means you have to had roll your own Typescript definition file. I had to struggle a bit to find the exact TypeScript syntax to map ColladaLoader so it will run in TypeScript within the THREE namespace with proper callback syntax.  First off, create a file called ColladaLoader.d.ts   Now enter the following code:

 

///<reference path="./three.d.ts"/>

declare module THREE {
    export class ColladaLoader{
        options:any;
        load(
            name:string,
            readyCallback:(result:any)=> void,
            progressCallback:( total:number,loaded:number)=> void);
    }
}

 

 

I should probably point out, I only implemented the barest minimum of what I required.  In your case you may have to implement more of the interface.  Also note I also took the lazy approach to defining options.  By returning any, my code will compile in TypeScript, but I do lose some of the type checking.  The alternative would have been to define the Options type and I am way too lazy for that.  The above definition enable me to call the load() method and set options, which is all I actually needed.  I don’t even want to talk about how long it took me to puzzle out those 10 lines of code so that the generated code actually matched THREE.js!

 

OK, we now have ColladaLoader.d.ts defined let’s look at code to use ColladaLoader to load a DAE (COLLADA) file:

 

///<reference path="./three.d.ts"/>
///<reference path="./ColladaLoader.d.ts"/>


class ThreeJSTest {
    renderer:THREE.WebGLRenderer;
    scene:THREE.Scene;
    camera:THREE.Camera;
    loader:THREE.ColladaLoader;
    light:THREE.PointLight;

    constructor() {
        this.renderer = new THREE.WebGLRenderer({ alpha: true });

        this.renderer.setSize(500, 500);
        this.renderer.setClearColor(0xFFFFFF, 1);

        document.getElementById('content').appendChild(this.renderer.domElement);

        this.scene = new THREE.Scene();;

        this.camera = new THREE.PerspectiveCamera(75
            , 1
            , 0.1, 1000);

        this.camera.position = new THREE.Vector3(5, 0, 5);
        this.camera.lookAt(new THREE.Vector3(0, 0, 0));

        // Create a loader
        this.loader = new THREE.ColladaLoader();

        // Add a point light to the scene to light up our model
        this.light = new THREE.PointLight();
        this.light.position.set(100,100,100);
        this.light.intensity = 0.8;
        this.scene.add(this.light);

        this.renderer.render(this.scene, this.camera);

        // Blender COLLADA models have a different up vector than Three.js, set 
        this option to flip them
        this.loader.options.convertUpAxis = true;

        // Now load the model, passing the callback finishedLoading() when done.
        this.loader.load("robot.dae",
            (result) => this.finishedLoading(result),
            (length,curLength)=>{
                // called as file is loading, if you want a progress bar
            }
        );
    }

    finishedLoading(result){
        // Model file is loaded, add it to the scene
        this.scene.add(result.scene);
    }
    render() {
        requestAnimationFrame(() => this.render());
        this.renderer.render(this.scene, this.camera);
    }

    start() {
        this.render();
    }
}

window.onload = () => {
    var three = new ThreeJSTest();
    three.start();
};

 

 

Finally of course we need to export our COLLADA model.  Using Blender, you can export using File->Export->Collada menu option.  These are the settings I used:

image

 

And when you run it:

image

 

That said, there is a really good chance this isn’t what is going to happen to you when you run your project.  Instead you are going to probably receive a 404 error that your dae file is not found.  This is because, unlike before with the JSON file being added directly to your project, this time you are loading the model using an XML HTTP Request.  This causes a number of problems.  The first and most likely problem you are going to encounter is if you are running your application locally from your file system instead of a server.  By default XHR requests do not work this way ( no idea why, seems kinda stupid to me ).  There is a switch that allows chrome to run XHR local requests ( link here ) using --allow-file-access-from-files.

 

In my case the problem was a little bit different.  I use WebStorm, which includes a built in web server to make this kind of stuff easier.  This however raises a completely different set of problems…  CORS  Cross Origin Resource Sharing.  In a very simple description, CORS is a security method for making XML HTTP Requests across different servers.  That said, how the heck do you set it when you are working with a built in stripped down development server?  Fortunately WebStorm have thought about that.

 

Assuming you are using Chrome and have the Webstorm plugin install, in the Chrome address bar, go to chrome://extensions.

image

 

Click the Options button.

image

Now simply add 127.0.0.1 to the allow list and press Apply. 

 

Now if you run from Webstorm, no more 404 errors.

 

A moment about TypeScript

 

I’ve been using TypeScript a fair bit lately and this is the first time I’ve run into major problems with it.  But the experience is enough that I can safely say…

 

TypeScript is not appropriate for new developers to use!

 

Simply put, unless you have a decent amount of experience with JavaScript, you really shouldn’t use TypeScript.  You will have to read the generated code at some point in time, and if you don’t full understand the code it generates, you are doomed.  The minute definition files arent available to you the experience becomes a hell of a lot less fun.  The process of mapping TypeScript types to existing JavaScript libraries is not trivial and requires you to have a pretty good understanding of both languages.  Especially when the library you are trying to define uses a number of clever JavaScript tricks, which basically… is all of them.  The fact there isnt a reliable tool out there for generating at least boilerplate .d.ts files from .js files is a bit of a puzzle to me.

 

Next, I also have to say TypeScript’s handling of this is just as mind bogglingly stupid as JavaScript’s.  That fat arrow ( => ) functions are used to capture local context, until used as an anonymous method, at which point they capture global (window) context, forcing you to resort to function() is downright perplexing.  I simply couldn’t get anonymous callback functions to have the proper this context no matter what syntax combination I tried.  Infuriatingly, the _this value Typescript automatically contains was set to the right value.

 

One other major downside I noticed about the language with my recent struggles is the newness of the language is very much an annoyance.  When researching bugs or workarounds you quite often find things that are reported as bugs, reported as changed,  or reported and never responded to.  This isn’t a bash on the language as it’s really only a problem that time can solve.  However, for a new developer, dealing with a language where a great deal of the material out there is potentially wrong because of language changes, that is certainly a challenge.  All languages change over time of course, but young languages change more and more dramatically.

 

Don’t get me wrong, I am not off Typescript, even though it spent a good part of the last two days pissing me off.  At least until ECMAScript 6 is the norm I can see a great deal of value in using TypeScript for large projects.

 

For beginners though, with little JavaScript experience… forget about it.  It’s going to cause more headaches than it’s worth.

Programming


18. July 2014

I just received the following email from Unreal:

 

TranslusentFogDemo

Unreal Engine 4.3 Released!

 

More than 500 updates ship in this release! Unreal Engine 4.3 includes greatly improved mobile support, awesome new rendering features, improved Blueprint workflows, and strides toward an excellent experience on Mac and laptops.

 

Check out the new World Composition tools, spline features, and the preview of Paper2D, our 2D toolset! You also get SpeedTree 7 support, our work on Metal API for iOS 8 to date, and new Oculus Rift features such as time warping.

 

There’s no limit to what you can do with Unreal Engine 4 for only $19 per month.

 

Paper2D Side Scroller Template

Have fun with the new side-scroller template game as you become acquainted with Paper2D.

Read More

 

VR Couch Knights

We love VR, and Unreal Engine 4.3 supports the new Oculus DK2 out of the box! Dive into Epic’s popular “Couch Knights” demo which has been making the rounds at GDC and other shows.

Read More

SpeedTree 7

SpeedTree 7 support is here, and UE4 trees are 33% off in the SpeedTree store throughJuly 26!

Read More

Rendering Goodies

Rendering goodies include distance field ambient occlusion, skylight global illumination and shadowed translucency.

Read More

Behavior Trees

Better AI tools! Switch to the new Blackboard mode inside the Behavior Tree Editor to edit and debug Blackboard entries.

Read More

Large World Support!

Large world support! Check out the new World Composition tools. Create sub-levels and position them anywhere.

Read More

Customize Your Static Mesh Collision!

Customize your static mesh collision!

Read More

Spline Editing

Edit splines directly within your levels!

Read More

 

Build games and apps for Windows, Mac, iOS, Android, PlayStation 4, Xbox One, Linux, SteamOS, HTML5 and VR platforms.

Get Unreal for $19/Month

Mobile Developers!

Zen Gardens

Google recently demonstrated the graphics power of L, the upcoming release of Android, using Epic's Rivalry demo running on Tegra K1 at Google I/O. Mobile is a huge focus for UE4, and we hope you’ll enjoy all the latest improvements!

Read More

 

 

The UE4 Roadmap continues to evolve, and we encourage you to vote for features that want to use.

 

To ask questions and share feedback, please visit the forums or join our live broadcasts at Twitch.tv every Thursday at 2pm ET, which you can always go back and view atYouTube.com.

 

Hats off to the developers who contributed to this great release! These who helped are forever immortalized in the Credits section under the editor’s Help menu.

 

Thank you for being a part of this adventure. We can’t wait to see what you build next.

 

We are one step closer to Paper2D support, which is their support for 2D engines. Occulus Rift support is no doubt cool for those developing for the Rift. Not quite as impressive as the last release, but still a good amount of progress from Unreal.

News


AppGameKit Studio

See More Tutorials on DevGa.me!

Month List