meetric1 / GMod-Seamless-Portals

My seamless portals addon for garrys mod
MIT License
89 stars 22 forks source link

Add exit portals to the PVS #47

Closed maxmol closed 1 year ago

maxmol commented 1 year ago

I've been playing with portals and noticed that I can't see entities outside of my PVS so here's a fix.

Before-After image image

Also made a small vid

I moved SeamlessPortals.ShouldRender from client to shared and added a new parameter to avoid code duplication. Though I'm not sure if calculating visibility will be less expensive than just checking TestPVS and adding more exit portals with AddOriginToPVS

meetric1 commented 1 year ago

does this impact framerate at all?

and if it does, how bad?

maxmol commented 1 year ago

Yes, certainly refreshing and drawing more entities should slightly affect the framerate. And calculating visibility on the server isn't free. But I haven't noticed any real difference when I tested it, so I think it's worth it 😄

dvdvideo1234 commented 1 year ago

It is not actually faster. Bailing out when condition is present will be always faster:

SeamlessPortals = {}

SeamlessPortals.ShouldRender = function(arg)
  local portal, eyePos, eyeAngle, distance = arg[1], arg[2], arg[3], arg[4]
    local portalPos, portalUp, exitSize = portal:GetPos(), portal:GetUp(), portal:GetSize()
    local max = math.max(exitSize[1], exitSize[2])
    return ((eyePos - portalPos):Dot(portalUp) > -max and 
    eyePos:DistToSqr(portalPos) < distance^2 * max and 
    (eyePos - portalPos):Dot(eyeAngle:Forward()) < max)
end

SeamlessPortals.ShouldRenderNew = function(arg)
  local portal, eyePos, eyeAngle, distance = arg[1], arg[2], arg[3], arg[4]
    local portalPos, portalUp, exitSize = portal:GetPos(), portal:GetUp(), portal:GetSize()
  local vec, max = (eyePos - portalPos), math.max(exitSize[1], exitSize[2])
  if((vec):Dot(portalUp) <= -max) then return false end
  if(vec:LengthSqr() >= distance^2 * max) then return false end
  if(vec:Dot(eyeAngle:Forward()) >= max) then return false end
  return true
end

local stEstim = {
  testexec.Case(SeamlessPortals.ShouldRender, "original"),
  testexec.Case(SeamlessPortals.ShouldRenderNew, "modified")
}

local stCard = {
  AcTime = 1, -- Draw a dot after X seconds
  FnCount = 800, -- Amount of loops to be done for the test card
  FnCycle = 1500, -- Amount of loops to be done for the function tested
  ExPercn = .1, -- Draw percent completed every X margin ( 0 to 1 )
  {"basic", {ent , Vector(1,1,1), pang, 10}, false}
}

testexec.Run(stCard,stEstim)

Started 1 tast cases for 2 functions...
Testing case[1]: <basic>
 Input: <table: 0x00937b60>
Output: <false>
 Tests: {800, 1500}
Proces: {10%, 80}
TimNow: {16:04:46}
TimCnt: {00:00:00} (0.047)
TimCyc: {00:00:38} (37.6)
......10% ......20% .......30% ......40% ......50% ......60% .......70% ......80% .......90% ......100% Done
Estimation for [original]: 100.000 Time:  126.198 (  36.191[s])       33157.415[c/s] Failed: 0
Estimation for [modified]: 100.000 Time:  100.000 (  28.678[s])       41843.922[c/s] Failed: 0

Test finished all 1 cases successfully!
Overall testing rank list summary:
[         36.191]: original
[         28.678]: modified
Program completed in 65.16 seconds (pid: 27580).