Sandbox Logo
19 May 2023

Hammer Gizmos

Allowing custom scene editors in Hammer
Think of gizmos like IMGUI but for the 3d world. You can use them to draw lines, shapes, models, sprites or particles.

Our main use case here is for adding development gizmos, like position and rotate.. but you could totally use them to render effects and other client-side 3d interactions in your actual game.

Example

Each banana in this scene is rendered using the Gizmo API. Every frame a function is called which is saying "render a banana here". The gizmo library does all the optimizing work on the backend saying "this is the same banana object as the last one, so don't change anything" to keep things running nice.

The code for rendering one of these bananas is simply this:

// make the next section clickable Gizmo.Hitbox.Sphere( new Sphere( 0.0f, 4.0f ) ); // draw a different color if the hitbox above is hovered Gizmo.Draw.Color = Gizmo.IsHovered ? Color.Green : Color.White; // change the size if the hitbox above is pressed down if ( Gizmo.IsPressed ) Gizmo.Transform = Gizmo.Transform.WithScale( 2.0f ); // draw the banana model Gizmo.Draw.Model( "models/rust_props/small_junk/banana.vmdl" );
Hammer Gizmos let us interact with the editor session, displaying and modifying entities' properties directly from our game code.

It's actually pretty agnostic of Hammer, so we could use them in any editor.

Here's some code that draws a sphere from a radius, with a drag control for it.
public class MyEntity : Entity
{
[Property]
public float Radius { get; set; }

public static void DrawGizmos( EditorContext ctx )
{
// This is a serialized version of the Entity currently being drawn
SerializedObject target = ctx.TargetObject;

// We can get key values from it
var radius = target.GetProperty( "radius" ).As.Float;

// Draw a sphere the size of the radius
Gizmo.Draw.Color = Gizmo.Colors.Green;
Gizmo.Draw.SolidSphere( Vector3.Zero, radius, 8, 8 );

// Gizmo that can control the radius
if( Gizmo.Control.Arrow( "radius-arrow", Camera.Rotation.Up,
out var distance, axisOffset: radius + 5,
length: 5, head: "cone", girth: 15.0f ) )
radius += distance;

// And change them
target.GetProperty( "radius" ).SetValue( radius );
}
}
The editor is running the game code through reflection without an instance, there's some obvious advantages to doing it this way:
  • It's really simple to add a method to any entity
  • Don't need #ifdef UNITY_EDITOR everywhere
  • Can ship a single dll
But also some disadvantages:
  • The entity doesn't actually exist, can be confusing and limiting at first
  • No normal access to editor API
Overall I think it works pretty good.. here's some basic examples of what you can do with your own entities.
There's a lot more to explore here in terms of what's possible. I can definitely see this being useful in gameplay. For example, I wish I'd have had this when making the faceposer or hand poser in GMod.

We'll continue to explore, in the meantime, those that are in the dev preview can start playing and making their own controls right now.