mirror of
https://github.com/wiremod/wire.git
synced 2025-03-04 03:03:04 -05:00
RT Camera fixes and improvements (#3019)
* Added FPS limiter to RT Cameras, refactored code a bit * Changed RT Camera FPS limiter algorithm * Actually made good RT Camera FPS limiter * Changed ActiveCameras to be set-like array instead of set-like table. * Fixed undefined behavior in RT Camera ENT:SetIsObserved * Linter pass * Removed debug print * Fixed undefined behavior on `ObservedCameras` iteration * Removed debug print *again* * Removed unused `table.SeqCount` function
This commit is contained in:
parent
1c5f5a0cb0
commit
60b23aa599
@ -50,13 +50,17 @@ function ENT:TriggerInput( name, value )
|
||||
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 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)
|
||||
|
||||
local ActiveCameras = {}
|
||||
local ObservedCameras = {}
|
||||
-- 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
|
||||
@ -66,12 +70,14 @@ if CLIENT then
|
||||
|
||||
local function SetCameraActive(camera, isActive)
|
||||
if isActive then
|
||||
ActiveCameras[camera] = true
|
||||
if not table.HasValue(ActiveCameras, camera) then
|
||||
table.insert(ActiveCameras, camera)
|
||||
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
|
||||
|
||||
@ -97,22 +103,27 @@ if CLIENT then
|
||||
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
|
||||
|
||||
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()
|
||||
@ -120,17 +131,17 @@ if CLIENT then
|
||||
|
||||
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,
|
||||
@ -155,34 +166,54 @@ if CLIENT then
|
||||
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
|
||||
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()
|
||||
SkippedFrames = SkippedFrames - 1
|
||||
|
||||
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
|
||||
if SkippedFrames <= 0 then
|
||||
local rendered_cams = RenderCamerasImpl()
|
||||
SkippedFrames = math.ceil(rendered_cams * cvar_skip_frame_per_cam:GetFloat())
|
||||
end
|
||||
end)
|
||||
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user