Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
8. December 2015

 

This tutorial came about as a result of a question on my YouTube channel, although it is one of those things that you are going to need to know before long in 3D game programming, so I have made the answer part of the official Godot Engine tutorial series.  The question was:

I am making a 3d game and I want to use a sort [of] top down style camera.


I want it so that if an object gets between the player and the camera, that same object will become transparent. For that ( I think ) I can use the "Use Alpha" function in the fixed material settings.
So I think I need a raycast shooting rays ( between the player and the camera ) and if it hits something it needs to "find' which object was hit en change the material settings so it becomes transparent.


Now, the problem is that I don't know how to set this up;
-how can I get which object is hit by the ray and how to change the material?
-do I need to create a separate layer for this?

This is one of those things even the most simple 3D game is going to encounter, but the solution isn’t obvious, although the questioner was extremely close in his guess.  You can solve this using Ray casting, it’s probably just the how of it all that is difficult to figure out.

 

As always there is a video version of this tutorial available here.

 

If you have a situation like the above, where you want to determine if something is in the way of your camera, it’s exactly RayCasting that you want.  Let’s take a look at how.

 

Setting Up The Scene

 

First you need your scene to be set up correctly.  This means that each entity in your scene that can be collided with has to be a physics object of some kind.  I created the following scene arrangement:

image

 

As you can see, I have a camera and two Rigid Body objects, each with a CollisionShape (Cube) and a Test Cube child.  Additionally I created a RayCast object as a child of my camera.  Be sure to create the RayCast child before you transform your camera, so it is positioned properly.  For my RayCast I use the following settings:

image

 

My scene ends up looking like this:

image

 

The Code

 

As you can see, the Ray extends from my camera and through both objects in the scene.  In this example we want to see if we hit the first cube (“RigidBody 2”) and if we do, we want to hide it.  Time to look at some code, the following script was attached to the camera:

extends Camera


var ray = null

func _ready():
	ray = get_node("RayCast")
	set_process(true)


func _process(delta):
	if(Input.is_key_pressed(KEY_UP)):
		self.translate(Vector3(0,0.1,0))
	if(Input.is_key_pressed(KEY_DOWN)):
		self.translate(Vector3(0,-0.1,0))
	if(ray.is_enabled() and ray.is_colliding()):
		var collidedWithObject = ray.get_collider()
		if(collidedWithObject.get_name() == "RigidBody 2"):
			collidedWithObject.hide()
	else:
		get_parent().get_node("RigidBody 2").show()

 

… and that’s it.  We check to see that our ray is enabled and if it is currently colliding with something.  If it is, the first collided object is returned by the call get_collider().  In a bit of a hard coded hack, we check the name of that object, and if its our second cube, we hide the entire hierarchy.  In the event that no collision occurs, we make sure that RIgid Body 2 is visible with a call to Show().  You will notice that there is code in there to move the camera on press of the Up and Down arrow keys.  As you will see, as you move the camera, when the ray isn’t colliding, the second cube is shown, otherwise it is, like so:

 

GIF

 

It is also possible to create the ray programmatically using the PhysicsServer, like so:

extends Camera

func _ready():
	set_fixed_process(true)

func _fixed_process(delta):
	if(Input.is_key_pressed(KEY_UP)):
		self.translate(Vector3(0,0.1,0))
	if(Input.is_key_pressed(KEY_DOWN)):
		self.translate(Vector3(0,-0.1,0))

	var directState = PhysicsServer.space_get_direct_state(self.get_world().get_space())
	var collisions = directState.intersect_ray(get_translation(),Vector3(0,0,0))
	
	if(collisions.size() and collisions["collider"].get_name() == "RigidBody 2"):
		collisions["collider"].hide()
	else:
		get_parent().get_node("RigidBody 2").show()

 

Note that _process what changed to _fixed_process().  This is because space_get_direct_state() is only valid during _fixed_process or _integrate_forces() calls.  Otherwise we crate an intersect_ray() between the camera position and the origin, which in turn returns if there is a collision between those two points.  If there is, we hide the collided objects, otherwise we call show().

 

The Video

Programming


28. September 2015

 

Now that we have covered 3D basics and loading and creating static meshes now it’s time to move on to loading and using animated models.  Godot currently supports animation only in COLLADA format, which is supported with varying degrees of success in all popular 3D modelling applications.  If you are exporting from Blender, consider using the Godot Blender exporter plugin instead of the built in exporter.

 

As always there is an HD video of this tutorial available here.

 

In the video I show the entire process of creating the animated mesh in Blender.  If you want to see how it is done, I recommend you watch the video.  Unfortunately I could not get COLLADA to export multiple named animations, so I had to create all the animations along a single timeline.  If you work in Maya or Max it may be possible to get named animation clips to work correctly.

EDIT – I was mistaken about how to export multiple animations using the Better Collada plugin.  It does in fact work and the process is demonstrated in this video.  Sorry for that.

 

Here is the model and animation we are working with:

animatedModel

It’s 100 frames of animation in length driven by 3 bones.

 

Importing a 3D Model

 

First let’s start with the process of importing a 3D model.   In Godot a 3D Model is imported as a scene.  This means it will also have all of the miscellaneous things included in your scene, such as lights and cameras.  Be sure to remove those or not export them if you do not want them as part of the hierarchy.  Also be sure to save your existing scene before importing a new model, as unsaved changes will be discarded.

 

Godot only supports dae (COLLADA format) models.  Import by selecting Import->3D Scene.

image

 

In the resulting dialog, you have to select a file, as well as a location to put it.  There are several other things we can set controlling how the mesh is imported, how textures work and even defining animation clips, but the defaults will work for now.

image

 

Again, be certain to save your scene before you click Import and Open!

 

Now your model will load in a new scene.  It will default oriented about the origin and there is a good chance your camera will be inside your model, simply use the scroll wheel to zoom out.

 

image

 

Note that the scene has the same name as your model by default.  Notice also the hierarchy of nodes it created.  At the top is a Spatial, and if you have a skeleton attached and Armature exists with the Mesh(es) as children.  If there are animations, there will also be an AnimationPlayer node created.  This is what we are going to focus on next.

 

Splitting Animations

 

We want to split our single long animation into a pair of smaller animations.  Note that in the import that default FPS of the animation was set to 15FPS ( you can change it if you wish ).  Select the AnimationPlayer Node and look in inspector.  If you didn’t specify any clips in the import process you will have simple “Default”.  If you go to Play you can set the animation that plays on start up:

image

 

With the AnimationPlayer selected you will also see that the animation editor is shown at the bottom:

image

 

Using this tool, you can duplicate the default animation twice and then crop each animation accordingly.  We actually already covered using the AnimationPlayer editor in this post so I wont be covering it again.  If you struggle with the process however, simply watch the video and it is shown in detail.  I created two animations, BendForward and BendUp by copying and halving the default timeline.

 

Creating a Model Instance

 

Now that we’ve got a model to work with, let’s flip back to our original scene and put it to use.  Save your scene, then in Godot select Scene->Go To Previous Scene, or simply load the .scn file.

image

 

Now we add an instance of our scene to our scenegraph.  Click the + icon:

image

 

In the file dialog, select your recently created scene.  Your scene graph should now look like this:

image

 

And your model should now appear in your scene.  Not the drop down icon beside the node, this can be used to open that scene or to toggle the visibly of child nodes in your parent scene:

image

 

Playing Animation

 

Now that we’ve got our model in our scene and our animations defined, let’s play them in code.  The process is remarkably simple.  Attach a script to the root of your scene and add the following code:

image

 

As you can see, you access the nodes just like any other in Godot.  There is even autocompletion on the available animations in the play() method!  That’s all you need to do to play the animation.  If you refer to the earlier animation tutorial, all the same logic can be used to create extremely complex animation systems.

 

The Video


Programming


25. September 2015

 

Building on the previous 3D Godot Engine tutorial, today we are going to look at dealing with static meshes in Godot.  That is, meshes that don’t change and do not contain animations.  We will look first at loading a 3D model in OBJ format, apply a texture, then finally look at programmatic mesh creation.  Then in the follow up tutorial, we will look at importing and using animated (COLLADA) meshes.

 

As always there is an HD video version of this post available here.

 

Importing a 3D Static Mesh

 

For simple non-animated models you can import them using the OBJ format which is supported by just about every single content creation tool available, but is very limited in functionality.  First of course you are going to need a 3D model in OBJ format to work with. If you are incapable of creating one yourself, there are plenty available on OpenGameArt.org.  Personally I just opened Blender and textured mapped a simple cube with a test pattern like so:

image

 

Be sure to save your texture externally if you go this route!  Another thing to notice is that the up axis in Blender is Z, while the up axis in Godot is Y.  Notice the orientation of the texture in the above image.  When you export your OBJ file from Blender, you can select the UP axis:

image

 

It beats rotating everything by hand, no?

 

Importing your Model into Godot

Importing a OBJ format model is trivial in Godot.  Simply select Import->3D Mesh.

image

 

The following dialog will appear:

image

 

For the most part you will keep the defaults as they are, however if you made use of smoothing in your DCC, you may want to enable it here.

 

Instancing a Mesh

 

Now that we have our model loaded, we can create an instance of it.  As you may be able to guess, we use the node MeshInstance, which of course is a Spatial.

image

 

You can have multiple instances of the same mesh.  However if you are going to have several instances of the same mesh, and they are relatively close together instead use MultiMeshInstance.  It’s a Node for optimizing performance.  If you have several instances of the same mesh, MultiMeshInstance will batch them all together into a single draw call.  For now though let’s focus on MeshInstance.  Create a new one in your scene like so:

image

 

Now in the Inspector select the Mesh and pick the mesh you just imported:

image

 

You should now see your imported object in your scene:

image

 

But UGH, no texture.  Let’s fix that.  Select Material Override and choose New FixedMaterial:

image

 

Next import your image into Godot as 2D Texture:

image

 

Now select the fixed material  again and edit:

image

 

Scroll down and locate Textures->Diffuse, then Load:

image

 

Select your texture map.  Now you should see:

image

Woot, textured 3D object.

 

Now there was a TON of stuff we just glossed over.  There are dozens of settings you can set on the FixedMaterial, then there was the ShaderMaterial, which enables you to use a GLSL shader on your 3D object.  We will cover these at a later point in time.

 

Dynamic Geometry

 

Sometimes you may find need to create your geometry dynamically.  Godot fully supports this, in fact there are two way to go about it.  The first is using an ImmediateGeometry node.  This provides an OpenGL 1.1 like fixed pipeline interface for creating geometry.  It’s intended for geometry that is going to change often.  I added an ImmediateGeometry node to my scene, then attached the following script:

extends ImmediateGeometry

func _ready():
  self.begin(VS.PRIMITIVE_TRIANGLES,null)
  self.add_vertex(Vector3(0,2,0))
  self.add_vertex(Vector3(2,0,0))
  self.add_vertex(Vector3(-2,0,0))
  self.end()

When run:

image

 

You can also generate a mesh dynamically using SurfaceTool.  A more expensive process, so not something you are going to want to change on a frame by frame basis.  In this case we use MeshInstance just like we did when we loaded the Obj file, but in this case we create the mesh instead of loading it from file.

 

Here is the script to create a triangle, this time with UV information specified so it can be textured:

extends MeshInstance

#export(FixedMaterial)    var material    = null

func _ready():
  
  var surfTool = SurfaceTool.new()
  var mesh = Mesh.new()
  var material = FixedMaterial.new()
  material.set_parameter(material.PARAM_DIFFUSE,Color(1,0,0,1))
  
  surfTool.set_material(material)
  surfTool.begin(VS.PRIMITIVE_TRIANGLES)
  
  surfTool.add_uv(Vector2(0,0))
  surfTool.add_vertex(Vector3(-10,-10,0))
  
  surfTool.add_uv(Vector2(0.5,1))
  surfTool.add_vertex(Vector3(0,10,0))
  
  surfTool.add_uv(Vector2(1,0))
  surfTool.add_vertex(Vector3(10,-10,0))
  
  
  surfTool.generate_normals()
  surfTool.index()
  
  surfTool.commit(mesh)
  
  self.set_mesh(mesh)
  

 

Now when you run it:

image

 

Explaining how to generate a mesh, what UV coordinates are, etc are way beyond the scope of this tutorial.  Most introductory OpenGL or Direct3D tutorials will give you the knowledge you need to create geometry programmatically.

 

Notice in the example above the line that is commented out?

 

export(FixedMaterial)    var material    = null

This is an EXTREMELY powerful feature of Godot, enabling you to use built in editors to set values of your game objects.  Uncomment that line and comment out the FixedMaterial.new() line and look at your object in Inspector:

image

 

By simply exporting a var from your node you get editor access.  Very cool.

 

That’s it for now.  In the next tutorial we will look at loading more complex COLLADA models with animations.  By the way, if you are looking for a great primitive library, or a more indepth procedural mesh example, be sure to check out this project.

 

The Video

 


Programming


22. September 2015

 

In this next part in the ongoing Godot Tutorial Series we are going to begin looking at how you work in 3D in the Godot game engine.  Today we are going to cover the basics of 3D, followed shortly by another tutorial on working with 3D models.  As always I assume you have gone through the previous tutorials in the series or understand the concepts they cover.

 

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

 

3D in Godot

 

After working with 2D in Godot, you will find that 3D is remarkably similar.  No doubt you have been overlooking the interface since the first day you loaded Godot:

image

 

The scene works remarkably similarly, you create a hierarchy of nodes that compose your 3D scene.  In 2D, the root class for displayable nodes was CanvasItem.  In 3D, the base class is instead Spatial:

image

 

Creating a Simple 3D Scene

 

Now let’s assemble a simple 3D scene.  Beyond a TestCube, Godot does not have any built in 3D primitives, so a cube we shall test with!

 

As it was with the 2D world, you still need a root node to hold your scene, in this case I am going to use Node.  Now let’s go ahead and add a Cube at the world origin.  The node name is TestCube:

image

 

So your scene should look like:

image

 

And in the 3D view:

image

 

Now let’s pause a moment to discuss working in 3D…

 

3D Navigation and Editing

 

The 3D Panel in Godot works quite similarly to the 2D view, however different angles and viewports come into play.  One important thing to realize up front is the axis directions in Godot.  Godot is a Y-up engine.  That is, the Y axis represents up and down on your screen, while X represents left and right.  The Z-axis then represents depth… imagine you had the ability to push your hand into your monitor… that would be the Z-axis.  Keep in mind, different tools use different up-axis, so you have have to take this into account when importing models.

 

It’s also often handy to have multiple viewports open when placing things in 3D.  This can be accomplished using the View menu:

image

 

Here is the result of a 4 viewport view ( also available by hitting Ctrl + 4 ):

image

 

You can set the individual camera of each view by clicking the label at the top left corner of a viewport:

image

 

You can also freely rotate the camera.  By default the controls are:

  • Scroll Wheel – Zoom in and out
  • Middle Mouse Button – Orbit
  • Shift + MMB – Pan
  • Ctrl + MMB – Zoom

Modifying entities in the scene is a bit different than 2D as there is now an additional axis.  You still translate, scale and rotate using the same toolbar and hotkeys:

image

 

However, the resulting widget is a fair bit different.  There is a color coded widget per axis, enabling you to make edits a single axis at a time.  Here for example is a rotation in effect:

3DWidget

 

Each axis is colour coded.  Red is the x axis, green is y, while blue is z.  You can see each axis rendered in the grid behind with the matching colour scheme.

 

You can also transform using direct numeric entry, via the Transform-> Transform Dialog… menu:

image

Then…

image

 

If you come from a different 3D background, there are actually several settings to make Godot perform in a way you are more familiar with.  Click settings at the top right corner of the IDE and there are a number of 3D settings you can configure including configuring Godot to work like Maya or Modo if you prefer.  You can also resize the gizmo and alter it’s transparency, etc.

image

 

 

Creating a Camera

 

Ok, now that you know how to navigate around the 3D interface, let’s hop back to our 3D scene and add some life.  Even though you’ve added a box to our world, if you run the game you will see nothing.  There are a couple reasons for this, the first of which is that there is no camera in the scene.  Unlike a 2D game, the default viewport isn’t enough, you have to create a camera.

 

A camera is simply a Spatial derived node, simply add one to the root of your scene:

image

 

Be sure you add the Camera node inherited from Spatial, Camera2D will not work.  Additionally InterpolateCamera is probably not what you want either… think of that class as more like a Camera Swing  arm that helps move the camera around instead of as a camera itself.  I will probably cover this in the future.

 

Once the camera is added to the scene, be sure to move it so it can see your cube, like so:

image

 

With a camera in the scene, you can click the “Preview” button at the top right corner of any view to preview what a camera sees.  This is one of the ways a split view certainly comes in handy, use one or more views for positioning your scene, and dedicate one to previewing your camera.

 

If you look down at the Inspector with your camera selected, you will see that there are several settings:

image

 

Projection determines the type of your camera, Perspective or Orthogonal.  With a perspective camera, as things get further away ( z-axis ) they appear to be smaller, mimicking the way the human eye works.  With an orthographic camera, sizes stay the same.  As a general rule, a 3D game uses perspective, a 2D game use orthographic.

Fovy is the field of view, or the number of degrees along the Y axis the camera can see.  A FoV of 180 for example would allow you to see both your left and right hand if you held them out to your side.  Most games however use much lower values.  On consoles 60-75 are typical values, while on a PC where you are much closer to the monitor, a higher value like 90 is often used.

Near and far values control how close the camera starts recording, and how far out it captures an image.  Basically this is the “range” of the camera.  FOV, Aspect Ratio and Near/Far plane all go together to calculate the camera’s view frustum.

The Current value is very important if you have multiple camera’s in your scene.  Whichever one is flagged as current is the one that will be rendered.  If only one camera is specified, current does not need to be set.

 

Adding a Light

 

If you press play at this point, you will still see nothing, as there is no light in the world.  Just like in real life, no light, no visibility.  There are three options available for lighting:

image

 

An omni light is like a light that radiates in all directions.  This a typical table lamp without a lamp shade.

A spot light on the other hand is a light with a defined beam and direction.  Think headlights on a car or the light of a flashlight.

A directional light on the other hand is basically a massive light source with a direction and that’s about it.  Think… the sun.

 

In this example lets fake a sun by adding a directional light to the scene. At this point your scene should look something like this:

image

 

The directional light shows up as a big wireframe arrow in the 3D scene.  Using movement and rotation, position it so it’s shining down on your box on an angle, like so:

image

 

You will notice in the Inspector you can now set properties for both the light and the shadows it creates:

image

 

In this case we will stay with default settings.  The most important settings you will see in those dialogs are Shadow, which enables you to turn shadow generation on and off, Colors, which sets the color of the light, and Energy, which sets the intensity of the light. 

 

Now that we finally have a camera, a light and a 3D object, if we press play we should see:

image

TADA!  Your first Godot 3D application!

 

The Video

 

Programming


4. September 2015

 

While on vacation I have been looking at the process of extending the Godot Game engine using C++.  Due to the vacation, this isn’t a proper tutorial, I may do one later on when I have access to video, etc…  There is pretty solid documentation of the process in this post on the Godot wiki beyond that however there is a huge lack of information.  So the following is mostly trial and error.

 

I worked entirely in Visual Studio for this example and am working from the most recent source from Github.  If you have trouble working in Visual Studio with Godot, be sure to check out this post.

 

We are going to have to create several files in the modules folder, but don’t worry many can be copy/pasted from an existing module.  I created a new module called modTest inside the modules folder, and the contents end up looking like:

 

image

 

Many I coped directly from gridmap, but I will show the entire contents below.

 

config.py

def can_build(platform):
  return True
  
  
def configure(env):
  pass
  

 

SCSub

Import('env')

env.add_source_files(env.modules_sources,"*.cpp")


 

register_types.h

void register_modtest_types();
void unregister_modtest_types();

 

register_types.cpp

#include "register_types.h"
#include "object_type_db.h"
#include "modtest.h"
#include "modtest_editor.h"

#define TOOLS_ENABLED 1

void register_modtest_types() {
  ObjectTypeDB::register_type<ModTest>();

#ifdef TOOLS_ENABLED
  EditorPlugins::add_by_type<modtest_editor_plugin>();
#endif
}



void unregister_modtest_types() {


}

 

modtest.h

#ifndef MODTEST_H
#define MODTEST_H

#include "scene/2d/node_2d.h"

class ModTest : public Node2D {
  OBJ_TYPE(ModTest, Node2D);
};

#endif

 

modtest.cpp

#include "modtest.h"

 

modtest_editor.h

#pragma once

#include "tools/editor/editor_plugin.h"
#include "tools/editor/editor_node.h"
#include "tools/editor/pane_drag.h"


class ModtestEditor : public VBoxContainer {
  OBJ_TYPE(ModtestEditor, VBoxContainer);

public:
  ModtestEditor(){}
  ModtestEditor(EditorNode * p_editor);


private:
  VBoxContainer * container;
  Label* label;
  EditorNode* _editor;
};




class modtest_editor_plugin : public EditorPlugin
{
  OBJ_TYPE(modtest_editor_plugin, EditorPlugin);

public:
  modtest_editor_plugin(EditorNode *p_editor);
  ~modtest_editor_plugin();

  virtual void make_visible(bool isVisible);
  virtual void edit(Object *p_node);
  virtual bool handles(Object *p_node) const;

private:
  EditorNode * _editor;
  ModtestEditor* modtestEditor;
};

 

modtest_editor.cpp

#include "modtest_editor.h"
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
#include "tools/editor/editor_settings.h"

#include "scene/main/viewport.h"

#include <iostream>


ModtestEditor::ModtestEditor(EditorNode* p_editor){
  std::cout << "New Modtest Editor" << std::endl;

  this->set_size(Size2(600, 600));
  label = new Label();
  label->set_text("Hello World");
  this->add_child(label);

  //p_editor->add_child(this);
  p_editor->get_scene_root()->add_child(this);
  _editor = p_editor;
  
  this->hide();
}


// **************************** PLUGIN BEGIN ********************************************

modtest_editor_plugin::modtest_editor_plugin(EditorNode * p_editor)
{
  _editor = p_editor;
  modtestEditor = memnew(ModtestEditor(_editor));
  
  std::cout << "Editor" << std::endl;
  
}


modtest_editor_plugin::~modtest_editor_plugin()
{
}


void modtest_editor_plugin::make_visible(bool isVisible){
  std::cout << "Make visible" << std::endl;
  if (isVisible){
    std::cout << "Showing" << std::endl;
    modtestEditor->show();
  }
  else{
    std::cout << "Hiding" << std::endl;
    modtestEditor->hide();
  }
}

void modtest_editor_plugin::edit(Object *p_object) {
  std::cout << "Edit" << std::endl;
}

bool modtest_editor_plugin::handles(Object *p_object) const {

  return p_object->is_type("ModTest");
}


So that was a mountain of examples, but nothing particularly complicated.

 

The SCSub and config.py files simply tell the Scons build system how to build your module, both of them can be copied in unchanged from the gridmap module.  It’s only if your module doesn’t build for every platform or you need to do something other than compile all the included cpp files that you need to alter either of these files.

 

Next up are the register_types cpp and h files, which registers your type with Godot.  ModTest is a simple Node2D extension type, it can be registered using ObjectTypeDB::register_type().  Additionally we have an editor we want to show when editing our new type, that is registered using EditorPlugins::add_by_type() .  The TOOLS_ENABLED means that you are building Godot with full tooling support, as opposed to building just a game (without the editor in the generated binary).

 

Our extension is completely pointless.  It’s inherited from Node2D and well, that’s about it.  Obviously you would add functionality as you go.  The simple fact it inherits from Node2D makes it available in Godot as a Node:

image

 

Next we register an editor and a plugin for our ModTest type.  The ModtestEditor class is going to be the editor displayed within Godot.  It’s a simple VBoxContainer.  In this case all we do is add a label with the text Hello World then add it to the editor using the passed in pointer to the EditorNode.  This is generally where the majority of logic will go.

 

Next up is the modtest_editor_plugin which inherits EditorPlugin.  This class is loaded with Godot by the call EditorPlugins::add_by_type<modtest_editor_plugin>().  The important call is modtest_editor_plugin::handles(), which attaches the editor to the type it edits.  In the constructor, we create an instance of our editor.  The make_visible() method is called each time the editor is needed, or no longer needed and toggles the visibility of our editor.

 

As you add or select a node of ModTest type, the editor will automatically be shown:

image

 

Obviously this is a barebones example.  As I implement a more detailed example I will share the results.

Programming


See More Tutorials on DevGa.me!

Month List