Issue with rendering beams for everyone.

I am trying to render a beam that starts at the muzzle position of a weapon, and ends where the entity with the weapon is aiming. This is a bit difficult, since render.DrawBeam() is client sided only, so what I decided to do was send a net message to all clients that contained the entity that was firing the beam. I then went on and found the muzzle position of their weapon the only way I know how, and then I found the entity’s eye trace. I do that part in the “PostDrawOpaqueRenderables” hook, so the entity’s muzzle position and eye trace is found and drawn every single frame to make it as smooth as possible.

The issue with all this is that the beam only shows up for the entity firing it, even though it should be showing up for everyone, as far as I could tell. Can anyone help?

--[===[ In a SWEP ]===]--
alreadySent = false
function SWEP:PrimaryAttack()
if SERVER then
   if alreadySent then return end
   net.WriteEntity( self:GetOwner() )
   alreadySent = true

--[===[ In cl_init ]===]--
net.Receive("drawE", function()
   local shootingent = net.ReadEntity()
   local matEl = Material( "cable/blue_elec" )
   local viewm = shootingent:GetViewModel()
   local obj = viewm:LookupAttachment( "muzzle" )
   hook.Add("PostDrawOpaqueRenderables", "drawF", function() 
   local startpos = viewm:GetAttachment( obj ).Pos
   local endpos = shootingent:GetEyeTrace().HitPos
   render.SetMaterial( matEl )
   render.DrawBeam( startpos , endpos , 20, 1 , 1 , Color(255,255,255) )

You should draw it from the view model if the player is holding the weapon, and from the world model if it’s someone else’s weapon.

[editline]27th May 2015[/editline]

Also unless you make drawF unique then you’ll only see one beam

So something like this would work?

   if shootingent == LocalPlayer() then
   local viewm = shootingent:GetViewModel()
   else local viewm = shootingent:GetWorldModel()

Also, what do you mean about making it unique?

[editline]27th May 2015[/editline]

I just realized that there’s no such function as GetWorldModel(). How would I go about getting the world model muzzle position?

[editline]26th May 2015[/editline]


[editline]26th May 2015[/editline]


Instead of sending the player entity I would send the weapon entity.
On the client you get the sent entity and check if it is equal to LocalPlayer():GetActiveWeapon().

  • If it is, get the view model and use that instead.
  • otherwise just go ahead and use the weapon entity (it IS the world model)

But, instead of using net messages I would be doing it with an Effect, and instead of adding and removing hooks you could just use the Render function of the effect. Effects also have a helper function that does exactly what I am describing with viewmodel vs worldmodel muzzle EFFECT:GetTracerShootPos (it expects Ent to be the weapon entity)

Thanks! I’m new to GMod Lua, and I don’t know exactly what’s going on a lot of the time.

This is what, your fifth thread on the same issue?

It should really be something like:

SWEP.BeamMat = Material( "yourmat" )

function SWEP:PrimaryAttack( )
  self:SetDTBool( 0, true )

function SWEP:SetSecondaryAttack( )
  self:SetDTBool( 0, false )

function SWEP:RenderBeam( )
 local tr, att, o, vm

  if self:GetDTBool( 0 ) and o then
    tr = self.Owner:GetEyeTrace( )

    vm = self.Owner:GetViewModel( )
    att = vm:LookupAttachment( "muzzle" )
    o = vm:GetAttachment( att )

    render.SetMaterial( self.BeamMat )
    render.DrawBeam( o.Pos, tr.HitPos, 20, 1, 1, color_white )

function SWEP:DrawWorldModel( )
  self:DrawModel( )

  if not self.Owner:IsValid( ) then

  self:RenderBeam( ) 

function SWEP:ViewModelDrawn( )
  self:RenderBeam( )

You’re really over-complicating this. There’s absolutely no need to network this to each player in a net message when you can just build it into the swep.

Yeah, it might be because this is the first thread where people have actually offered any original ideas. I’m new to GMod Lua, and I’m really clueless, and I never learn anything if no one tells me anything new.

Would you be able to explain why/how this works? I get the gist of it, but there’s a bit that I’m still lost on.

I was under the impression that a “PostDrawOpaqueRenderables” was the only way to render beams. Can it be rendered by any effect function?

also, this still doesn’t work because render.DrawBeam is clientside

ViewModelDrawn and WorldModelDrawn are both clientside functions. SWEP:ViewModelDrawn is called each frame that the player’s viewmodel is visible, and DrawWorldModel is called each frame that the player can see the weapon ( on the ground, another player, an npc, etc ).

The reason this works is because we set a networked bool ( DTBool ) on the weapon, which is replicated automatically to all clients, even ones who join after you send your net message for the existing players - so they don’t need to be explicitly told to render a beam since the weapon knows they should see a beam if that value is true.

You can render beams ( and other things from the render library ) generally in any 3d rendering context - cam.Start3D, any 3d rendering hook ( PostDraw*Renderables, etc ), or in specific weapon / sent functions that already have a 3d context. Some things you’d want to do in other specific ones such as using PostDrawOpaqueRenderables for 3d2d stuff to prevent the world from rendering on top of it.

Alright, thanks! There is still an issue, though. The beam still only rendered for the person who was holding the gun, and the if statement never passed because of the variable you named “o”. I don’t know why, but the variable did not pass when I left it the way you had it, but it worked fine when I removed the “and o” part of it. That, of course, led to the issue of “o” being nil later on.

I’m still lost here.

Bump- Is there any good way to actually render a beam for client and server?

I have no idea how to set that up in a way that would work. Could you point me in the right direction?

[editline]29th May 2015[/editline]

Oh, also, how the hell do I get the muzzle position from the entity?

Call this once and cache the results:


Then call this with the results obtained above: