Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Professional Discussion / Is there a better way to do this?

Author
Message
LiamBradbury
8
Years of Service
User Offline
Joined: 28th Apr 2011
Location: Manchester, UK
Posted: 8th Apr 2019 18:05
I'm trying to optimise the performance of a game, I'm hiding all objects that are off screen and then showing them again if they are on screen but I believe there is a better solution to it than the one I'm currently doing.

This is what I'm doing at the moment:


But that is counting from 10 to 20000 every cycle. Is there a way to detect the object number as soon as it comes on screen rather than checking every single object number?
www.liambradburymusic.com - professional music for your games.
Raven
14
Years of Service
User Offline
Joined: 23rd Mar 2005
Location: Hertfordshire, England
Posted: 8th Apr 2019 23:58
A For...Next Loop essentially is quite lightweight.
20,000 Loops will typically take ~80,000 Cycles (on a Single Core), which when even "Low Frequency" Processors are performing 1.8 Billion Cycles / Second... yeah, you're "Good" in terms of performance in that regard.

The issue isn't so much the actual number of Loops, but what you're doing For Each Loop.
Both the Object In Screen( ObjectID ) and Hide Object / Show Object are fairly performance intensive... although for different reasons.

Object In Screen, has to do a Collision Check between the Object Bounds and View Frustum (which typically is done via Ray Casting).
This is CPU Expensive!!

Where-as Hide/Show Object are Object State Changes., this incurs an additional Draw Call (yes EVEN if it's Hidden)… So you ONLY want to call these IF the State actually changes.

< • >

So, how do we Optimise this?
Well … what we first want to do is create 2 Array Lists.



We could technically have these all as a Single Array with a Custom Type Attribute such-as IsStatic As Boolean … but if we're Optimising, let's not do it half-arsed.
As only the Active Objects will ever Move, this means we only actually need to check and update said Active Entities.

Once we've done this, the next step is to determine the World Size Boundaries.
Ideally you actually want to have a Preset Maximum Values for this... even assuming that we're in a Contiguous Open World with "No Loading Screens", we are still going to want to break it down into "Areas" that Load / Unload as needed, to ensure that you only have the Objects and Data Loaded that are actually going to be required.

If we take something like Fallout 4 (for example) … while sure, the map is 10×10km … it's only actually loading between 1 - 4x 1×1km Chunks at any given time rather than the whole map.
We're not just doing this for Performance / Memory Space purposes either, but it also allows for "Streaming" (background loading) of Data to remove Loading Screens as much as possible...

A Good Example of this would be The Division 2... while a counter-example would be Anthem.
It's also why you'll notice a lot of games (especially open world) have a Grid Overlay on their Maps., such-as Fortnite, The Division 2, Fallout 76, etc.
Typically those Grid Squares as "Arbitrary" in size as they might appear, are actually typically the Chunk Size used for each Area being Streamed in.

In order to keep this simple... let's follow the basic approach of:
Area > Sector > Sub-Sector

Each of these are 1/2 the Size of the Previous:
i.e.
500×500×500 = Area
250×250×250 = Sector
125×125×125 = Sub-Sector

As such we have: 1 Area = 4 Sector = 16 Sub-Sector
Now as a note, if these are Dark BASIC Professional Boxes, that are Hidden … we can still perform Object Collision, to check to see if 2 Objects Intersect.

For Static Objects we ONLY have to do this OnLoad( ) … even then we don't have to check all of the Potential Collisions., but rather (at most) 9; to figure out what Sub-Sector(s) that said Objects "Reside" in.

Now what's even better is, we also then don't have to check individual objects if they're "On Screen" … but instead we just have to Check if the Sub-Sectors are.
As a result... those 20,000 Checks are reduced to 16 * Visible Areas., and as you want (at most) a Visible Range of ~5,560 Units as a "Maximum Draw Distance" … but manually control this via a Game Settings., for example Draw Distance Low = 750 : Medium = 1,500 : High = 3,000 : Ultra = 6,000 or whatever ends up a good balance of Performance Vs. Perceptive.

Then we're still looking < 512 Sub-Sectors Visible at any given point.
Assuming you track the Visible Sub-Sectors from the Previous Frame, then what you're looking for at that point is just "Which Sub-Sectors are no Longer Visible, and which have Become Visible" … then simply go through that Sub-Sector Array List to Show / Hide the assigned Objects.

As a note there's more that can be done with this as well... because you can also use this for an LOD System., remember you don't need the Physical Objects there; only a Root Collision Box... that you can then replace with an instance of said preloaded base object(s).
In this respect; instead of individually checking Distance of each Object for LOD Swapping; basically you can say "All Objects in Sub-Sectors X > Y > Z Away get High > Med > Low Polygon Versions of the Object"

This should (when all is said and done) not just dramatically reduce the number of Per-Frame Checks, Object State Changes but also the Overall Scene Complexity.
It also means you don't need to focus much on specific Individual Objects., but rather now you're just essentially performing various Look-Up Table Checks.

< • >

Hopefully that should be helpful ^_^
Bored of the Rings
14
Years of Service
User Offline
Joined: 25th Feb 2005
Location: Middle Earth
Posted: 9th Apr 2019 10:12
that looks like a good way to do it. I might have a look at this and see what I can come up with. Nothing like a good challenge.
Professional Programmer, languages: SAS, C++, SQL, PL-SQL, DBPro, Purebasic, JavaScript, others
Derek Darkly
7
Years of Service
User Offline
Joined: 22nd Sep 2011
Location: Whats Our Vector, Victor?
Posted: 10th Apr 2019 02:52

Could you explain, in more real-world terms, what you are trying to make your program do?
Is it vegetation? Buildings? Other objects?

It helps to lend some visual impressions in regards to your question.
I only say this because different programmers think differently.
Send your parents to noisy sprite demo hell... enter the D-Zone
WickedX
10
Years of Service
User Offline
Joined: 8th Feb 2009
Location: A Mile High
Posted: 12th Apr 2019 02:08 Edited at: 12th Apr 2019 02:09
Quote: "I'm trying to optimise the performance of a game, I'm hiding all objects that are off screen and then showing them again if they are on screen but I believe there is a better solution to it than the one I'm currently doing."


The best solution would be, do nothing. Frustum Culling is handled internally before an object is drawn. This is a post of GG's asking how to show objects off screen.
Scorpyo
16
Years of Service
User Offline
Joined: 26th Aug 2002
Location: italy
Posted: 12th Apr 2019 08:11 Edited at: 12th Apr 2019 08:51
Quote: "
do nothing
"


Not sure that what you're saying above is totally true
____________________
HIDE OBJECT

This command will hide the specified 3D object from view. You can substantially increase the performance of your 3D program if you hide objects whenever possible. The contents of a room behind a closed
door can be hidden for as long as the door remains closed, allowing your program to run much faster and improve overall performance. The parameter should be specified using an integer value.
_____________________

This simple subroutine saves me 6000 draw calls per cycle and improves fps on dense vegetation areas:


cx# and cz# = camera coords

it's a distance check that provides to hide objects beyond a certain distance. Of course not good for every situation , depends on your scenery lay-out and your graphical desires.
Being that objects are not evenly spread across big areas ( think about dense tree/plant area spots ) , it also saves from huge fps drop spikes at certain view angles.

A better tweak would be this combined with hiding all objects behind the camera. But that should already be in place as per your comment.

Another option (which I haven't tested yet ) would be to use the EXCLUDE OBJECT ON command in that fashion. Not sure you would gain anything more over HIDE OBJECT but I will test it.

My 2 cents
Cheers
Scorpyo
WickedX
10
Years of Service
User Offline
Joined: 8th Feb 2009
Location: A Mile High
Posted: 13th Apr 2019 00:57 Edited at: 13th Apr 2019 00:58
Ok, I'll rephrase. Attempting to optimize by hiding objects off screen is not necessary.

Though this would hide all object at a distance, you could just lower the far clipping plane with (Set Camera Range). Excluding a object will exclude that object in collision checks as well, if that matters. Also keep in mind – excluding an instanced object will exclude the parent object.
kasapin
6
Years of Service
User Offline
Joined: 11th Dec 2012
Location:
Posted: 13th Apr 2019 03:49
I`v tried using the same way you did but function "object in screen" never worked for me.So this is how i do it

First i create a box with desired size and position the box in front of the camera.This box will be the colision object for hiding and showing the scene objects.All objects that are inside the box will be visible,logicaly.
this is the code :

make object box obj,xSize,ySize,zSize

loop:

position object obj,newxvalue(camera position x(),camera angle y(),zSize-n),camera position y(),newzvalue(camera position z(),camera angle y(),zSize-n)
{"n" is the size to move object behind camera just a litle,so that some of the objects dont sudenly pop out in screen.}
for o=1 to objNr
if object visible(o)=0 and object collision(o,,obj)>0 then show object o
if object visible(o)=1 and object collision(o,,obj)=0 then hide object o
next o

Now the main trick is to introduce the delay function in loop.
For example, you run your program on 60 fps,which means that your "hide/show" function will be checked 60 passes in one second.You dont need this.Set the delay function to check this "hide/show" function ,for example ,only 10 times in 1 second.

if Delay>0
dec Delay
if Delay<=0 then execute "hide/show" function : Delay=5
endif

This is the best way to for me.
Scorpyo
16
Years of Service
User Offline
Joined: 26th Aug 2002
Location: italy
Posted: 13th Apr 2019 15:47
Isn't the "if object visible etc.." part totally redundant there ?
Freddix
AGK Developer
16
Years of Service
User Offline
Joined: 19th Sep 2002
Location: France
Posted: 14th Apr 2019 20:22 Edited at: 14th Apr 2019 20:35
A good solution may be to split game in cubic areas.
Each object is in an area ...
Calculate the visibility of each area and calculate the object visbilitiy, only for those that are in visibles areas ...

Regards,
Virtual Nomad
13
Years of Service
User Offline
Joined: 14th Dec 2005
Location: SF Bay Area, USA
Posted: 14th Apr 2019 20:56
liam, is this for CreoScape? ie, movement only on x & y?
if so, there's a much easier way (which makes freddix' suggestion even simpler where the (max) visible area should be 'fixed' vs calculated).

Login to post a reply

Server time is: 2019-07-17 01:44:52
Your offset time is: 2019-07-17 01:44:52