Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RT Camera fixes and improvements #3019

Merged
merged 10 commits into from
Mar 26, 2024
131 changes: 81 additions & 50 deletions lua/entities/gmod_wire_rt_camera.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,17 @@
end

if CLIENT then
local wire_rt_camera_resolution_h = CreateClientConVar("wire_rt_camera_resolution_h", "512", true, nil, nil, 128)
local wire_rt_camera_resolution_w = CreateClientConVar("wire_rt_camera_resolution_w", "512", true, nil, nil, 128)
local wire_rt_camera_filtering = CreateClientConVar("wire_rt_camera_filtering", "2", true, nil, nil, 0, 2)
local wire_rt_camera_hdr = CreateClientConVar("wire_rt_camera_hdr", "1", true, nil, nil, 0, 1)

local ActiveCameras = {}
local ObservedCameras = {}
local cvar_resolution_h = CreateClientConVar("wire_rt_camera_resolution_h", "512", true, nil, nil, 128)
local cvar_resolution_w = CreateClientConVar("wire_rt_camera_resolution_w", "512", true, nil, nil, 128)
local cvar_filtering = CreateClientConVar("wire_rt_camera_filtering", "2", true, nil, nil, 0, 2)
local cvar_hdr = CreateClientConVar("wire_rt_camera_hdr", "1", true, nil, nil, 0, 1)

-- array(Entity)
WireLib.__RTCameras_Active = WireLib.__RTCameras_Active or {}
local ActiveCameras = WireLib.__RTCameras_Active
-- table(Entity, true)
WireLib.__RTCameras_Observed = WireLib.__RTCameras_Observed or {}
local ObservedCameras = WireLib.__RTCameras_Observed

concommand.Add("wire_rt_camera_recreate", function()
for _, cam in ipairs(ObservedCameras) do
Expand All @@ -66,12 +70,14 @@

local function SetCameraActive(camera, isActive)
if isActive then
ActiveCameras[camera] = true
if not table.HasValue(ActiveCameras, camera) then
table.insert(ActiveCameras, camera)
stepa2 marked this conversation as resolved.
Show resolved Hide resolved
end
else
if camera.SetIsObserved then -- undefi
if camera.SetIsObserved then -- May be undefined (?)
camera:SetIsObserved(false)
end
ActiveCameras[camera] = nil
table.RemoveByValue(ActiveCameras, camera)
end
end

Expand All @@ -97,40 +103,45 @@
self.IsObserved = isObserved

if isObserved then
local index = #ObservedCameras + 1
ObservedCameras[index] = self
self.ObservedCamerasIndex = index
self.ObservedCamerasIndex = table.insert(ObservedCameras, self)

self:InitRTTexture()
else
ObservedCameras[self.ObservedCamerasIndex] = nil
self.ObservedCamerasIndex = nil
self.RenderTarget = nil

local oldi = table.RemoveFastByValue(ObservedCameras, self)
if oldi == nil then return end
self.ObservedCamerasIndex = nil

Check warning on line 115 in lua/entities/gmod_wire_rt_camera.lua

View workflow job for this annotation

GitHub Actions / lint

"Trailing whitespace"

Trailing whitespace
local shifted_cam = ObservedCameras[oldi]
if IsValid(shifted_cam) then
shifted_cam.ObservedCamerasIndex = oldi
end
end
end

local function CreateRTName(index)
return "improvedrtcamera_rt_"..tostring(index).."_"..wire_rt_camera_filtering:GetString().."_"
..wire_rt_camera_resolution_h:GetString().."x"..wire_rt_camera_resolution_w:GetString()..
(wire_rt_camera_hdr:GetInt() and "_hdr" or "_ldr")
return "improvedrtcamera_rt_"..tostring(index).."_"..cvar_filtering:GetString().."_"
..cvar_resolution_h:GetString().."x"..cvar_resolution_w:GetString()..
(cvar_hdr:GetInt() and "_hdr" or "_ldr")
end

function ENT:InitRTTexture()
local index = self.ObservedCamerasIndex

local filteringFlag = 1 -- pointsample

if wire_rt_camera_filtering:GetInt() == 1 then
if cvar_filtering:GetInt() == 1 then
filteringFlag = 2 -- trilinear
elseif wire_rt_camera_filtering:GetInt() == 2 then
elseif cvar_filtering:GetInt() == 2 then
filteringFlag = 16 -- anisotropic
end

local isHDR = wire_rt_camera_hdr:GetInt() ~= 0
local isHDR = cvar_hdr:GetInt() ~= 0

local rt = GetRenderTargetEx(CreateRTName(index),
wire_rt_camera_resolution_w:GetInt(),
wire_rt_camera_resolution_h:GetInt(),
cvar_resolution_w:GetInt(),
cvar_resolution_h:GetInt(),
RT_SIZE_LITERAL,
MATERIAL_RT_DEPTH_SEPARATE,
filteringFlag + 256 + 32768,
Expand All @@ -155,34 +166,54 @@
if CameraIsDrawn then return false end
end)

local function RenderCamerasImpl()
local isHDR = cvar_hdr:GetInt() ~= 0
local renderH = cvar_resolution_h:GetInt()
local renderW = cvar_resolution_w:GetInt()

local renderedCameras = 0

for _, ent in ipairs(ActiveCameras) do
if not IsValid(ent) or not ent.IsObserved then goto next_camera end

Check warning on line 177 in lua/entities/gmod_wire_rt_camera.lua

View workflow job for this annotation

GitHub Actions / lint

"Goto"

Don't use labels and gotos unless you're jumping out of multiple loops.
renderedCameras = renderedCameras + 1

render.PushRenderTarget(ent.RenderTarget)
local oldNoDraw = ent:GetNoDraw()
ent:SetNoDraw(true)
CameraIsDrawn = true
cam.Start2D()
render.OverrideAlphaWriteEnable(true, true)
render.RenderView({
origin = ent:GetPos(),
angles = ent:GetAngles(),
x = 0, y = 0, h = renderH, w = renderW,
drawmonitors = true,
drawviewmodel = false,
fov = ent:GetCamFOV(),
bloomtone = isHDR
})

cam.End2D()
CameraIsDrawn = false
ent:SetNoDraw(oldNoDraw)
render.PopRenderTarget()

::next_camera::
end

return renderedCameras
end


local cvar_skip_frame_per_cam = CreateClientConVar("wire_rt_camera_skip_frame_per_camera", 0.8, true, nil, nil, 0)

local SkippedFrames = 0
hook.Add("PreRender", "ImprovedRTCamera", function()
local isHDR = wire_rt_camera_hdr:GetInt() ~= 0
local renderH = wire_rt_camera_resolution_h:GetInt()
local renderW = wire_rt_camera_resolution_w:GetInt()

for ent, _ in pairs(ActiveCameras) do
if IsValid(ent) and ent.IsObserved then
render.PushRenderTarget(ent.RenderTarget)
local oldNoDraw = ent:GetNoDraw()
ent:SetNoDraw(true)
CameraIsDrawn = true
cam.Start2D()
render.OverrideAlphaWriteEnable(true, true)
render.RenderView({
origin = ent:GetPos(),
angles = ent:GetAngles(),
x = 0, y = 0, h = renderH, w = renderW,
drawmonitors = true,
drawviewmodel = false,
fov = ent:GetCamFOV(),
bloomtone = isHDR
})

cam.End2D()
CameraIsDrawn = false
ent:SetNoDraw(oldNoDraw)
render.PopRenderTarget()
end
SkippedFrames = SkippedFrames - 1

if SkippedFrames <= 0 then
local rendered_cams = RenderCamerasImpl()
SkippedFrames = math.ceil(rendered_cams * cvar_skip_frame_per_cam:GetFloat())
end
end)

Expand Down
7 changes: 7 additions & 0 deletions lua/wire/stools/rt_camera.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ if CLIENT then
language.Add("tool.wire_rt_camera.settings.cl_filtering_1", "Trilinear")
language.Add("tool.wire_rt_camera.settings.cl_filtering_2", "Anisotropic")
language.Add("tool.wire_rt_camera.settings.cl_apply", "Apply player-specific changes")
language.Add("tool.wire_rt_camera.settings.cl_skipframe", "Rendering slowdown")
language.Add("tool.wire_rt_camera.settings.cl_skipframe_hint",
"The greater this value, the greater your FPS is and the lesser FPS of the cameras is.\n"..
"Technically, it is amount of camera renders to skip per one rendered camera.\n"..
"Fractional values work too. Set to 0 to disable.")

WireToolSetup.setToolMenuIcon( "icon16/camera.png" )
end
Expand Down Expand Up @@ -69,4 +74,6 @@ function TOOL.BuildCPanel(panel)
end

panel:Button("#tool.wire_rt_camera.settings.cl_apply", "wire_rt_camera_recreate")
panel:NumSlider("#tool.wire_rt_camera.settings.cl_skipframe", "wire_rt_camera_skip_frame_per_camera", 0, 3, 2)
panel:Help("#tool.wire_rt_camera.settings.cl_skipframe_hint")
end
13 changes: 13 additions & 0 deletions lua/wire/wireshared.lua
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ function table.Compact(tbl, cb, n) -- luacheck: ignore
end
end

-- Removes `value` from `tbl` by shifting last element of `tbl` to its place.
-- Returns index of `value` if it was removed, nil otherwise.
function table.RemoveFastByValue(tbl, value)
for i, v in ipairs(tbl) do
if v == value then
tbl[i] = tbl[#tbl]
tbl[#tbl] = nil

return i
end
end
end

function string.GetNormalizedFilepath( path ) -- luacheck: ignore
local null = string.find(path, "\x00", 1, true)
if null then path = string.sub(path, 1, null-1) end
Expand Down
Loading