Skip to content

Quick Start Guide

Sandman13sq edited this page Feb 10, 2024 · 31 revisions

NOTE: This wiki page is a work-in-progress. Incomplete pages will link back to this guide

== Importing model from Blender to Game Maker ==

The purpose of this guide is to show the minimum effort needed to get a model from Blender showing up in a Game Maker project using DmrVBM.
For details on the features of DmrVBM, see the DmrVBM Wiki

Game Maker - Create Project

  • Create a new Game Maker Project.

New GMS Project

  • Create an Object and place it in the default room.

New Object

  • Import the DmrVBM package.
    • Tools > Import Local Package
    • Navigate to extracted folder and select DmrVBM_GameMaker.yymps
    • Click Add All, then Import
      • Re-importing the package will show an extra menu for overwriting scripts.
      • Click Replace All, then Import

Import Package

Blender - Load Addon and Export Model

  • In Blender, open a file with your desired model. Preferably one with vertex colors since it's the easiest to display.

    • Sprites can be used as textures using the sprite_get_texture(sprite, subimage) function.
  • Import DmrVBM_Blender addon.

    • Preferences > Add-ons > Install
    • Select DmrVBM_Blender.zip and click Install (Do not unzip!)
    • Click "Save Preferences" with the hamburger menu on the bottom-left
  • For extra debugging info, on the menu bar go to Window > Toggle System Console

    • On MacOS, Blender has to be run from the terminal to see console output.

Import Addon

  • In Scene properties, create a new Vertex Format with the + button in the VBM Vertex Formats panel under VBM Export

Define Format

  • In the 3D view or Outliner, select all objects that are part of your model.
  • Press the Export VBM button under Properties > VBM Export
  • Make sure your newly created format is active in the "Format" section.
  • In the dialog, navigate to your Game Maker Project's datafiles folder and save your model as "model.vbm"
    • A message will appear at the bottom of the window when the export is complete

Export VBM

Game Maker - Load Model and Render to Screen

  • Back to Game Maker, in the object's Create event, load your saved vbm file:
vbm = OpenVBM("model.vbm");	// Reads vbm data from file
  • Define projection and view matrices in the Create event too:
matproj = matrix_build_projection_perspective_fov(
	50,	// Field of View
	window_get_width()/window_get_height(),	// Pixel Aspect ratio. Dictates how tall drawn pixels are
	0.2,	// Geometry BELOW this distance from the camera will not be drawn.
	100	// Geometry ABOVE this distance from the camera will not be drawn
	);

// Appropriate location differs per model size. Feel free to adjust
matview = matrix_build_lookat(
	0, -3, 1,	// Camera Location
	0, 0, 1,	// Camera Direction Target. Where to look.
	0, 0, 1		// Camera Up Vector
	);
  • In the Draw Event, set the projection and view matrices and submit your vbm.
matrix_set(matrix_projection, matproj);	// View > Screen
matrix_set(matrix_view, matview);	// World > View

vbm.Submit();	// Draw Model

Object Events

  • Run the game with F5 or the Play button.
    • If you see something drawn on your screen, you're on track

First Run

Game Maker's default GPU settings are designed for drawing sprites, so some changes are needed to fit 3D drawing purposes.

  • Add this to the start of the Draw event:
gpu_push_state();	// Save current GPU state
gpu_set_zwriteenable(true);	// Enable writing to the depth buffer
gpu_set_ztestenable(true);	// Sort fragments using depth buffer
gpu_set_cullmode(cull_clockwise);	// Only draw front-facing triangles
  • Add this to the end of the Draw event:
gpu_pop_state();	// Restore last saved GPU state

Object Events 2

  • Run the game with F5 or the Play button.
    • Your model should be visible, but mirrored.

GPU Render

  • Game Maker works with a -Y Up coordinate system, which makes sense for 2D, but doesn't help for 3D.
  • For this guide's purposes, we can fix this by negating the aspect ratio for the projection matrix:
matproj = matrix_build_projection_perspective_fov(
	50,	// Field of View
	-window_get_width()/window_get_height(),	// Pixel Aspect ratio. Negative for y-flip
	0.2,	// Geometry BELOW this distance from the camera will not be drawn.
	100	// Geometry ABOVE this distance from the camera will not be drawn
	);

Y-Flip

We can transform the model by changing the world matrix:

  • In the Create event, add this line:
matwrld = matrix_build_identity();
  • Add a Step event to the object and insert this block:
// Rotate model using program's time value
matwrld = matrix_build(
	0, 0, 0,
	0, 0, current_time / 30,
	1, 1, 1
);
  • In the Draw event, add this line before submitting the model:
matrix_set(matrix_world, matwrld);	// Model -> World
  • And finally, add this line at the end of the Draw event, when all 3D rendering is complete:
matrix_set(matrix_projection, camera_get_proj_mat(view_camera[view_current]));	// Reset projection
matrix_set(matrix_view, camera_get_view_mat(view_camera[view_current]));	// Reset view
matrix_set(matrix_world, matrix_build_identity());	// Reset matrix for application surface drawing

Object Events 3

  • Running the game now should look more like what was exported in Blender.

Correct Run

At this point, with a little bit of surface level linear algebra and trig along with sprite billboarding, you can start making your own DOOM clone, or retro RPG focused around monsters that can (theoretically) fit in your pocket. "Pouch-Mon", maybe.

  • Note that all of Game Maker's trigonometry functions (sine, cosine, matrix_build, etc.) calculate results with a -Y up coordinate system, as the origin of a room in GMS is at the top left.

If you have rigged models with an animation to demo, see below.

Blender - Exporting Models with Animations

  • To export models with skeletal animations, they must be rigged beforehand

    • VBM's soft bone limit is 128. This can be adjusted by changing the VBM_MATPOSEMAX macro in the scr_dmrvbm script to a different value.
  • Select your rig armature and set its action through the Dope Sheet area.

  • In DmrVBM under scene properties, click the push down arrow to add the action to the armature's action list.

Set Animation

  • To export bone indices and weights, the format must be updated to include them.
    • Add a Bone Indices attribute to the format
    • Add a Weights attribute to the format

Rig Attributes

  • Select the model objects and export the VBM file. The action should appear as part of the "Checkout" section
    • Make sure that Meshes, Skeleton, and Animations are all enabled on the top of the dialog options
    • The delimiter options trims names using hyphens ("-") by default, so "treat-walk" would become just "walk".
      • To disable this behavior, remove the hyphen from the delimiter options under the "Checkout" section of the export dialog

Animation in Checkout

Game Maker - Drawing Models with Animations

With an attribute format that differs from Game Maker's native format, a new shader is needed to draw the model.

  • Create a new shader in the Game Maker project, and copy the below shader code to the Vertex shader (.vsh). Fragment shader (.fsh) can be left alone
//
//	Not-so-simple skinned vertex shader
//
attribute vec3 in_Position;                  // (x,y,z)
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)
attribute vec4 in_Bone;		// (b0,b1,b2,b3)
attribute vec4 in_Weight;	// (w0,w1,w2,w3)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform mat4 u_bonetransforms[128];	// Passed in via shader_set_uniform_matrix_array()

void main()
{
    vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
	
	// Compose transform matrix out of weighted bone transforms
	mat4 m = mat4(0.0);
	for (int i = 0; i < 4; i++)
	{
		m += u_bonetransforms[ int(in_Bone[i]) ] * in_Weight[i];
	}
	
	object_space_pos = m * object_space_pos; // Update vertex position
	
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
    
    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
}
  • In the object's Create Event, add these lines after loading the model:
animator = vbm.CreateAnimator();	// Instances an animator to animate vbm
animator.PlayAnimation("walk");	// <-- Name of your animation goes here

u_bonetransforms = shader_get_uniform(Shader1, "u_bonetransforms");	// Find uniform handle to set bone transforms
  • Add this to the Step Event:
animator.Update(1);	// Update model animation
  • And finally, replace the vbm.Submit() line with this block:
shader_set(Shader1);	// Set active shader to bone shader
shader_set_uniform_matrix_array(u_bonetransforms, animator.OutputPose());	// Sets uniform for shader

vbm.Submit();	// Draw Model

shader_reset();	// Reset to Native GM shader

Object Events 3

Vertex Shader Code

  • Run the game
    • If the model is in its base pose with no animation, either the animation did not get exported or the key used in PlayAnimation() was not found.

Treat Walking


Game Maker Code

Object Events

  • Create Event
/// @description 

vbm = OpenVBM("model.vbm");	// Opens and returns VBM struct
animator = vbm.CreateAnimator();	// Instances an animator to animate vbm
animator.PlayAnimation("walk");

u_bonetransforms = shader_get_uniform(Shader1, "u_bonetransforms");	// Find uniform handle to set bone transforms

matproj = matrix_build_projection_perspective_fov(
	50,	// Field of View
	-window_get_width()/window_get_height(),	// Pixel Aspect ratio. Negative for y-flip
	0.2,	// Geometry BELOW this distance from the camera will not be drawn.
	100	// Geometry ABOVE this distance from the camera will not be drawn
	);

// Appropriate location differs per model size. Feel free to adjust
matview = matrix_build_lookat(
	0, -3, 1,	// Camera Location
	0, 0, 1,	// Camera Direction Target. Where to look.
	0, 0, 1		// Camera Up Vector
	);

matwrld = matrix_build_identity();

  • Step Event
/// @description 

// Rotate model using program's time value
matwrld = matrix_build(
	0, 0, 0,
	0, 0, current_time / 30,
	1, 1, 1
);

animator.Update(1);	// Update model animation
  • Draw Event
/// @description 

gpu_push_state();	// Save current GPU state
gpu_set_zwriteenable(true);	// Enable writing to the depth buffer
gpu_set_ztestenable(true);	// Sort fragments using depth buffer
gpu_set_cullmode(cull_clockwise);	// Only draw front-facing triangles

matrix_set(matrix_projection, matproj);	// View > Screen
matrix_set(matrix_view, matview);	// World > View
matrix_set(matrix_world, matwrld);	// Model -> World

shader_set(Shader1);	// Set active shader to bone shader
shader_set_uniform_matrix_array(u_bonetransforms, animator.OutputPose());	// Sets uniform for shader

vbm.Submit();	// Draw Model

shader_reset();	// Reset to Native GM shader
gpu_pop_state();	// Restore last saved GPU state

matrix_set(matrix_projection, camera_get_proj_mat(view_camera[view_current]));	// Reset projection
matrix_set(matrix_view, camera_get_view_mat(view_camera[view_current]));	// Reset view
matrix_set(matrix_world, matrix_build_identity());	// Reset matrix for application surface drawing
  • Vertex Shader
/*
	Not-so-simple skinned vertex shader
*/
attribute vec3 in_Position;                  // (x,y,z)
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)
attribute vec4 in_Bone;		// (b0,b1,b2,b3)
attribute vec4 in_Weight;	// (w0,w1,w2,w3)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform mat4 u_bonetransforms[128];	// Passed in via shader_set_uniform_matrix_array()

void main()
{
	vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
	
	// Compose transform matrix out of weighted bone transforms
	mat4 m = mat4(0.0);
	for (int i = 0; i < 4; i++)
	{
		m += u_bonetransforms[ int(in_Bone[i]) ] * in_Weight[i];
	}
	
	object_space_pos = m * object_space_pos; // Update vertex position
	
	gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
	
	v_vColour = in_Colour;
	v_vTexcoord = in_TextureCoord;
}