RenderTarget shenanigans

As some of you may know, I am trying to add some easy-to-use rendertarget functions in ARCLib
Most of my issues have been solved, however, it doesn’t draw LocalPlayer when I want it to!

This is the behaviour I am getting

http://www.aritzcracker.ca/uploads/aritz/Garry’s Mod 2016-11-08 1_14_19 PM.mp4

SO SOMEHOW DRAWING A HALO FIXES EVERYTHING!

Here’s the file that goes in lua/arclib/client



-- Big shoutout to bobbleheadbob and JamesXx for helping me with this

local RTs = {}
local DRAWING_RT = false
ARCLib.TrackRT = false
hook.Add( "RenderScene", "ARCLib RenderRTs", function( wat, skybox )

    if ( not LocalPlayer() ) then return end
    if ( not skybox ) then return end

    if ( not DRAWING_RT ) then
        DRAWING_RT = true

        for k, v in pairs( RTs ) do
            if v.Update then

                local oldW, oldH = ScrW(), ScrH()
                local oldRT = render.GetRenderTarget()

                render.SetRenderTarget( v.RenderTarget )
                render.Clear( 0, 0, 0, 255, true, true )
                render.SetViewPort( 0, 0, v.renderInformation.w, v.renderInformation.h )
                    
                    if ARCLib.TrackRT then
                        MsgN("BeforeRender "..k.." "..SysTime())
                    end
                    render.RenderView(v.renderInformation)
                    if ARCLib.TrackRT then
                        MsgN("AfterRender "..k.." "..SysTime())
                    end
                    render.UpdateScreenEffectTexture()
                    if v.Screenie then
                        v.Screenie(render.Capture({
                            format = v.ScreenieFormat,
                            quality = v.ScreenieQuality,
                            h = v.renderInformation.h,
                            w = v.renderInformation.w,
                            x = v.renderInformation.x,
                            y = v.renderInformation.y,
                        }))
                        v.Screenie = nil
                        v.ScreenieFormat = nil
                        v.ScreenieQuality = nil
                    end
                render.SetRenderTarget( oldRT )
                render.SetViewPort( 0, 0, oldW, oldH )

            end
        end

        DRAWING_RT = false
    end

end)

hook.Add( "ShouldDrawLocalPlayer", "ARCLib PlayerRTs", function( ply )
    if ARCLib.TrackRT then
        MsgN("ShouldDrawLocalPlayer "..tostring(DRAWING_RT).." "..SysTime())
    end
    if ( DRAWING_RT ) then
        return true
    end
    --return false
end)

hook.Add( "GetMotionBlurValues", "ARCLib PlayerRTs GetMotionBlurValues", function( x, y, fwd, spin )
    if ( DRAWING_RT ) then
        return 0, 0, 0, 0
    end
end )
 
hook.Add( "PostProcessPermitted", "ARCLib PlayerRTs PostProcessPermitted", function( element )
    if ( DRAWING_RT and element == "bloom" ) then
        return false
    end
end )


function ARCLib.CreateRenderTarget(name,w,h,pos,angles,fov)
    local rt = {}
    assert(isstring(name) and name != "","ARCLib.CreateRenderTarget: Render targets need a name!")
    assert(isnumber(w) and w > 16,"ARCLib.CreateRenderTarget: Width must be greater than 16")
    assert(isnumber(h) and h > 16,"ARCLib.CreateRenderTarget: Height must be greater than 16")
    pos = pos or vector_origin
    angles = angles or angle_zero
    fov = fov or 75
    
    
    rt.RenderTarget = GetRenderTarget( name, w, h, false )
    rt.renderInformation = {
        origin = pos,
        angles = angles,
        x = 0,
        y = 0,
        w = w,
        h = h,
        dopostprocess = false,
        drawhud = false,
        drawmonitors = false,
        drawviewmodel = true,
        ortho = false
    }
    RTs[name] = rt
end

function ARCLib.DisableRenderTarget(name)
    RTs[name].Update = false
end

function ARCLib.EnableRenderTarget(name)
    RTs[name].Update = true
end

function ARCLib.SetRenderTargetPos(name,pos)
    RTs[name].renderInformation.origin = pos or vector_origin
end
function ARCLib.SetRenderTargetAngles(name,ang)
    RTs[name].renderInformation.angles = ang or angle_zero
end

function ARCLib.CaptureRenderTarget(name,format,quality,cal  lback)
    RTs[name].Screenie = callback
    RTs[name].ScreenieFormat = format
    RTs[name].ScreenieQuality = quality
end

function ARCLib.DestroyRenderTarget(name)
    RTs[name] = nil --TODO: There's a GetRenderTarget, but there is no KillRenderTarget??
end

function ARCLib.GetRenderTargetTexture(name)
    return RTs[name].RenderTarget
end

function ARCLib.GetRenderTargetMaterial(name)
    if !RTs[name].material then
        local params = {}
        params[ "$basetexture" ] = RTs[name].RenderTarget:GetName()
        params[ "$vertexcolor" ] = 1
        params[ "$vertexalpha" ] = 0
        -- params[ "$model" ] = 1 -- TODO: Is this required?
        RTs[name].material = CreateMaterial( "arclib_rt_"..name, "UnlitGeneric", params )
    end
    return RTs[name].material
end


shared.lua for sent_arc_camera



ENT.Base = "base_anim"
ENT.Type = "anim"

ENT.PrintName        = "Camera"
ENT.Author            = "ARitz Cracker"
ENT.Category         = "Test"
ENT.Contact            = ""
ENT.Purpose         = ""
ENT.Instructions     = ""

ENT.Spawnable = true;
ENT.AdminOnly = false


cl_init.lua for sent_arc_camera



-- cl_init.lua
include('shared.lua')
function ENT:Initialize()
    ARCLib.CreateRenderTarget("arc_camera"..self:EntIndex(),256,256,self:GetPos(),self:GetAn  gles(),75)
    ARCLib.EnableRenderTarget("arc_camera"..self:EntIndex())
end

function ENT:Think()
    ARCLib.SetRenderTargetPos("arc_camera"..self:EntIndex(),self:GetPos() + self:GetAngles():Forward()*7)
    ARCLib.SetRenderTargetAngles("arc_camera"..self:EntIndex(),self:GetAngles())
end

function ENT:OnRemove()
    ARCLib.DestroyRenderTarget("arc_camera"..self:EntIndex())
end


hook.Add( "HUDPaint", "ARCTestCamera", function()
    for k,v in ipairs(ents.FindByClass("sent_arc_camera")) do 
        surface.SetDrawColor(255,255,255,255)
        surface.SetMaterial( ARCLib.GetRenderTargetMaterial("arc_camera"..v:EntIndex()) ) 
        surface.DrawTexturedRect( -256 + (256+16)*k,16,256,256 ) 
    end
end)


init.lua for sent_arc_camera



AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include('shared.lua')
function ENT:Initialize()
    self:SetModel( "models/dav0r/camera.mdl" )
    self:PhysicsInit( SOLID_VPHYSICS )
    self:SetMoveType( MOVETYPE_VPHYSICS )
    self:SetSolid( SOLID_VPHYSICS )
    self:SetUseType( SIMPLE_USE )
    self.phys = self:GetPhysicsObject()
    if self.phys:IsValid() then
        self.phys:Wake()
    end
end
function ENT:SpawnFunction( ply, tr )
     if ( !tr.Hit ) then return end
    local blarg = ents.Create ("sent_arc_camera")
    blarg:SetPos(tr.HitPos + tr.HitNormal * 40)
    blarg:Spawn()
    blarg:Activate()
    return blarg
end


I bound a couple of keys to ARCLib.TrackRT = false and ARCLib.TrackRT = true, it just raised more questions that answers.
This has been troubling me for days :cry:

I just took the time to test around with this.

First of all, a general tip - when you come across a problem and you have no idea what its source is, that’s when you drop whatever you’re doing and test that one thing, separately, outside of your complex system.

In this case, the code I used to test looks like this:
[lua]local sdlp = nil

hook.Add(“PreRender”,“any identifier”,function()
if RENDER_VIEW_WITH_PLAYER and not sdlp then
sdlp = true
render.RenderView()
sdlp = nil
end
end)

hook.Add(“ShouldDrawLocalPlayer”,“any identifier”,function() return sdlp end)[/lua]

“PreRender” was originally “RenderView”, and your problem was apparent. When I changed it to PreRender, though, the problem went away.

I think what’s happening is that, for some reason, the new result of ShouldDrawLocalPlayer called by render.RenderView overrides the previous (or future?) result of ShouldDrawLocalPlayer that should affect the bigger frame. The engine, having already called ShouldDrawLocalPlayer, thinks that that result is applicable to all rendering operations currently in progress.

When it’s done in PreRender, the ‘real’ rendering operation hasn’t started yet, so it will call ShouldDrawLocalPlayer again a second time, as we want it to do.

You should use PreRender instead of RenderScene. For the record, if I’m not mistaken you can also use Think - you don’t have to use a rendering hook.

Two more things - you seem to have some really weird parameters for that hook (wat, skybox), is that intentional? The other thing is that for code cleanliness, should be using render.PushRenderTarget and render.PopRenderTarget. The “oldRT” trick is ugly in comparison.

[editline]9th November 2016[/editline]

And for the record, I totally think render.RenderView should accept the drawviewer element to decide whether to draw the local player. You should request it on the requests github if it hasn’t been already

Hello! Thanks for responding.
Unfortunately, PreRender was my first (failed) attempt at a solution. The resulting rendertarget is 100% black. Using Think also has the same result. (wat, skybox) is intentional, that is because the first argument is listed as “unknown” on the wiki :smile:

I’ll use pop and push. I didn’t know that Push supported changing the viewport as well, so I’ll go ahead and do that!