Garry's Mod Wiki

Revision Difference

cam.Start3D2D#561633

<function name="Start3D2D" parent="cam" type="libraryfunc"> <description> Sets up a new 2D rendering context. Must be finished by <page>cam.End3D2D</page>. This function pushes a new matrix onto the stack. (<page>cam.PushModelMatrix</page>) Sets up the model transformation matrix to draw 2D content in 3D space and pushes it into the stack (<page>cam.PushModelMatrix</page>). Matrix formula: ``` local m = Matrix() m:SetAngles(angles) m:SetTranslation(pos) m:SetScale(Vector(scale, -scale, 1)) ``` ⤶ <rendercontext hook="true" type="2D"></rendercontext>⤶ <rendercontext hook="true" type="3D"></rendercontext>⤶ <warning>This should be closed by <page>cam.End3D2D</page> otherwise the game crashes</warning>⤶ <warning>This must be closed by <page>cam.End3D2D</page>. If not done so, unexpected issues might arise.</warning>⤶ </description> <realm>Client</realm> <args> <arg name="pos" type="Vector">Origin of the 3D2D context, ie. the top left corner, (0, 0).</arg> <arg name="angles" type="Angle">Angles of the 3D2D context. +x in the 2d context corresponds to +x of the angle (its forward direction). +y in the 2d context corresponds to -y of the angle (its right direction). If (dx, dy) are your desired (+x, +y) unit vectors, the angle you want is dx:AngleEx(dx:Cross(-dy)).</arg> <arg name="scale" type="number">The scale of the render context. If scale is 1 then 1 pixel in 2D context will equal to 1 unit in 3D context.</arg> </args> </function> <example> <description>Makes a floating rectangle with text above where the player is looking at, pointing at the player</description> <code> hook.Add("PostDrawOpaqueRenderables", "example", function() -- Get the game's camera angles⤶ local angle = EyeAngles() -- Only use the Yaw component of the angle⤶ angle = Angle( 0, angle.y, 0 ) -- Apply some animation to the angle⤶ angle.y = angle.y + math.sin( CurTime() ) * 10⤶ ⤶ -- Correct the angle so it points at the camera⤶ -- This is usually done by trial and error using Up(), Right() and Forward() axes⤶ angle:RotateAroundAxis( angle:Up(), -90 )⤶ angle:RotateAroundAxis( angle:Forward(), 90 ) ⤶ -- A trace just for a position⤶ local trace = LocalPlayer():GetEyeTrace()⤶ local pos = trace.HitPos⤶ -- Raise the hitpos off the ground by 20 units and apply some animation⤶ pos = pos + Vector( 0, 0, math.cos( CurTime() / 2 ) + 20 ) -- Notice the scale is small, so text looks crispier⤶ cam.Start3D2D( pos, angle, 0.1 ) -- Get the size of the text we are about to draw⤶ local text = "Testing"⤶ surface.SetFont( "Default" )⤶ local tW, tH = surface.GetTextSize( "Testing" )⤶ ⤶ -- This defines amount of padding for the box around the text⤶ local pad = 5⤶ -- Draw a rectable. This has to be done before drawing the text, to prevent overlapping⤶ -- Notice how we start drawing in negative coordinates⤶ -- This is to make sure the 3d2d display rotates around our position by its center, not left corner⤶ surface.SetDrawColor( 0, 0, 0, 255 ) surface.DrawRect( -tW / 2 - pad, -pad, tW + pad * 2, tH + pad * 2 ) -- Draw some text draw.SimpleText( "Testing", "Default", -tW / 2, 0, color_white )⤶ cam.End3D2D()⤶ ⤶ surface.CreateFont( "PlayerTagFont", { font = "Arial",⤶ size = 72, } ) ⤶ hook.Add( "PostDrawOpaqueRenderables", "player_name_tags", function() for id, ply in player.Iterator() do⤶ ⤶ -- Player too far, don't bother⤶ if ( ply:GetPos():Distance( EyePos() ) > 512 ) then continue end⤶ -- Player is the local player in the first person, don't bother⤶ if ( ply == LocalPlayer() ) then continue end⤶ ⤶ -- Get the player position, and move it above their head. local pos = ply:GetPos() + ply:GetUp() * ( ply:OBBMaxs().z + 5 )⤶ ⤶ -- Apply some neat bobbing animation⤶ pos = pos + Vector( 0, 0, math.cos( CurTime() / 2 ) )⤶ -- Get the angle between game's game and the target player⤶ local angle = ( pos - EyePos() ):GetNormalized():Angle() -- Only use the Yaw component of the angle⤶ angle = Angle( 0, angle.y, 0 ) -- Apply some animation to the angle⤶ angle.y = angle.y + math.sin( CurTime() ) * 10⤶ ⤶ -- Correct the angle so it points at the camera⤶ -- This is usually done by trial and error using Up(), Right() and Forward() axes⤶ angle:RotateAroundAxis( angle:Up(), -90 )⤶ angle:RotateAroundAxis( angle:Forward(), 90 )⤶ -- Notice the scale is small, so text looks crispier⤶ cam.Start3D2D( pos, angle, 0.05 )⤶ -- Get the size of the text we are about to draw⤶ surface.SetFont( "PlayerTagFont" ) local tW, tH = surface.GetTextSize( ply:Nick() ) -- This defines amount of padding for the box around the text local padX = 20⤶ local padY = 5⤶ ⤶ -- Draw a rectable. This has to be done before drawing the text, to prevent overlapping⤶ -- Notice how we start drawing in negative coordinates⤶ -- This is to make sure the 3d2d display rotates around our position by its center, not left corner⤶ surface.SetDrawColor( 0, 0, 0, 200 )⤶ surface.DrawRect( -tW / 2 - padX, -padY, tW + padX * 2, tH + padY * 2 )⤶ ⤶ -- Draw some text⤶ draw.SimpleText( ply:Nick(), "PlayerTagFont", -tW / 2, 0, color_white )⤶ cam.End3D2D()⤶ end⤶ end ) </code> <output>⤶ <image src="70c/8dc53c0087ef97a.png" size="928654" name="image.png" />⤶ </output>⤶ </example> <example> <description>An example on how to correctly rotate and position 3D2D "screen" attached to a prop.</description>⤶ <code> hook.Add("PostDrawOpaqueRenderables", "example", function() local trace = LocalPlayer():GetEyeTrace() local angle = trace.HitNormal:Angle() render.DrawLine( trace.HitPos, trace.HitPos + 8 * angle:Forward(), Color( 255, 0, 0 ), true ) render.DrawLine( trace.HitPos, trace.HitPos + 8 * -angle:Right(), Color( 0, 255, 0 ), true ) render.DrawLine( trace.HitPos, trace.HitPos + 8 * angle:Up(), Color( 0, 0, 255 ), true ) cam.Start3D2D( trace.HitPos, angle, 1 )⤶ surface.SetDrawColor( 255, 165, 0, 255 )⤶ surface.DrawRect( 0, 0, 8, 8 )⤶ render.DrawLine( Vector( 0, 0, 0 ), Vector( 8, 8, 8 ), Color( 100, 149, 237, 255 ), true )⤶ ⤶ function ENT:Draw( flags ) self:DrawModel( flags ) local ang = self:GetAngles() -- Change these numbers to rotate the screen correctly for your model⤶ ang:RotateAroundAxis( self:GetUp(), 90 ) ang:RotateAroundAxis( self:GetRight(), -90 + 4.5 ) ang:RotateAroundAxis( self:GetForward(), 0 ) ⤶ local pos = self:GetPos() -- Change these numbers to position the screen on your model⤶ pos = pos + self:GetForward() * 11.7⤶ pos = pos + self:GetRight() * 9.69⤶ pos = pos + self:GetUp() * 11.8⤶ ⤶ -- Higher the value, the better the resolution⤶ local resolution = 1.1⤶ ⤶ cam.Start3D2D( pos, ang, 0.05 / resolution )⤶ -- Paint the background. Effectively a 388x320 pixel screen⤶ surface.SetDrawColor( 0, 0, 0, 255 )⤶ surface.DrawRect( 0, 0, 388 * resolution, 320 * resolution )⤶ ⤶ -- Paint the content⤶ draw.SimpleText( "Loading GMod BIOS v0.9.....", "Default", 5, 5, color_white )⤶ draw.SimpleText( "Fancy text..", "Default", 5, 16, color_white )⤶ cam.End3D2D() end )⤶ end⤶ </code> <output><image src="cam.Start3D2D_example_1.png"/></output>⤶ <output>⤶ <image src="70c/8dc53be7f864914.png" size="608035" name="image.png" />⤶ </output>⤶ </example>