Garry's Mod Wiki

Render Reference - Render Targets

Render Library References

These pages seek to provide helpful insight into the groups of functions provided by the Render Library.

The major function groups are:

What are Render Targets?

A Render Target is a special kind of texture that is created during gameplay via the game's code, rather than from a pre-existing image that is loaded from the game's files. Like other textures, Render Targets can be drawn as 2D images, like a HUD element, or as the base texture for Materials to be used on 3D objects.

Render Targets have a fixed resolution, measured in pixels, that is defined when they are first created.
Unless your specific use-case has a reason not to, it's recommended to use the game's render resolution (Obtained via ScrW and ScrH.)

Render Targets have 3 layers:

  1. The Color Channel (or simply "Color")
    • This is what will be seen when the Render Target is drawn onto the screen.
    • Each pixel in the Render Target's Color Channel has a red, green, blue, and alpha value.
  2. The Depth Buffer (or simply "Depth")
    • This layer keeps track of how far away from the camera each pixel in the Render Target is.
    • Each pixel in the Depth Buffer has a whole, integer number between 0-255 where 0 is close to the camera and 255 is far from the camera.
  3. The Stencil Buffer (or simply "Stencils")
    • The Stencil layer controls whether or not each individual pixel in the Render Target is able to be modified by drawing and rendering operations.
    • Each pixel in the Stencil buffer has a whole, integer number between 0-255.
    • By default, the Stencil layer is configured so that all pixels can be drawn to.

What are Practical Uses for Render Targets?

While this is not a complete or exhaustive list, here are some examples of situations where a Render Target would be useful:

  • A rear-view mirror for a vehicle.
  • A security camera feed shown on a TV in a building's security room.
  • A painting canvas that players can draw on.

The Game's Main View is a Render Target

It's important to understand that Render Targets are a core piece of the game's rendering system.
Any drawing or rendering operation that you can do to the game's main view can be done to a Render Target because they are both Render Targets.

The Source Engine, and by extension Garry's Mod, uses a "double buffered" rendering system. This means the game creates two Render Targets (Called "Frame Buffers" when used for this purpose.) One of these Render Targets is the "Front" and one is the "Back". The Front Render Target is what gets drawn onto the screen for the player to see. Meanwhile, the next frame of the game gets drawn onto the Back Render Target. Once the frame has been fully drawn onto the Back Render Target, the rendering system swaps (Called "Spinning") the Front and Back Render Targets and the process starts again.

Example Code

Example

The following example code should provide a good demonstration of how to set up a basic Render Target, how to draw 2D and 3D elements onto it, and then how to draw the Render Target onto the screen.

-- Create the Render Target we'll be using throughout this example local renderTarget = GetRenderTarget( "RenderTargetExample", -- The name we'll call new Render Target's Texture 1024, 1024 -- The size of the Render Target ) -- Create a Material that corresponds to the Render Target we just made local renderTargetMaterial = CreateMaterial( "RenderTargetExampleMaterial", -- All Materials need a name "UnlitGeneric", -- This shader will work great for drawing onto the screen, but can't be used on models -- To use this material on a model, this would need to use the "VertexLitGeneric" shader. { ["$basetexture"] = renderTarget:GetName(), -- Use our Render Target as the Texture for this Material ["$translucent"] = "1", -- Without this, the Material will be fully opaque and any translucency won't be shown } ) -- Used later for some 3D rendering local clientsideModel = ClientsideModel( "models/props_lab/huladoll.mdl", RENDERGROUP_OPAQUE ) clientsideModel:SetNoDraw( true ) -- An all-white material is built-in to the game local colorMaterial = Material( "color" ) -- This function just gives us something to draw that uses a 2D context -- It can be replaced with any other 2D drawing operation(s) local function DrawSomething2D() surface.SetMaterial( colorMaterial ) surface.SetDrawColor( Color( 255, 0, 255, 200 ) ) surface.DrawTexturedRectRotated( ScrW()/2, ScrH()/2, 500, 500, ( CurTime() * 200 ) % 360 ) end -- Same as DrawSomething2D, but with 3D content local function DrawSomething3D() -- To brighten the model without setting up lighting render.SuppressEngineLighting( true ) -- By default, 3D rendering to a Render Target will put the Depth Buffer into the alpha channel of the image. -- I do not know why this is the case, but we can disable that behavior with this function. render.SetWriteDepthToDestAlpha( false ) render.Model( { model = "models/props_lab/huladoll.mdl", -- You can ignore this math, it's just to make the hula doll do a little dance pos = Vector( 20, -math.sin( CurTime() * 7.5 ) * 0.35, -3.5 ), angle = Angle( 0, 180 + math.sin( CurTime() * 7.5 ) * 7, math.sin( CurTime() * 7.5 ) * 15 ) }, clientsideModel ) render.SetWriteDepthToDestAlpha( true ) render.SuppressEngineLighting( false ) end -- In a hook that runs every frame, draw to the Render Target -- Note: You could use any hook for this. hook.Add( "PreDrawEffects", "DrawingToExampleRenderTarget", function() -- Start drawing onto our render target render.PushRenderTarget( renderTarget ) -- Remove the Render Target's contents from the previous frame so we can draw a new one on a fresh "canvas" render.Clear( 0, 255, 0, 200, true, true ) -- Start drawing in a 2D context -- By default this hook provides a 3D context, so we need to change it. cam.Start2D() -- Draw some fun 2D content to the Render Target DrawSomething2D() cam.End2D() -- The hook's original 3D context has an unknown position and rotation. -- Because we want control over our Render Target, we need to start a new 3D context. -- You can think of this as setting up the "camera" we're about to render with. cam.Start3D( Vector( 0, 0, 0 ), -- The position of this 3D context's view Angle( 0, 0, 0 ), -- The direction this 3D context's view is pointing in 40 -- The field of view, in degrees ) -- Now that we're in a 3D context, let's draw something 3D DrawSomething3D() cam.End3D() -- Stop drawing on our render target and let the rendering system continue normally render.PopRenderTarget() end ) -- In a completely different hook we can draw the Render Target to the screen via its Material -- This is done in a different hook purely to demonstrate that the Render Target can be used -- outside of the place it is drawn in. hook.Add( "DrawOverlay", "DrawingRenderTargetToScreen", function() surface.SetMaterial( renderTargetMaterial ) surface.SetDrawColor( Color( 255, 255, 255, 255 ) ) surface.DrawTexturedRectRotated( 300, 300, 500, 500, 0 ) end )
Output: