-
Notifications
You must be signed in to change notification settings - Fork 0
Quick Start Guide
NOTE: This wiki page is a work-in-progress. Incomplete pages will link back to this guide
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
- Create a new Game Maker Project.
- Create an Object and place it in the default room.
- Import the DmrVBM package.
- Tools > Import Local Package
- Navigate to extracted folder and select DmrVBM_GameMaker.yymps
- Click
Add All
, thenImport
- Re-importing the package will show an extra menu for overwriting scripts.
- Click
Replace All
, thenImport
-
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.
- Sprites can be used as textures using the
-
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.
- In Scene properties, create a new Vertex Format with the
+
button in theVBM Vertex Formats
panel underVBM Export
- 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
- 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
- Run the game with
F5
or thePlay
button.- If you see something drawn on your screen, you're on track
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
- Run the game with
F5
or thePlay
button.- Your model should be visible, but mirrored.
- 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
);
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
- Running the game now should look more like what was exported in Blender.
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.
-
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 thescr_dmrvbm
script to a different value.
- VBM's soft bone limit is 128. This can be adjusted by changing the
-
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.
- 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
- Add a
- Select the model objects and export the VBM file. The action should appear as part of the "Checkout" section
- Make sure that
Meshes
,Skeleton
, andAnimations
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
- Make sure that
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
- 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.
- If the model is in its base pose with no animation, either the animation did not get exported or the key used in
- 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;
}