http://freepdf-books.com
http://freepdf-books.com
Unity5GameOptimization
http://freepdf-books.com
TableofContents
Unity5GameOptimization
Credits
AbouttheAuthor
Acknowledgments
AbouttheReviewers
www.PacktPub.com
Supportfiles,eBooks,discountoffers,andmore
Whysubscribe?
FreeaccessforPacktaccountholders
Preface
Whatthisbookcovers
Whatyouneedforthisbook
Whothisbookisfor
Conventions
Readerfeedback
Customersupport
Downloadingtheexamplecode
Errata
Piracy
Questions
1.DetectingPerformanceIssues
TheUnityProfiler
LaunchingtheProfiler
Editororstandaloneinstances
Editorprofiling
TheUnityWebplayerconnection
RemoteconnectiontoaniOSdevice
RemoteconnectiontoanAndroiddevice
TheProfilerwindow
http://freepdf-books.com
Controls
CPUArea
TheGPUArea
TheRenderingArea
TheMemoryArea
TheAudioArea
ThePhysics3D/2DArea
Bestapproachestoperformanceanalysis
Verifyingscriptpresence
Verifyingscriptcount
Minimizingongoingcodechanges
Minimizinginternaldistractions
Minimizingexternaldistractions
Targetedprofilingofcodesegments
Profilerscriptcontrol
CustomCPUProfiling
SavingandloadingProfilerdata
SavingProfilerdata
LoadingProfilerdata
FinalthoughtsonProfilingandAnalysis
UnderstandingtheProfiler
Reducingnoise
Focusingontheissue
Summary
2.ScriptingStrategies
CacheComponentreferences
ObtainingComponentsusingthefastestmethod
Removingemptycallbackdeclarations
AvoidingtheFind()andSendMessage()methodsatruntime
Staticclasses
SingletonComponents
http://freepdf-books.com
Assigningreferencestopre-existingobjects
Aglobalmessagingsystem
Agloballyaccessibleobject
Registration
Messageprocessing
Implementingthemessagingsystem
Messagequeuingandprocessing
Implementingacustommessage
Messageregistration
Messagesending
Messagecleanup
Wrappingupthemessagingsystem
Disablingunusedscriptsandobjects
Disablingobjectsbyvisibility
Disablingobjectsbydistance
Considerusingdistance-squaredoverdistance
AvoidretrievingstringpropertiesfromGameObjects
Update,Coroutines,andInvokeRepeating
ConsidercachingTransformchanges
FasterGameObjectnullreferencechecks
Summary
3.TheBenefitsofBatching
DrawCalls
MaterialsandShaders
DynamicBatching
Vertexattributes
Uniformscaling
DynamicBatchingsummary
StaticBatching
TheStaticflag
Memoryrequirements
http://freepdf-books.com
Materialreferences
StaticBatchingcaveats
EditModedebuggingofStaticBatching
Avoidinginstantiatingstaticmeshesatruntime
Visibilityandrendering
StaticBatchingsummary
Summary
4.KickstartYourArt
Audio
Loadingaudiofiles
Profilingaudio
Additionalloadingoptions
Encodingformatsandqualitylevels
Audioperformanceenhancements
MinimizeactiveAudioSourcecount
MinimizeAudioClipreferences
EnableForcetoMonofor3Dsounds
Resampletolowerfrequencies
Considerallencodingformats
Bewareofstreaming
ApplyFiltereffectsthroughMixergroupstoreduceduplication
Use“WWW.audioClip”responsibly
ConsiderAudioModulefilesforbackgroundmusic
Texturefiles
Compressionformats
Textureperformanceenhancements
ReduceTexturefilesize
UseMipMapswisely
Manageresolutiondownscalingexternally
AdjustAnisotropicFilteringlevels
ConsiderAtlasing
http://freepdf-books.com
Adjustcompressionratesfornon-squareTextures
SparseTextures
ProceduralMaterials
Meshandanimationfiles
Reducingpolygoncount
TweakingMeshCompression
UseRead-WriteEnabledappropriately
Import/calculateonlywhat’sneeded
Considerbakedanimations
LetUnityoptimizemeshes
Combinemeshes
Summary
5.FasterPhysics
PhysicsEngineinternals
Physicsandtime
TheFixedUpdateloop
MaximumAllowedTimestep
Physicsupdatesandruntimechanges
StaticandDynamicColliders
Collisiondetection
Collidertypes
TheCollisionMatrix
Rigidbodyactiveandsleepingstates
Rayandobjectcasting
Physicsperformanceoptimizations
Scenesetup
Scaling
Positioning
Mass
UseStaticCollidersappropriately
OptimizetheCollisionMatrix
http://freepdf-books.com
Preferdiscretecollisiondetection
ModifytheFixedUpdatefrequency
AdjusttheMaximumAllowedTimestep
Minimizecastandbounding-volumechecks
AvoidcomplexMeshColliders
Usesimplerprimitives
UsesimplerMeshColliders
Avoidcomplexphysicscomponents
Letphysicsobjectssleep
ModifySolverIterationCount
Optimizingragdolls
ReduceJointsandColliders
Avoidinter-ragdollcollisions
Disableorremoveinactiveragdolls
Knowwhentousephysics
ConsiderupgradingtoUnity5
Summary
6.DynamicGraphics
Profilingrenderingissues
GPUprofiling
TheFrameDebugger
Bruteforcetesting
CPU-bound
Multithreadedrendering
GPUSkinning
Frontendbottlenecks
LevelOfDetail
DisableGPUSkinning
Reducetessellation
Backendbottlenecks
Fillrate
http://freepdf-books.com
Overdraw
OcclusionCulling
Shaderoptimization
ConsiderusingShadersintendedformobileplatforms
Usesmalldatatypes
Avoidchangingprecisionwhileswizzling
UseGPU-optimizedhelperfunctions
Disableunnecessaryfeatures
Removeunnecessaryinputdata
Onlyexposenecessaryvariables
Reducemathematicalcomplexity
Reducetexturelookups
Avoidconditionalstatements
Reducedatadependencies
SurfaceShaders
UseShader-basedLOD
Memorybandwidth
Uselesstexturedata
TestdifferentGPUTextureCompressionformats
Minimizetexturesampling
Organizeassetstoreducetextureswaps
VRAMlimits
Texturepreloading
Texturethrashing
LightingandShadowing
ForwardRendering
DeferredShading
VertexLitShading(legacy)
Real-timeShadows
Lightingoptimization
UsetheappropriateShadingMode
http://freepdf-books.com
UseCullingMasks
UseBakedLightmaps
OptimizeShadows
Optimizinggraphicsformobile
MinimizeDrawCalls
MinimizetheMaterialcount
MinimizetexturesizeandMaterialcount
Maketexturessquareandpowerof2
UsethelowestpossibleprecisionformatsinShaders
AvoidAlphaTesting
Summary
7.MasterfulMemoryManagement
TheMonoplatform
Thecompilationprocess
ManualJITcompilation
Memoryusageoptimization
Unitymemorydomains
Nativememory
Managedmemory
Garbagecollection
Memoryfragmentation
Garbagecollectionatruntime
Threadedgarbagecollection
Garbagecollectiontactics
ValuetypesandReferencetypes
Passbyvalueandpassbyreference
StructsareValuetypes
ArraysareReferencetypes
StringsareimmutableReferencetypes
Stringconcatenation
Boxing
http://freepdf-books.com
Theimportanceofdatalayout
TheUnityAPI
Theforeachloops
Coroutines
Closures
.NETlibraryfunctions
Temporaryworkbuffers
Objectpooling
Prefabpooling
PoolableComponents
ThePrefabpoolingsystem
Prefabpools
Objectspawning
Instanceprespawning
Objectdespawning
Prefabpooltesting
PrefabpoolingandSceneloading
Prefabpoolingsummary
ThefutureofMonoandUnity
Summary
8.TacticalTipsandTricks
Editorhotkeytips
GameObjects
SceneView
Arrays
Interface
Other
Editorinterfacetips
General
TheInspectorView
TheProjectView
http://freepdf-books.com
TheHierarchyView
TheSceneandGameViews
PlayMode
Scriptingtips
General
Attributes
Variableattributes
Classattributes
Logging
Usefullinks
Customeditors/menustips
Externaltips
Othertips
Summary
Index
http://freepdf-books.com
http://freepdf-books.com
Unity5GameOptimization
http://freepdf-books.com
http://freepdf-books.com
Unity5GameOptimizationCopyright©2015PacktPublishing
Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.
Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.
PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.
Firstpublished:November2015
Productionreference:1281015
PublishedbyPacktPublishingLtd.
LiveryPlace
35LiveryStreet
BirminghamB32PB,UK.
ISBN978-1-78588-458-0
www.packtpub.com
http://freepdf-books.com
http://freepdf-books.com
CreditsAuthor
ChrisDickinson
Reviewers
CliffordChampion
Dr.SebastianT.Koenig
AcquisitionEditor
IndrajitDas
ContentDevelopmentEditor
AthiraLaji
TechnicalEditor
PrajaktaMhatre
CopyEditor
CharlotteCarneiro
ProjectCoordinator
BijalPatel
Proofreader
SafisEditing
Indexer
RekhaNair
Graphics
JasonMonteiro
ProductionCoordinator
AparnaBhagat
CoverWork
AparnaBhagat
http://freepdf-books.com
http://freepdf-books.com
AbouttheAuthorChrisDickinsongrewupinEnglandwithastrongpassionforscience,mathematics,andvideogames.Hereceivedhismaster’sdegreeinphysicswithelectronicsfromtheUniversityofLeedsin2005,andimmediatelytraveledtoCaliforniatoworkonscientificresearchintheheartofSiliconValley.Findingthatcareerpathunsuitable,hebeganworkinginthesoftwareindustry.
Overthelastdecade,hehasmadeacareerinsoftwaredevelopment,becomingaseniorsoftwaredeveloper.Chrishasprimarilyworkedinsoftwareautomationandinternaltesttooldevelopment,buthispassionforvideogamesneverfullyfaded.In2010,hetookthepathofdiscoveringthesecretsofgamedevelopmentand3Dgraphicsbycompletingaseconddegree—abachelor’sdegreeingameandsimulationprogramming.Heauthoredatutorialbookongamephysics(LearningGamePhysicswithBulletPhysicsandOpenGLbyPacktPublishing).Hecontinuestoworkinsoftwaredevelopment,creatingindependentgameprojectsinhissparetimewithtoolssuchasUnity3D.
http://freepdf-books.com
http://freepdf-books.com
AcknowledgmentsI’vemanagedtograspanabsolutelyridiculousamountofknowledgeinjust5years.Noneofthiswouldhavebeenpossiblewithouttheconstantmotivationfrommycoworkers,tutors,friends,andfamily.
ThankstomycomradesinsoftwaredevelopmentforbeingsounderstandingofmyerraticschedulewhileIwaslearninggamedevelopmentatschool.
Thanksalsotomycollegetutorsforhelpingacceleratemepastthecorematerialandlearnsomuchaboutgamedevelopmentsoquickly.
ThankstomyfriendsforalwaysbeingaconstantsourceofharassmentandinquisitivenessaboutwhatI’vebeenworkingon.
Thankstomyfamilyforgivingmetheopportunitytolearn,live,andlovesomuchinsuchashorttime.
Andofcourse,thankstomywonderfulwifeandbestfriend,Jamie,forbeingsocaringandsupportiveofallthelatenightsandhelpingmestaycreative.
http://freepdf-books.com
http://freepdf-books.com
AbouttheReviewersCliffordChampionhasabroadbackgroundinsoftwareengineering,withyearsofexperiencespanning3Dgames,Internetapplications,andartificialintelligence.HeholdsdegreesinmathematicsandcomputersciencefromUCLAandUCSD,respectively.Inthepast,CliffordworkedforvideogametechnologycompanyHavok(nowpartofMicrosoft),andinteractivemediaanddesigncompanyPlainJoeStudios.Currently,heleadsasoftwareteamatzSpace(zspace.com),aVRcompanyspecializingin3Dforclassroomsandindustry.
CliffordcanbefoundonTwitterat@duckmaestroandwelcomesdiscussionsonanytopic.
Dr.SebastianT.KoenigreceivedhisPhDinhumaninterfacetechnologyfromtheUniversityofCanterbury,NewZealand,developingaframeworkforindividualizedvirtualrealitycognitiverehabilitation.HeobtainedhisdiplomainpsychologyfromtheUniversityofRegensburg,Germany,intheareasofclinicalneuropsychologyandvirtualrealityrehabilitation.
SebastianisthefounderandCEOofKatanaSimulations,whereheoverseesthedesign,development,andevaluationofcognitiveassessmentandtrainingsimulations.Hisprofessionalexperiencespansover10yearsofclinicalworkincognitiverehabilitationandover8yearsofvirtualrealityresearch,development,andusertesting.Hehasextensiveexperienceasaspeakeratinternationalconferencesandasareviewerofscientificpublicationsintheareasofrehabilitation,cognitivepsychology,neuropsychology,softwareengineering,gamedevelopment,gameuserresearch,andvirtualreality.
Sebastianhasdevelopednumeroussoftwareapplicationsforcognitiveassessmentandtraining.Forhisworkonthevirtualmemorytask,hewasawardedtheprestigiousLavalVirtualAwardin2011,fortheMedicineandHealthcategory.OtherapplicationsofhisincludethevirtualrealityexecutivefunctionassessmentincollaborationwiththeKesslerFoundation,NewJersey,USA,andthepatent-pendingMicrosoftKinect-basedmotorandcognitivetrainingJewelMine/MysticIsleattheUSCInstituteforCreativeTechnologies,California,USA.
Hemaintainsthewebsiteatwww.virtualgamelab.com,whichfeatureshisresearchandhissoftwaredevelopmentprojects.HiswebsitealsocontainsacomprehensivelistoftutorialsfortheUnitygameengine.
http://freepdf-books.com
http://freepdf-books.com
www.PacktPub.com
http://freepdf-books.com
Supportfiles,eBooks,discountoffers,andmoreForsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com.
DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<[email protected]>formoredetails.
Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.
https://www2.packtpub.com/books/subscription/packtlib
DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.
http://freepdf-books.com
Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser
http://freepdf-books.com
FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.
http://freepdf-books.com
http://freepdf-books.com
PrefaceUserexperienceisacriticalcomponentofanygame.Userexperienceincludesnotonlyourgame’sstoryanditsgameplay,butalsohowsmoothlythegraphicsrun,howreliablyitconnectstomultiplayerservers,howresponsiveitistouserinput,andevenhowlargethefinalapplicationfilesizeisduetotheprevalenceofappstoresandclouddownloads.Thebarriertoenteringgamedevelopmenthasbeenloweredconsiderablythankstothereleaseofcheap,AAA-industry-levelgamedevelopmenttoolssuchasUnity.However,thefeaturesandqualityofthefinalproductthatourplayersexpectustoprovideisincreasingwitheverypassingday.Weshouldexpectthateveryfacetofourgamecanandwillbescrutinizedbyplayersandcriticsalike.
Thegoalsofperformanceoptimizationaredeeplyentwinedwithuserexperience.Poorlyoptimizedgamescanresultinlowframerates,freezes,crashes,inputlag,longloadingtimes,inconsistentandjitteryruntimebehavior,physicsenginebreakdowns,andevenexcessivelyhighbatterypowerconsumption(particularlyimportantinthiseraofmobiledevices).Havingjustoneoftheseissuescanbeagamedeveloper’sworstnightmareasreviewswilltendtofocusontheonethingthatwedidbadly,inspiteofallthethingsthatwedidwell.
Performanceisallaboutmakingthebestuseoftheavailableresources,whichincludestheCPUresourcessuchasCPUcyclesandmainmemoryspace,GraphicsProcessingUnit(GPU)resourcessuchasmemoryspace(VRAM)andmemorybandwidth,andsoon.Butoptimizationalsomeansmakingsurethatnosingleresourcecausesabottleneckataninappropriatetime,andthatthehighestprioritytasksgettakencareoffirst.Evensmall,intermittenthiccupsandsluggishnessinperformancecanpulltheplayeroutoftheexperience,breakingimmersionandlimitingourpotentialtocreatetheexperienceweintended.
Itisalsoimportanttodecidewhentotakeastepbackandstopmakingperformanceenhancements.Inaworldwithinfinitetimeandresources,therewouldalwaysbeanotherwaytomakeitbetter,faster,oreasiertomaintain.Theremustbeapointduringdevelopmentwherewedecidethattheproducthasreachedacceptablelevelsofquality.Ifnot,weriskdoomingourselvestoimplementingfurtherchangesthatresultinlittleornotangiblebenefit.
Thebestwaytodecideifaperformanceissueisworthfixingistoanswerthequestion“willtheusernoticeit?”.Iftheanswertothisquestionsis“no”,thenperformanceoptimizationwouldbeawastedeffort.Thereisanoldsayinginsoftwaredevelopment:
Prematureoptimizationistherootofallevil
Prematureoptimizationisthecardinalsinofreworkingandrefactoringcodetoenhanceperformancewithoutanyproofthatitisnecessary.Thiscouldmeaneithermakingchangeswithoutshowingthataperformanceproblemevenexists(answeringthequestionofwhetherornotitwouldbenoticeabletotheuser),ormakingchangesbecauseweonly
http://freepdf-books.com
believeaperformanceissuemightstemfromaparticularareabeforeithasbeenproventobetrue.Makingthesemistakeshascostsoftwaredevelopers,asacollectivewhole,adepressingnumberofworkhoursfornothing.
Thisbookintendstogiveusthetools,knowledge,andskillsweneedtobothdetectandfixperformanceissuesinourapplication,nomatterwheretheystemfrom.ThiscouldbehardwarecomponentssuchastheCPU,GPU,orRAM,withinsoftwaresubsystemssuchasPhysics,Rendering,orwithintheUnityEngineitself.Inaddition,themoreresourceswesave,themorewecandowithintheUnityEnginewiththesamehardwaresystem,allowingustogeneratemoreinterestinganddynamicgameplay.
Thiswillgiveourgameabetterchanceofsucceedingandstandingoutfromthecrowdinamarketplacethatisinundatedwithnew,highqualitygameseverysingleday.
http://freepdf-books.com
WhatthisbookcoversChapter1,DetectingPerformanceIssues,providesanexplorationoftheUnityProfilerandaseriesofmethodstoprofileourapplication,detectperformancebottlenecks,andperformrootcauseanalysis.
Chapter2,ScriptingStrategies,dealswiththebestpracticesforourUnityC#Scriptcode,minimizingComponentoverhead,improvinginter-objectcommunication,andmore.
Chapter3,TheBenefitsofBatching,exploresUnity’sDynamicandStaticBatchingsystemstoeasetheburdenontherenderingsystem.
Chapter4,KickstartYourArt,helpsyouunderstandtheunderlyingtechnologybehindourartassetsandlearnhowtoavoidcommonpitfallswithimporting,compression,andencoding.
Chapter5,FasterPhysics,isaboutinvestigatingthenuancesofUnity’sphysicssystemforboth3Dand2Dgames,andhowtoproperlyorganizeourphysicsobjectsforimprovedperformance.
Chapter6,DynamicGraphics,providesanin-depthexplorationoftherenderingsystem,andhowtoimproveapplicationsthatsufferrenderingbottlenecksintheGPU,orCPU,andspecializedtechniquesformobiledevices.
Chapter7,MasterfulMemoryManagement,examinestheinnerworkingsoftheUnityEngine,theMonoFramework,andhowmemoryismanagedwithinthesecomponentstoprotectourapplicationfromheapallocationsandruntimegarbagecollection.
Chapter8,TacticalTipsandTricks,dealswithamultitudeofusefultechniquesusedbyprofessionalstoimproveprojectworkflowandscenemanagement.
http://freepdf-books.com
http://freepdf-books.com
WhatyouneedforthisbookThemajorityofthisbookwillfocusonfeatureswithinthecontextofUnityversion5.x.MostofthetechniquescanbeappliedtoUnity4.xprojects,butmayrequireanupgradetoUnity4ProEditioninordertoaccesssomeofthem(suchasOcclusionCulling,StaticBatching,andeventheProfileritself).
http://freepdf-books.com
http://freepdf-books.com
WhothisbookisforThisbookisintendedforintermediateandadvancedUnitydeveloperswhohaveexperiencewithmostofUnity’sfeatureset,andthosewhowanttomaximizetheperformanceoftheirgameorsolveparticularbottlenecks.WhetherthebottleneckiscausedbyCPUoverload,runtimespiking,slowmemoryaccess,fragmentation,garbagecollection,poorGPUfillrate,ormemorybandwidth,thisbookwillteachyouthetechniquesyouneedtoidentifythesourceoftheproblemandhelpexploremultiplewaysofreducingtheirimpactonyourapplication.
FamiliaritywiththeC#languagewillbeneededforsectionsinvolvingscriptingandmemoryusage,andabasicunderstandingofcgwillbeneededforareasinvolvingShaderoptimization.
http://freepdf-books.com
http://freepdf-books.com
ConventionsInthisbook,youwillfindanumberoftextstylesthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.
Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“ThemainUnitycallbackforapplicationupdatesistheUpdate()function.”
Ablockofcodeissetasfollows:
publicclassTestComponent:MonoBehaviour{
voidUpdate(){
if(Input.GetKeyDown(KeyCode.Space)){
PerformProfilingTest();
}
}
}
Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevantlinesoritemsaresetinbold:
publicclassTestComponent:MonoBehaviour{
voidUpdate(){
if(Input.GetKeyDown(KeyCode.Space)){
PerformProfilingTest();
}
}
}
Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,forexample,inmenusordialogboxes,appearinthetextlikethis:“ThethresholdvalueforthesleepingstatecanbemodifiedunderEdit|ProjectSettings|Physics|SleepThreshold.”
NoteWarningsorimportantnotesappearinaboxlikethis.
TipTipsandtricksappearlikethis.
http://freepdf-books.com
http://freepdf-books.com
ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.
Tosendusgeneralfeedback,simplye-mail<[email protected]>,andmentionthebook’stitleinthesubjectofyourmessage.
Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.
http://freepdf-books.com
http://freepdf-books.com
CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.
http://freepdf-books.com
DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.
http://freepdf-books.com
ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.
Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.
http://freepdf-books.com
PiracyPiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.
Pleasecontactusat<[email protected]>withalinktothesuspectedpiratedmaterial.
Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.
http://freepdf-books.com
QuestionsIfyouhaveaproblemwithanyaspectofthisbook,youcancontactusat<[email protected]>,andwewilldoourbesttoaddresstheproblem.
http://freepdf-books.com
http://freepdf-books.com
Chapter1.DetectingPerformanceIssuesPerformanceevaluationformostsoftwareproductsisaveryscientificprocess:determinethemaximumsupportedperformancemetrics(numberofconcurrentusers,maximumallowedmemoryusage,CPUusage,andsoon);performloadtestingagainsttheapplicationinscenariosthattrytosimulatereal-worldbehavior;gatherinstrumentationdatafromtestcases;analyzethedataforperformancebottlenecks;completearoot-causeanalysis;makechangesintheconfigurationorapplicationcodetofixtheissue;andrepeat.
Justbecausegamedevelopmentisaveryartisticprocessdoesnotmeanitshouldnotbetreatedinequallyobjectiveandscientificways.Ourgameshouldhaveatargetaudienceinmind,whocantellusthehardwarelimitationsourgamemightbeunder.Wecanperformruntimetestingofourapplication,gatherdatafrommultiplecomponents(CPU,GPU,memory,physics,rendering,andsoon),andcomparethemagainstthedesiredmetrics.Wecanusethisdatatoidentifybottlenecksinourapplication,performadditionalinstrumentationtodeterminetherootcauseoftheissue,andapproachtheproblemfromavarietyofangles.
Togiveusthetoolsandknowledgetocompletethisprocess,thischapterwillintroduceavarietyofmethodsthatwewillusethroughoutthebooktodeterminewhetherwehaveaperformanceproblem,andwheretherootcauseoftheperformanceissuecanbefound.Theseskillswillgiveusthetechniquesweneedtodetect,analyze,andprovethatperformanceissuesareplaguingourUnityapplication,andwhereweshouldbegintomakechanges.Indoingso,youwillprepareyourselvesfortheremainingchapterswhereyouwilllearnwhatcanbedoneabouttheproblemsyou’refacing.
WewillbeginwithanexplorationoftheUnityProfileranditsmyriadoffeatures.Wewillthenexploreahandfulofscriptingtechniquestonarrow-downoursearchfortheelusivebottleneckandconcludewithsometipsonmakingthemostofbothtechniques.
http://freepdf-books.com
TheUnityProfilerTheUnityProfilerisbuiltintotheUnityEditoritself,andprovidesanexpedientwayofnarrowingoursearchforperformancebottlenecksbygeneratingusageandstatisticsreportsonamultitudeofUnity3Dcomponentsduringruntime:
CPUusagepercomponentoftheUnity3DEngineRenderingstatisticsGPUusageonseveralprogrammablepipelinestepsandstagesMemoryusageandstatisticsAudiousageandstatisticsPhysicsengineusageandstatistics
NoteWiththereleaseofUnity5.0,UnityTechnologieshasmadetheProfileravailabletoalldevelopersrunningthePersonalEdition(thenewnamefortheFreeEdition).
UsersrunningtheFreeEditionofUnity4musteitherupgradetoUnity5,orpurchasealicenseforUnity4ProEdition.
Thisadditionalreportingcomeswithaprice,however.Additionalinstrumentationflagswillbeenabledwithinthecompiler,generatingruntimeloggingeventsandadifferentlevelofautomatedcodeoptimizationwhiletheProfilerisinuse,whichcausessomeadditionalCPUandmemoryoverheadatruntime.Thisprofilingcostisnotcompletelynegligible,andislikelytocauseinconsistentbehaviorwhentheProfileristoggledonandoff.
Inaddition,weshouldalwaysavoidusingEditorModeforanykindofprofilingandbenchmarkingpurposesduetotheoverheadcostsoftheEditor;itsinterface,andadditionalmemoryconsumptionofvariousobjectsandcomponents.Itisalwaysbettertotestourapplicationinastandaloneformat,onthetargetdevice,inordertogetamoreaccurateandrealisticdatasample.
TipUserswhoarealreadyfamiliarwithconnectingtheUnityProfilertotheirapplicationsshouldskiptothesectiontitledTheProfilerwindow
http://freepdf-books.com
LaunchingtheProfilerWewillbeginwithabrieftutorialonhowtoconnectourgametotheUnityProfilerwithinavarietyofcontexts:
Localinstancesoftheapplication,eitherthroughtheEditororstandaloneProfilingtheEditoritselfLocalinstancesoftheapplicationinUnityWebplayerRemoteinstancesoftheapplicationonaniOSdevice(theiPadtabletortheiPhonedevice)RemoteinstancesoftheapplicationonanAndroiddevice(atabletorphonedevicerunningAndroidOS)WewillbrieflycovertherequirementsforsettinguptheProfilerineachofthesecontexts.
EditororstandaloneinstancesTheonlywaytoaccesstheProfileristolaunchitthroughtheUnityEditorandconnectittoarunninginstanceofourapplication.Thisisthecasewhetherwe’rerunningourgamewithintheEditor,runningastandaloneapplicationonthelocalorremotedevice,orwhenwewishtoprofiletheEditoritself.
ToopentheProfiler,navigatetoWindow|ProfilerwithintheEditor.IftheEditorisalreadyrunninginPlayMode,thenwemayseereportingdatagatheringintheProfilerWindow:
TipToprofilestandaloneprojects,ensurethattheUseDevelopmentModeandAutoconnectProfilerflagsareenabledwhentheapplicationisbuilt.
SelectingwhethertoprofileanEditor-basedinstance(throughtheEditor’sPlayMode)orastandaloneinstance(separatelybuiltandrunninginthebackground)canbeachievedthroughtheActiveProfileroptionintheProfilerwindow.
http://freepdf-books.com
TheUnityProfiler
EditorprofilingProfilingtheEditoritself,suchasprofilingcustomEditorScripts,canbeenabledwiththeProfileEditoroptionintheProfilerwindowasshowninthefollowingscreenshot.NotethatthisrequirestheActiveProfileroptiontobeconfiguredtoEditor.
TheUnityWebplayerconnectionTheProfilercanalsoconnecttoaninstanceoftheUnityWebplayerthatiscurrentlyrunninginabrowser.Thisenablesustoprofileourweb-basedapplicationinamorereal-worldscenariothroughthetargetbrowser,andtestmultiplebrowsertypesforinconsistenciesinbehavior.
1. EnsurethattheUseDevelopmentModeflagisenabledwhentheWebplayerapplicationisbuilt.
2. LaunchthecompiledWebplayerapplicationinabrowserand,whileitisactiveinthebrowserwindow,holdtheAltkey(OptionkeyonaMac)andright-clickontheWebplayerobjectwithinthebrowsertoopentheReleaseChannelSelectionmenu.ThenselecttheDevelopmentchannel,asshowninthefollowingscreenshot:
NoteNotethatchangingtheReleaseChanneloptionwillrestarttheWebplayerapplication.
http://freepdf-books.com
3. Asshowninthefollowingscreenshot,opentheProfilerintheUnityEditorwithintheProfilerwindow,andthennavigatetoActiveProfiler|WindowsWebPlayer(COMPUTERNAME)orActiveProfiler|OSXWebPlayer(COMPUTERNAME),dependingontheOperatingSystem:
YoushouldnowseereportingdatacollectingintheProfilerwindow.
RemoteconnectiontoaniOSdeviceTheProfilercanalsobeconnectedtoanactiveinstanceoftheapplicationrunningremotelyonaniOSdevice,suchasaniPadoriPhone.ThiscanbeachievedthroughasharedWiFiconnection.FollowthegivenstepstoconnecttheProfilertoanAppledevice:
NoteNotethatremoteconnectiontoanAppledeviceisonlypossiblewhentheProfilerisrunningonanAppleMacdevice.
1. EnsurethattheUseDevelopmentModeandAutoconnectProfilerflagsareenabledwhentheapplicationisbuilt.
2. ConnectboththeiOSdeviceandMactoalocalorADHOCWiFinetwork.3. AttachtheiOSdevicetotheMacviatheUSBortheLightningcable.4. BeginbuildingtheapplicationwiththeBuild&Runoptionasnormal.
http://freepdf-books.com
5. OpentheProfilerwindowintheUnityEditorandselectthedeviceunderActiveProfiler.
YoushouldnowseetheiOSdevice’sprofilingdatagatheringintheProfilerwindow.
TipTheProfilerusesports54998to55511tobroadcastprofilingdata.Makesuretheseportsareavailableforoutboundtrafficifthereisafirewallonthenetwork.
RemoteconnectiontoanAndroiddeviceTherearetwodifferentmethodsforconnectinganAndroiddevicetotheUnityProfiler:eitherthroughaWiFiconnectionorusingtheAndroidDebugBridge(ADB)tool.ADBisasuiteofdebuggingtoolsthatcomesbundledwiththeAndroidSDK.
FollowthegivenstepsforprofilingoveraWiFiconnection:
1. EnsurethattheUseDevelopmentModeandAutoconnectProfilerflagsareenabledwhentheapplicationisbuilt.
2. ConnectboththeAndroidanddesktopdevicestoalocalWiFinetwork.3. AttachtheAndroiddevicetothedesktopdeviceviatheUSBcable.4. BeginbuildingtheapplicationwiththeBuild&Runoptionasnormal.5. OpentheProfilerwindowintheUnityEditorandselectthedeviceunderActive
Profiler.
YoushouldnowseetheAndroiddevice’sprofilingdatagatheringintheProfilerWindow.
ForADBprofiling,followthegivensteps:
1. FromtheWindowscommandprompt,runtheadbdevicescommand,whichchecksifthedeviceisrecognizedbyADB(ifnot,thenthespecificdevicedriversforthedevicemayneedtobeinstalledand/orUSBdebuggingneedstobeenabledonthetargetdevice).
NoteNotethat,iftheadbdevicescommandisn’tfoundwhenitisrunfromthecommandprompt,thentheAndroidSDKfoldermayneedtobeappendedontotheEnvironment’sPATHvariable.
2. EnsurethattheUseDevelopmentModeandAutoconnectProfilerflagsareenabledwhentheapplicationisbuilt.
3. AttachtheAndroiddevicetothedesktopdeviceviathecable(forexample,USB).4. BeginbuildingtheapplicationwiththeBuild&Runoptionasnormal.5. OpentheProfilerWindowintheUnityEditorandselectthedeviceunderActive
Profiler.
YoushouldnowseetheAndroiddevice’sprofilingdatagatheringintheProfilerwindow.
http://freepdf-books.com
TheProfilerwindowWewillnowcovertheessentialfeaturesoftheProfilerastheycanbefoundwithintheinterface.
NoteNotethatthissectioncoversfeaturesastheyappearintheUnityProfilerwithinUnity5.AdditionalfeatureswereaddedtotheProfilerwiththereleaseofUnity5;thesemaybedifferent,ornotexist,inUnity4’sProfiler.
TheProfilerwindowissplitintothreemainareas:
ControlsTimelineViewBreakdownView
Theseareasareasshowninthefollowingscreenshot:
ControlsThetopbarcontainsmultiplecontrolswecanusetoaffectwhatisbeingprofiledandhowdeeplyinthesystemdataisgatheredfrom.Theyare:
AddProfiler:Bydefault,theProfilershowsseveralofUnity’senginecomponentsintheTimelineView,buttheAddProfileroptioncanbeusedtoaddadditionalitems.
http://freepdf-books.com
SeetheTimelineViewsectionforacompletelistofcomponentswecanprofile.Record:EnablingthisoptionwillmaketheProfilercontinuouslyrecordprofilingdata.NotethatdatacanonlyberecordedifPlayModeisenabled(andnotpaused)orifProfileEditorisenabled.DeepProfile:OrdinaryprofilingwillonlyrecordthetimeandmemoryallocationsmadebyanyUnitycallbackmethods,suchasAwake(),Start(),Update(),FixedUpdate(),andsoon.EnablingDeepProfilerecompilesourscriptstomeasureeachandeveryinvokedmethod.Thiscausesanevengreaterinstrumentationcostduringruntimeandusessignificantlymorememorysincedataisbeingcollectedfortheentirecallstackatruntime.Asaconsequence,DeepProfilingmaynotevenbepossibleinlargeprojectsrunningonweakhardware,asUnitymayrunoutofmemorybeforetestingcanevenbegin!
TipNotethatDeepProfilingrequirestheprojecttoberecompiledbeforeprofilingcanbegin,soitisbesttoavoidtogglingtheoptionduringruntime.
Becausethisoptionmeasuresallmethodsacrossourcodebaseinablindfashion,itshouldnotbeenabledduringmostofourprofilingtests.Thisoptionisbestreservedforwhendefaultprofilingisnotprovidingenoughdetail,orinsmalltestScenes,whichareusedtoprofileasmallsubsetofgamefeatures.
IfDeepProfilingisrequiredforlargerprojectsandScenes,buttheDeepProfileoptionistoomuchofahindranceduringruntime,thentherearealternativesthatcanbefoundintheupcomingsectiontitledTargetedProfilingofcodesegments.
ProfileEditor:ThisoptionenablesEditorprofiling—thatis,gatheringprofilingdatafortheUnityEditoritself.ThisisusefulinordertoprofileanycustomEditorScriptswehavedeveloped.
TipNotethatActiveProfilermustbesettotheEditoroptionforthisfeaturetowork.
ActiveProfiler:Thisdrop-downgloballyofferschoicestoselectthetargetinstanceofUnitywewishtoprofile;this,aswe’velearned,canbethecurrentEditorapplication,alocalstandaloneinstanceofourapplication,oraninstanceofourapplicationrunningonaremotedevice.Clear:ThisclearsallprofilingdatafromtheTimelineView.FrameSelection:TheFramecountershowshowmanyframeshavebeenprofiled,andwhichframeiscurrentlyselectedintheTimelineView.Therearetwobuttonstomovethecurrentlyselectedframeforwardorbackwardbyoneframe,andathirdbutton(theCurrentbutton)thatresetstheselectedframetothemostrecentframeandkeepsthatposition.ThiswillcausetheBreakdownViewtoalwaysshowtheprofilingdataforthecurrentframeduringruntimeprofiling.TimelineView:TheTimelineViewrevealsprofilingdatathathasbeencollectedduringruntime,organizedbyareasdependingonwhichcomponentoftheenginewasinvolved.
http://freepdf-books.com
EachAreahasmultiplecoloredboxesforvarioussubsectionsofthosecomponents.Thesecoloredboxescanbetoggledtoreveal/hidethecorrespondingdatatypeswithintheTimelineView.
EachAreafocusesonprofilingdataforadifferentcomponentoftheUnityengine.WhenanAreaisselectedintheTimelineView,essentialinformationforthatcomponentwillberevealedintheBreakdownViewforthecurrentlyselectedframe.
TheBreakdownViewshowsverydifferentinformation,dependingonwhichAreaiscurrentlyselected.
TipAreascanberemovedfromtheTimelineViewbyclickingonthe‘X‘atthetoprightofanArea.AreascanberestoredtotheTimelineViewthroughtheAddProfileroptionintheControlsbar.
CPUArea
ThisAreashowsCPUUsageformultipleUnitysubsystemsduringruntime,suchasMonoBehaviourcomponents,cameras,somerenderingandphysicsprocesses,userinterfaces(includingtheEditor’sinterface,ifwe’rerunningthroughtheEditor),audioprocessing,theProfileritself,andmore.
TherearethreewaysofdisplayingCPUUsagedataintheBreakdownView:
HierarchyRawHierarchyTimeline
TheHierarchyModegroupssimilardataelementsandglobalUnityfunctioncallstogetherforconvenience—forinstance,renderingdelimiters,suchasBeginGUI()andEndGUI()callsarecombinedtogetherinthisMode.
TheRawHierarchyModewillseparateglobalUnityfunctioncallsintoindividuallines.ThiswilltendtomaketheBreakdownViewmoredifficulttoread,butmaybehelpfulifwe’retryingtocounthowmanytimesaparticularglobalmethodhasbeeninvoked,ordeterminingifoneofthesecallsiscostingmoreCPU/memorythanexpected.Forexample,eachBeginGUI()andEndGUI()callwillbeseparatedintodifferententries,possiblyclutteringtheBreakdownView,makingitdifficulttoread.
Perhaps,themostusefulmodefortheCPUAreaistheTimelineModeoption(nottobeconfusedwiththemainTimelineView).ThisModeorganizesCPUusageduringthecurrentframebyhowthecallstackexpandedandcontractedduringprocessing.BlocksatthetopofthisviewweredirectlycalledbytheUnityEngine(suchastheStart(),Awake(),orUpdate()methods),whileblocksunderneaththemaremethodsthatthosemethodshadcalled,whichcanincludemethodsonotherComponentsorobjects.
Meanwhile,thewidthofagivenCPUTimelineBlockgivesustherelativetimeittooktoprocessthatmethodcomparedtootherblocksaroundit.Inaddition,methodcallsthatconsumerelativelylittleprocessingtime,relativetothemoregreedymethods,areshown
http://freepdf-books.com
asgrayboxestokeepthemoutofsight.
ThedesignoftheCPUTimelineModeoffersaverycleanandorganizedwayofdeterminingwhichparticularmethodinthecallstackisconsumingthemosttime,andhowthatprocessingtimemeasuresupagainstothermethodsbeingcalledduringthesameframe.Thisallowsustogaugewhichmethodisthebiggestculpritwithminimaleffort.
Forexample,let’sassumethatwearelookingataperformanceprobleminthefollowingscreenshot.Wecantell,withaquickglance,thattherearethreemethodsthatarecausingaproblem,andtheyeachconsumesimilaramountsofprocessingtime,duetohavingsimilarwidths.
Inthisexample,thegoodnewsisthatwehavethreepossiblemethodsthroughwhichtofindperformanceimprovements,whichmeanslotsofopportunitiestofindcodethatcanbeimproved.Thebadnewsisthatincreasingtheperformanceofonemethodwillonlyimproveaboutone-thirdofthetotalprocessingforthatframe.Hence,allthreemethodswillneedtobeexaminedandimprovedinordertominimizetheamountofprocessingtimeduringthisframe.
TheCPUAreawillbemostusefulduringChapter2,ScriptingStrategies.
TheGPUArea
TheGPUAreaissimilartotheCPUArea,exceptthatitshowsmethodcallsandprocessingtimeasitoccursontheGPU.RelevantUnitymethodcallsinthisAreawillrelatetocameras,drawing,opaqueandtransparentgeometry,lightingandshadows,andsoon.
TheGPUAreawillbebeneficialduringChapter6,DynamicGraphics.
TheRenderingArea
TheRenderingAreaprovidesrenderingstatistics,suchasthenumberofSetPasscalls,thetotalnumberofBatchesusedtorenderthescene,thenumberofBatchessavedfromDynamicandStaticBatching,memoryconsumedforTextures,andsoon.
TheRenderingAreawillbeusefulinChapter3,TheBenefitsofBatching.
http://freepdf-books.com
TheMemoryArea
TheMemoryAreaallowsustoinspectmemoryusageoftheapplicationintheBreakdownViewintwodifferentways:
SimpleModeDetailedMode
TheSimpleModeprovidesonlyahigh-leveloverviewofmemoryconsumptionofcomponentssuchasUnity’slow-levelEngine,theMonoframework(totalheapsizethatwillbegarbage-collected),Graphics,Audio(FMOD),andevenmemoryusedtostoredatacollectedbytheProfiler.
TheDetailedModeshowsmemoryconsumptionofindividualgameobjectsandcomponents,forboththeirnativeandmanagedrepresentations.Italsohasacolumnexplainingthereasonforthatobjectconsumingmemoryandwhenitmightbede-allocated.
TheMemoryAreawillbethemainfocalpointofChapter7,MasterfulMemoryManagement.
TheAudioArea
TheAudioAreagrantsanoverviewofaudiostatisticsandcanbeusedbothtomeasureCPUusagefromtheaudiosystem,aswellastotalmemoryconsumedbyAudioSources(forbothplayingandpausedsources)andAudioClips.
TheAudioAreawillcomeinhandyasweexploreartassetsinChapter4,KickstartYourArt.
TipAudioisoftenoverlookedwhenitcomestoperformanceenhancements,butaudiocanbecomeofthebiggestsourcesofbottlenecksifitisnotmanagedproperly.It’sworthperformingoccasionalchecksontheAudiosystem’smemoryandCPUconsumptionduringdevelopment.
ThePhysics3D/2DArea
TherearetwodifferentPhysicsAreas,onefor3Dphysics(Nvidia’sPhysX)andanotherforthe2Dphysicssystem(Box2D)thatwasintegratedintotheUnityEngineinversion4.5.ThisAreaprovidesvariousphysicsstatisticssuchasRigidbody,Collider,andContactcounts.
WewillbemakinguseofthisAreainChapter5,FasterPhysics.
NoteAsofthepublicationofthistext,withUnityv5.2.2f1asthemostrecentversion,thePhysics3DAreaonlyprovidesahandfulofitems,whilethePhysics2DAreaprovidessignificantlymoreinformation.
http://freepdf-books.com
http://freepdf-books.com
BestapproachestoperformanceanalysisGoodcodingpracticesandprojectassetmanagementoftenmakefindingtherootcauseofaperformanceissuerelativelysimple,atwhichpointtheonlyrealproblemisfiguringouthowtoimprovethecode.Forinstance,ifthemethodonlyprocessesasinglegiganticforloop,thenitwillbeaprettysafeassumptionthattheproblemiseitherwiththeiterationofthelooporhowmuchworkisprocessedeachiteration.
Ofcourse,alotofourcode,whetherwe’reworkingindividuallyorinagroupsetting,isnotalwayswritteninthecleanestwaypossible,andweshouldexpecttohavetoprofilesomepoorcodingworkfromtimetotime.Sometimes,hack-ysolutionsareinevitable,andwedon’talwayshavethetimetogobackandrefactoreverythingtokeepupwithourbestcodingpractices.
It’seasytooverlooktheobviouswhenproblemsolvingandperformanceoptimizationisjustanotherformofproblemsolving.ThegoalistouseProfilersanddataanalysistosearchourcodebaseforcluesaboutwhereaproblemoriginates,andhowsignificantitis.It’softenveryeasytogetdistractedbyinvaliddataorjumptoconclusionsbecausewe’rebeingtooimpatientormissedasubtleclue.Manyofushaverunintooccasions,duringsoftwaredebugging,wherewecouldhavefoundtherootcauseoftheproblemmuchfasterifwehadsimplychallengedandverifiedourearlierassumptions.Alwaysapproachingdebuggingunderthebeliefthattheproblemishighlycomplexandtechnicalisagoodwaytowastevaluabletimeandeffort.Performanceanalysisisnodifferent.
Achecklistoftaskswouldbehelpfultokeepusfocusedontheissue,andnotwastetimechasing“ghosts”.Everyprojectisdifferentandhasadifferentsetofconcernsanddesignparadigms,butthefollowingchecklistisgeneralenoughthatitshouldbeabletoapplytoanyUnityproject:
VerifyingthetargetScriptispresentintheSceneVerifyingtheScriptappearsintheScenethecorrectnumberoftimesMinimizingongoingcodechangesMinimizinginternaldistractionsMinimizingexternaldistractions
http://freepdf-books.com
VerifyingscriptpresenceSometimestherearethingsweexpecttosee,butdon’t.Theseareusuallyeasytonote,becausethehumanbrainisverygoodatpatternrecognition.Ifsomethingdoesn’tmatchtheexpectedpattern,thenittendstobeveryobvious.Meanwhile,therearetimeswhereweassumesomethinghasbeenhappening,butitdidn’t.Thesearegenerallymoredifficulttonotice,becausewe’reoftenscanningforthefirstkindofproblem.Verificationoftheintendedorderofeventsiscritical,orweriskjumpingtoconclusions,wastingvaluabletime.
InthecontextofUnity,thismeansitisessentialtoverifythatthescriptweexpecttoseetheeventcomingfromisactuallypresentintheScene,andthatthemethodcallshappenintheorderweintended.
ScriptpresencecanbequicklyverifiedbytypingthefollowingintotheHierarchywindowtextbox:
t:<monobehaviourname>
Forexample,typingt:mytestmonobehaviour(note:itisnotcase-sensitive)intotheHierarchytextboxwillshowashortlistofallGameObjectsthatcurrentlyhaveaMyTestMonobehaviourscriptattachedasaComponent.
TipNotethatthisshortlistfeaturealsoincludesanyGameObjectswithComponentsthatderivefromthegivenscriptname.
http://freepdf-books.com
Weshouldalsodouble-checkthattheGameObjectstheyareattachedtoarestillenabled,sincewemayhavedisabledthemduringearliertesting,orsomeone/somethinghasaccidentallydeactivatedtheobject.
http://freepdf-books.com
VerifyingscriptcountIfweassumethataMonoBehaviour,whichiscausingperformanceproblems,onlyappearsonceinourScene,thenwemayignorethepossibilitythatconflictingmethodinvocationsarecausingabottleneck.Thisisdangerous;whatifsomeonecreatedtheobjecttwiceormoreintheScenefile,orweaccidentallyinstantiatedtheobjectmorethanoncefromcode?WhatweseeintheProfilercanbeaconsequenceofthesameexpensivemethodbeinginvokedmorethanonceatthesametime.Thisissomethingwewillwanttodouble-checkusingthesameshortlistmethodasbefore.
IfweexpectedonlyoneoftheComponentstoappearintheScene,buttheshortlistrevealedmorethanone,thenwemaywishtorethinkourearlierassumptionsaboutwhat’scausingthebottlenecks.Wemaywishtowritesomeinitializationcodethatpreventsthisfromeverhappeningagain,and/orwritesomecustomEditorhelperstodisplaywarningstoanyleveldesignerswhomightbemakingthismistake.
Preventingcasualmistakeslikethisisessentialforgoodproductivity,sinceexperiencetellsusthat,ifwedon’texplicitlydisallowsomething,thensomeone,somewhere,atsomepoint,forwhateverreason,willdoitanyway,andcostusagooddealofanalysiswork.
http://freepdf-books.com
MinimizingongoingcodechangesMakingcodechangestotheapplicationinordertohuntdownperformanceissuesisnotrecommended,asthechangesareeasytoforgetastimewearson.Addingdebugloggingstatementstoourcodecanbetempting,butrememberthatitcostsustimetointroducethesecalls,recompileourcode,andremovethesecallsonceouranalysisiscomplete.Inaddition,ifweforgettoremovethem,thentheycancostunnecessaryruntimeoverheadinthefinalbuildsinceUnity’sDebugloggingcanbeprohibitivelyexpensiveinbothCPUandmemory.
Onewaytocombatthisproblemistouseasource-controltooltodifferentiatethecontentsofanymodifiedfiles,and/orrevertthembacktotheiroriginalstate.Thisisanexcellentwaytoensurethatunnecessarychangesdon’tmakeitintothefinalversion.
Makinguseofbreakpointsduringruntimedebuggingisthepreferredapproach,aswecantracethefullcallstack,variabledata,andconditionalcodepaths(forexample,if-elseblocks),withoutriskinganycodechangesorwastingtimeonrecompilation.
http://freepdf-books.com
MinimizinginternaldistractionsTheUnityEditorhasitsownlittlequirksandnuancesthatcanleaveusconfusedbycertainissues.
Firstly,ifasingleframetakesalongtimetoprocess,suchthatourgamenoticeablyfreezes,thentheProfilermaynotbecapableofpickinguptheresultsandrecordingthemintheProfilerwindow.Thiscanbeespeciallyannoyingifwewishtocatchdataduringapplication/Sceneinitialization.Theupcomingsection,CustomCPUProfiling,willoffersomealternativestoexploretosolvethisproblem.
Onecommonmistake(thatIhaveadmittedlyfallenvictimtomultipletimesduringthewritingofthisbook)is:ifwearetryingtoinitiateatestwithakeystrokeandwehavetheProfileropen,weshouldnotforgettoclickbackintotheEditor’sGamewindowbeforetriggeringthekeystroke!IftheProfileristhemostrecentlyclickedwindow,thentheEditorwillsendkeystrokeeventstothat,insteadoftheruntimeapplication,andhencenoGameObjectwillcatchtheeventforthatkeystroke.
VerticalSync(otherwiseknownasVSync)isusedtomatchtheapplication’sframeratetotheframerateofthedeviceitisbeingdisplayedon(forexample,themonitor).ExecutingtheProfilerwiththisfeatureenabledwillgeneratealotofspikesintheCPUusageareaundertheheadingWaitForTargetFPS,astheapplicationintentionallyslowsitselfdowntomatchtheframerateofthedisplay.Thiswillgenerateunnecessaryclutter,makingithardertospottherealissue(s).WeshouldmakesuretodisabletheVSynccoloredboxundertheCPUAreawhenwe’reonthelookoutforCPUspikesduringperformancetests.WecandisabletheVSyncfeatureentirelybynavigatingtoEdit|ProjectSettings|Qualityandthenthesubpageforthecurrentlyselectedbuildplatform.
Weshouldalsoensurethatadropinperformanceisn’tadirectresultofamassivenumberofexceptionsanderrormessagesappearingintheEditorconsole.Unity’sDebug.Log(),andsimilarmethodssuchasDebug.LogError(),Debug.LogWarning(),andsoon,arenotoriouslyexpensiveintermsofCPUusageandheapmemoryconsumption,whichcanthencausegarbagecollectiontooccurandevenmorelostCPUcycles.
ThisoverheadisusuallyunnoticeabletoahumanbeinglookingattheprojectinEditorMode,wheremosterrorscomefromthecompilerormisconfiguredobjects.Buttheycanbeproblematicwhenusedduringanykindofruntimeprocess;especiallyduringprofiling,wherewewishtoobservehowthegamerunsintheabsenceofexternaldisruptions.Forexample,ifwearemissinganobjectreferencethatweweresupposedtoassignthroughtheEditoranditisbeingusedinanUpdate()method,thenasingleMonoBehaviourcouldbethrowingnewexceptionseverysingleupdate.Thisaddslotsofunnecessarynoisetoourprofilingdata.
NotethatwecandisabletheInfoorWarningcheckboxes(showninthefollowingscreenshot)fortheprojectduringPlayModeruntime,butitstillcostsCPUandmemorytoexecutedebugstatements,eventhoughtheyarenotbeingrendered.Itisoftenagoodpracticetokeepalloftheseoptionsenabled,toverifythatwe’renotmissinganythingimportant.
http://freepdf-books.com
http://freepdf-books.com
MinimizingexternaldistractionsThisoneissimplebutabsolutelynecessary.Weshoulddouble-checkthattherearenobackgroundprocesseseatingawayCPUcyclesorconsumingvastswathesofmemory.Beinglowonavailablememorywillgenerallyinterferewithourtesting,asitcancausemorecachemisses,hard-driveaccessforvirtualmemorypage-fileswapping,andgenerallyslowresponsivenessoftheapplication.
http://freepdf-books.com
http://freepdf-books.com
TargetedprofilingofcodesegmentsIfourperformanceproblemisn’tsolvedbytheabovechecklist,thenweprobablyhavearealissueonourhandsthatdemandsfurtheranalysis.Thetaskoffiguringoutexactlywheretheproblemislocatedstillremains.TheProfilerwindowiseffectiveatshowingusabroadoverviewofperformance;itcanhelpusfindspecificframestoinvestigateandcanquicklyinformuswhichMonoBehaviourand/ormethodmaybecausingissues.However,wemuststilldetermineexactlywheretheproblemexists.Weneedtofigureoutiftheproblemisreproducible,underwhatcircumstancesaperformancebottleneckarises,andwhereexactlywithintheproblematiccodeblocktheissueisoriginatingfrom.
Toaccomplishthese,wewillneedtoperformsomeprofilingoftargetedsectionsofourcode,andthereareahandfulofusefultechniqueswecanemployforthistask.ForUnityprojects,theyessentiallyfitintotwocategories:
ControllingtheProfilerfromscriptcodeCustomtimingandloggingmethods
NoteNotethatthefollowingsectionmostlyfocussesonhowtoinvestigateScriptingbottlenecksthroughC#code.Detectingthesourceofbottlenecksinotherenginecomponentswillbediscussedintheirrelatedchapters.
http://freepdf-books.com
ProfilerscriptcontrolTheProfilercanbecontrolledinscriptcodethroughthestaticProfilerclass.ThereareseveralusefulmethodsintheProfilerclassthatwecanexplorewithintheUnitydocumentation,butthemostimportantmethodsarethedelimitermethodsthatactivateanddeactivateprofilingatruntime:Profiler.BeginSample()andProfiler.EndSample().
TipNotethatthedelimitermethods,BeginSample()andEndSample(),areonlycompiledindevelopmentbuilds,andassuchtheycausenooverheadinthefinalbuild.Therefore,itissafetoleavetheminourcodebaseifwewishtousethemforprofilingtestsatalaterdate.
TheBeginSample()methodhasanoverloadthatallowsacustomnameforthesampletoappearintheCPUUsageArea’sHierarchyModeview.Forexample,thefollowingcodewillprofileinvocationsofthismethodandmakethedataappearintheBreakdownViewunderacustomheading:
voidDoSomethingCompletelyStupid(){
Profiler.BeginSample("MyProfilerSample");
List<int>listOfInts=newList<int>();
for(inti=0;i<1000000;++i){
listOfInts.Add(i);
}
Profiler.EndSample();
}
TipDownloadingtheexamplecode
Youcandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.
Weshouldexpectthatinvokingthispoorlydesignedmethod(itgeneratesalistcontainingamillionintegers,andthendoesabsolutelynothingwithit)willcauseahugespikeinCPUusage,chewupseveralMegabytesofmemory,andappearintheProfilerBreakdownViewundertheheadingMyProfilerSampleasthefollowingscreenshotshows:
http://freepdf-books.com
NotethatthesecustomsamplenamesdonotappearattherootofthehierarchywhenweperformDeepProfiling.ThefollowingscreenshotshowstheBreakdownViewforthesamecodeunderDeepProfiling:
Notehowthecustomnameforthesampledoesnotappearatthetopofthesample,wherewemayexpectitto.It’sunclearwhatcausesthisphenomenon,butthiscancausesomeconfusionwhenexaminingtheDeepProfilingdatawithinHierarchyMode,soitisgoodtobeawareofit.
http://freepdf-books.com
CustomCPUProfilingTheProfilerisjustonetoolatourdisposal.Sometimes,wemaywanttoperformcustomizedprofilingandloggingofourcode.Maybewe’renotconfidenttheUnityProfilerisgivingustherightanswer,maybeweconsideritsoverheadcosttoogreat,ormaybewejustlikehavingcompletecontrolofeverysingleaspectofourapplication.Whateverourmotivations,knowingsometechniquestoperformanindependentanalysisofourcodeisausefulskilltohave.It’sunlikelywe’llonlybeworkingwithUnityfortheentiretyofourgamedevelopmentcareers,afterall.
Profilingtoolsareverycomplex,soit’sunlikelywewouldbeabletogenerateacomparablesolutiononourownwithinareasonabletimeframe.WhenitcomestotestingCPUusage,allweneedisanaccuratetimingsystem,afast,low-costwayofloggingthatinformation,andsomepieceofcodetotestagainst.Itjustsohappensthatthe.NETlibrary(or,technically,theMonoframework)comeswithaStopwatchclassundertheSystem.Diagnosticsnamespace.WecanstopandstartaStopwatchobjectatanytime,andwecaneasilyacquireameasureofhowmuchtimehaspassedsincetheStopwatchwasstarted.
Unfortunately,thisclassisnotveryaccurate—itisaccurateonlytomilliseconds,ortenthsofamillisecondatbest.Countinghigh-precisionrealtimewithaCPUclockcanbeasurprisinglydifficulttaskwhenwestarttogetintoit;so,inordertoavoidadetaileddiscussionofthetopic,weshouldtrytofindawayfortheStopwatchclasstosatisfyourneeds.
Beforewegetobsessedwiththetopicofhighprecision,weshouldfirstaskourselvesifweevenneedit.Mostgamesexpecttorunat30FPS(frames-per-second)or60FPS,whichmeanstheyonlyhavearound33msor16ms,respectively,tocomputeeverythingfortheentireframe.So,hypothetically,ifweonlyneedtobringtheperformanceofaparticularcodeblockunder10ms,thenrepeatingthetestthousandsoftimestogetmicrosecondprecisionwouldn’treallytellusanythinguseful.
However,ifprecisionisimportant,thenoneeffectivewaytoincreaseitisbyrunningthesametestmultipletimes.Assumingthatthetestcodeblockisbotheasilyrepeatableandnotexceptionallylong,thenweshouldbeabletorunthousands,orevenmillions,oftestswithinareasonabletimeframeandthendividethetotalelapsedtimebythenumberoftestswejustperformedtogetamoreaccuratetimeforasingletest.
ThefollowingisaclassdefinitionforacustomtimerthatusesaStopwatchtocounttimeforagivennumberoftests:
usingUnityEngine;
usingSystem;
usingSystem.Diagnostics;
usingSystem.Collections;
publicclassCustomTimer:IDisposable{
privatestringm_timerName;
privateintm_numTests;
http://freepdf-books.com
privateStopwatchm_watch;
//givethetimeraname,andacountofthenumberoftestswe're
running
publicCustomTimer(stringtimerName,intnumTests){
m_timerName=timerName;
m_numTests=numTests;
if(m_numTests<=0)
m_numTests=1;
m_watch=Stopwatch.StartNew();
}
//calledwhenthe'using'blockends
publicvoidDispose(){
m_watch.Stop();
floatms=m_watch.ElapsedMilliseconds;
UnityEngine.Debug.Log(string.Format("{0}finished:{1:0.00}mstotal,
{2:0.000000}mspertestfor{3}tests",m_timerName,ms,ms/m_numTests,
m_numTests));
}
}
ThefollowingisanexampleoftheCustomTimerclassusage:
intnumTests=1000;
using(newCustomTimer("MyTest",numTests)){
for(inti=0;i<numTests;++i){
TestFunction();
}
}//thetimer'sDispose()methodisautomaticallycalledhere
Therearethreethingstonotewhenusingthisapproach.Firstly,weareonlymakinganaverageofmultiplemethodinvocations.Ifprocessingtimevariesenormouslybetweeninvocations,thenthatwillnotbewell-representedinthefinalaverage.Secondly,ifmemoryaccessiscommon,thenrepeatedlyrequestingthesameblocksofmemorywillresultinanartificiallyhighercachehitrate,whichwillbringtheaveragetimedownwhencomparedtoatypicalinvocation.Thirdly,theeffectsofJITcompilationwillbeeffectivelyhiddenforsimilarlyartificialreasonsasitonlyaffectsthefirstinvocationofthemethod.JITcompilationissomethingthatwillbecoveredinmoredetailinChapter7,MasterfulMemoryManagement.
Theusingblockistypicallyusedtosafelyensurethatunmanagedresourcesareproperlydestroyedwhentheygooutofscope.Whentheusingblockends,itwillautomaticallyinvoketheobject’sDispose()methodtohandleanycleanupoperations.Inordertoachievethis,theobjectmustimplementtheIDisposableinterface,whichforcesittodefinetheDispose()method.
However,thesamelanguagefeaturecanbeusedtocreateadistinctcodeblock,whichcreatesashort-termobject,whichthenautomaticallyprocessessomethingusefulwhenthecodeblockends.
Note
http://freepdf-books.com
Notethattheusingblockshouldnotbeconfusedwiththeusingstatement,whichisusedatthestartofascriptfiletopullinadditionalnamespaces.It’sextremelyironicthatthekeywordformanagingnamespacesinC#hasanamingconflictwithanotherkeyword.
Asaresult,theusingblockandtheCustomTimerclassgiveusacleanwayofwrappingourtargettestcodeinawaywhichmakesitobviouswhenandwhereitisbeingused.
Anotherconcerntoworryaboutisapplicationwarmup.UnityhasasignificantstartupcostwhenaScenebegins,giventhenumberofcallstovariousGameObjects’Awake()andStart()methods,aswellasinitializationofothercomponentssuchasthePhysicsandRenderingsystems.Thisearlyoverheadmightonlylastasecond,butthatcanhaveasignificanteffectontheresultsofourtesting.Thismakesitcrucialthatanyruntimetestingbeginsaftertheapplicationhasreachedasteadystate.
Ifpossible,itwouldbewisetowrapthetargetcodeblockinanInput.GetKeyDown()methodcheckinordertohavecontroloverwhenitisinvoked.Forexample,thefollowingcodewillonlyexecuteourtestmethodwhentheSpaceBarispressed:
if(Input.GetKeyDown(KeyCode.Space)){
intnumTests=1000;
using(newCustomTimer("ControlledTest",numTests)){
for(inti=0;i<numTests;++i){
TestFunction();
}
}
}
TherearethreeimportantdesignfeaturesoftheCustomTimerclass:itonlyprintsasinglelogmessagefortheentiretest,onlyreadsthevaluefromtheStopwatchafterithasbeenstopped,andusesstring.Format()forgeneratingacustomstring.
Asexplainedearlier,Unity’sconsoleloggingmechanismisprohibitivelyexpensive.Asaresult,weshouldneverusetheseloggingmethodsinthemiddleofaprofilingtest(orevengameplay,forthatmatter).Ifwefindourselvesabsolutelyneedingdetailedprofilingdatathatprintsoutlotsofindividualmessages(suchasperformingatimingtestoneachiterationofaloop,tofindwhichiterationiscostingmoretimethantherest),thenitwouldbewisertocachetheloggingdataandprintitallattheend,astheCustomTimerclassdoes.Thiswillreduceruntimeoverhead,atthecostofsomememoryconsumption.ThealternativeisthatmanymillisecondsarelosttoprintingeachDebug.Log()messageinthemiddleofthetest,whichpollutestheresults.
ThesecondfeatureisthattheStopwatchisstoppedbeforethevalueisread.Thisisfairlyobvious;readingthevaluewhileitisstillcountingmightgiveusaslightlydifferentvaluethanstoppingitfirst.UnlesswedivedeepintotheMonoprojectsourcecode(andthespecificversionUnityuses),wemightnotknowtheexactimplementationofhowStopwatchcountstime,atwhatpointsCPUticksarecounted,andatwhatmomentsanyapplicationcontextswitchingistriggeredbytheOS.So,itisoftenbettertoerronthesideofcautionandpreventanymorecountingbeforeweattempttoaccessthevalue.
http://freepdf-books.com
Finally,there’stheusageofstring.Format().ThiswillbecoveredinmoredetailinChapter7,MasterfulMemoryManagement,buttheshortexplanationisthatthismethodisusedbecausegeneratingcustomstringsusingthe+operatorresultsinasurprisinglylargeamountofmemoryconsumption,whichattractstheattentionofthegarbagecollector.Thiswouldconflictwithourgoalofachievingaccuratetimingandanalysis.
http://freepdf-books.com
http://freepdf-books.com
SavingandloadingProfilerdataTheUnityProfilercurrentlyhasafewfairlysignificantpitfallswhenitcomestosavingandloadingProfilerdata:
Only300framesarevisibleintheProfilerwindowatonceThereisnowaytosaveProfilerdatathroughtheuserinterfaceProfilerbinarydatacanbesavedintoafiletheScriptcode,butthereisnobuilt-inwaytoviewthisdata
Theseissuesmakeitverytrickytoperformlarge-scaleorlong-termtestingwiththeUnityProfiler.TheyhavebeenraisedinUnity’sIssueTrackertoolforseveralyears,andtheredoesn’tappeartobeanysalvationinsight.So,wemustrelyonourowningenuitytosolvethisproblem.
Fortunately,theProfilerclassexposesafewmethodsthatwecanusetocontrolhowtheProfilerlogsinformation:
1. TheProfiler.enabledmethodcanbeusedtoenable/disabletheProfiler,whichistheequivalentofclickingontheRecordbuttonintheControlViewoftheProfiler.
NoteNotethatchangingProfiler.enableddoesnotchangethevisiblestateoftheRecordbuttonintheProfiler’sControlsbar.Thiswillcausesomeconfusingconflictsifwe’recontrollingtheProfilerthroughbothcodeandtheuserinterfaceatthesametime.
2. TheProfiler.logFilemethodsetsthecurrentpathofthelogfilethattheProfilerprintsdataoutto.Beawarethatthisfileonlycontainsaprintoutoftheapplication’sframerateovertime,andnoneoftheusefuldatawenormallyfindintheProfiler’sTimelineView.Tosavethatkindofdataasabinaryfile,wemustusetheoptionsthatfollow.
3. TheProfiler.enableBinaryLogmethodwillenable/disableloggingofanadditionalfilefilledwithbinarydata,whichincludesalloftheimportantvalueswewanttosavefromtheTimelineandBreakdownViews.ThefilelocationandnamewillbethesameasthevalueofProfiler.logFile,butwith.dataappendedtotheend.
Withthesemethods,wecangenerateasimpledata-savingtoolthatwillgeneratelargeamountsofProfilerdataseparatedintomultiplefiles.Withthesefiles,wewillbeabletoperusethematalaterdate.
http://freepdf-books.com
SavingProfilerdataInordertocreateatoolthatcansaveourProfilerdata,wecanmakeuseofaCoroutine.Atypicalmethodwillbeexecutedfrombeginningtoendinonesitting.However,Coroutinesareusefulconstructsthatallowuswritemethodsthatcanpauseexecutionuntilalatertime,oraneventtakesplace.Thisisknownasyielding,andisaccomplishedwiththeyieldstatement.Thetypeofyielddetermineswhenexecutionwillresume,whichcouldbeoneofthefollowingtypes(theobjectthatmustbepassedintotheyieldstatementisalsogiven):
Afteraspecificamountoftime(WaitForSeconds)AfterthenextUpdate(WaitForEndOfFrame)AfterthenextFixedUpdate(WaitForFixedUpdate)JustpriortothenextLateUpdate(null)AfteraWWWobjectcompletesitscurrenttask,suchasdownloadingafile(WWW)AfteranotherCoroutinehasfinished(areferencetoanotherCoroutine)
TheUnityDocumentationonCoroutinesandExecutionOrderprovidesmoreinformationonhowtheseusefultoolsfunctionwithintheUnityEngine:
http://docs.unity3d.com/Manual/Coroutines.htmlhttp://docs.unity3d.com/Manual/ExecutionOrder.html
TipCoroutinesshouldnotbeconfusedwiththreads,whichexecuteindependentlyofthemainUnitythread.Coroutinesalwaysrunonthemainthreadwiththerestofourcode,andsimplypauseandresumeatcertainmoments,dependingontheobjectpassedintotheyieldstatement.
Gettingbacktothetaskathand,thefollowingistheclassdefinitionforourProfilerDataSaverComponent,whichmakesuseofaCoroutinetorepeatanactionevery300frames:
usingUnityEngine;
usingSystem.Text;
usingSystem.Collections;
publicclassProfilerDataSaverComponent:MonoBehaviour{
int_count=0;
voidStart(){
Profiler.logFile="";
}
voidUpdate(){
if(Input.GetKey(KeyCode.LeftControl)&&Input.GetKeyDown(KeyCode.H))
{
StopAllCoroutines();
_count=0;
StartCoroutine(SaveProfilerData());
http://freepdf-books.com
}
}
IEnumeratorSaveProfilerData(){
//keepcallingthismethoduntilPlayModestops
while(true){
//generatethefilepath
stringfilepath=Application.persistentDataPath+"/profilerLog"+
_count;
//setthelogfileandenabletheprofiler
Profiler.logFile=filepath;
Profiler.enableBinaryLog=true;
Profiler.enabled=true;
//count300frames
for(inti=0;i<300;++i){
yieldreturnnewWaitForEndOfFrame();
//workaroundtokeeptheProfilerworking
if(!Profiler.enabled)
Profiler.enabled=true;
}
//startagainusingthenextfilename
_count++;
}
}
}
TryattachingthisComponenttoanyGameObjectintheScene,andpressCtrl+H(OSXuserswillwanttoreplacetheKeyCode.LeftControlcodewithsomethingsuchasKeyCode.LeftCommand).TheProfilerwillstartgatheringinformation(whetherornottheProfilerWindowisopen!)and,usingasimpleCoroutine,willpumpthedataoutintoaseriesoffilesunderwhereverApplication.persistantDataPathispointingto.
TipNotethatthelocationofApplication.persistantDataPathvariesdependingontheOperatingSystem.ChecktheUnityDocumentationformoredetailsathttp://docs.unity3d.com/ScriptReference/Application-persistentDataPath.html.
ItwouldbeunwisetosendthefilestoApplication.dataPath,asitwouldputthemwithintheProjectWorkspace.TheProfilerdoesnotreleasethemostrecentlogfilehandleifwestoptheProfilerorevenwhenPlayModeisstopped.Consequently,asfilesaregeneratedandplacedintotheProjectworkspace,therewouldbeaconflictinfileaccessibilitybetweentheUnityEditortryingtoreadandgeneratecomplementarymetadatafiles,andtheProfilerkeepingafilehandletothemostrecentlogfile.Thiswouldresultinsomenastyfileaccesserrors,whichtendtocrashtheUnityEditorandloseanyScenechangeswe’vemade.
http://freepdf-books.com
WhenthisComponentisrecordingdata,therewillbeasmalloverheadinharddiskusageandtheoverheadcostofIEnumeratorcontextswitchingevery300frames,whichwilltendtoappearatthestartofeveryfileandconsumeafewmillisecondsofCPU(dependingonhardware).
Eachfilepairshouldcontain300framesworthofProfilerdata,whichskirtsaroundthe300framelimitintheProfilerwindow.AllweneednowisawayofpresentingthedataintheProfilerwindow.
HereisascreenshotofdatafilesthathavebeengeneratedbyProfilerDataSaverComponent:
NoteNotethatthefirstfilemaycontainlessthan300framesifsomeframeswerelostduringProfilerwarmup.
http://freepdf-books.com
LoadingProfilerdataTheProfiler.AddFramesFromFile()methodwillloadagivenprofilerlogfilepair(thetextandbinaryfiles)andappenditintotheProfilertimeline,pushingexistingdatafurtherbackintime.Sinceeachfilewillcontain300frames,thisisperfectforourneeds,andwejustneedtocreateasimpleEditorWindowclassthatcanprovidealistofbuttonstoloadthefilesintotheProfiler.
TipNotethatAddFramesFromFile()onlyrequiresthenameoftheoriginallogfile.Itwillautomaticallyfindthecomplimentarybinary.datafileonitsown.
ThefollowingistheclassdefinitionforourProfilerDataLoaderWindow:
usingUnityEngine;
usingUnityEditor;
usingSystem.IO;
usingSystem.Collections;
usingSystem.Collections.Generic;
usingSystem.Text.RegularExpressions;
publicclassProfilerDataLoaderWindow:EditorWindow{
staticList<string>s_cachedFilePaths;
staticints_chosenIndex=-1;
[MenuItem("Window/ProfilerDataLoader")]
staticvoidInit(){
ProfilerDataLoaderWindowwindow=
(ProfilerDataLoaderWindow)EditorWindow.GetWindow
(typeof(ProfilerDataLoaderWindow));
window.Show();
ReadProfilerDataFiles();
}
staticvoidReadProfilerDataFiles(){
//makesuretheprofilerreleasesthefilehandle
//toanyofthefileswe'reabouttoloadin
Profiler.logFile="";
string[]filePaths=Directory.GetFiles
(Application.persistentDataPath,"profilerLog*");
s_cachedFilePaths=newList<string>();
//wewanttoignoreallofthebinary
//filesthatendin.data.TheProfiler
//willfigurethatpartout
Regextest=newRegex(".data$");
for(inti=0;i<filePaths.Length;i++){
stringthisPath=filePaths[i];
http://freepdf-books.com
Matchmatch=test.Match(thisPath);
if(!match.Success){
//notabinaryfile,addittothelist
Debug.Log("Foundfile:"+thisPath);
s_cachedFilePaths.Add(thisPath);
}
}
s_chosenIndex=-1;
}
voidOnGUI(){
if(GUILayout.Button("FindFiles")){
ReadProfilerDataFiles();
}
if(s_cachedFilePaths==null)
return;
EditorGUILayout.Space();
EditorGUILayout.LabelField("Files");
EditorGUILayout.BeginHorizontal();
//createsomestylestoorganizethebuttons,andshow
//themostrecently-selectedbuttonwithredtext
GUIStyledefaultStyle=newGUIStyle(GUI.skin.button);
defaultStyle.fixedWidth=40f;
GUIStylehighlightedStyle=newGUIStyle(defaultStyle);
highlightedStyle.normal.textColor=Color.red;
for(inti=0;i<s_cachedFilePaths.Count;++i){
//list5itemsperrow
if(i%5==0){
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
}
GUIStylethisStyle=null;
if(s_chosenIndex==i){
thisStyle=highlightedStyle;
}else{
thisStyle=defaultStyle;
}
if(GUILayout.Button(""+i,thisStyle)){
Profiler.AddFramesFromFile(s_cachedFilePaths[i]);
s_chosenIndex=i;
}
http://freepdf-books.com
}
EditorGUILayout.EndHorizontal();
}
}
ThefirststepincreatinganycustomEditorWindowiscreatingamenuentrypointwitha[MenuItem]attributeandthencreatinganinstanceofaWindowobjecttocontrol.BothoftheseoccurwithintheInit()method.
We’realsocallingtheReadProfilerDataFiles()methodduringinitialization.ThismethodreadsallfilesfoundwithintheApplication.persistantDataPathfolder(thesamelocationourProfilerDataSaverComponentsavesdatafilesto)andaddsthemtoacacheoffilenamestouselater.
Finally,thereistheOnGUI()method.Thismethoddoesthebulkofthework.Itprovidesabuttontoreloadthefilesifneeded,verifiesthatthecachedfilenameshavebeenread,andprovidesaseriesofbuttonstoloadeachfileintotheProfiler.ItalsohighlightsthemostrecentlyclickedbuttonwithredtextusingacustomGUIStyle,makingiteasytoseewhichfile’scontentsarevisibleintheProfileratthecurrentmoment.
TheProfilerDataLoaderWindowcanbeaccessedbynavigatingtoWindow|ProfilerDataLoaderintheEditorinterface,asshowinthefollowingscreenshot:
Hereisascreenshotofthedisplaywithmultiplefilesavailabletobeloaded.ClickingonanyofthenumberedbuttonswillpushtheProfilerdatacontentsofthatfileintotheProfiler.
http://freepdf-books.com
TheProfilerDataSaverComponentandProfilerDataLoaderWindowdonotpretendtobeexhaustiveorfeature-rich.Theysimplyserveasaspringboardtogetusstartedifwewishtotakethesubjectfurther.Formostteamsandprojects,300framesworthofshort-termdataisenoughfordeveloperstoacquirewhattheyneedtobeginmakingcodechangestofixtheproblem.
http://freepdf-books.com
http://freepdf-books.com
FinalthoughtsonProfilingandAnalysisOnewayofdescribingperformanceoptimizationis“theactofstrippingawayunnecessarytasksthatspendvaluableresources”.Wecandothesameandmaximizeourownproductivitythroughminimizingwastedeffort.Effectiveuseofthetoolswehaveatourdisposalisofparamountimportance.Itwouldserveuswelltooptimizeourownworkflowbykeepingawareofsomebestpracticesandtechniques.
Most,ifnotall,adviceforusinganykindofdata-gatheringtoolproperlycanbesummarizedintothreedifferentstrategies:
UnderstandingthetoolReducingnoiseFocusingontheissue
http://freepdf-books.com
UnderstandingtheProfilerTheProfilerisanarguablywell-designedandintuitivetool,sounderstandingthemajorityofitsfeaturesetcanbegainedbysimplyspendinganhourortwoexploringitsoptionswithatestprojectandreadingitsdocumentation.Themoreweknowaboutourtoolintermsofitsbenefits,pitfalls,features,andlimitations,themoresensewecanmakeoftheinformationitisgivingus,soitisworthspendingthetimetouseitinaplaygroundsetting.Wedon’twanttobetwoweeksawayfromrelease,withahundredperformancedefectstofix,withnoideahowtodoperformanceanalysisefficiently!
Forexample,alwaysremainawareoftherelativenatureoftheTimelineView’sgraphicaldisplay.JustbecauseaspikeorrestingstateintheTimelineseemslargeandthreatening,doesnotnecessarilymeanthereisaperformanceissue.BecausetheTimelineViewdoesnotprovidevaluesonitsverticalaxis,andautomaticallyreadjuststhisaxisbasedonthecontentofthelast300frames,itcanmakesmallspikesappeartobeabiggerproblemthantheyreallyare.SeveralareasintheTimelineprovidehelpfulbenchmarkbars,givingaglimpseofhowtheapplicationwasperformingatthatmoment.Theseshouldbeusedtodeterminethemagnitudeoftheproblem.Don’tlettheProfilertrickusintothinkingthatbigspikesarealwaysbad.Asalways,it’sonlyimportantiftheuserwillnoticeit!
Asanexample,ifalargeCPUusagespikedoesnotexceedthe60FPSor30FPSbenchmarkbars(dependingontheapplication’stargetframerate),thenitwouldbewisetoignoreitandsearchelsewhereforCPUperformanceissues,asnomatterhowmuchweimprovetheoffendingpieceofcodeitwillprobablyneverbenoticedbytheenduser,andisn’tacriticalissuethataffectsproductquality.
http://freepdf-books.com
ReducingnoiseTheclassicaldefinitionofnoiseincomputerscienceismeaninglessdata,andabatchofprofilingdatathatwasblindlycapturedwithnospecifictargetinmindisalwaysfullofdatawhichwon’tinterestus.Moredatatakesmoretimetomentallyprocessandfilter,whichcanbeverydistracting.Oneofthebestmethodstoavoidthisittosimplyreducetheamountofdataweneedtoprocess,bystrippingawayanydatadeemednonvitaltothecurrentsituation.
ReducingclutterintheProfiler’sgraphicalinterfacewillmakeiteasiertodeterminewhichcomponentiscausingaspikeinresourceusage.RemembertousethecoloredboxesineachTimelineareatonarrowthesearch.However,thesesettingsareautosavedintheEditor,sobesuretore-enablethemforthenextprofilingsessionasthismightcauseustomisssomethingimportantnexttime!
Also,GameObjectscanbedeactivatedtopreventthemfromgeneratingprofilingdata,whichwillalsohelpreduceclutterinourprofilingdata.Thiswillnaturallycauseaslightperformanceboostforeachobjectwedeactivate.But,ifwe’regraduallydeactivatingobjectsandperformancesuddenlybecomessignificantlymoreacceptablewhenaspecificobjectisdeactivated,thenclearlythatobjectisrelatedtotherootcauseoftheproblem.
http://freepdf-books.com
FocusingontheissueThiscategorymayseemredundant,giventhatwe’vealreadycoveredreducingnoise.Allweshouldhaveleftistheissueathand,right?Notexactly.Focusistheskillofnotlettingourselvesbecomedistractedbyinconsequentialtasksandwildgoosechases.
RecallthatprofilingwiththeUnityProfilercomeswithaminorperformancecost.ThiscostisevenmoreseverewhenusingtheDeepProfilingoption.Wemightevenintroducemoreminorperformancecostsintoourapplicationwithadditionalloggingandsoon.It’seasytoforgetwhenandwhereweintroducedprofilingcodeifthehuntcontinuesforseveralhours.
Weareeffectivelychangingtheresultbymeasuringit.Anychangesweimplementduringdatasamplingcansometimesleadustochaseafternonexistentbugsintheapplication,whenwecouldhavesavedourselvesalotoftimebyattemptingtoreplicatethescenarioundernon-profilingconditions.Ifthebottleneckisreproducibleandnoticeablewithoutprofiling,thenit’sacandidatetobeginaninvestigation.Butifnewbottleneckskeepappearinginthemiddleofanexistinginvestigation,thenkeepinmindthattheycouldsimplybebottleneckswerecentlyintroducedwithtestcode,andnotsomethingthat’sbeennewlyexposed.
Finally,whenwehavefinishedprofiling,havecompletedourfixes,andarenowreadytomoveontothenextinvestigation,weshouldmakesuretoprofiletheapplicationonelasttimetoverifythatthechangeshavehadtheintendedeffect.
http://freepdf-books.com
http://freepdf-books.com
SummaryYoulearnedagreatdealthroughoutthischapteronhowtodetectperformanceissueswithinyourapplication.YoulearnedaboutmanyoftheProfiler’sfeaturesandsecrets,youexploredavarietyoftacticstoinvestigateperformanceissueswithamorehands-on-approach,andyou’vebeenintroducedtoavarietyofdifferenttipsandstrategiestofollow.Youcanusethesetoimproveyourproductivityimmensely,solongasyouappreciatethewisdombehindthemandremembertoexploitthemwhenthesituationmakesitpossible.
Thischapterhasintroducedustothetips,tactics,andstrategiesweneedfindaperformanceproblemthatneedsimprovement.Duringtheremainingchapters,wewillexploremethodsonhowtofixissues,andimproveperformancewheneverpossible.So,giveyourselfapatonthebackforgettingthroughtheboringpartfirst,andlet’smoveontolearningsomestrategiestoimproveourC#scriptingpractices.
http://freepdf-books.com
http://freepdf-books.com
Chapter2.ScriptingStrategiesSincescriptingwillconsumeagreatdealofourdevelopmenttime,itwillbeenormouslybeneficialtolearnsomebestpractices.Scriptingisaverybroadterm,sowewilltrytolimitourexposureinthischaptertosituationsthatareveryUnityspecific,focusingonproblemsarisingfromwithintheUnityAPIsandenginedesign.WewilldiscussthenuancesandadvancedtopicsoftheC#language,.NETlibrary,andMonoFramework,inChapter7,MasterfulMemoryManagement.
Whetheryouhavesomespecificproblemsinmindthatyouwishtosolveoryoujustwanttolearnsometechniquesforfuturereference,thischapterwillintroduceyoutoanarrayofmethodsthatyoucanusetoimproveyourscriptingeffortsnowandinthefuture.Ineachcase,wewillexplorehowandwhytheperformanceissuearises,anexamplesituationinwhichtheproblemisoccurring,andoneormoresolutionstocombattheissue.
http://freepdf-books.com
CacheComponentreferencesAcommonmistakewhenscriptinginUnityistooverusetheGetComponent()method.Forexample,thefollowingscriptcodeistryingtocheckacreature’shealthvalue,andifitshealthgoesbelow0,disableaseriesofComponentstoprepareitforadeathanimation:
voidTakeDamage(){
if(GetComponent<HealthComponent>().health<0){
GetComponent<Rigidbody>().enabled=false;
GetComponent<Collider>().enabled=false;
GetComponent<AIControllerComponent>().enabled=false;
GetComponent<Animator>().SetTrigger("death");
}
}
Eachtimethismethodexecutes,itwillreacquirefivedifferentComponentreferences.Thisisgoodintermsofheapmemoryconsumption(inthatitdoesn’tcostany),butitisnotveryfriendlyonCPUusage.ThisisparticularlyproblematicifthemainmethodwerecalledduringUpdate().Evenifitisnot,itstillmightcoincidewithotherimportantevents,suchascreatingparticleeffects,replacinganobjectwitharagdoll(thusinvokingvariousactivityinthephysicsengine),andsoon.Thiscodingstylecanseemharmless,butitcancausealotoflong-termproblemsandruntimeworkforverylittlebenefit.
Itcostsusverylittlememoryspace(only32or64bitseachtime;Unityversion,platform,andfragmentationpermitting)tocachethesereferencesforfutureuse.So,unlessyou’reextremelybottleneckedonmemory,abetterapproachwouldbetoacquirethereferencesduringinitializationandkeepthemuntiltheyareneeded:
privateHealthComponent_healthComponent;
privateRigidbody_rigidbody;
privateCollider_collider;
privateAIControllerComponent_aiController;
privateAnimator_animator;
voidAwake(){
_healthComponent=GetComponent<HealthComponent>();
_rigidbody=GetComponent<Rigidbody>();
_collider=GetComponent<Collider>();
_aiController=GetComponent<AIControllerComponent>();
_animator=GetComponent<Animator>();
}
voidTakeDamage(){
if(_healthComponent.health<0){
_rigidbody.detectCollisions=false;
_collider.enabled=false;
_aiController.enabled=false;
_animator.SetTrigger("death");
}
}
CachingtheComponentreferencesinthiswaysparesusfromreacquiringthemeachtime
http://freepdf-books.com
they’reneeded,savingussomeCPUoverheadeachtime,attheexpenseofsomeadditionalmemoryconsumption.
http://freepdf-books.com
http://freepdf-books.com
ObtainingComponentsusingthefastestmethodThereareseveralvariationsoftheGetComponent()method,anditbecomesprudenttocallthefastestpossibleversionofthismethod.ThethreeoverloadsavailableareGetComponent(string),GetComponent<T>(),andGetComponent(typeof(T)).ItturnsoutthatthefastestversiondependsonwhichversionofUnitywearerunning.
InUnity4,theGetComponent(typeof(T))methodisthefastestoftheavailableoptionsbyareasonablemargin.Let’sprovethiswithsomesimpletesting:
intnumTests=1000000;
TestComponenttest;
using(newCustomTimer("GetComponent(string)",numTests)){
for(vari=0;i<numTests;++i){
test=(TestComponent)GetComponent("TestComponent");
}
}
using(newCustomTimer("GetComponent<ComponentName>",numTests)){
for(vari=0;i<numTests;++i){
test=GetComponent<TestComponent>();
}
}
using(newCustomTimer("GetComponent(typeof(ComponentName))",numTests)){
for(vari=0;i<numTests;++i){
test=(TestComponent)GetComponent(typeof(TestComponent));
}
}
ThiscodetestseachoftheGetComponent()overloadsamilliontimes.Thisisfarmoreteststhanwouldbesensibleforatypicalproject,butitisenoughteststoprovethepoint.
Hereistheresultwegetwhenthetestscomplete:
Asyoucansee,GetComponent(typeof(T))issignificantlyfasterthanGetComponent<T>(),whichisaroundfivetimesfasterthanGetComponent(string).ThistestwasperformedagainstUnity4.5.5,butthebehaviorshouldbeequivalentallthewaybacktoUnity3.x.
Note
http://freepdf-books.com
GetComponent(string)shouldnotbeused,sinceitisnotoriouslyslowandisonlyincludedforcompleteness.
TheseresultschangewhenweruntheexactsametestinUnity5.UnityTechnologiesmadesomeperformanceenhancementstohowSystem.TypereferencesarepassedaroundinUnity5.0,and,asaresult,GetComponent<T>()andGetComponent(typeof(T))becomeessentiallyequivalent:
Asyoucansee,theGetComponent<T>()methodisonlyatinyfractionfasterthanGetComponent(typeof(T)),whileGetComponent(string)isnowaround30timesslowerthanthealternatives(interestingly,itbecameevenslowerthanitwasinUnity4).Multipletestswillprobablyyieldsmallvariationsintheseresults,butultimatelywecanfavoreitherofthetype-basedversionsofGetComponent()whenwe’reworkinginUnity5,andtheoutcomewillbeaboutthesame.
Thereisonecaveat,however.Ifwe’rerunningUnity4,thenwestillhaveaccesstoavarietyofquickaccessorpropertiessuchascollider,rigidbody,camera,andsoon.ThesepropertiesbehavelikeprecachedComponentmembervariables,whicharesignificantlyfasterthanallofthetraditionalGetComponent()methods:
intnumTests=1000000;
Rigidbodytest;
using(newCustomTimer("Cachedreference",numTests))
{
for(vari=0;i<numTests;++i){
test=gameObject.rigidbody;
}
}
NoteNotethatthiscodeisintendedforUnity4,andwillnotcompileinUnity5duetotheremovaloftherigidbodyproperty.
RunningthistestinUnity4givesusthefollowingresult:
Inanefforttoreducedependenciesandimprovecodemodularizationintheengine’sbackend,UnityTechnologieshasdeprecatedallofthesequickaccessorvariablesinUnity5.Onlythetransformpropertyremains.
http://freepdf-books.com
TipUnity4usersconsideringanupgradetoUnity5shouldknowthatupgradingwillautomaticallymodifyanyofthesepropertiestousetheGetComponent<T>()method.However,thiswillresultinuncachedGetComponent<T>()callsscatteredthroughoutyourcode,possiblyrequiringyoutorevisitthetechniquesintroducedintheearliersection,entitledCacheComponentReferences.
ThemoralofthestoryisthatifwearerunningUnity4,andtherequiredComponentisoneofGameObject’sbuilt-inaccessorproperties,thenweshouldusethatversion.Ifnot,thenweshouldfavorGetComponent(typeof(T)).Meanwhile,ifwe’rerunningUnity5,thenwecanfavoreitherofthetype-basedversions:GetComponent<T>()orGetComponent(typeof(T)).
http://freepdf-books.com
http://freepdf-books.com
RemovingemptycallbackdeclarationsWhenwecreatenewMonoBehaviourscriptfilesinUnity,whetherwe’reusingUnity4orUnity5,itcreatestwoboilerplatemethodsforus:
//Usethisforinitialization
voidStart(){
}
//Updateiscalledonceperframe
voidUpdate(){
}
TheUnityenginehooksintothesemethodsduringinitializationandaddsthemtoalistofmethodstocallbackatkeymoments.However,ifweleavetheseasemptydeclarationsinourcodebase,thentheywillcostusasmalloverheadwhenevertheengineinvokesthem.
TheStart()methodisonlycalledwhentheGameObjectisinstantiatedforthefirsttime,whichcanbewheneverthesceneisloadedoranewGameObjectisinstantiatedfromaPrefab.Therefore,leavingtheemptyStart()declarationmaynotbeparticularlynoticeableunlessthere’salotofGameObjectsinthesceneinvokingthematstartuptime.However,italsoaddsunnecessaryoverheadtoanyGameObject.Instantiate()call,whichtypicallyhappensduringkeyevents,sotheycanpotentiallycontributeto,andexacerbate,alreadypoorperformancessituationwhenlotsofeventsarehappeningsimultaneously.
Meanwhile,theUpdate()methodiscalledeverytimethesceneisrendered.IfourscenecontainsthousandsofGameObjectsowningcomponentswiththeseemptyUpdate()declarations,thenwecanbewastingalotofCPUcyclesandcausinghavoconourframerate.
Let’sprovethiswithasimpletest.OurtestsceneshouldhaveGameObjectswithtwotypesofComponent,onetypewithanemptyUpdate()declaration,andanotherwithnomethodsdefined:
publicclassCallbackTestComponent:MonoBehaviour{
voidUpdate(){}
}
publicclassEmptyTestComponent:MonoBehaviour{
}
Herearethetestresultsfor32,768Componentsofeachtype.Ifweenableallobjectswithnostubmethodsduringruntime,thennothinginterestinghappenswithCPUusageintheProfiler.WemaynoticesomememoryconsumptionchangesandsomeslightlydifferentVSyncactivity,butnothingveryconcerning.However,assoonasweenablealltheobjectswithemptyUnitycallbackdeclarations,wewillobserveahugeincreaseinCPUusage:
http://freepdf-books.com
Thefixforthisissimple;deletetheemptydeclarations.Unitywillhavenothingtohookinto,andnothingwillbecalled.Sometimes,findingsuchemptydeclarationsinanexpansivecodebasecanbedifficult,butusingsomebasicregularexpressions(regex),weshouldbeabletofindwhatwe’relookingforrelativelyeasily.
TipAllcommoncode-editingtoolsforUnity,suchasMonoDevelop,VisualStudio,andevenNotepad++,provideawaytoperformaregex-basedsearchontheentirecodebase.Checkthetool’sdocumentationformoreinformation,sincethemethodcanvarygreatlydependingonthetoolanditsversion.
ThefollowingregexsearchshouldfindanyemptyUpdate()declarationsinourcode:
void\s*Update\s*?\(\s*?\)\s*?\n*?\{\n*?\s*?\}
ThisregexchecksforastandardmethoddefinitionoftheUpdate()method,whileincludinganysurpluswhitespaceandnewlinecharactersthatcanbedistributedthroughoutthemethoddeclaration.
Naturally,alloftheaboveisalsotrueforthenon-boilerplateUnitycallbacks,suchasOnGUI(),OnEnable(),OnDestroy(),FixedUpdate(),andsoon.ChecktheMonoBehaviourUnityDocumentationpageforacompletelistofthesecallbacksathttp://docs.unity3d.com/ScriptReference/MonoBehaviour.html.
Itmightseemunlikelythatsomeonegeneratedemptyversionsofthesecallbacksinourcodebase,butneversaynever.Forexample,ifweuseacommonbaseclassMonoBehaviourthroughoutallofourcustomcomponents,thenasingleemptycallbackdeclarationinthatbaseclasswillpermeatetheentiregame,whichcancostusdearly.BeparticularlycarefuloftheOnGUI()method,asitcanbeinvokedmultipletimeswithinthesameframeoruserinterface(UI)event.
http://freepdf-books.com
http://freepdf-books.com
AvoidingtheFind()andSendMessage()methodsatruntimeTheSendMessage()methodandfamilyofGameObject.Find()methodsarenotoriouslyexpensive,andshouldbeavoidedatallcosts.TheSendMessage()methodisabout2,000timesslowerthanasimplefunctioncall,andthecostoftheFind()methodscalesverypoorlywithScenecomplexitysinceitmustiteratethrougheveryGameObjectintheScene.ItissometimesreasonabletocallFind()duringinitializationofaScene,suchasAwake()andStart(),onlyforobjectsthatalreadyexistsintheScene.However,usingeithermethodforinter-objectcommunicationatruntimeislikelytogenerateaverynoticeableoverhead.
RelyingonFind()andSendMessage()typemethodsistypicallysymptomaticofpoordesign,inexperienceinprogrammingwithC#andUnity,orjustplainlazinessduringprototyping.Theirusagehasbecomesomethingofanepidemicamongbeginner-andintermediate-levelprojects,suchthatUnityTechnologiesfeelstheneedtokeepremindinguserstoavoidusingtheminarealgame,overandoveragainintheirdocumentationandattheirconferences.Theyonlyexistasalessprogrammer-ywaytointroducenewuserstointer-objectcommunication,andforsomespecialcaseswheretheycanbeusedinalazy,butresponsible,way.
Tobefair,Unitytargetsawidedemographicofusers,fromindividualhobbyists,students,andthosewithdelusionsofgrandeur,tosmall,mid-sized,andlargedevelopmentteams.Thisresultsinanincrediblywiderangeofsoftwaredevelopmentability.Whenyou’restartingoutwithUnity,itcanbedifficulttofigureoutonyourownwhatyoushouldbedoingdifferently,especiallygivenhowtheUnityenginedoesnotadheretothedesignparadigmsofmanyothergameengines.Ithassomeforeignandquirkyconceptssurroundingscenesandprefabs,aswellasnogodclassentrypoints,noranyobviousraw-datastoragesystemstoworkwith.
Sincewe’retalkingaboutscriptingoptimizationinthissection,let’sexplorethesubjectinsomedetail,discussingsomealternativemethodsforinter-objectcommunication.
Let’sstartbyexaminingaworst-caseexample,whichusesbothFind()andSendMessage()methods,anddiscoversomewaystoimproveuponit.Thefollowingexamplemethodattemptstoinstantiateagivennumberofenemiesfromaprefab,andthennotifiesanEnemyManagerobjectoftheirexistence:
publicvoidSpawnEnemies(intnumEnemies){
for(inti=0;i<numEnemies;++i){
GameObjectenemy=(GameObject)GameObject.Instantiate(_enemyPrefab,
Vector3.zero,Quaternion.identity);
GameObjectenemyManagerObj=GameObject.Find("EnemyManager");
enemyManagerObj.SendMessage("AddEnemy",enemy,
SendMessageOptions.DontRequireReceiver);
}
}
http://freepdf-books.com
Puttingmethodcallsinsidealoop,whichalwaysoutputtothesameresult,isabigredflagforpoorperformance,andwhenwe’redealingwithexpensivemethodssuchasFind(),weshouldalwayslookforwaystocallthemasfewtimesaspossible.Ergo,oneimprovementwecanmakeistomovetheFind()calloutsideoftheforloopandcachetheresultinalocalvariabletobeusedwithintheloop.
WecanalsooptimizeourusageoftheSendMessage()methodbyreplacingitwithaGetComponent()call.Thisreplacesaverycostlymethodwithamuchgentlervariation,achievingeffectivelythesameresult.
Thisgivesusthefollowing:
publicvoidSpawnEnemies(intnumEnemies){
GameObjectenemyManagerObj=GameObject.Find("EnemyManager");
EnemyManagerComponentenemyMgr=
enemyManagerObj.GetComponent<EnemyManagerComponent>();
for(inti=0;i<numEnemies;++i){
GameObjectenemyIcon=(GameObject)GameObject.Instantiate(_enemyPrefab,
Vector3.zero,Quaternion.identity);
enemyMgr.AddEnemy(enemy);
}
}
IfthismethodiscalledduringtheinitializationoftheScene,andwe’renotoverlyconcernedwithloadingtime,thenwecanprobablyconsiderourselvesfinishedwithouroptimizationwork.
However,weoftenneednewobjectsthatareinstantiatedatruntimetofindanexistingobjecttocommunicatewith.Inthisexample,wewantnewenemyobjectstoregisterwithourEnemyManagerComponentsothatitcandowhateveritneedstodotocontroltheenemyobjectsinourScene.WewouldlikeareliableandfastwayfornewobjectstofindexistingobjectswithoutunnecessaryusageoftheFind()method,duetotheoverheadinvolved.
Therearemultipleapproacheswecantaketosolvingthisproblem,eachwiththeirownbenefitsandpitfalls:
StaticclassesSingletonComponentsAssignreferencestopre-existingobjectsAglobalmessagingsystem
http://freepdf-books.com
StaticclassesThisapproachinvolvescreatingaclassthatisgloballyaccessibletotheentirecodebaseatanytime.Theobjectstaysalivefromthemomenttheapplicationstarts,tothemomentitisclosed.Globalmanagerclassesareoftenfrownedupon,sincethenamedoesn’tsaymuchaboutwhatit’smeanttodo,andtheycanbedifficulttodebugsincechangescanoccurfromanywhere,atanypointduringruntime.Inaddition,itisprobablytheleastrobustapproachwhenitcomestochangingorreplacingitatafuturedate.Despiteallofthesedrawbacks,itisbyfartheeasiestsolutiontoimplement,andsowewillcoveritfirst.
TheSingletondesignpatternisacommonwayofensuringthatwehaveaglobally-accessibleobject,andthatonlyoneinstanceeverexistsinmemory.However,thewaythatSingletonsareprimarilyused(notethequalifier)inUnityprojects,canbeeasilyreplacedwithasimpleC#Staticclasswithouttheneedtoimplementprivateconstructors,andtheunnecessarypropertyaccessofanInstancevariable.Essentially,implementingatypicalSingletondesignpatterninC#justtakesmorecode,andtime,toachievethesameresultasastaticclass.
AstaticclassthatfunctionsinmuchthesamewayasourEnemyManagerComponentisusedinthepreviousexamplecanbedefinedasfollows:
usingSystem.Collections.Generic;
publicstaticclassEnemyManager{
staticList<GameObject>_enemies;
publicstaticvoidAddEnemy(GameObjectenemy){
_enemies.Add(enemy);
}
publicstaticvoidRollCall(){
for(inti=0;i<_enemies.Count;++i){
Debug.Log(string.Format("Enemy\"{0}\"reportingin…",
_enemies[i].name));
}
}
}
Notethateverymemberandmethodhasthestatickeywordattached,whichimpliesthatonlyoneinstanceofthisobjectwilleverresideinmemory.Staticclasses,bydefinition,donotallowanynonstaticinstancememberstobedefined,asthatwouldimplythatwecouldsomehowduplicatetheobject.
Staticclassescanbegivenastaticconstructor,whichcanbeusedtoinitializememberdata.Astaticconstructorcanbedefinedlikeso,anditiscalledthemomenttheclassisfirstaccessed(eitherthroughamembervariableoramemberfunction):
staticEnemyManager(){
_enemies=newList<GameObject>();
}
Thistypeofglobalclassisgenerallyconsideredtobeacleanerandeasier-to-useversion
http://freepdf-books.com
ofthetypicalSingletondesignpatternintheworldofC#development.
http://freepdf-books.com
SingletonComponentsThedisadvantageofthestaticclassapproachisthattheymustinheritfromthelowestformofclass—Object.ThismeansthatstaticclassescannotinheritfromMonoBehaviourandthereforewecannotmakeuseofanyofitsUnity-relatedfunctionality,includingtheall-importanteventcallbacks,aswellasCoroutines.Also,sincethere’snoobjecttoselect,welosetheabilitytoinspecttheobject’sdataatruntimethroughtheInspector.ThesearefeaturesthatwemaywishtomakeuseofinourglobalSingletonclasses.
Acommonsolutiontothisproblemistoimplementa“SingletonasaComponent”classthatspawnsaGameObjectcontainingitself,andprovidingstaticmethodstograntglobalaccess.Notethat,inthiscase,wemustessentiallyimplementthetypicalSingletondesignpattern,withprivatestaticinstancevariables,andaglobalInstancemethodforglobalaccess.
HereisthedefinitionforaSingletonAsComponentclass:
publicclassSingletonAsComponent<T>:MonoBehaviourwhereT:
SingletonAsComponent<T>{
privatestaticT__Instance;
protectedstaticSingletonAsComponent<T>_Instance{
get{
if(!__Instance){
T[]managers=
GameObject.FindObjectsOfType(typeof(T))asT[];
if(managers!=null){
if(managers.Length==1){
__Instance=managers[0];
return__Instance;
}elseif(managers.Length>1){
Debug.LogError("Youhavemorethanone"+
typeof(T).Name+"inthescene.Youonly
need1,it'sasingleton!");
for(inti=0;i<managers.Length;++i){
Tmanager=managers[i];
Destroy(manager.gameObject);
}
}
}
GameObjectgo=newGameObject(typeof(T).Name,
typeof(T));
__Instance=go.GetComponent<T>();
DontDestroyOnLoad(__Instance.gameObject);
}
return__Instance;
}
set{
__Instance=valueasT;
}
}
http://freepdf-books.com
}
Sincewewishthistobeaglobalandpersistentobject,weneedtocallDontDestroyOnLoad()shortlyaftertheGameObjectiscreated.ThisisaspecialfunctionthattellsUnitythatwewishtheobjecttopersistbetweenScenesforaslongastheapplicationisrunning.Fromthatpointonward,whenanewsceneisloaded,theobjectwillnotbedestroyedandwillretainallofitsdata.
Thisclassdefinitionassumestwothings.Firstly,becauseitisusinggenericstodefineitsbehavior,itmustbederivedfrominordertocreateaconcreteclass.Secondly,amethodwillbedefinedtoassignthe_Instancevariableandcastitto/fromthecorrectType.
Forexample,thefollowingisallthatisneededtosuccessfullygenerateanewSingletonAsComponentderivedclasscalledMySingletonComponent:
publicclassMySingletonComponent:
SingletonAsComponent<MySingletonComponent>{
publicstaticMySingletonComponentInstance{
get{return((MySingletonComponent)_Instance);}
set{_Instance=value;}
}
}
ThisclasscanbeusedatruntimebyhavinganyotherobjectaccesstheInstancepropertyatanytime.IftheComponentdoesnotalreadyexistinourScene,thentheSingletonAsComponentbaseclasswillinstantiateitsownGameObjectandattachaninstanceofthederivedclasstoitasaComponent.Fromthatpointforward,accessthroughtheInstancepropertywillreferencetheComponentthatwascreated.
TipWhileitispossible,weshouldnotplaceourSingletonAsComponentderivedclassinaSceneHierarchy.ThisisbecausetheDontDestroyOnLoad()methodwillneverbecalled!ThiswouldpreventtheSingletonComponent’sGameObjectfrompersistingwhenthenextSceneisloaded.
PropercleanupofaSingletonComponentcanbealittleconvolutedbecauseofhowUnitytearsdownScenes.Anobject’sOnDestroy()methodiscalledwheneveritisdestroyedduringruntime.Thesamemethodiscalledduringapplicationshutdown,wherebyeveryComponentoneveryGameObjecthasitsOnDestroy()methodcalledbyUnity.ApplicationshutdownalsotakesplacewhenweendPlayModeintheEditorandreturntoEditMode.However,destructionofobjectsoccursinarandomorder,andwecannotassumethattheSingletonComponentwillbethelastobjectdestroyed.
Consequently,ifanyobjectattemptstodoanythingwiththeSingletoninthemiddleoftheirOnDestroy()method,thentheywillbecallingtheInstanceproperty.IftheSingletonhasalreadybeendestroyedpriortothismoment,thencallingInstanceduringanotherobject’sdestructionwouldcreateanewinstanceoftheSingletonComponentinthemiddleofapplicationshutdown!ThiscancorruptourScenefiles,asinstancesofourSingletonComponentswillbeleftbehindintheScene.Ifthishappens,thenUnitywillthrowthefollowingerrormessageatus:
http://freepdf-books.com
ThereasonsomeobjectsmaywishtocallintoourSingletonduringdestructionisthatSingletonsoftenmakeuseoftheObserverpattern.Thisdesignpatternallowsotherobjectstoregister/deregisterwiththemforcertaintasks,similartohowUnitylatchesontocallbackmethods,butinalessautomatedfashion.WewillseeanexampleofthisintheupcomingsectionAglobalmessagingsystem.Objectsthatareregisteredwiththesystemduringconstructionwillwanttoderegisterwiththesystemduringtheirownshutdown,andthemostconvenientplacetodothisiswithinitsOnDestroy()method.Consequently,suchobjectsarelikelytorunintotheaforementionedproblem,whereSingletonsareaccidentallycreatedduringapplicationshutdown.
Tosolvethisproblem,weneedtomakethreechanges.Firstly,weneedtoaddanadditionalflagtotheSingletonComponent,whichkeepstrackofitsactivestate,anddisableitattheappropriatetimes.ThisincludestheSingleton’sowndestruction,aswellasapplicationshutdown(OnApplicationQuit()isanotherusefulUnitycallbackforMonoBehaviours,whichiscalledduringthistime):
privatebool_alive=true;
voidOnDestroy(){_alive=false;}
voidOnApplicationQuit(){_alive=false;}
Secondly,weshouldimplementawayforexternalobjectstoverifytheSingleton’scurrentstate:
publicstaticboolIsAlive{
get{
if(__Instance==null)
returnfalse;
return__Instance._alive;
}
}
Finally,anyobjectthatattemptstocallintotheSingletonduringitsownOnDestroy()method,mustfirstverifythestateusingtheIsAlivepropertybeforecallingInstance.Forexample:
publicclassSomeComponent:MonoBehaviour{
voidOnDestroy(){
if(MySingletonComponent.IsAlive){
MySingletonComponent.Instance.SomeMethod();
}
}
}
ThiswillensurethatnobodyattemptstoaccessInstanceduringdestruction.Ifwedon’tfollowthisrule,thenwewillrunintoproblemswhereinstancesofourSingletonobjectwillbeleftbehindintheSceneafterreturningtoEditMode.
TheironyoftheSingletonComponentapproachisthatweareusingoneofUnity’s
http://freepdf-books.com
Find()methodstodeterminewhetherornotoneoftheseSingletonComponentsalreadyexistsintheScenebeforeweattempttoassignthe__Instancereferencevariable.Fortunately,thiswillonlyhappenwhentheSingletonComponentisfirstaccessed,butit’spossiblethattheinitializationoftheSingletonwouldnotnecessarilyoccurduringSceneinitializationandcanthereforecostusaperformancespikeatabadmomentduringgameplay,whenthisobjectisfirstinstantiatedandFind()getscalled.TheworkaroundforthisistohavesomegodclassconfirmthattheimportantSingletonsareinstantiatedduringSceneinitializationbysimplycallingInstanceoneachone.
Thedownsidetothisapproachisthatifwelaterdecidethatwewantmorethanoneofthesemanagerclassesexecutingatonce,orwewishtoseparateitsbehaviortobemoremodular,thentherewouldbealotofcodethatneedstochange.
Therearefurtheralternativesthatwecanexplore,suchasmakinguseofUnity’sbuilt-inbridgebetweenscriptcodeandtheInspectorinterface.
http://freepdf-books.com
Assigningreferencestopre-existingobjectsAnotherapproachtotheproblemofinter-objectcommunicationistouseUnity’sbuilt-inserializationsystems.Softwaredesignpuriststendtogetalittlecombativeaboutthisfeature,sinceitbreaksencapsulation;itmakesvariablesmarkedprivateactinawaythattreatsthemaspublic.EventhoughthevalueonlybecomespublicwithrespecttotheUnityInspectorandnothingelse,thisisstillenoughtowavesomeredflags.
However,itisaveryeffectivetoolforimprovingdevelopmentworkflow.Thisisparticularlytruewhenartists,designers,andprogrammersarealltinkeringwiththesameproduct,whereeachhaswildlyvaryinglevelsofcomputerscienceandsoftwareprogrammingknowledge.Sometimesit’sworthbendingafewrulesinthenameofproductivity.
Wheneverwecreateapublicvariable,UnityautomaticallyserializesandexposesthevalueintheInspectorinterfacewhentheComponentisselected.However,publicvariablesaredangerousfromasoftwaredesignperspective—thesevariablescanbechangedthroughcodeatanytime,whichcanmakeithardtokeeptrackofthevariable,andintroducealotofunexpectedbugs.
Asanalternative,wecantakeanyprivateorprotectedmembervariableofaclassandexposeittotheUnityEditorInspectorinterfacewiththe[SerializeField]attribute.Thisapproachispreferredoverpublicvariables,asitgivesusmorecontrolofthesituation.Thisway,atleastweknowthevariablescannotbechangedatruntimeviacodeoutsidetheclass(orderivedclass),andthereforemaintainencapsulationfromtheperspectiveofscriptcode.
Forexample,thefollowingclassexposesthreeprivatevariablestotheInspector:
publicclassEnemySpawnerComponent:MonoBehaviour{
[SerializeField]privateint_numEnemies;
[SerializeField]privateGameObject_enemyPrefab;
[SerializeField]privateEnemyManagerComponent_enemyManager;
voidStart(){
SpawnEnemies(_numEnemies);
}
voidSpawnEnemies(int_numEnemies){
for(inti=0;i<_numEnemies;++i){
GameObjectenemy=(GameObject)GameObject.Instantiate(_enemyPrefab,
Vector3.zero,Quaternion.identity);
_enemyManager.AddEnemy(enemy);
}
}
}
TipNotethattheprivateaccessspecifiersshownintheprecedingcodeareredundantkeywordsinC#,asmembervariablesarealwaysprivateunlessspecifiedotherwise,but
http://freepdf-books.com
theseaccessspecifiersareincludedforcompleteness.
LookingatthisComponentintheInspectorviewrevealsthreevalues,initiallygivendefaultvaluesof0,ornull,whichcanbemodifiedthroughtheInspectorinterface:
WecandraganddropaPrefabreferencefromtheProjectswindowintotheEnemyPrefabfield,or,ifwefeltsoinclined,evenareferencetoanotherGameObjectthatispresentintheScene.Although,giventhatit’sbeingusedlikeaPrefabinthecode,itwouldbeunwisetodothis,sincewewouldbecloningaGameObjectthatmighthavealreadyundergonechangesintheScene.PrefabsservethepurposeofablueprintfromwhichtoinstantiatenewGameObjectsandshouldbeusedassuch.
TheEnemyManagerfieldisinterestingbecauseitisaComponentreferenceandnotaGameObjectreference.IfaGameObjectisdroppedintothisfield,thenitwillrefertotheComponentonthegivenobject,asopposedtotheGameObjectthatwedraggedanddroppedintothefield.IfthegivenobjectdoesnothavetheexpectedComponent,thennothingwillbeassigned.
TipAcommonusageoftheComponentreferencetechniqueistoobtainreferencestoComponentsattachedtothesameGameObjectitisattachedto.ThisisanalternativeapproachtothetopicdiscussedinthesectionentitledCacheComponentReferences,earlierinthischapter.
ThedangerhereisthatsincePrefabsareessentiallyGameObjects,PrefabswiththerequiredComponentcanbeassignedtothesefields,eventhoughwemightnotwishthemtobe.UnityloadsPrefabsintomemorymuchlikeGameObjects,andassumesthey’llbeusedinPrefab-likeways;thatis,treatedasnothingmorethanblueprintstobeinstantiatedfromonanas-neededbasis.However,theystillcountasdatastoredinmemoryandcanthereforebeeditedonawhim,makingthemsusceptibletochangesthatdirectlyaffectallfutureGameObjectsinstantiatedfromthem.
Tomakemattersworse,thesechangesbecomepermanenteveniftheyaremadeduringPlayMode,sincePrefabsoccupythesamememoryspacewhetherPlayModeisactiveornot.ThismeansthatwecanaccidentallycorruptourPrefabs,ifweassignthemtothewrongfields.Consequently,thisapproachisamoreteam-friendlywayofsolvingtheoriginalproblemofinter-objectcommunication,butitisnotidealduetoalloftherisksinvolvedwithteammembersaccidentallybreakingthingsorleavingnullreferencesinplace.
ItisalsoimportanttonotethatnotallobjectscanbeserializedbytheInspectorview.
http://freepdf-books.com
Unitycanserializeallprimitivedatatypes(ints,floats,strings,andbools),variousbuilt-intypessuchas(Vector3,Quaternion,andsoon)enums,classes,andstructs,aswellasarraysandlistsofotherserializabletypes.However,itisunabletoserializestaticfields,read-onlyvalues,properties,anddictionaries.
TipSomeUnitydevelopersliketoimplementpseudo-serializationofdictionariesviatwoseparatelistsforkeysandvalues,alongwithaCustomEditorscript,orviaasinglelistofobjects,whichcontainbothkeysandvalues.Bothofthesesolutionsarealittleclumsy,butperfectlyvalid.
Thelastsolutionwewilllookatwillprovideawaytohopefullygetthebestofbothworldsbycombiningeaseofimplementation,easeofextension,andstrictusagethatavoidstoomuchhumanerror.
http://freepdf-books.com
AglobalmessagingsystemThefinalsuggestedapproachtotheproblemofinter-objectcommunicationistoimplementaglobalmessagingsystemthatanyobjectcanaccessandsendmessagesthroughtoanyobjectthatmaybeinterestedinlisteningtothatspecifictypeofmessage.Objectseithersendmessagesorlistenforthem,andtheresponsibilityisonthelistenertodecidewhatmessagesitisinterestedin.Themessagesendercanbroadcastthemessagewithoutcaringatallwhoislistening.Thisapproachisexcellentforkeepingourcodemodularanddecoupled.
Thekindsofmessagewewishtosendcantakemanyforms,suchasincludingdatavalues,references,instructionsforlisteners,andmore,buttheyshouldallhaveacommon,basicdeclarationthatourmessagingsystemcanusetodeterminewhatthemessageis,andwhoitisintendedfor.
ThefollowingisasimpleclassdefinitionforaMessageobject:
publicclassBaseMessage{
publicstringname;
publicBaseMessage(){name=this.GetType().Name;}
}
TheBaseMessageclass’sconstructorcachestheTypeinalocalstringpropertytobeusedlaterforcataloguinganddistributionpurposes.CachingthisvalueisimportantaseachcalltoGetType().Namewillresultinanewstringbeingallocatedontheheap,andwewanttominimizethisasmuchaspossible.Ourcustommessagesmustderivefromthisclass,whichallowsthemtoaddwhateversuperfluousdatatheywish,whilestillmaintainingtheabilitytobesentthroughourmessagingsystem.Takenotethat,despiteacquiringtheTypenameduringthebaseclassconstructor,thenamepropertywillstillcontainthenameofthederivedclass,notthebaseclass.
MovingontoourMessagingSystemclass,weshoulddefineitsfeaturesbywhatkindofrequirementsweneedittofulfill:
ItshouldbegloballyaccessibleAnyobject(MonoBehaviourornot)shouldbeabletoregister/deregisteraslisteners,toreceivespecificmessagetypes(thatis,theObserverpattern)RegisteringobjectsshouldprovideamethodtocallwhenthegivenmessageisbroadcastThesystemshouldsendthemessagetoalllistenerswithinareasonabletimeframe,butnotchokeontoomanyrequestsatonce
AgloballyaccessibleobjectThefirstrequirementmakesthemessagingsystemanexcellentcandidateforaSingletonobject,sinceweshouldonlyeverneedoneinstanceofthesystem.Although,itiswisetothinklongandhardifthisistrulythecasebeforecommittingtoimplementingaSingleton.Ifwelaterdecidethatwewantmultipleinstancesofthisobjecttoexist,thenitcanbedifficulttorefactorduetoallofthedependencieswewillgraduallyintroduceto
http://freepdf-books.com
ourcodebaseasweusethesystemmoreandmore.
Forthisexample,wewillassumethatweareabsolutelypositivethatwewillonlyneedoneofthesesystems,anddesignitaccordingly.
RegistrationMeetingthesecondandthirdrequirementscanbeachievedbyofferingsomepublicmethodsthatallowregistrationwiththemessagingsystem.Ifweforcethelisteningobjecttoprovideusadelegatefunctiontocallwhenthemessageisbroadcast,thenthisallowslistenerstocustomizewhichmethodiscalledforwhichmessage.Thiscanmakeourcodebasemucheasiertounderstand,ifwenamethedelegateafterthemessageitisintendedtoprocess.
TipDelegatefunctionsareincrediblyusefulconstructsinC#thatallowsustopasslocalmethodsaroundasargumentstoothermethods,andaretypicallyusedforcallbacks.ChecktheMSDNC#ProgrammingGuideformoreinformationondelegatesathttps://msdn.microsoft.com/en-us/library/ms173171.aspx.
Insomecases,wemightwishtobroadcastageneralnotificationmessageandhavealllistenersdosomethinginresponse,suchasan“EnemySpawned”message.Othertimes,wemightbesendingamessagethatspecificallytargetsasinglelisteneramongstagroup.Forexample,wemightwishtosendan“EnemyHealthValueChanged”messagethatisintendedforaspecifichealthbarobjectthatisattachedtotheenemythatwasdamaged.Ifweimplementawayforlistenerstostopmessageprocessingearly,thenwecansaveasignificantnumberofCPUcycles,iftherearemanylistenerswaitingforthesamemessagetype.
Thedelegatewedefineshouldthereforeprovideawayofretrievingthemessageviaanargument,andreturnaresponsethatdetermineswhetherornotprocessingforthemessageshouldstopwhenthelistenerisdonewithit.ThedecisiononwhethertostopprocessingornotcanbeachievedbyreturningasimpleBoolean,wheretrueimpliesthatthislistenerhashandledthemessage,andprocessingforthemessagemuststop.
Hereisthedefinitionforthedelegate:
publicdelegateboolMessageHandlerDelegate(BaseMessagemessage);
ListenersmustdefineamethodofthisformandpassareferencetoitwhenitregisterswiththeMessagingSystem,thusprovidinganentrypointforthemessagingsystemtocallwhenthemessageisbroadcast.
MessageprocessingThefinalrequirementforourmessagingsystemisthatthisobjecthassomekindoftiming-basedmechanismbuiltintopreventitfromchokingontoomanymessagesatonce.Thismeansthat,somewhereintheprocess,wewillneedtomakeuseofMonoBehavioureventcallbacksinordertoworkduringUnity’sUpdate()andbeabletocounttime.
http://freepdf-books.com
Thiscanbeachievedwiththestaticclass-basedSingleton(whichwedefinedearlier),whichwouldrequiresomeotherMonoBehaviour-basedgodclasstocallintoit,informingitthattheScenehasupdated.Alternatively,wecanusetheSingletonAsComponenttoachievethesamething,butdosoindependentlyofanygodclass.Theonlydifferencebetweenthetwoiswhetherornotthesystemisdependentonthecontrolofotherobjects.
TheSingletonAsComponentapproachisprobablythebest,sincetherearen’ttoomanyoccasionswherewewouldn’twantthissystemactingindependently,evenifmuchofourgamelogicdependsuponit.Forexample,evenifthegamewaspaused,wewouldn’twantthegamelogictopauseourmessagingsystem.Westillwantthemessagingsystemtocontinuereceivingandprocessingmessagessothatwecan,forexample,keepUI-relatedComponentscommunicatingwithoneanotherwhilethegameplayisinapausedstate.
ImplementingthemessagingsystemLet’sdefineourmessagingsystembyderivingfromtheSingletonAsComponentclass,andprovideamethodforobjectstoregisterwithit:
usingSystem.Collections.Generic;
publicclassMessagingSystem:SingletonAsComponent<MessagingSystem>{
publicstaticMessagingSystemInstance{
get{return((MessagingSystem)_Instance);}
set{_Instance=value;}
}
privateDictionary<string,List<MessageHandlerDelegate>>_listenerDict=
newDictionary<string,List<MessageHandlerDelegate>>();
publicboolAttachListener(System.Typetype,MessageHandlerDelegate
handler){
if(type==null){
Debug.Log("MessagingSystem:AttachListenerfailedduetonomessage
typespecified");
returnfalse;
}
stringmsgName=type.Name;
if(!_listenerDict.ContainsKey(msgName)){
_listenerDict.Add(msgName,newList<MessageHandlerDelegate>());
}
List<MessageHandlerDelegate>listenerList=_listenerDict[msgName];
if(listenerList.Contains(handler)){
returnfalse;//listeneralreadyinlist
}
listenerList.Add(handler);
returntrue;
}
}
http://freepdf-books.com
The_listenerDictvariableisadictionaryofstringsmappedtolistsofMessageHandlerDelegates.Thisdictionaryorganizesourlistenerdelegatesintolistsbywhichmessagetypetheywishtolistento.Thus,ifweknowwhatmessagetypeisbeingsent,thenwecanquicklyretrievealistofalldelegatesthathavebeenregisteredforthatmessagetype.Wecantheniteratethroughthelist,queryingeachlistenertoseeifoneofthemwantstohandleit.
TheAttachListener()methodrequirestwoparameters;amessagetypeintheformofaSystem.Type,andaMessageHandlerDelegatetosendthemessagetowhenitcomesthroughthesystem.
MessagequeuingandprocessingInordertoprocessmessages,ourMessagingSystemshouldmaintainaqueueofincomingmessageobjectssothatwecanprocessthemintheordertheyarebroadcasted:
privateQueue<BaseMessage>_messageQueue=newQueue<BaseMessage>();
publicboolQueueMessage(BaseMessagemsg){
if(!_listenerDict.ContainsKey(msg.name)){
returnfalse;
}
_messageQueue.Enqueue(msg);
returntrue;
}
Themethodsimplychecksifthegivenmessagetypeispresentinourdictionarybeforeaddingittothequeue.Thiseffectivelytestswhetherornotanobjectactuallycarestolistentothemessagebeforewequeueittobeprocessedlater.Wehaveintroducedanewprivatemembervariable,_messageQueue,forthispurpose.
Next,we’lladdadefinitionforUpdate().ThismethodwillbecalledregularlybytheUnityEngine.Itspurposeistoiteratethroughthecurrentcontentsofthemessagequeue,onemessageatime,verifywhetherornottoomuchtimehaspassedsincewebeganprocessing,andifnot,passthemalongtothenextstageintheprocess:
privatefloatmaxQueueProcessingTime=0.16667f;
voidUpdate(){
floattimer=0.0f;
while(_messageQueue.Count>0){
if(maxQueueProcessingTime>0.0f){
if(timer>maxQueueProcessingTime)
return;
}
BaseMessagemsg=_messageQueue.Dequeue();
if(!TriggerMessage(msg))
Debug.Log("Errorwhenprocessingmessage:"+msg.name);
if(maxQueueProcessingTime>0.0f)
timer+=Time.deltaTime;
}
http://freepdf-books.com
}
Thetime-basedsafeguardisinplacetomakesurethatitdoesnotexceedaprocessingtimelimitthreshold.Thispreventsthemessagingsystemfromfreezingourgameiftoomanymessagesgetpushedthroughthesystemtooquickly.Ifthetotaltimelimitisexceeded,thenallmessageprocessingwillstop,leavinganyremainingmessagestobeprocessedduringthenextframe.
Lastly,weneedtodefinetheTriggerMessage()method,whichdistributesmessagestolisteners:
publicboolTriggerMessage(BaseMessagemsg){
stringmsgName=msg.name;
if(!_listenerDict.ContainsKey(msgName)){
Debug.Log("MessagingSystem:Message\""+msgName+"\"hasno
listeners!");
returnfalse;//nolistenersformessagesoignoreit
}
List<MessageHandlerDelegate>listenerList=_listenerDict[msgName];
for(inti=0;i<listenerList.Count;++i){
if(listenerList[i](msg))
returntrue;//messageconsumedbythedelegate
}
returntrue;
}
Thismethodisthemainworkhorseofthemessagingsystem.TheTriggerEvent()‘spurposeistoobtainthelistoflistenersforthegivenmessagetypeandgiveeachofthemanopportunitytoprocessit.Ifoneofthedelegatesreturnstrue,thenprocessingofthecurrentmessageceasesandthemethodexits,allowingtheUpdate()methodtoprocessthenextmessage.
Normally,wewouldwanttouseQueueEvent()tobroadcastmessages,butTriggerEvent()canbecalledinstead.ThismethodallowsmessagesenderstoforcetheirmessagestobeprocessedimmediatelywithoutwaitingforthenextUpdate()event.Thisbypassesthethrottlingmechanism,butthismightbenecessaryformessagesthatneedtobesentduringcriticalmomentsingameplay,wherewaitingoneadditionalframemightresultinstrange-lookingbehavior.
ImplementingacustommessageWe’vecreatedthemessagingsystem,butanexampleofhowtouseitwouldhelpuswrapourheadsaroundtheconcept.Let’sstartbydefiningasimplemessageclass,whichwecanusetotransmitsomedata:
publicclassMyCustomMessage:BaseMessage{
publicreadonlyint_intValue;
publicreadonlyfloat_floatValue;
publicMyCustomMessage(intintVal,floatfloatVal{
_intValue=intVal;
_floatValue=floatVal;
http://freepdf-books.com
}
}
Goodpracticeformessageobjectsistomaketheirmembervariablesreadonly.Thisensuresthatthedatacannotbechangedaftertheobject’sconstruction.Thissafeguardsthecontentofourmessagesagainstbeingaltered,asthey’repassedbetweenonelistenerandanother.
MessageregistrationHere’sasimpleclassthatregisterswiththemessagingsystem,requestingtohaveitsHandleMyCustomMessage()methodcalledwheneveraMyCustomMessageobjectisbroadcastfromanywhereinourcodebase:
publicclassTestMessageListener:MonoBehaviour{
voidStart(){
MessagingSystem.Instance.AttachListener(typeof(MyCustomMessage),
this.HandleMyCustomMessage);
}
boolHandleMyCustomMessage(BaseMessagemsg){
MyCustomMessagecastMsg=msgasMyCustomMessage;
Debug.Log(string.Format("Gotthemessage!{0},{1}",
castMsg._intValue,castMsg._floatValue));
returntrue;
}
}
WheneveraMyCustomMessageobjectisbroadcast(fromanywhere!),thislistenerwillretrievethemessagethroughitsHandleMyCustomMessage()method.Itcanthentypecastitintotheappropriatederivedmessagetypeandhandlethemessageinitsownuniqueway.Otherclassescanregisterforthesamemessage,andhandleitdifferentlythroughitsowncustomdelegatemethod(assuminganearlierobjectdidn’treturntruefromitsowndelegate).
WeknowwhattypeofmessagewillbeprovidedbythemsgargumentoftheHandleMyCustomMessage()method,becausewedefineditduringregistrationthroughtheAttachListener()call.Duetothis,wecanbecertainthatourtypecastingissafe,andwecansavetimebynothavingtodoanullreferencecheck,although,technically,thereisnothingstoppingususingthesamedelegatetohandlemultiplemessagetypes!Inthesecases,thoughwewouldneedtoimplementawayofdeterminingwhichmessageobjectisbeingpassed,andtreatitaccordingly.Thebestapproachistodefineauniquemethodforeachmessagetypeinordertokeepthingsappropriatelydecoupled.
NotehowtheHandleMyCustomMessagemethoddefinitionmatchesthefunctionsignatureofMessageHandlerDelegate,andthatitisbeingreferencedintheAttachListener()call.Thisishowwetellthemessagingsystemwhatmethodtocallwhenthegivenmessagetypeisbroadcast,andhowdelegatesensuretypesafety.Ifthefunctionsignaturehadadifferentreturnvalueoradifferentlistofarguments,thenitwouldbeaninvaliddelegatefortheAttachListener()method,andwewouldgetcompilererrors.
http://freepdf-books.com
Thebeautifulpartisthatwe’refreetogivethedelegatemethodwhatevernamewewant.Themostsensibleapproachistonamethemethodafterthemessagewhichithandles.Thismakesitcleartoanyonereadingourcodewhatthemethodisusedforandwhatmessageobjecttypeisrequiredtocallit.
MessagesendingFinally,let’simplementanexampleofsendingamessagesothatwecantestthissystemout!Here’sacomponentthatwillbroadcastaninstanceofourMyCustomMessageclassthroughthemessagingsystemwhentheSpaceBarispressed:
publicclassTestMessageSender:MonoBehaviour{
publicvoidUpdate(){
if(Input.GetKeyDown(KeyCode.Space)){
MessagingSystem.Instance.QueueMessage(newMyCustomMessage(5,
13.355f));
}
}
}
IfweaddboththeTestMessageSenderandTestMessageListenerobjectstoourSceneandpresstheSpacebar,weshouldseealogmessageappearintheconsole,informingusofasuccessfultest:
OurMessagingSystemSingletonobjectwillbecreatedimmediatelyuponSceneinitialization,whentheTestMessageListener‘sStart()methodiscalledanditregisterstheHandleMyCustomMessagedelegate.NoadditionaleffortisrequiredonourparttocreatetheSingletonweneed.
MessagecleanupSincemessageobjectsareclasses,theywillbecreateddynamicallyinheapmemoryandwillbedisposedofshortlyafterwardswhenthemessagehasbeenprocessedanddistributedamongstalllisteners.However,asyouwilllearninChapter7,MasterfulMemoryManagement,thiswilleventuallyresultinagarbagecollectionasheapmemoryaccumulatesovertime.Ifourapplicationrunsforlongenough,itwilleventuallyresultintheoccasionalgarbagecollection.Therefore,itiswisetousethemessagingsystemsparinglyandavoidspammingmessagestoofrequentlyoneveryupdate.
Themoreimportantclean-upoperationtoconsiderisderegistrationofdelegatesifanobjectneedstobedestroyedorde-spawned.Ifwedon’thandlethisproperly,thenthemessagingsystemwillhangontodelegatereferencesthatpreventobjectsfrombeingfullydestroyedandfreedfrommemory.
Essentially,weneedtopaireveryAttachListener()callwithanappropriateDetachListener()methodwhentheobjectisdestroyed,disabled,orweotherwisedecide
http://freepdf-books.com
thatwenolongerneedittobequeriedwhenmessagesarebeingsent.
ThefollowingmethoddefinitionintheMessagingSystemclasswilldetachalistenerforaspecificevent:
publicboolDetachListener(System.Typetype,MessageHandlerDelegate
handler)
{
if(type==null){
Debug.Log("MessagingSystem:DetachListenerfailedduetonomessage
typespecified");
returnfalse;
}
stringmsgName=type.Name;
if(!_listenerDict.ContainsKey(type.Name)){
returnfalse;
}
List<MessageHandlerDelegate>listenerList=_listenerDict[msgName];
if(!listenerList.Contains(handler)){
returnfalse;
}
listenerList.Remove(handler);
returntrue;
}
HereisanexampleusageoftheDetachListener()method,addedtoourTestMessageListenerclass:
voidOnDestroy(){
if(MessagingSystem.IsAlive){
MessagingSystem.Instance.DetachListener(typeof(MyCustomMessage),
this.HandleMyCustomMessage);
}
}
NotehowthisdefinitionmakesuseoftheIsAlivepropertydeclaredintheSingletonAsComponentclass.Thissafeguardsusagainsttheaforementionedproblemsduringapplicationshutdown,wherewecannotguaranteethattheSingletonwasdestroyedlast.
WrappingupthemessagingsystemCongratulationsareinorder,aswehavefinallybuiltafullyfunctionalglobalmessagingsystemthatanyandallobjectscaninterfacewith,tosendmessagesbetweenoneanother!AusefulfeatureofthisapproachisthatitisMonoBehaviour-agnostic,meaningthatthemessagesendersandlistenersdonotevenneedtoderivefromMonoBehaviourtointerfacewiththemessagingsystem;itjustneedstobeaclassthatprovidesamessagetypeandadelegatefunctionofthematchingfunctionsignature.
AsfarasbenchmarkingtheMessagingSystemclassgoes,weshouldfindthatifitis
http://freepdf-books.com
capableofprocessinghundreds,ifnotthousandsofmessagesinasingleframewithminimalCPUoverhead(dependingontheCPU,ofcourse).TheCPUusageisessentiallythesamewhetheronemessageisbeingdistributedto100differentlisteners,100messagesaredistributedtojustonelistener.Itcostsaboutthesameeitherway.
Evenifwe’repredominantlysendingmessagesduringUIorgameplayevents,thisisprobablyfarmorepowerthanweneed.So,ifitdoesseemtobecausingperformanceproblems,thenit’sfarmorelikelytobecausedbywhatthelistenerdelegatesaredoingwiththemessagethanthemessagingsystem’sabilitytoprocessthosemessages.
Therearemanywaystoenhancethemessagingsystemtoprovidemoreusefulfeatureswemayneedinthefuture,suchas:
Allowmessagesenderstosuggestadelay(intimeorframecount)beforeamessageisprocessedanddistributedAllowmessagelistenerstodefineapriorityforhowurgentlyitshouldreceivemessagescomparedtootherlistenerswaitingforthesamemessagetype—awayofskippingtothefrontofthequeueifitregisteredlaterthanotherlistenersImplementsomesafetycheckstohandlesituationswherealistenergetsaddedtothelistofmessagelistenersforaparticularmessage,whileamessageofthattypeisstillbeingprocessed—C#willthrowanenumerationexceptionatussincethedelegatelistwillbechangedbyAttachListener(),whileitisstillbeingiteratedthroughinTriggerEvent()
Atthispoint,wehaveprobablyexploredmessagingsystemsenough,sothesetaskswillbeleftasanacademicexerciseforyoutoundertake,ifyoubecomecomfortableusingthissolutioninyourgames.
Let’sexploresomefurthertechniquesthatwecanusetoimproveperformancethroughscripting.
http://freepdf-books.com
http://freepdf-books.com
DisablingunusedscriptsandobjectsScenescangetprettybusysometimes,especiallywhenwe’rebuildinglarge,openworlds.ThemoreobjectsinvokingcodeinanUpdate()method,theworsethingswillscaleandthesloweryourgamebecomes.However,muchofwhatisbeingprocessedmaybecompletelyunnecessaryifitisoutsideoftheplayer’svieworsimplytoofarawaytomatter.Thismaynotbeapossibilityinlargecity-buildingsimulationgameswheretheentiresimulationmustbeprocessedatalltimes,butitisoftenpossibleinfirstpersonandracinggames,wheretheplayeriswanderingaroundalargeexpansivearea,wherenon-visibleobjectscanbetemporarilydisabledwithouthavinganynoticeableeffectongameplay.
http://freepdf-books.com
DisablingobjectsbyvisibilitySometimes,wewantComponentsorGameObjectstobedisabledwhenthey’renotvisible.Unitycomeswithbuilt-inrenderingfeaturestoavoidrenderingobjectsthatarenotvisiblebyCameras(FrustumCulling,whichisautomaticinallversions),andtoavoidrenderingobjectsthatarehiddenbehindotherobjects(OcclusionCulling,tobediscussedinChapter6,DynamicGraphics),butthisdoesnotaffectComponentsthatarenon-renderable,suchasAIscripts.Wemustcontrolthatbehaviorourselves.
ThisproblemcanbesolvedeasilybyusingtheOnBecameVisible()andOnBecameInvisible()MonoBehaviourcallbacks.Asthenamesimply,thesecallbackmethodsareinvokedwhenarenderableobjecthasbecomevisibleorinvisiblewithrespecttothegameviewandanyCamerasinourScene.Inaddition,whentherearemultipleCamerasinaScene(forexample,alocalmultiplayergame),thecallbacksareonlyinvokediftheobjectbecomesvisibletoanyoneCamera,andbecomesinvisibletoallCameras.Thismeanstheaforementionedcallbackswillbecalledatexactlytherighttimestoimplementthisfeature.
Sincethevisibilitycallbacksrelatetoandcommunicatewiththerenderingsystem,theGameObjectmusthavearenderableobjectattached,suchasaMeshorSkinnedMesh.WemustensurethattheComponentswewanttoreceivethevisibilitycallbacksfromareattachedtothesameGameObjectastherenderableobjectandnotsomeparentorsub-object,otherwisetheywon’tbeinvoked.
TipNotethatUnityalsocountsthehiddencameraoftheSceneViewtowardstheOnBecameVisible()andOnBecameInvisible()callbacks.IfwefindthatthesemethodsarenotbeinginvokedproperlyduringPlayModetesting,makesuretoturntheSceneViewCameraawayfromeverything.
Toenable/disableindividualcomponentswiththevisibilitycallbacks,wecanaddthefollowingmethods:
voidOnBecameVisible(){enabled=true;}
voidOnBecameInvisible(){enabled=false;}
And,toenable/disabletheentireGameObjecttheComponentisattachedto,wecanimplementthemethodsthiswayinstead:
voidOnBecameVisible(){gameObject.SetActive(true);}
voidOnBecameInvisible(){gameObject.SetActive(false);}
http://freepdf-books.com
DisablingobjectsbydistanceInothersituations,wewantComponentsorGameObjectstobedisabledaftertheyarefarenoughawayfromtheplayer,suchthattheymaybebarelyvisible,buttoofarawaytomatter.AgoodcandidateforthistypeofactivityisroamingAIcreaturesthatwewanttoseeatadistance,butwherewedon’tneedittoprocessanything.
ThefollowingcodeisasimpleCoroutinethatperiodicallychecksthetotaldistancefromthetargetobjectanddisablesitselfifitstraystoofarawayfromit:
[SerializeField]GameObject_target;
[SerializeField]float_maxDistance;
[SerializeField]int_coroutineFrequency;
voidStart(){
StartCoroutine(DisableAtADistance());
}
IEnumeratorDisableAtADistance(){
while(true){
floatdistSqrd=(Transform.position-
_target.transform.position).sqrMagnitude;
if(distSqrd<_maxDistance*_maxDistance){
enabled=true;
}else{
enabled=false;
}
for(inti=0;i<_coroutineFrequency;++i){
yieldreturnnewWaitForEndOfFrame();
}
}
}
WeshouldassignthePlayerobject(orwhateverobjectwewantittocomparewith)tothe_targetfieldintheInspector,definethemaximumdistancein_maxDistance,andmodifythefrequencywithwhichtheCoroutineisinvokedbyusingthe_coroutineFrequencyproperty.Anytimetheobjectgoesfurtherthan_maxDistancedistanceawayfromtheobjectassignedto_target,itwillbedisabled.Itwillbere-enabledifitreturnswithinthatdistance.
Asubtleperformance-enhancingfeatureofthisimplementationiscomparingagainstdistance-squaredinsteadoftherawdistance.Thisleadsusconvenientlytoournexttip.
http://freepdf-books.com
http://freepdf-books.com
Considerusingdistance-squaredoverdistanceItissafetosaythatCPUsarerelativelygoodatmultiplyingfloating-pointnumberstogether,butrelativelydreadfulatcalculatingsquarerootsfromthem.EverytimeweaskaVector3tocalculateadistancewiththemagnitudepropertyorwiththeDistance()method,we’reaskingittoperformasquarerootcalculation(asperthePythagoreantheorem),whichcancostalotofCPUoverheadcomparedtomanyothertypesofvectormathcalculations.
However,theVector3classalsooffersasqrMagnitudeproperty,whichisthesameasdistance,onlysquared.Thisletsusperformessentiallythesamecomparisoncheckwithouttheexpensivesquarerootincluded,solongaswealsosquarethevaluewe’retryingtocompareitagainst;or,todescribethismathematically,ifthemagnitudeofAislessthanthemagnitudeofB,thenA2willbelessthanB2.
Forexample,considercodelikethefollowing:
floatdistance=(transform.position–
other.transform.position).Distance();
if(distance<targetDistance){
//dostuff
}
Thiscanbereplacedwiththefollowingandachieveanearlyidenticalresult:
floatdistanceSqrd=(transform.position–
other.transform.position).sqrMagnitude;
if(distanceSqrd<targetDistance*targetDistance){
//dostuff
}
Thereasontheresultisnearlyidenticalisbecauseoffloating-pointprecision.We’relikelytolosesomeoftheprecisionthatwewouldhavehadfromusingthesquare-rootvalues,sincethevaluewillbeadjustedtoanareawithadifferentdensityofrepresentablenumbers;itcanlandexactlyon,orcloserto,amoreaccuraterepresentablenumber,or,morelikely,itwilllandonanumberwithlessaccuracy.Asaresult,thecomparisonisnotexactlythesame,butinmostcases,itiscloseenoughtobeunnoticeable,andtheperformancegaincanbequitesignificantforeachinstructionwereplaceinthismanner.
Ifthisminorprecisionlossisnotimportanttoyou,thenthisperformancetrickshouldbeconsidered.However,ifprecisionisveryimportanttoyou(suchasrunninganaccuratelarge-scalegalacticspacesimulation),thenyoumightwanttolookelsewhereforperformanceimprovements.
Notethatthistechniquecanbeusedforanysquare-rootcalculations;notjustfordistance.Thisissimplythemostcommonexampleyoumightrunacross,andbringtolighttheimportantsqrMagnitudepropertyoftheVector3class—apropertywhichUnityTechnologiesintentionallyexposedforustomakeuseofinthismanner.
http://freepdf-books.com
http://freepdf-books.com
http://freepdf-books.com
AvoidretrievingstringpropertiesfromGameObjectsOrdinarily,retrievingastringpropertyfromanobjectisthesameasretrievinganyotherreferencetypepropertyinC#;itisacquiredwithnoadditionalmemorycost.However,forwhateverarcanereasonhiddenwithintheUnitysourcecode,retrievingstringpropertiesfromGameObjectsduplicatesthestringinmemoryandresultsinaheapallocation.ThisdrawstheattentionoftheGarbageCollector,which,ifwearenotcareful,cancauseCPUspikesthatwillaffectperformanceduringruntime.
ThetwopropertiesofGameObjectaffectedbythisstrangebehavioraretagandname.Retrievingeitherofthesepropertiesforanyreasonwillcauseunnecessaryheapallocations.Therefore,itisunwisetouseeitherpropertyduringgameplay,andyoushouldonlyusetheminperformance-inconsequentialareassuchasEditorScripts.However,theTagsystemiscommonlyusedforruntimeidentificationpurposes,whichcanmakethisasignificantproblemforsometeams.
Forexample,thefollowingcodewouldcauseanadditionalheapmemoryallocationduringeveryiterationoftheloop:
for(inti=0;i<listOfObjects.Count;++i){
if(listOfObjects[i].tag=="Player"){
//dosomethingwiththisobject
}
}
ItisoftenbetterpracticetoidentifyobjectsbytheirComponents,classtypes,andidentifyingvaluesthatdonotinvolvestrings,butsometimeswe’reforcedintoacorner.Maybewedidn’tknowanybetterwhenwestarted,weinheritedsomeoneelse’scodebase,orwe’reusingitasaworkaroundforsomething.Let’sassumethat,forwhateverreason,we’restuckwiththeTagsystem,andwewanttoavoidtheseheapallocations.
Fortunately,thetagpropertyismostoftenusedincomparisonsituations,andGameObjectprovidesanalternativewaytocomparetagproperties,whichdoesnotcauseaheapallocation—theCompareTag()method.
Let’sperformasimpletesttoprovehowthissimplechangecanmakeallthedifferenceintheworld:
voidUpdate(){
intnumTests=10000000;
if(Input.GetKeyDown(KeyCode.Alpha1)){
for(inti=0;i<numTests;++i){
if(gameObject.tag=="Player"){
//dostuff
}
}
}
if(Input.GetKeyDown(KeyCode.Alpha2)){
http://freepdf-books.com
for(inti=0;i<numTests;++i){
if(gameObject.CompareTag("Player")){
//dostuff
}
}
}
}
Wecanexecutethesetestsbypressingthe1and2keystotriggertherespectiveforloop.Herearetheresults:
LookingattheBreakdownviewforeachspike,wecanseetwocompletelydifferentsituations:
Retrievingthetagproperty10milliontimesresultsinabout363MBofmemorybeingallocatedjustforstringsalone.Thistakes2435millisecondstoprocess,where488millisecondsarespentongarbagecollection.Meanwhile,usingCompareTag()10milliontimescosts1788millisecondstoprocess,andcausesnoheapmemoryallocations,andhencenoGarbageCollection.Thisshouldmakeitabundantlyclearthatwemustavoidusingthenameandtagproperties.So,ifTagcomparisonbecomesnecessary,thenweshouldmakeuseofCompareTag().
Notethatpassinginastringliterallike"Player"doesnotresultinaruntimeheapallocation,sincetheapplicationtechnicallyallocatesthisvalueduringinitializationandmerelyreferencesitatruntime.However,ifwedynamicallygeneratethecomparisonstring,thenwewillrunintothesameheapmemoryallocationproblems,becausewe’reessentiallycreatinganewstringobjecteachtime.
http://freepdf-books.com
YouwilllearnmorenuancesabouttheGarbageCollectorandstringusageinChapter7,MasterfulMemoryManagement.
http://freepdf-books.com
http://freepdf-books.com
Update,Coroutines,andInvokeRepeatingUpdateiscalledeveryframe,butsometimeswehackinwaysfortheUpdatetobecalledlessfrequentlythannormal,andperhaps,withoutrealizingit,wecreateasituationwhereanemptymethodiscalledmoreoftenthannot:
voidUpdate(){
_timer+=Time.deltaTime;
if(_timer>_aiUpdateFrequency){
ProcessAI();
_timer-=_aiUpdateFrequency;
}
}
Withthisfunctiondefinition,weareessentiallycallinganemptyfunctionalmosteveryframe.Infact,itisworsethanthat;we’realsoperformingaBooleancheckthatalmostalwaysreturnsfalse.Thisisfineifwedon’tabusetheconcept,butasyou’velearned,havingtoomanyoftheseunnecessaryfunctioncallshidinginourScenecanbeasneakyhitonourperformance.
ThisfunctionisaperfectexampleofafunctionwecanconvertintoaCoroutinetomakeuseoftheirdelayed-invocationproperties:
voidStart(){
StartCoroutine(UpdateAI());
}
IEnumeratorUpdateAI(){
while(true){
yieldreturnnewWaitForSeconds(_aiUpdateFrequency);
ProcessAI();
}
}
However,thisapproachhasitsdrawbacks.Forone,aCoroutinecomeswithanadditionaloverheadcostrelativetoastandardfunctioncall(aroundtwiceasslow),aswellassomeheapmemoryallocationstostorethecurrentstateinmemoryuntilthenexttimeitisinvoked.Secondly,onceinitialized,Coroutinesrunindependent,oftheGameObject’sUpdate()processandwillbeinvokedregardlessofwhethertheGameObjecthasbeendisabledornot.Caremustbetakenbeforedecidingtoadoptthisapproach.
However,ifthesituationisappropriate,thebenefitsofcallingnothingduringmostframes,oftenoutweighstheadditionalcostduringtheframeswhereitisinvoked.Indeed,ifwearen’tperformingtoomanycomplexthingswithyieldstatements,thenwecanoftencreateanevensimplerversionofthemethodusingInvokeRepeating(),whichhasaslightlysmalleroverheadcost(about1.5timesslowerthanastandardfunctioncall):
voidStart(){
InvokeRepeating("ProcessAI",0f,_aiUpdateFrequency);
}
NotethatInvokeRepeatingisalsoindependentoftheGameObject’sUpdate()method,
http://freepdf-books.com
andwillcontinuetobeinvokedeveniftheobjectisdisabled.
Regardlessofwhichapproachwepick,thereisanadditionalrisk—havingtoomanymethodstriggeringinthesameframesimultaneously.ImaginethousandsoftheseobjectsthatinitializedtogetherduringSceneinitialization.Everytime_aiUpdateFrequencysecondsgoby,theywillallinvoketheProcessAI()methodwithinthesameframe,andcauseahugespikeinCPUusage.
Possiblesolutionstothisprobleminclude:
GeneratinganewrandomtimetowaiteachtimethetimerexpiresorCoroutinetriggersSpreadoutCoroutineinitializationsothatonlyahandfulofthemarestartedeachframeDelegatetheresponsibilityofcallingupdatestosomemasterclassthatplacesalimitonthenumberofinvocationsthatoccureachframe
ReducingexcessiveUpdatedefinitionstoasimpleCoroutinecanpotentiallysaveusalotofunnecessaryoverhead,soweshouldconsiderconvertingthemwheneverwefeelitisappropriate.However,wemightalsoconsiderre-evaluatingoursolutiontotheoriginalprobleminordertopreventlotsoftimedeventsalltriggeringatthesamemoment.
AnotherapproachtooptimizingupdatesistonotuseUpdate()atall,ormoreaccurately,toonlyuseitonce.WhenUnitycallsUpdate(),itinvolvesbridgingthegapbetweenaGameObject’snativeandmanagedrepresentationoftheGameObject,whichcanbeacostlytask.Youwilllearnmoreaboutthisnative-managedbridgeinChapter7,MasterfulMemoryManagement,butfornow,justconsiderthateverycallbackwerelyonUnitytoinvokeforuscomeswithahiddenprocessingcostattachedrelativetoastandardfunctioncall.
Wecanthereforeminimizethisoverheadbylimitinghowoftenitneedstocrossthebridge.Wecandothisbyhavingagodclasstakecareofcallingourowncustomupdate-stylemethodacrossallofourcustomComponents,initsowndefinitionofUpdate().Infact,manyUnitydeveloperspreferthisapproachrightfromthestartoftheirprojects,asitgivesthemfinercontroloverwhenandhowupdatespropagatethroughoutthesystem,forthingssuchasmenupausingandcooltimemanipulationeffects.
Allobjectswantingtointegratewithsuchasystemmusthaveacommonentrypoint.Wecanachievethisthroughaninterfaceclass.Interfacesessentiallysetupacontractwherebyanyclassthatimplementstheinterfacemustprovideaspecificseriesofmethods.Inotherwords,ifweknowtheobjectimplementsaninterface,thenwecanbecertainaboutwhatmethodsareavailable.InC#,classescanonlyderivefromasinglebaseclass,buttheycanimplementanynumberofinterfaces(thisavoidsthe“deadlydiamondofdeath”problemthatC++programmersmaybefamiliarwith).
Thefollowinginterfacedefinitionwillsuffice,whichonlyrequirestheimplementingclasstodefineasinglemethod:
publicinterfaceIUpdateable{
voidOnUpdate(floatdt);
http://freepdf-books.com
}
Next,we’lldefineaMonoBehaviourclass,whichimplementsthisinterface:
publicclassUpdateableMonoBehaviour:MonoBehaviour,IUpdateable
{
publicvirtualvoidOnUpdate(floatdt){}
}
Notethatwe’renamingthemethodOnUpdate()ratherthanUpdate().We’redefiningacustomversionofthesameconcept,butwewanttoavoidnamecollisionswiththestandardUpdate()callback.
TheOnUpdate()methodoftheUpdateableMonoBehaviourclassretrievesthecurrentdeltatime(dt),tospareusfromabunchofunnecessaryTime.deltaTimecalls.We’vealsomadethefunctionvirtual,toallowderivedclassestocustomizeit.However,asyouknow,UnityautomaticallygrabsandinvokesmethodsdefinedwiththenameUpdate(),butsincewe’redefiningourowncustomupdatewithadifferentname,thenweneedtoimplementsomethingthatwillcallthismethodwhenthetimeisappropriate;somekindof“GameLogic”godclass.
DuringtheinitializationofthisComponent,weshoulddosomethingtonotifyourGameLogicobjectofbothitsexistenceanditsdestruction,sothatitknowswhentostartandstopcallingitsOnUpdate()function.
Inthefollowingexample,wewillassumethatourGameLogicclassisaSingletonComponent,asdefinedearlierinthesectionentitledSingletonComponents,andhasappropriatestaticfunctionsdefinedforregistrationandderegistration(althoughbearinmindthatitcanjustaseasilyuseourmessagingsystem!).
ForMonoBehaviourstohookintothissystem,themostappropriateplaceiswithinStart()andOnDestroy():
voidStart(){
GameLogic.Instance.RegisterUpdateableObject(this);
}
voidOnDestroy(){
GameLogic.Instance.DeregisterUpdateableObject(this);
}
ItisbesttousetheStart()methodforthistask,sinceusingStart()meansthatwecanbecertainallotherpre-existingComponentswillhaveatleasthadtheirAwake()methodscalledpriortothismoment.Thisway,anycriticalinitializationworkwillhavealreadybeendoneontheobjectbeforewestartinvokingupdatesonit.
Notethat,becausewe’reusingStart()inaMonoBehaviourbaseclass,ifwedefineaStart()methodinaderivedclass,thenitwilleffectivelyoverridethebase-classdefinitionandUnitywillgrabthederivedStart()methodasacallbackinstead.Itwould,therefore,bewisetoimplementavirtualInitialize()methodsothatderivedclassescanoverrideittocustomizeinitializationbehaviorwithoutinterferingwiththebaseclass’staskofnotifyingtheGameLogicobjectofourcomponent’sexistence.
http://freepdf-books.com
Forexample:
voidStart(){
GameLogic.Instance.RegisterUpdateableObject(this);
Initialize();
}
protectedvirtualvoidInitialize(){
//derivedclassesshouldoverridethismethodforinitializationcode
}
Weshouldtrytomaketheprocessasautomaticaspossibletospareourselveshavingtore-implementthesetasksforeachnewComponentwedefine.AssoonasaclassinheritsfromourUpdateableMonoBehaviourclass,thenshouldbesecureintheknowledgethatitsOnUpdate()methodwillbecalledwheneveritisappropriate.
Finally,weneedtoimplementtheGameLogicclass.TheimplementationisprettymuchthesamewhetheritisaSingletonComponentorastandaloneComponent,andwhetherornotitusestheMessagingSystem.Eitherway,ourUpdateableMonoBehaviourclassmustregisterandderegisterasIUpdateableObjectobjects,andtheGameLogicclassmustuseitsownUpdate()callbacktoiteratethrougheveryregisteredobjectandcalltheirOnUpdate()function.
HereistheclassdefinitionfortheGameLogicsystem:
publicclassGameLogic:SingletonAsComponent<GameLogic>{
publicstaticGameLogicInstance{
get{return((GameLogic)_Instance);}
set{_Instance=value;}
}
List<IUpdateableObject>_updateableObjects=newList<IUpdateableObject>();
publicvoidRegisterUpdateableObject(IUpdateableObjectobj){
if(!_Instance._updateableObjects.Contains(obj)){
_Instance._updateableObjects.Add(obj);
}
}
publicvoidDeregisterUpdateableObject(IUpdateableObjectobj){
if(_Instance._updateableObjects.Contains(obj)){
_Instance._updateableObjects.Remove(obj);
}
}
voidUpdate(){
floatdt=Time.deltaTime;
for(inti=0;i<_Instance._updateableObjects.Count;++i){
_Instance._updateableObjects[i].OnUpdate(dt);
}
}
}
IfwemakesureallofourcustomMonoBehavioursinheritfromthe
http://freepdf-books.com
UpdateableMonoBehaviourclass,thenwe’veeffectivelyreplacedNinvocationsoftheUpdate()callbackwithjustoneUpdate()callback,plusNvirtualfunctioncalls.Thiscansaveusalargeamountofperformanceoverhead,becauseeventhoughwe’recallingvirtualfunctions,we’restillkeepingtheoverwhelmingmajorityofupdatebehaviorinsidemanagedcode,andavoidingthenative-managedbridgeasmuchaspossible.
Dependingonhowdeepyoualreadyareintoyourcurrentproject,suchchangescanbeincrediblydaunting,time-consuming,andlikelytointroducealotofbugsassubsystemsareupdatedtomakeuseofacompletelydifferentsetofdependencies.However,thebenefitscanoutweightherisksiftimeisonyourside.ItwouldbewisetodosometestingonagroupofobjectsinaScenethatissimilarlydesignedtoyourcurrentScenefilestoverifyifthebenefitsoutweighthecosts.
http://freepdf-books.com
http://freepdf-books.com
ConsidercachingTransformchangesTheTransformComponentonlystoresdatarelativetoitsownparent.ThismeansthataccessingandmodifyingaTransformComponent’sposition,rotation,andscalepropertiescanresultinalotofunanticipatedmatrixmultiplicationcalculationstogeneratethecorrectTransformrepresentationfortheobjectthroughitsparents’Transforms.ThedeepertheobjectisintheHierarchy,themorecalculationsareneededtodeterminethefinalresult.Tomakemattersworse,changestoaTransformComponentalsosendinternalnotificationstocolliders,rigidbodies,lights,andcameras,whichmustbeprocessed.
However,thisalsomeansthatusinglocalPosition,localRotation,andlocalScalehavearelativelytrivialcostassociatedwiththem,becausethevaluescanberetrievedandwrittenastheyarepassedin.Therefore,theselocalpropertyvaluesshouldbeusedwheneverpossible.However,changingourmathematicalcalculationsfromworldspacetolocalspacecanovercomplicatewhatwereoriginallysimple(andsolved!)problems,somakingsuchchangesrisksbreakingourimplementationandintroducingalotofunexpectedbugs.Sometimesit’sworthabsorbingaminorperformancehitinordertosolveacomplex3Dmathematicalproblemmoreeasily!
Inaddition,itisnotuncommon,duringsomecomplexevent,wereplaceaTransform’spropertiesmultipletimesinthesameframe(althoughthisisprobablyawarningsignofover-engineereddesign).WecanconsiderminimizingthenumberoftimeswemodifytheTransformvaluesbycachingtheminamembervariableandcommittingthemonlyattheendoftheframe,asfollows:
privatebool_positionChanged;
privateVector3_newPosition;
publicvoidSetPosition(Vector3position){
_newPosition=position;
_positionChanged=true;
}
voidFixedUpdate(){
if(_positionChanged){
transform.position=_newPosition;
_positionChanged=false;
}
}
ThiscodewillonlycommitchangestothepositioninthenextFixedUpdate()method.
Notethatthiswillnotresultinsluggish-lookingbehaviorduringgameplay,sinceallphysicscalculationsareperformedimmediatelyafterFixedUpdate().TherewouldnotbeanyframesrenderedbeforethephysicsenginegetsachancetorespondtotheTransformchange.
http://freepdf-books.com
http://freepdf-books.com
FasterGameObjectnullreferencechecksItturnsoutthatperforminganullreferencecheckagainstaUnityobjectinvokesamethodontheothersideofthenative-managedbridge(mentionedearlierandexploredinmoredetailinChapter7,MasterfulMemoryManagement),which,asexpected,resultsinsomeunnecessaryperformanceoverhead:
if(gameObject!=null){
//dostuffwithgameObject
}
Thereisasimplealternativethatgeneratesafunctionallyequivalentoutput,butoperatesaroundtwiceasquickly(althoughitdoesobfuscatethepurposeofthecodealittle):
if(!System.Object.ReferenceEquals(gameObject,null)){
//dostuffwithgameObject
}
ThisappliestobothGameObjectsandComponents,aswellasotherUnityobjects,whichhavebothnativeandmanagedrepresentations.However,somerudimentarytestingrevealsthateitherapproachstillconsumesmerenanosecondsonanIntelCorei53570Kprocessor.So,unlessyouareperformingmassiveamountsofnullreferencechecks,thenthegainsmightbemarginalatbest.
However,itisnoteworthyinthesensethattherecanbemanyothersimplealternativesthathaveyettobediscovered,whichcanhelpimproveperformancebycircumventingthenative-managedbridge.
http://freepdf-books.com
http://freepdf-books.com
SummaryThischapterintroducedyoutomanymethodsofimprovingyourscriptingpracticesintheUnityEngine,withtheaimofimprovingperformanceif(andonlyif)youhavealreadyproventhemtobethecauseofaperformanceproblem.Someofthesetechniquesdemandsomeforethoughtandprofilinginvestigationbeforebeingimplemented,sincetheyoftencomewithintroducingadditionalrisksorobfuscatingourcodebasefornewdevelopers.Workflowisoftenjustasimportantasperformanceanddesign,sobeforeyoumakeanyperformancechangestothecode,youshouldconsiderwhetherornotyou’resacrificingtoomuchonthealtarofperformanceoptimization.
Wewillinvestigatemoreadvancedscriptingimprovementtechniqueslater,inChapter7,MasterfulMemoryManagement,butlet’stakeabreakfromstaringatcodeandexploresomewaystoimproveapplicationperformanceusingbuilt-inUnityfeaturessuchasStaticandDynamicBatching.
http://freepdf-books.com
http://freepdf-books.com
Chapter3.TheBenefitsofBatchingIn3Dgraphicsandgames,batchingisaverygeneraltermdescribingtheprocessofgroupingalargenumberofwaywardpiecesofdataandprocessingthemtogetherasasingle,largeblockofdata.Thegoalofthisprocessistoreducecomputationtime,oftenbyexploitingparallelprocessingorreducingoverheadcosts,iftheentirebatchistreatedasindividualelements.Insomecases,theactofbatchingcentersaroundmeshes,largesetsofvertices,edges,UVcoordinates,andsoon,whichareusedtorepresenta3Dobject.However,thetermcouldjustaseasilyrefertotheactofbatchingaudiofiles,sprites,andtexturefiles(alsoknownasAtlasing),andotherlargedatasets.
So,justtoclearupanyconfusion,whenthetopicofbatchingismentionedinUnity,itisusuallyreferringtothetwoprimarymechanismsitoffersforbatchingmeshfiles:StaticandDynamicBatching.Thesemethodsareessentiallyaformofgeometryinstancing,whereweusethesamemeshdatainmemorytorepeatedlyrenderthesameobjectmultipletimeswithoutneedingtopreparethedatamorethanonce.
Thesebatchingfeaturesofferusopportunitiestoimprovetheperformanceofourapplication,butonlyaslongastheyareusedwisely.Theyarefairlynuancedsystems,andtherehasbeenalotofconfusionsurroundingtheconditionsthattheyaretriggeredunder,andjustasimportantly,underwhatconditionswewouldevenseeaperformanceimprovement.Insomecases,batchingcanactuallydegradeperformanceifbatchesareaskedtoprocessdatasetsunderconditionsthatdon’tfitaveryparticularmold.
ThebatchingsystemsinUnityaremostlyablackbox,inwhichUnitytechnologieshavenotrevealedmuchdetailed,technicalinformationabouttheirinnerworkings.But,basedontheirbehavior,profilerdata,andthelistofrequirementsneededtomakethemwork,wecanstillinferagreatdeal.Thischapterintendstodispelmuchofthemisinformationfloatingaroundaboutbatchingsystems.Wewillobserve,viaexplanation,exploration,andexamples,justhowthesetwobatchingmethodsoperate.Thiswillenableustomakeinformeddecisions,makingthemostofthemtoimproveourapplication’sperformance.
http://freepdf-books.com
DrawCallsBeforewediscussStaticandDynamicBatchingindependently,let’sfirstunderstandtheproblemsthattheyarebothtryingtosolvewithinthegraphicspipeline.Wewilltrytokeepfairlylightonthetechnicalities.WewillexplorethistopicingreaterdetailinChapter6,DynamicGraphics.
TheprimarygoalofthesebatchingmethodsistoreducethenumberofDrawCallsrequiredtorenderallobjectsinthecurrentview.Atitsmostbasicform,aDrawCallisarequestsentfromtheCPUtotheGPU,askingittodrawanobject.But,beforeaDrawCallcanberequested,severalimportantcriterianeedtobemet.Firstly,meshandtexturedatamustbepushedfromtheCPUmemory(RAM)intoGPUmemory(VRAM),whichtypicallytakesplaceduringinitializationoftheScene.Next,theCPUmustpreparetheGPUbyconfiguringtheoptionsandrenderingfeaturesthatareneededtoprocesstheobjectthatisthetargetoftheDrawCall.
ThesecommunicationtasksbetweentheCPUandGPUtakeplacethroughtheunderlyinggraphicsAPI,whichcouldbeeitherDirectXorOpenGLdependingontheplatformwe’retargetingandcertaingraphicssettings.TheseAPIsfeaturemanycomplexandinterrelatedsettings,statevariables,anddatasetsthatcanbeconfigured,andtheavailablefeatureschangeenormouslybasedonthehardwaredevicewe’reoperatingon.ThemassivearrayofsettingsthatcanbeconfiguredbeforerenderingasingleobjectisoftencondensedintoasingletermknownastheRenderState.UntiltheseRenderStateoptionsarechanged,theGPUwillmaintainthesameRenderStateforallincomingobjectsandrendertheminasimilarfashion.
ChangingtheRenderStatecanbeatime-consumingprocess.Wewon’tgotoodeeplyintotheparticularsofthis,butessentiallytheRenderStateisacollectionofglobalvariablesthataffecttheentiregraphicspipeline.Changingaglobalvariablewithinaparallelsystemismucheasiersaidthandone.AlotofworkmusthappenontheGPUtosynchronizetheoutcomeofthesestatechanges,whichofteninvolveswaitingforthecurrentbatchtofinish.InamassivelyparallelsystemsuchasaGPU,alotofvaluabletimecanbelostwaitingforonebatchtofinishbeforebeginningthenext.ThingsthatcantriggerthissynchronizationmayincludepushinganewtextureintotheGPU,changingaShader,changinglightinginformation,shadows,transparency,andchangingalmostanysettingwecanthinkof.
OncetheRenderStatehasbeenconfigured,theCPUmustdecidewhatmeshtodraw,whatMaterialitshoulduse,andwheretodrawtheobjectbasedonitsposition,rotation,andscale(allrepresentedwithinasingletransformmatrix).InordertokeepthecommunicationbetweenCPUandGPUverydynamic,newrequestsarepushedintoaCommandBuffer.Thisisabufferedlist,whichtheCPUsendsinstructionsto,andwhichtheGPUpullsfromwheneveritfinishesthepreviouscommand.TheCommandBufferbehaveslikeaFirstInFirstOut(FIFO)queue,andeachtimetheGPUfinishesonecommand,itpopstheoldestcommandfromthefrontofthequeue,processesit,andrepeatsuntiltheCommandBufferisempty.
http://freepdf-books.com
NotethatanewDrawCalldoesnotnecessarilymeanthatanewRenderStatemustbeconfigured.IftwoobjectssharetheexactsameRenderStateinformation,thentheGPUcanimmediatelybeginrenderingthenewobjectsincethesameRenderStateismaintainedafterthelastobjectwasfinished.
Becausetherenderingprocessrequirestwohardwarecomponentstoworkintandem,itisverysensitivetobottlenecks,whichcouldoriginateinoneorbothcomponents.GPUscanrenderindividualobjectsincrediblyquickly,soiftheCPUisspendingtoomuchtimegeneratingDrawCallcommands(orsimplygeneratingtoomanyofthem),thentheGPUwillwaitforinstructionsmoreoftenthanitisworking.Inthiscase,ourapplication’sgraphicswouldbeCPU-bound.We’respendingmoretimewaitingontheCPUtodecidewhattodraw,thantheGPUspendsdrawingit.Conversely,beingGPU-boundmeanstheCommandBufferfillsupwithrequestsastheGPUcannotprocessrequestsfromtheCPUquicklyenough.
NoteYouwilllearnmoreaboutwhatitmeanstohaverenderingbottlenecksineithertheCPUorGPU,andhowtosolvebothcases,inChapter6,DynamicGraphics.
Anothercomponentwhichcanimpedethespeedofgraphicsactivityinthischainofeventsiswithinthehardwaredriver.ThiscomponentmediatescommandscomingthroughthegraphicsAPI,whichcancomefrommultiplesourcessuchasourapplication,otherapplications,andeventheOperatingSystemitself(suchasrenderingthedesktop).Becauseofthis,usingupdateddriverscansometimesresultinafairlysignificantincreaseinperformance!
Next-generationgraphicsAPIs,suchasMicrosoft’sDirectX12,Apple’sMetal,andtheKronosGroup’sVulcan,allaimtoreducetheoverheadonthedriverbysimplifyingandparallelizingcertaintasks;particularly,howinstructionsarepassedintotheCommandBuffer.OncetheseAPIsbecomecommonplace,wemaybeabletogetawaywithusingsignificantlymoreDrawCallscomfortablywithinourapplication.ButuntiltheseAPIsmature,wemusttreatourDrawCallconsumptionwithagooddealofconcern,inordertoavoidbecomingCPU-bound.
http://freepdf-books.com
http://freepdf-books.com
MaterialsandShadersShadersareshortprogramswhichdefinehowtheGPUshouldrenderincomingvertexandpixeldata.AShaderonitsowndoesnothavethenecessaryknowledgeofstatetoaccomplishanythingofvalue.Itrequiresinputssuchasdiffusetextures,normalmaps,colors,andsoon,andmustdecidewhatRenderStatevariablesarerequiredinordertocompleteitsintendedtask.
Unity’sMaterialsystemisessentialtoprovidingthisinformationtoourShaders.Ultimately,thisjustmeansaShaderisdependentuponaMaterialinordertobeusedtorenderanobject.EveryShaderneedsaMaterial,andeveryMaterialmusthaveaShader.EvennewlyimportedmeshesthatareintroducedintotheScenewithoutanyassignedMaterialsareautomaticallyassignedadefault(hidden)Material,whichgivesthemabasicdiffuseShaderandawhitecoloration.So,thereisnowayofgettingaroundthisrelationship.
NoteAsingleMaterialcanonlysupportasingleShader.TheuseofmultipleShadersonthesamemeshrequiresseparateMaterialstobeassignedtodifferentpartsofthesamemesh.
ThesetwosystemscapturethemajorityoftheRenderStatevariableswediscussedintheprevioussection.Asaresult,ifwecanminimizethenumberofMaterialsbeingusedtorendertheScene,thenweminimizetheamountofRenderStatechangesrequired,andhencereducetheamountoftimetheCPUspendspreparingtheGPUeachframe.
Let’sbeginwithasimpleSceneinordertovisualizethebehaviorofMaterialsandbatching.But,beforewestart,weshoulddisableseveralglobaloptionsforrenderingfeaturestoavoiddistractingourselveswithadvancedrenderingfeatures:
NavigatetoEdit|ProjectSettings|QualityandsetShadowstoDisableShadows(orselectthedefaultFastestqualitylevel)NavigatetoEdit|ProjectSettings|Player,opentheOtherSettingstab,anddisableStaticBatching,DynamicBatching,andGPUSkinningiftheyareenabled
TipTheStaticBatchingandGPUSkinningoptionsarenotavailableinUnity4FreeEdition,andrequireanupgradetoUnity4ProEdition.
Next,we’llcreateaScenethatcontainsasingleDirectionalLightandeightmeshes;fourcubes,andfourspheres,whereeachobjecthasitsownuniqueMaterial,position,rotation,andscale:
http://freepdf-books.com
IfweobservetheBatchingvalueintheGameView’sStatspopup,weseeninetotalbatches(notethatthisvaluewillbelabeledDrawCallsintheUnity4Statspopup).UnlesstheCamera’sClearFlagssettingissettoDon’tClear,thenonebatchwillbeconsumeddrawingtheCamerabackground.ThiscouldbetheScene’sSkyboxorasinglequadthatfillsthescreenwithallpixelscoloredaspertheCamera’sBackgroundcolorproperty.
Thenexteightbatchesareusedtodrawoureightobjects.Ineachcase,theDrawCallinvolvespreparingtherenderingsystemusingtheMaterial’spropertiesandaskingtheGPUtorenderthegivenmeshatitscurrentposition,rotation,andscale.TheMaterialalsodefineswhichShaderisused,whichcontrolstheprogrammablepartsofthegraphicspipeline(vertexandfragmentsteps).
NotethatiftheRenderingPathsettingunderthePlayerSettingsissettoForward,thenwecanenableanddisabletheDirectionalLightinourSceneandthenumberofbatchesremainsatnine.ThefirstDirectionalLightinForwardrenderingiseffectivelyfreeatleastintermsofDrawCalls.AssoonasweaddmoreLightstoourScene,whethertheyareDirectional,Point,Spot,orAreaLights,wecauseallobjectstoberenderedwithanadditional“pass”throughtheShaderforeachLight,uptothevalueofthePixelLightCountvalueundertheQualitySettings(lightswithhighbrightnessvaluesareprioritizedfirst).
NoteLightingoptionscanbecomeasignificantsourceofDrawCalls,andyouwilllearnmoreaboutthissysteminChapter6,DynamicGraphics.
Aspreviouslymentioned,wecantheoreticallyminimizethenumberofDrawCallsby
http://freepdf-books.com
reducinghowoftenwecausethesystemtochangeRenderStateinformation.So,partofthegoalthereforeistoreducetheamountofMaterialsweuse.But,ifwesetallobjectstousethesameMaterial,wedon’tseeanybenefitandthenumberofbatchesremainsatnine:
Thisisbecausewe’renotactuallyreducingthenumberofRenderStatechangesnorefficientlygroupingmeshinformation.Withoutanyformofbatching,therenderingsystemisnotsmartenoughtorealizewe’reoverwritingtheexactsameRenderStatevalues,andthenaskingittorenderthesamemeshes,overandoveragain.Thispresentsanopportunitytohavetherenderingprocessrecognizethesesituations,renderallofthesemeshestogetherasoneobject,andavoidunnecessaryDrawCalls.ThisisbasicallyhowDynamicBatchingworkstoreduceourDrawCalls.
http://freepdf-books.com
http://freepdf-books.com
DynamicBatchingThepurposeofDynamicBatchingistobundletogetherlargegroupsofsimplemeshesandpushthemthroughtherenderingsystemasifitwasasinglemesh.OnlymeshesthatarecurrentlyvisibleintheCameraviewarecandidatesforDynamicBatching,whichmeansthatmostofthebatchingworkisaccomplishedatruntime,ratherthanpre-calculated.Thismeansthattheobjectsthatarebatchedtogetherwillvaryfromframetoframe.Hence,thename“Dynamic”Batching.
IfwereturntothePlayerSettingspageandenableDynamicBatching,weshouldseethatthenumberofbatchesdropsfromninedowntosix.DynamicBatchingisautomaticallyrecognizingthatourobjectsshareMaterialandmeshinformationandcancombinethemintoasinglebatchforprocessing.ThisisadecentCPUcost-savingstechniqueandreducesthelikelihoodthatourgamewithbeCPU-bound,sinceitfreesupmoretimeforothertasks,suchasAIandPhysicsprocessing.
Attheriskofsoundingungrateful,weshouldaskourselveswhyweonlysavethreeDrawCalls,andnotsix.Wewouldhopethatthesystemissmartenoughtogroupallofthecubestogetherinonebatchandallofthespheresinanother,takingonlytwoDrawCallstorenderthemall(plusoneDrawCallforthebackground).
ThecompletelistoftherequirementsneededtosuccessfullydynamicallybatchameshcanbefoundintheUnitydocumentationathttp://docs.unity3d.com/Manual/DrawCallBatching.html.
AllmeshinstancesmustusethesameMaterialreferenceOnlyparticlesystemsandmeshrenderersaredynamicallybatched.Skinnedmeshrenderers(foranimatedcharacters)andallotherrenderablecomponenttypescannotbebatchedThetotalnumberofvertexattributesusedbytheShadermustbenogreaterthan900Eitherallmeshinstancesshoulduseauniformscaleorallmeshesshoulduseanonuniformscale,butnotamixtureofthetwoMeshinstancesshouldrefertothesameLightmapfileTheMaterial’sShadershouldnotdependonmultiplepassesMeshinstancesmustnotreceivereal-timeShadows
TherearealsoacoupleofundocumentedrequirementsthathavebeenrevealedduringsomeUniteConferencepanels:
Thereisalimitof300meshesperbatchTheremustbenomorethan32,000meshindicesintheentirebatch
However,acoupleoftheserequirementsarenotcompletelyintuitiveorclearfromthedescription,whichmeritssomeadditionalexplanation.
http://freepdf-books.com
VertexattributesAvertexattributeisapropertycontainedwithinameshfileonapervertexbasis.Thisincludes,butisnotlimitedto,avertex’sposition,anormalvector(mostoftenusedinlightingcalculations),andUVcoordinates(usedtodefinehowatexturewrapsaroundthemesh).Onlymesheswithlessthan900totalvertexattributesusedbytheShadercanbeincludedinDynamicBatching.
TipNotethatlookingintoamesh’srawdatafilemaycontainlessvertexattributeinformationthanUnityloadsintomemorybecauseofhowtheengineconvertsmeshdatafromoneofseveralrawdataformatsintoaninternalformat.
UsingmoreattributedatapervertexwithintheaccompanyingShaderwillconsumemorefromour900-attributebudgetandhencereducethenumberofverticesthemeshisallowedtohavebeforeitcannolongerbeusedinDynamicBatching.Forexample,asimpleShaderwhichonlyusesthreeattributespervertex,suchassomeofthelegacydiffuseShaders,cansupportDynamicBatchingusingmesheswithupto300vertices.ButamorecomplexShader,requiringfiveattributespervertex,canonlysupportDynamicBatchingwithmeshesupto180vertices.
ThisrestrictioniswhyourSceneonlysavesthreeDrawCallswithDynamicBatchingenabled,despitehavingallobjectssharethesameMaterialreference.ThecubethatisautogeneratedbyUnitycontains8verticeseachwithposition,normal,andUVdata,for24attributesintotal.Thisisfarlessthanthe900-vertexattributelimitwhenallofthisdataisusedbytheShader.However,anautogeneratedspherecontains515vertices,whichclearlycannotbedynamicallybatchedifwecountaposition,normal,andUVcoordinateforeachvertex.ThisexplainsoursixDrawCalls:oneforthebackground,oneforabatchedgroupofcubes,andfourforthespheresthatarenotbeingdynamicallybatched,whichmustberenderedwithseparateDrawCalls.
http://freepdf-books.com
UniformscalingThedocumentationsuggeststhat,generally,objectsshouldeithershareauniformscaleoreachhaveauniquenonuniformscaleinordertobeincludedindynamicbatching.But,inreality,thebehaviorofthisrestrictionchangesslightlydependingonwhichversionofUnitywearerunningduetosomechangestotheDynamicBatchingsysteminUnity5.
TipAuniformscalemeansthatallthreecomponentsofthescalevector(x,y,andz)areidentical.
InbothversionsofUnity,ifallinstancesofameshhaveauniformscale,thentheycanbegroupedtogetherinthesamedynamicbatch.InUnity5,itwilldynamicallybatchallnonuniformlyscaledinstancesofthemeshwiththeoriginalbatch,nomattertheirscale.However,inUnity4,nonuniformlyscaledobjects,usingthesamemeshandMaterial,willbegroupedtogetherintoseparatebatches.
Thisassumeswe’reworkingwithpositivescales.Thescalerestrictiongetsalittleunintuitivewhenwe’redealingwithnegativescales.InUnity4,negativescalesdonotaffectDynamicBatchingandallofthesamerulesapplyasbefore.But,inUnity5,ifthemeshhasoneorthreenegativevaluesinitsscalevector,thenitwillnotbeincludedinthebatch.Ifitcontainstwonegativevalues,thenitcanbebatchedalongwithalloftheotherinstances.Itdoesnotevenmatterwhichofthethreevaluesarenegative,onlythattherearezeroortwoofthem.
Presumably,thisisabi-productofthealgorithmusedtodetectvalidbatchablegroups,sincemirroringameshintwodimensionsismathematicallyequivalenttorotatingthemeshaboutbothofthesameaxes180degrees.Thus,thebehaviorweobserveisjusttheDynamicBatchingsystemautomaticallytransformingtheobjectforus.
So,itisworthkeepinginmindthatDynamicBatchingisalittlemoreefficientinUnity5,butithassometrade-offs.Ifwewishtousenegativescalesasashortcuttomirroramesh,thenitwillbeincapableofbeingDynamicallyBatched.
http://freepdf-books.com
DynamicBatchingsummaryTherewereclearlysomesignificantimprovementsmadetotheDynamicBatchingsysteminUnity5,allowingittobemoreversatiletoavarietyofsituations.However,nomatterwhichversionofUnityweareusing,DynamicBatchingisveryusefulwhenwewishtorenderverylargegroupsofsimplemeshes.
Thedesignofthesystemmakesitidealtousewhenallofthemesheswe’reDynamicallyBatchingaresimpleandnearlyidenticalinappearance.PossiblesituationstoapplyDynamicBatchingcouldbeasfollows:
Alargeforestfilledwithrocks,trees,andbushesAbuilding,factory,orspacestationwithmanycommonelements(computers,pipes,andsoon)throughouttheSceneAgamefeaturingmanydynamic,nonanimatedobjectswithsimplegeometryandparticleeffects(agamesuchasGeometryWarsspringstomind)
ThepotentialbenefitsofDynamicBatchingaresignificantenoughtosetasidesometimetoinvestigateifandwherewecanmakeuseofitinourScene.TherearenottoomanyoccasionswhereDynamicBatchingwouldactuallydegradeperformance.
ThemostcommonmistakewithDynamicBatchingistosetupaScenethatgenerateslotsofbatches,whicheachcontainonlyahandfulofmeshes.Inthesecases,theoverheadcostofdetectingandgeneratingthebatchesmightcostmorethanthetimeitsavesjustmakingaseparateDrawCallforeachmesh.
Inaddition,we’refarmorelikelytoinflictperformancelossesonourapplicationbysimplyassumingDynamicBatchingistakingplace,whenwe’veactuallyforgottenoneoftheessentialrequirements.Everysituationisunique,soitisworthexperimentingwithourMaterials,meshes,andShaderstodeterminewhatcanandcannotbedynamicallybatched.
http://freepdf-books.com
http://freepdf-books.com
StaticBatchingUnityoffersasecondbatchingmechanismthroughStaticBatching.ThepurposeofthisfeatureistograntusawaytobatchnonidenticalmeshesofanysizeintoasinglebatchwithasimilargoalandmethodologytoDynamicBatching,butsolvingtheproblemforadifferentsetofconditions.TheessentialdifferencebetweenthetwobatchingmethodsisthatStaticBatchingoccursduringapplicationinitialization,whereasDynamicBatchingtakesplaceatruntime.WethereforehavealotmorecontroloverwhenandwhereStaticBatchingtakesplace.
NoteStaticBatchingisavailableinalleditionsofUnity5,butonlyintheProEditionofUnity4.Unity4FreeuserswillneedtoupgradetotheProEditiontomakeuseofthisfeature.
TheStaticBatchingsystemhasitsownsetofrequirements:
Asthenameimplies,themeshesmustbeflaggedasStaticAdditionalmemorymustbesetasideforeachmeshbeingstaticallybatchedThemeshinstancescancomefromanysourcemesh,buttheymustsharethesameMaterial
Let’scovereachoftheserequirementsinmoredetail.
http://freepdf-books.com
TheStaticflagStaticBatchingcanonlybeappliedtoobjectswiththeStaticflagenabledor,morespecifically,theBatchingStaticsubflag(alsoknownasStaticEditorFlags).ClickingonthedownarrownexttotheStaticoptionforaGameObjectwillrevealadropdownoftheseStaticEditorFlags,whichcanaltertheobject’sbehaviorforvariousStaticprocesses.
http://freepdf-books.com
MemoryrequirementsTheadditionalmemoryrequirementforStaticBatchingwillvarydependingontheamountofreplicationoccurringwithinthebatchedmeshes.StaticBatchingworksbycombiningallflaggedmeshesintoasingle,largemesh,andpassingitintotherenderingsystemthroughasingleDrawCall.Ifallofthemeshesbeingstaticallybatchedareunique,thenthiswouldcostusnoadditionalmemoryusagecomparedtorenderingtheobjectsnormally,asthesameamountofmemoryspaceisrequiredtostorethemeshes.
However,staticallybatchedduplicatescostusadditionalmemoryequaltothenumberofmeshesmultipliedbythesizeoftheoriginalmesh.Ordinarily,renderingone,ten,oramillionclonesofthesameobjectcostsusthesameamountofmemory,becausethey’reallreferencingthesamemeshdata.Theonlydifferenceisthetransformofeachobject.But,becauseStaticBatchingneedstocopythedataintoalargebuffer,completewithitstransformdata,thisreferencingislost,andanewduplicateoftheoriginalmeshiscopiedintothebufferwithahard-codedtransformposition,regardlessofwhetherthesamemeshhasalreadybeencopiedin.
Therefore,usingStaticBatchingtorender1,000identicaltreeobjectswillcostus1,000timesmorememorythanrenderingthesameobjectsnormally,becauseeachtreemustbecopiedintotheStaticBatchingbufferasauniquesetofvertexdata.ThiscausessomesignificantmemoryconsumptionandperformanceissuesifStaticBatchingisnotusedwisely.
http://freepdf-books.com
MaterialreferencesFinally,wealreadyknowaboutsharingmaterialreferencesasameansofreducingRenderStatechanges,sothisrequirementisfairlyobvious.However,sometimeswe’restaticallybatchingmeshesthatrequiremultiplematerials.Inwhichcase,allmeshesusingadifferentmaterialwillbegroupedtogetherintheirownstaticbatch,andagainforeachuniquematerialbeingused.
Thedownsidetothisdesignfeatureisthat,atbest,StaticBatchingcanonlyrenderallofthestaticmeshesusinganumberofDrawCallsequaltothenumberofmaterialstheyneed.But,thebenefitisthatwecancontrolwhichmeshesgetbatchedtogetherusingdifferentmaterials,effectivelyforcingittostartanewstaticbatchthroughsomecunningmaterialduplication.ThiswillbecomeclearafterwecoversomeoftheStaticBatchingsystem’scaveats.
http://freepdf-books.com
StaticBatchingcaveatsTheStaticBatchingsystemisnotwithoutitsdrawbacks.Becauseofhowitapproachesthebatchingsolution,bycombiningmeshesintoasinglegreatermesh,theStaticBatchingsystemhasafewcaveatsthatweneedtobeawareof.TheseconcernsrangefromminorinconveniencestomajordrawbacksdependingontheScene:
DrawCallsavingsarenotimmediatelyvisiblefromtheStatswindowuntilruntimeStaticobjectsshouldnotbeintroducedtotheSceneatruntimeStaticallybatchedmeshescannotbemovedfromtheiroriginalstartingtransformIfanyoneofthestaticallybatchedmeshesisvisible,thentheentiregroupwillberendered
EditModedebuggingofStaticBatchingTryingtodeterminetheoveralleffectthatStaticBatchingishavingonourScenecanbealittletrickysincenothingisbeingStaticallyBatchedwhileinEditMode.AllofthemagichappensduringSceneinitialization,whichcanmakeitdifficulttodeterminewhatbenefitsStaticBatchingisactuallyproviding.Thisisespeciallytrueifweleaveimplementingthisfeatureuntillateintheprojectlifecycle,wherewecanspendalotoftimelaunching,tweaking,andrelaunchingourScenetoensurewe’regettingtheDrawCallsavingswe’reexpecting.Consequently,itisbesttostartworkingonStaticBatchingoptimizationearlyintheprocessofbuildinganewScene.
AvoidinginstantiatingstaticmeshesatruntimeNewstaticobjectsintroducedintotheScenewillnotbeautomaticallycombinedintoanyexistingbatchbytheStaticBatchingsystem.Todosowouldcauseanenormousruntimeoverheadbetweenrecalculatingthemeshandsynchronizingwiththerenderingsystem,soUnitydoesnotevenattempttodoit.Thisrestrictionmeansweshouldnotattempttodynamicallyinstantiatethestaticallybatchedcontent.AllmesheswewishtostaticallybatchshouldbepresentintheoriginalScenefile.
NoteDynamicinstantiationofobjectscanbeacostlyactioninitsownright.WewillcoversolutionstothatprobleminChapter7,MasterfulMemoryManagement.
Aswiththepreviouscaveat,staticallybatchedmeshesshouldnotbemovedaftertheyhavebeenbatched,sincedoingsowouldgenerateatremendousCPUoverhead.TheStaticBatchingsystemhasalreadytakentheoriginaldataandcombineditintoanewmeshobject.MovingtheoriginalmeshesisbothimpossiblewhiletheStaticflagisenabled,andnotevenrecognizedbytheUnitysystemiftheflagisdisabledandtheobject’stransformischanged.
VisibilityandrenderingThefinalcaveatisperhapsthemostimportant.IfevenasinglevertexofaStaticallyBatchedmeshisvisibletotheCamera,thenthewholemeshwillbepushedintothe
http://freepdf-books.com
renderingsystemandprocessedinitsentirely.WeneedtobesmartabouthowweuseStaticBatchingandoptimizeitsusagetopreventusrenderingagiganticmesheachandeveryframe!
Forexample,ifwehaveaScenewithmanyroomsconnectedtogetherwhichallsharethesameMaterial,thenenablingStaticBatchingforeveryroomobjectwillcauseeverysingleroomtoberenderedevenifonlyasingleroomisvisible,andeveniftheplayerisstaringstraightintoawall.SuchSceneswouldfarebetterusingOcclusionCulling(exploredinChapter6,DynamicGraphics)topreventnonvisibleroomsfrombeingrendered.
Meanwhile,largeoutdoorsceneswillfinditusefultoduplicateMaterials.Thisisausefultricktoforcesimilarobjectstobestaticallybatchedintodifferentgroups.Assigningidentical,butduplicateMaterialstodifferentsectionsoftheworldwillrenderthemthesame;however,theywillbegroupedseparately.ThiswouldincreasethenumberofDrawCalls,butallowustoreusethesameTexture,Material,andShaderfilesfortheentireScene.
DuplicatingMaterialscanbecomeabitofachorefromthemaintenanceperspective,sinceanychangesmadetooneMaterialmustalsobemadetotheothers.Hypothetically,wemightthinkwecanaccomplishthisthroughScriptbyattachingaComponentthatautomaticallyduplicatesaMaterialandassignsittothemeshduringSceneinitialization.Unfortunately,StaticBatchinghappenstooearlyintheinitializationprocessforustointerceptthroughacustomComponentsuchasthis,sothetaskmustbedonethroughtheEditor(agoodopportunitytomakeuseofEditorscripts).
http://freepdf-books.com
StaticBatchingsummaryStaticBatchingisapowerful,butdangeroustool.Ifwedon’tuseitwisely,wecanveryeasilyinflictperformancelossesviamemoryconsumptionandrenderingcostsonourapplication.Italsotakesagoodamountofmanualtweakingandconfiguration.However,itdoeshaveasignificantadvantage:itcanbeusedonobjectsetsofanysize.ThereisessentiallynolimitasfarasStaticBatchingisconcerned.
http://freepdf-books.com
http://freepdf-books.com
SummaryItisclearthattheStaticandDynamicBatchingfeaturesarenosilverbullet.WecannotblindlyapplythemtoanygivenSceneandexpectimprovements.IfourapplicationandScenehappentofitaparticularsetofparameters,thenthesemethodsareveryeffectiveatreducingCPUloadandrenderingbottlenecks.But,ifnot,thensomeadditionalworkisrequiredtoprepareourScenetomatchitsfeaturerequirements.Ultimately,onlyagoodunderstandingofthebatchingsystemsandhowtheyfunctioncanhelpusdeterminewhereandwhenthisfeaturecanbeapplied.
WewillcovermoregraphicsimprovementtechniquesinChapter6,DynamicGraphics.Untilthen,let’smoveontoadifferenttopic,andlookintosomeofthemoresubtleperformanceimprovementsthatwecanachievethroughmanagingourartassetsinintelligentways.
http://freepdf-books.com
http://freepdf-books.com
Chapter4.KickstartYourArtArtisaverysubjectivearea,dominatedbypersonalopinionandpreference.Itcanbedifficulttosaywhetheronepieceofartis“better”thantheother,andit’slikelythatwewon’tbeabletofindcompleteconsensusonouropinions.Thetechnicalaspectsbehindartassetsthatsupportagame’sartistrycanalsobeverysubjective.Therearemultipleworkaroundsthatcanbeimplementedtoimproveperformance,butthesetendtoresultinalossofqualityforthesakeofspeed.Ifwe’retryingtoreachpeakperformance,thenit’simportantthatweconsultwithourteammemberswheneverwedecidetomakeanychangestoourartassetsasitisprimarilyabalancingact,whichcanbeanartforminitself.
Whetherwe’retryingtominimizeourruntimememoryfootprint,keepingthesmallestpossibleexecutablesize,maximizingloadingspeed,ormaintainingconsistencyinframerate,thereareplentyofoptionstoexplore.Therearesomemethodsthatareclearlyalwaysideal,andotherswhichmayrequirealittlemorecareandforethoughtbeforebeingadopted,astheymightresultinreducedqualityorincreasethechancesofdevelopingbottlenecksinothercomponents.
Wewillbeginexaminingaudiofiles,followedbyTexturefiles,andfinishupwithmeshesandanimations.Ineachcase,wewillinvestigatehowUnityloads,stores,andmanipulatestheseassetsduringruntime,whatouroptionsare,andwhatwecandotoavoidbehaviorthatmightgenerateperformancebottlenecks.
http://freepdf-books.com
AudioDependingonthescopeoftheproject,audiofilescanrangeanywherefromthelargestdiskspaceconsumer,tothesmallest.Unity,asaframework,canbeusedtobuildsmallapplicationsthatrequireonlyahandfulofsoundeffectsandasinglebackgroundtrack,ortobuildlargeexpansiveroleplayinggamesthatneedmillionsoflinesofspokendialog,musictracks,andambientsounds.ItwillbeusefultomakesenseofhowaudiofilesaremanagedinUnitytobetterunderstandwhatweshoulddoforthesakeofoptimizationinbothcases.
ManydevelopersaresurprisedtofindthatruntimeaudioprocessingcanturnintoasignificantsourceofCPUandmemoryconsumption.Audioisoftenneglectedonbothsidesofthegamingindustry;developerstendnottocommitmanyresourcestoituntilthelastminute,whileuserswillrarelydrawattentiontoit.Nobodynoticeswhentheaudioisgoodorpassable,butweallknowwhatbadaudiosoundslike;it’sinstantlyrecognizable,jarring,andguaranteedtocatchunwantedattention.Thismakesitcrucialnottosacrificetoomuchaudioclarityinthenameofperformance.
Audiobottleneckscancomefromavarietyofsources.Excessivecompression,toomuchaudiomanipulation,toomanyactiveaudioclips,inefficientmemorystoragemethods,andaccessspeedsareallwaystoinvitepoormemoryandCPUperformance.But,withalittleeffortandunderstanding,allittakesisafewtweakshereandtheretosaveusfromauser-experiencedisaster.
NoteSeveralaudiooptionsarenamedslightlydifferentlybetweenUnity4andUnity5,butthefeaturesareidenticalforallintentsandpurposes.WewillproceedusingtheUnity5nameforeachfeature.
http://freepdf-books.com
LoadingaudiofilesWhenweselectanimportedAudioClipintheUnityEditor,weseethatthefirstoptionisthefile’sLoadType.Therearethreepossiblesettingsavailable:
DecompressOnLoadCompressedInMemoryStreaming
TheactualmomentwhenthefileisfirstloadedwilldependonotherAudioClipsettingsandhowtheyareusedduringruntime,whichwewillexplorelater.Thisoptionmerelydefinesthemethodofloadingwhenitoccurs.
DecompressOnLoadcompressesthefileondisktosavespace,anddecompressesitintomemorywhenitisfirstloaded.Thisisthestandardmethodofloadinganaudiofile,andshouldbeusedinmostcases.
CompressedInMemoryloadsthecompressedfilestraightintomemorywhenitisloaded,anddecompressesitduringruntimewhenitisbeingplayed.ThiswillsacrificeruntimeCPUwhentheclipisplayed,butimprovesloadingspeedandreducesruntimememoryconsumption.Hence,thisoptionisbestusedforverylargeaudiofilesthatareusedfairlyfrequently,orifwe’reincrediblybottleneckedonmemoryconsumptionandarewillingtosacrificesomeCPUcyclestoplaytheAudioClip.
Finally,theStreamingoptionwillload,decode,andplayfileson-the-flyatruntimebygraduallypushingthefilethroughasmallbuffer.ThismethodusestheleastamountofmemoryforaparticularAudioClipandthelargestamountofruntimeCPU.Thiscomeswiththeunfortunatedrawbackthattheycannotbereferencedmorethanonce.AttemptingtostreammultiplecopiesofthesameAudioClipwillgenerateanewbufferforeachinstance,resultinginasignificantamountofRAMandruntimeCPUcostifusedrecklessly.Consequently,thisoptionisbestreservedforsingle-instanceAudioClipsthatplayregularlyandneverneedtooverlapwithotherinstances.Ergo,thissettingisbestusedwithbackgroundmusicandambientsoundeffectsthatneedtoplayduringthemajorityofaScene’slifetime.
ProfilingaudioWecanconfirmmuchofthisbehaviorbyplayingmultipleinstancesofanygivenAudioClipviamultipleAudioSourcesinaScene,andbenchmarkingusingtheAudioViewoftheProfilertoseehowmuchmemoryandCPUisconsumedusingthevariousLoadTypeoptions.However,beawarethattheProfileroutputforaudiomemoryandCPUconsumptioninEditorModecanbeverymisleading,sinceitperformsaudioloadingdifferentlytohowitwouldoccurinaruntimeapplication.
ThefirsttimeweloadtheEditorandenterPlayMode,theEditorwilldecompressaudiofiles,costingacertainamountofmemoryandCPUcyclesduringinitializationinordertoaccomplishthis.WecanobservethememorycostsofthisprocessintheProfilerundertheAudioArea.However,ifwerestarttheScene,thenwemaynoticethatthememoryspentondecompressingaudiofilessuddenlydropstonearly0KB,sincefileshavealreadybeen
http://freepdf-books.com
decompressedandtheEditorhasflushedawaydataitnolongerneeds.Thisisnotrepresentativeofarealsituation,asapplicationswouldneedtoperformthisdecompression.
So,ifwewantaccurateaudioprofilinginUnity,weshouldruntheProfileragainstastandalone,orremote,versionofourapplicationontheintendedplatform/device.
AdditionalloadingoptionsThereisanadditionalpairofoptionsthataffectaudiofileloadingbehavior:
LoadInBackgroundPreloadAudioData
Inthetypicalusecase,whereanAudioClipisassignedtoanAudioSourceComponentinaScene,theaudiofilewillbeloadedintomemoryduringSceneinitialization.But,iftheLoadInBackgroundoptionisenabled,thenloadingtheAudioClipwillbedeferredtoabackgroundtaskthatbeginsoncetheScenehasfinishedinitializingandgameplayhasessentiallybegun.So,itstandstoreasonthatwecanimprovetheSceneloadingspeedbyenablingthisoptionforAudioClipsthatwewon’tneeduntillaterintheScene’slifetime,suchassoundeffectsusedinmid-levelcutScenes.
WecanuseanAudioClipobject’sloadStatepropertytoverifyiftheassetisloadedbeforeattemptingtouseit.But,usingtheLoadInBackgroundoptionrisksintroducingjarringbehaviorifwetrytoaccessasoundfilebeforeitisfullyloaded.Inthesecases,thesoundfilewon’tplayuntilthebackgroundloadingtaskhascompleted,inwhichcasethesoundwillprobablyplayataninappropriatemoment.
Thesecondoption,PreloadAudioData,isenabledbydefault,whichtellstheUnityEnginetoautomaticallybeginloadingthefileduringSceneinitialization.DisablingthisoptiondefersloadingtothefirstinstantthattheAudioSourceobject’sPlay()orPlayOneShot()methodsareinvokedatruntime.ThiswillcauseaspikeintheCPU,astheaudiodataisloadedfromthedisk,decompressed(ornot,dependingontheLoadTypesetting),pushedintomemory,andeventuallyplayedonceloaded.
Duetotheamountofplaybackdelay,andtheperformancecost,itisnotrecommendedtorelyonloadingoccurringatthemomentthataudioplaybackisneeded.WeshouldinsteadcontrolloadingourselvesbycallingtheAudioClipobject’sLoadAudioData()atsomeconvenientmomentbeforethefileisneeded.Moderngamestypicallyimplementconvenientstoppingpointsinlevelstoperformtaskssuchasthis,suchasanelevatorbetweenfloorsorlongcorridors,whereverylittleactionistakingplace.NotethatwecanalsomanuallycontrolthefreeingofaudiofilememoryusingtheAudioClipobject’sUnloadAudioData()method.
Solutionsinvolvingcustomloadingandunloadingofaudiodataviathesemethodswouldneedtobetailor-madetotheparticulargame,dependingonwhenAudioClipsareneeded,howlongthey’reneededfor,howScenesareputtogether,andhowplayer(s)traversethem.Thiscanrequireasignificantnumberofspecial-casechanges,testing,andassetmanagementtweakstoachieve.So,itisrecommendedtosavethisapproachasa“Nuclear
http://freepdf-books.com
Option”tobeusedlateinproduction,intheeventthatallothertechniqueshavenotsucceededaswellaswehoped.
http://freepdf-books.com
EncodingformatsandqualitylevelsUnitysupportsthreegeneral-caseencodingformatsforaudiofiles,withafewspecificcasesthatareplatform-dependent(suchasHEVAGforthePSVitaandXMAforXBoxOne).Wewillfocusonthethreeoptionalencodingformats:
CompressedPCMADPCM
ThecompressionalgorithmusedwiththeCompressedformatwilldependontheplatformbeingtargeted.Standaloneapplications,WebGL,andothernon-mobileplatformsuseOgg-Vorbisforcompression,whilemobileplatformsuseMPEG-3(MP3).
TheaudiofilesweimportintotheUnityEnginecanbeoneofmanypopularaudiofileformats,buttheactualencodingthatisbundledintotheexecutablewillendupinoneofthepreviouslymentionedformats.StatisticsareprovidedforthecurrentlyselectedformatintheareafollowingtheCompressionFormatoption,providinganideaofhowmuchdiskspaceisbeingsavedbythecompression,andhowmuchmemorytheAudioClipwillconsumeatruntime(notethatthisalsodependsonthecurrentlyselectedLoadType).
Theencoding/compressionformatusedcanhaveadramaticeffectonthequality,filesize,andmemoryconsumptionoftheaudiofileduringruntime,andonlytheCompressedoptiongivesustheabilitytoalterthequalitywithoutaffectingthesamplingrateofthefile.ThePCMandADPCMformatsdonotprovidethisluxury,andwe’restuckwithwhateverfilesizethosecompressionformatsdecidetogiveus,unlesswe’rewillingtoreduceaudioqualityforthesakeoffilesizebyreducingthesamplingrate.
Eachencodingandcompressionformatprovidesdifferentbenefitsandpitfalls,andeachaudiofilemaybeabletosacrificeonemetricforanotherbasedonitspurposeandcontents.Ifwewishtoproperlyoptimizeourapplication’saudiofiles,thenweneedtobewillingtousealloftheavailableformatsinasingleapplicationtomakethemostofouraudiofiles.
ThePCMformatisalosslessanduncompressedaudioformat,providingacloseapproximationofanalogaudio.Ittradeslargefilesizesforhigheraudioquality,andisbestusedforveryshortsoundeffectsthatrequirealotofclaritywhereanycompressionwouldotherwisedistorttheexperience.
Meanwhile,theADPCMformatisfarmoreefficientinbothsizeandCPUconsumptionthanPCM,butcompressionresultsinafairamountofnoise.Thisnoisecanbehiddenifitisreservedforshortsoundeffectswithalotofchaos,suchasexplosions,collisions,andimpactsoundswherewemightnotbeawareofanygeneratedartefacts.
Finally,theCompressedformatwillresultinsmallfilesthathavelowerqualitythanPCM,butsignificantlybetterqualitythanADPCM,attheexpenseofadditionalruntimeCPUusage.Thisformatshouldbeusedinmostcases.Thisoptionallowsuscustomizetheresultantqualitylevelofthecompressionalgorithm,totweakqualityagainstfilesize.BestpracticeswiththeQualityslideraretosearchforaqualitylevelthatisassmallas
http://freepdf-books.com
possible,butunnoticeabletousers.Someusertestingmayberequiredtofindthe“sweetspot”foreachfile.
TipDonotforgetthatanyadditionalaudioeffectsappliedtothefileatruntimewillnotplaythroughtheEditorinEditMode,soanychangesshouldbefullytestedthroughtheapplicationinPlayMode.
http://freepdf-books.com
AudioperformanceenhancementsNowthatwehaveabetterunderstandingofaudiofileformats,loadingmethods,andcompressionmodes,let’sexploresomeapproachesthatwecanmaketoimproveperformancethroughtweakingaudiobehavior.
MinimizeactiveAudioSourcecountSinceeachactivelyplayingAudioSourceconsumesaparticularamountofCPU,thenitstandstoreasonthatwecansaveCPUcyclesforeachredundantAudioSourcethatisplayinginourScene.OneapproachistocontrolourAudioSourcesinsuchawaythatweputahardcaponhowmanyinstancesofanAudioClipcanplaysimultaneouslysothatwedon’tattempttoplaytoomanyofthesamesoundeffectssimultaneously.WecandothisbyhavingamanagementobjecttakecontrolofourAudioSources.ItshouldacceptsoundplaybackrequestsandplaysthefilethroughanyAudioSourcesthataren’talreadybusyplayinganexistingsound.
Themanagementobjectcouldalsothrottletherequestssuchthatthereisalimittohowmanyversionsofthesamesoundeffectcanplay,andhowmanytotalsoundeffectsareplayingatanygiventime.Thiswouldbebestusedon2Dsoundeffectsorsingleinstancesof3Dsoundeffects(whichwouldrequiremovingtheAudioSourcetothecorrectlocationatthemomentofplayback).
AlmosteveryAudioManagementAssetavailableintheUnityAssetStoreimplementsanaudio-throttlingfeatureofsomekind(oftenknownas“audiopooling”),andforgoodreason;it’sthebesttrade-offinminimizingexcessiveaudioplaybackwiththesmallestamountofeffortinpreparingaudioassetstomakeuseofit.Forthisreason,andbecausetheseassetsoftenprovidemanymoresubtleperformance-enhancingfeatures,itisrecommendedtouseapre-existingsolution,ratherthanrollingoutourown,asthescriptingprocesscanbeveryinvolved.
Notethatambient3DsoundsstillneedtobeplacedatspecificlocationsintheScenetomakeuseofthelogarithmicvolumeeffect,whichgivesitthepseudo-3Deffect,sotheaudiomanagementsystemwouldprobablynotbeanidealsolution.Limitingplaybackonambientsoundeffectsisbestachievedbyreducingthetotalnumberofsources.Thebestapproachistoeitherremovesomeofthemorreducethemdowntoonelarger,louderAudioSource.Naturally,thisapproachaffectsthequalityoftheuserexperience,sinceitwouldappearthatthesoundiscomingfromasinglesourceandnotmultiplesources,andsoitshouldbeusedwithcare.
MinimizeAudioClipreferencesEachAudioSourceintheScenewithareferencetoanAudioClipwithPreloadAudioDataenabledwillconsumeacertainamountofmemoryfortheAudioClip(compressed,decompressed,orbuffered,dependingonLoadType)throughouttheentirelengthofthegivenScene.TheexceptiontothisruleisiftwoormoreAudioSourcesreferencethesameAudioClip,inwhichcasenoadditionalmemoryisconsumedasalloftheAudioSourcesarereferencingthesamelocationinmemoryandreadingfromitonanas-needed
http://freepdf-books.com
basis.
AudioClipsareunmanagedresourceswithinUnity,whichmeanstheywillnotbereleasedfrommemorymerelybysettingallreferencestonull.Unityexpectsustoloadandreleasetheseresourcesourselves,creatingandreleasingthemfrommemoryas-needed.Keepingfilesinmemoryforlongperiodsisreasonableforfrequentlyusedsoundeffects,sinceloadingafileintomemoryeverytimeitisrequestedwouldcostussomemeasureofCPUuse.
However,ifwefindthatweareusingtoomuchmemoryfromthesefrequentlyusedsoundeffects,thenwemustmakethedifficultchoiceofeitherreducingtheirqualityorremovingthementirely,tofindmemorysavings.Removingsoundeffectscompletelyisnotnecessarilyabadoption.Wemightbeabletoachieveauniquesoundeffectbyreusingexistingsoundeffectscombinedwithspecialeffectsandfilters.
Ontheotherhand,keepinginfrequentlyusedsoundeffectsinmemoryforthelengthofaScenecanposeasignificantproblem.Wemighthavemanyone-time-onlysoundeffects,suchasdialogclips,wherethereislittlereasontokeeptheminmemoryjustfortheoneuniquemomenttheyareneeded.CreatingAudioSourceswithassignedAudioClips(intheirAudioClipproperty)willgeneratesuchreferences,andcauseexcessmemoryconsumptionevenifweonlyusethemforasinglemomentduringgameplay.
ThesolutionistomakeuseofResources.Load()andResources.UnloadAsset()tokeeptheaudiodatainmemoryonlyforaslongasitisbeingplayed,andthenimmediatelyreleaseitonceitisnolongerneeded.Thefollowingcodesamplewillachievethiseffectinthesimplestmannerpossible(trackingonlyasingleAudioSourceandAudioClip)usingourSingletonAsComponentclass,justtogiveusanideaofwhatsuchasystemmightlooklike:
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
publicclassAudioSystem:SingletonAsComponent<AudioSystem>{
[SerializeField]AudioSource_source;
AudioClip_loadedResource;
publicstaticAudioSystemInstance{
get{return((AudioSystem)_Instance);}
set{_Instance=value;}
}
publicvoidPlaySound(stringresourceName){
_loadedResource=Resources.Load(resourceName)asAudioClip;
_source.PlayOneShot(_loadedResource);
}
voidUpdate(){
if(!_source.isPlaying&&_loadedResource!=null){
Resources.UnloadAsset(_loadedResource);
http://freepdf-books.com
_loadedResource=null;
}
}
}
ThisclasscanbetestedwiththefollowingComponent,whichloadsasoundfilewhentheAkeyispressed:
publicclassAudioSystemTest:MonoBehaviour{
voidUpdate(){
if(Input.GetKeyDown(KeyCode.A)){
AudioSystem.Instance.PlaySound("TestSound");
}
}
}
TipNotethat,totestthiscode,anaudiofilenamedTestSoundmustbeplacedwithinafoldernamedResourcesinorderforUnitytofinditatruntime.
Usingthisapproachtoplaysoundeffects,weshouldnotethatmemoryforthesoundisonlyallocatedwhenitisplayed,andthenimmediatelyfreedwhenthesoundeffectends.Onceagain,multipleaudiotoolsintheUnityAssetStoreprovidethisfeature,buttheAudioSystemclasscanbeexpandedtohandlemultipleAudioSourcesandAudioClipsfairlyeasilyifwewishtocustomizethesolution.
EnableForcetoMonofor3DsoundsEnablingtheForcetoMonosettingonastereoAudioFilewillmixittogetherwiththechannelsintoasinglechannel,saving50percentofthefile’stotaldiskandmemoryspaceusage.Enablingthisoptionisgenerallynotagoodideaforsome2Dsoundeffectswherethestereoeffectisoftenusedtocreateacertainaudioexperience.Butwecanenablethisoptionforsomegoodspacesavingson3Dsoundeffects,wherebeingastereosourceisgenerallymeaningless,and2Dsoundswherethestereoeffectisn’timportant.
ResampletolowerfrequenciesResamplingimportedaudiofilestolowerfrequencieswillreducethefilesizeandruntimememoryfootprint.ThiscanbeachievedthroughanAudioClip’sSampleRateSettingandSampleRateproperties.Somefilesrequirehighsampleratestosoundreasonable,suchasfileswithhighpitchesandmodernmusicfiles.However,lowersettingscanreducethefile’ssizewithoutmuchnoticeablequalitydegradationinmostcases.22050Hzisacommonvalueforsourcesthatinvolvehumanspeechandclassicalmusic.Somesoundeffectsmaybeabletogetawaywithevenlowerfrequencyvalues.But,eachsoundeffectwillbeaffectedbythissettinginauniqueway,soitwouldbewisetospendsometimedoingsometestingbeforewefinalizeourdecisiononsamplingrate.
ConsiderallencodingformatsIfmemoryandharddiskconsumptionarenotaburdenonourapplication,thentheWAVformatcanbeusedtoreduceCPUcostsatruntime,duetohavingasmalleroverhead
http://freepdf-books.com
requiredtodecodethedataduringeachplayback.Meanwhile,ifwehaveCPUcyclestospare,wecansavespacewithcompressedencoding.
BewareofstreamingStreamingfilesfromdiskshouldberestrictedtolarge,single-instancefilesonly,asitrequiresruntimeharddiskaccess;oneoftheslowestformsofdataaccessavailabletous.Layeredortransitioningmusicclipsmayrunintomajorhiccupsusingthismethod,atwhichpointitwouldbewisetoconsidertheResources.Load()approach.Weshouldalsoavoidstreamingmorethanonefileatatimeasitlikelytoinflictalotofcachemissesonthediskthatinterruptgameplay.
ApplyFiltereffectsthroughMixergroupstoreduceduplicationFiltereffectsareadditionalComponentsthatwecanattachtoanAudioSourcetomodifysoundplayback.EachindividualFiltereffectwillcostsomeamountofbothmemoryandCPU,andattachingduplicatestomanyAudioSourcesinourScenecanresultindireconsequencesifthey’reusedtoofrequently.AbetterapproachistomakeuseofUnity’sAudioMixerutilitytogeneratecommontemplatesthatmultipleAudioSourcescanreferencetominimizetheamountofmemoryoverhead.
TheofficialtutorialonAudioMixerscoversthetopicinexcellentdetail:
https://unity3d.com/learn/tutorials/modules/beginner/5-pre-order-beta/audiomixer-and-audiomixer-groups
Use“WWW.audioClip”responsiblyUnity’sWWWclasscanbeusedtostreamgamecontentinviatheWeb.But,accessingaWWWobject’saudioClippropertywillallocateawholenewAudioClipresourceeachtimeitisinvoked,andsimilarlywithotherWWWresource-acquiringmethods.ThisresourcemustbefreedwiththeResources.UnloadAsset()methodonceitisnolongerrequired.
Discardingthereference(settingittonull)willnotautomaticallyfreetheresource,soitwillcontinuetoconsumememory.Ergo,weshouldonlyobtaintheAudioClipthroughtheaudioClippropertyoncetoobtaintheresourcereference,useonlythatreferencefromthatpointforward,andreleaseitwhenitisnolongerrequired.
ConsiderAudioModulefilesforbackgroundmusicAudioModulefiles,alsoknownasTrackerModules,areanexcellentmeansofsavingasignificantamountofspacewithoutanynoticeablequalityloss.SupportedfileextensionsinUnityare.it,.s3m,.xm,and.mod.UnlikethecommonPCMaudioformats,whicharereadasbitstreamsofdatathatmustbedecodedatruntimetogenerateaspecificsound,TrackerModulescontainlotsofsmall,high-qualityPCMsamplesandorganizetheentiretracksimilartoamusicsheet;definingwhen,where,howloud,withwhatpitch,andwithwhatspecialeffectseachsampleshouldbeplayedwith.Thiscanprovidesignificantsizesavings,whilemaintaininghigh-qualitysampling.So,iftheopportunityisavailabletoustomakeuseofTrackerModuleversionsofourmusicfiles,thenitisworthexploring.
http://freepdf-books.com
http://freepdf-books.com
TexturefilesTheterms“Texture”and“Sprite”oftengetconfusedingamedevelopment,soit’sworthmakingthedistinctionthatinUnity3DaTextureissimplyanimagefile;abiglistofcolordatatellingtheinterpretingprogramwhatcoloreachpixeloftheimageshouldbe.WhereasaSpriteisthe2Dequivalentofamesh,whichjusthappenstobeasinglequadthatrendersflatagainstthecurrentcamera.TherearealsothingscalledSpriteSheets,whicharelargecollectionsofindividualimagescontainedwithinalargerTexturefile,commonlyusedtocontaintheanimationsofa2Dcharacter.ThesefilescanbesplitapartbyUnity’sSpriteBatchtool,toformindividualTexturesfortheanimationframes.
Let’strytoignorealloftheseconfusingnamingconventionoverlaps,andsimplytalkaboutTextures:theimagefileswe’reimportingintoourapplicationthatweregeneratedintoolssuchasAdobePhotoshoporGimp.Atruntime,thesefilesareloadedintomemory,pushedtotheGPU,andrenderedbytheShaderoverthetargetobjectduringagivenDrawCall.
http://freepdf-books.com
CompressionformatsMuchlikeAudiofiles,UnityprovidesuswithavarietyofcompressiontechniquestostoreourTexturefilesmoreefficiently.WhenaTexturefileisimported,thereareseveralsettingsthatwecanmanipulate.ThefirstisTextureType.Thissettingdoesnotaffectthefileitself,butratherhowUnitywillinterpret,manipulate,andcompressitwithinthefinalexecutablewebuild.
WithmostoftheTextureTypeoptions,theonlythreecompressionoptionsUnityexposestousareCompressed,16-bit,andTrueColor.Alternatively,ifwesettheTextureTypetoAdvanced,thenweexposealargernumberofsettings.ThisgivesusfarmorecontrolovertheinterpretationoftheTexturefile.
http://freepdf-books.com
Thiswillbeusefulinformationgoingforwardasthereareseveralperformance-enhancingopportunitiestofindthroughthisparticularviewofaTexturefile,whichwouldnotbevisibleordinarily.
ThenumberofcompressionformatsinAdvancedmodearesignificantlymorebroadandvaried,buttheoptionsremainidenticalbetweenUnity4andUnity5.Someformatsallowalphavalues,whereassomedonot,whichrestrictsourchoicesifwewishtomaintainalphatransparencyinourTexture(orafourthfloatdatavaluefromaTexturebeingusedasaHeightmap!).
SomeformatsalsocostdifferentlevelsofperformanceduringSceneinitializationtodecompressandpushintotheGPU,whichcanvaryenormouslydependingontheplatformwe’retargetingandthechosenformat.AdvancedmodeprovidestheAutomaticCompressedoption,whichtriestopickthebestoptionforthegivenplatformanddevice.Wecanusethisoptionifwe’renotcompletelysureaboutthebestformatforourgame,orwecanspendthetimetodosomeperformance-testingwithdifferentformatstoconfirmthebestchoice(s)forthetargetdevice.
http://freepdf-books.com
NotethatthePreviewWindowatthebottomoftheInspectorViewprovidessomeusefulstatisticstohelpusdeterminehoweffectivelythecurrentlyselectedcompressionmethodisbehaving.
http://freepdf-books.com
TextureperformanceenhancementsLet’sexploresomechangeswecanmaketoourTexturefiles,whichmighthelpimproveperformance,dependingonthesituationandthecontentofthefileswe’reimporting.Ineachcase,we’llexplorethechangesthatneedtobemade,andtheoveralleffecttheyhave,whetherthisresultsinapositiveornegativeimpactonmemoryorCPU,anincreaseordecreaseintheTexturequality,andunderwhatconditionswecanexpecttomakeuseofthesetechniques.
Also,becausetheUnity5PersonalEditionhasmademultiplefeaturesavailabletousthatwerepreviouslyonlyavailableintheProEdition,someusersmaynotbeawareofsomeadditionaltechniquesthatwecanapplytoourTexturestoimproveapplicationperformance.So,wewillalsocoversomeofthesetechniquestowardtheendofthissection.
ReduceTexturefilesizeThelargeragivenTexturefile,themoreGPUmemorybandwidthwillbeconsumedpushingtheTexturewhenitisneeded.Ifthetotalmemorypushedpersecondexceedsthegraphicscard’stotalmemorybandwidth,thenwewillhaveabottleneckastheGPUwaitsforallTexturestobeloadedbeforethenextrenderingpasscanbegin.SmallerTexturesarenaturallyeasiertopushthroughthepipelinethanlargerTextures,soweneedtofindagoodmiddlegroundbetweenhighqualityandperformance.
Acommontesttofindoutifwe’rebottleneckedinmemorybandwidthistosimplyreducetheresolutionofourgame’smostabundantandlargestTexturefilesandrelaunchtheScene.Iftheframeratesuddenlyimproves,thentheapplicationwasmostlikelyboundbytheTexturethroughput.Iftheframeratedoesnotimproveorimprovesverylittle,theneitherwestillhavesomememorybandwidthtomakeuseof,ortherearebottleneckselsewhereintherenderingpipelinepreventingusfromseeinganyfurtherimprovement.
UseMipMapswiselyTherewouldbenopointrenderingsmall,distantobjectssuchasrocksandtreeswithahigh-detailTextureifthere’snowaytheplayerwouldeverbeabletoseethatdetail,oriftheperformancelossistoogreattowarrantaminordetailincrease.MipMapswereinventedasawaytosolvethisproblem(aswellashelpingeliminatealiasingproblemsthatwereplaguingvideogamesataroundthesametime),bypregeneratinglower-resolutionalternativesofthesameTextureandkeepingthemtogetherinthesamememoryspace.Atruntime,theGPUpickstheappropriateMipMapoptionbasedonhowlargethesurfaceappearswithintheperspectiveview(essentiallybasedonthetexel-to-pixelratiowhentheobjectisrendered),andthenpicksanappropriatelyscaledMipMapoftheTexture.
ByenablingtheGenerateMipMapsoption,Unityautomaticallyhandlesthegenerationoftheselower-resolutioncopiesoftheTexture.Thesealternativesaregeneratedusinghigh-qualityresamplingandfilteringmethodswithintheEditor,ratherthanatruntime.
Thefollowingimageshowshowa1024x1024imagewillbeMipMappedintomultiple
http://freepdf-books.com
lower-resolutionduplicates:
ThedownsidetoMipMappingisthatithasanegativeimpactonfilesizeandloadingtimeduetothelargercombinedTexturefilesthatarebeingautomaticallygenerated.ThefinalTexturefilewillbearound33percentlargerwhenMipMappingisenabled.TherearealsosomesituationswheretheMipMappingprocessisawasteofeffort,soweshouldexaminesomeofourTexturefilestoseeifMipMapsarebeingappliedwisely.
MipMappingisonlyusefulifwehaveTexturesthatneedtoberenderedatvaryingdistancesfromthecamera.IfwehaveTexturesthatalwaysrenderedatasimilardistancefromthemaincamera,suchthattheMipMappedalternativesareneverused,thenenablingMipMapsisjustwastingspace.Inthesecases,weshoulddisabletheMipMappingfeaturebydisablingtheGenerateMipMapsoptionfortheTexture.
IfonlyasingleMipMapalternativeisused,thenweshouldconsiderdisablingMipMappinganddownscalingtheresolutionoftheoriginalTexturefile.
AdditionalcandidatesfordisablingtheMipMappingfeatureare:
AlmostanyTexturefileusedina2DgameUserInterface(GUI)TexturesTexturesformeshes,Sprites,andParticleEffects,whichalwaysrendernearthecamera—examplesincludetheplayercharactersthemselves,anyobjectstheyholdorcarry,andanyParticleEffectswhichalwayscenteraroundtheplayer
ManageresolutiondownscalingexternallyUnityputsalotofeffortintomakingthingsaseasytouseaspossibleandprovidesuswiththeabilitytoplacetheprojectfilesfromexternaltoolstoourProjectworkspace,suchasPSDandTIFFfiles,whichareoftenlargeandsplitintomultiplelayeredimages.UnityautomaticallygeneratesaTexturefilefromthefile’scontentsfortherestoftheEngineto
http://freepdf-books.com
makeuseof,whichcanbeveryconvenient,asweonlyneedtomaintainasinglecopyofthefilethroughSourceControlandtheUnitycopyisautomaticallyupdatedwhenanartistmakeschanges.
TheproblemisthatthealiasingintroducedbyUnity’sauto-Texturegenerationandcompressiontechniquesfromthesefilesmaynotbeasrobustandefficientasthetoolsweusetogeneratesuchfiles,suchasAdobePhotoshoporGimp.Unitymaybeintroducingartefactsthroughaliasing,andwemightfindourselvesgettingintothehabitofimportingimagefileswithahigherresolutionthannecessary,justtokeeptheintendedqualitylevel.But,hadwedownscaledtheimagethroughtheexternalapplicationfirst,wemightsuffermuchlessaliasing.Inthesecases,wemayhavebeenabletoachieveanacceptablelevelofqualitywithalowerresolution,whileconsuminglessoveralldiskandmemoryspace.
WecaneitheravoidusingPSDandTIFFfileswithinourUnityprojectasamatterofhabit(storingthemelsewhereandimportingthedownscaledversionintoUnity),orjustperformsomeoccasionaltestingtoensurewe’renotwastingfilesize,memory,andGPUmemorybandwidthusinglargerresolutionfilesthannecessary.Thiscostsussomeconvenienceinprojectfilemanagement,butcanprovidesomesignificantsavingsforsomeTextures,ifwe’rewillingtospendthetimecomparingthedifferentdownscaledversions.
AdjustAnisotropicFilteringlevelsAnisotropicFilteringisafeaturewhichimprovestheimagequalityofTextureswhentheyareviewedatveryshallow(oblique)angles.ThefollowingscreenshotshowstheclassicexampleofpaintedlinesonaroadwithandwithoutAnisotropicFilteringapplied.WithoutAnisotropicFiltering,thepaintedlinesappearblurryanddistortedthefurthertheyareawayfromthecamera,whereastheviewwithAnisotropicFilteringappliedmakestheselinesmorecrispandclear.
ThestrengthofAnisotropicFilteringappliedtotheTexturecanbehand-modifiedonaper-TexturebasiswiththeAnisoLevelsettingaswellasgloballyenabled/disabledusingtheAnisotropicTexturesoptionwithintheQualitySettingsscreen.
MuchlikeMipMapping,thiseffectcanbecostlyandsometimesunnecessary.IfthereareTexturesinourScenewherewearecertainwillneverbeviewedatanobliqueangle(such
http://freepdf-books.com
asdistantbackgroundspritesandparticle-effectTextures),thenwecansafelydisableAnisotropicFilteringforthemtosavesomeruntimeoverhead.WecanalsoconsideradjustingthestrengthoftheAnisotropicFilteringeffectonaper-Texturebasistofindthemagicspotbetweenqualityandperformance.
ConsiderAtlasingAtlasingisthetechniqueofcombininglotsofsmaller,isolatedTexturestogetherintoasingle-largeTexturefileinordertominimizethenumberofMaterials,andhenceDrawCalls,weneedtoapplybyexploitingDynamicBatching.Conceptually,thistechniqueisverysimilartotheapproachesofminimizingMaterialusageyoulearnedinChapter3,TheBenefitsofBatching.
EachuniqueMaterialwouldrequireanadditionalDrawCall,buteachMaterialonlysupportsasingleprimaryTexture(thisexcludesNormalMaps,EmissionMaps,andothersecondaryTextures).BycombiningallTexturesintoasinglecolossalTexture,wecanminimizethenumberofDrawCallsusedtorenderobjectsthatsharethisTexture:
Thebenefitsareclear;reducingDrawCallsresultsinreducingtheCPUworkloadandimprovingtheframerateifourapplicationisCPU-bound(orsimplyfreesupcyclesforothertasks).Therewillbenolossofquality,andmemoryconsumptionwillbeessentially
http://freepdf-books.com
identical.Allwe’redoingisexploitingUnity’sDynamicBatchingsystemtoreduceDrawCalls.NotethatAtlasingdoesnotresultinreducedmemorybandwidthconsumption,sincetheamountofdatabeingpushedisidentical.ItjusthappenstobebundledtogetherinonebiggerTexturefile.
TipAtlasingisonlyanoptionwhenallofthegivenTexturesrequirethesameShader.IfsomeoftheTexturesneeduniquegraphicaleffectsappliedthroughShaders,thentheymusteitherbeisolatedintotheirownMaterialsorAtlasedwithotherTextures,whichusethesameShader.
AtlasingisacommontacticappliedtoUserInterfaceelements,andingamesthatfeaturealotof2Dgraphics.AtlasingbecomespracticallyessentialwhendevelopingmobilegameswithUnity,sinceDrawCallstendtobethemostcommonbottleneckonthoseplatforms.But,wewouldnotwanttogeneratetheseatlasfilesmanually.LifewouldbemuchsimplerifwecouldcontinuetoeditourTexturesindividually,andautomatethetaskofcombiningthemintoalargerfile.
ManyGUI-relatedtoolsintheUnityAssetStoreprovideanautomatedTexture-atlasingfeature,therearesomestandaloneprogramsscatteredacrosstheInternet,whichcanhandlethiswork,andUnityitselfprovidedabuilt-inSpritePackertoolwiththenewUIsysteminversion4.6,whichcanbeeasilycustomizedtopackTexturesindifferentways.
ChecktheUnitydocumentationtodiscovermoreaboutthisusefulfeature,ifinterested:
http://docs.unity3d.com/Manual/SpritePacker.html
Eitherway,itisrecommendedtomakeuseofanexistingsolutionforatlasgenerationinordertoavoidreinventingthewheel.
TipNotethatTexturesmustbedefinedastheSpritetypeinordertoberecognizedandpackedbytheSpritePackertool.
Atlasingdoesnotneedtoapplyto2DgraphicsandUIelementseither.Wecanapplythistechniqueto3Dmeshesifwehappentobecreatingalotoflow-resolutionTextures.3DgamesthatfeaturesimpleTextureresolutions,oraflat-shadedlow-polyartstyle,areidealcandidatesforAtlasinginthisway.
However,becauseDynamicBatchingonlyaffectsnon-animatedmeshes(thatis,MeshRenderers,andnotSkinnedMeshRenderers),thereisnoreasontocombineTexturefilesforanimatedcharactersintoanatlas.Sincetheyareanimated,theGPUneedstomultiplyeachobject’sbonesbythetransformofthecurrentanimationstate.Thismeansauniquecalculationisneededforeachcharacter,andtheywillresultinanextraDrawCallregardlessofanyattemptswemaketohavethemshareMaterials.
Asaresult,combiningTexturesforanimatedcharactersshouldonlybedoneasamatterofconvenienceandspace-saving;forexample,inaflat-shadedlow-polyartstylegame,whereeverythinghappenstouseacommoncolorpalette,wecanmakesomesignificant
http://freepdf-books.com
spacesavingsbyusingasingleTexturefortheentiregameworld,objects,andcharacters.
ThedisadvantagesofAtlasingaremostlyintermsofdevelopmenttimeandworkflowcosts.ItrequiresalotofefforttooverhaulanexistingprojecttomakeuseofAtlasing,whichcanbealotofworkjusttofigureoutifitisworththeeffortornot.Inaddition,weneedtobewareofgeneratingatlasfiles,whicharetoolargeforthetargetplatform.
Somedevices(specificallymobiledevices)havearelativelylowlimitonthesizeofTexturesthatcanbepulledintothelowestmemorycacheoftheGPU.Iftheatlasistoolarge,thenitmustbebrokenupintosmallerTextures,tofitthetargetmemoryspace.IftherendererhappenstoneedTexturesfromdifferentpiecesoftheatlaseveryotherDrawCall,thennotonlywillweinflictalotofcachemisses,butalsowemightfindthatwechokethememorybandwidthasTexturesareconstantlypulledfromVRAMandthelower-levelcache.
WewouldprobablynothavethisproblemiftheatlaswasleftasindividualTextures.ThesameTextureswappingwouldoccur,butwillresultinmuchsmallerfilesbeingswappedatthecostofadditionalDrawCalls.OurbestoptionsatthisstagewouldbetolowertheatlasresolutionorgeneratemultiplesmalleratlasestohavebettercontroloverhowtheywillbeDynamicallyBatched.
So,Atlasingisclearlynotaperfectsolution.Ifitisnotclearwhetheritwouldresultinaperformancebenefit,thenweshouldbecarefulnottowastetoomuchtimeonimplementation.
Ingeneral,weshouldattempttoapplyAtlasingtomid-range/high-qualityMobilegamesrightfromthestartoftheproject,keepingwithintheTexturelimitforthetargetplatform,makingper-platformandper-deviceadjustmentsasnecessary.Ontheotherhand,thesimplestMobilegameswillmostlikelyfunctionwithoutneedinganyAtlasing.
Meanwhile,weshouldconsiderapplyingAtlasingtohigh-qualityDesktopgames,onlyifourDrawCallcountexceedsreasonablehardwareexpectations,sincewewillwantmanyofourTexturestomaintainhighresolutionsformaximumquality.Low-qualityDesktopgamescanprobablyaffordtoavoidAtlasing,sinceDrawCallsareunlikelytobethebiggestbottleneck.
Ofcourse,nomatterwhattheproductis,ifwe’reeverCPU-boundbyDrawCallsandwe’vealreadyexhaustedmanyofthealternativetechniques,thenAtlasingwouldbethenextbesttechniquetoimplement,asitcanresultinsomeimpressiveDrawCallsavingswhenusedproperly.
Adjustcompressionratesfornon-squareTexturesItisnotrecommendtoimportnon-squareand/ornon-power-of-2Texturesintoourapplication,becauseGPUsoftenrequirethepushedTexturetobesquare,andapower-of-2sizeresultsinunnecessaryworkloaddealingwithmalformedTexturesizes.UnitywillautomaticallyadjusttheTextureandaddadditionalemptyspaceinordertofittheformfactorthattheGPUexpects,whichwillresultinadditionalmemorybandwidthcosts,pushingwhatisessentiallyuselessdatatotheGPU.
http://freepdf-books.com
So,thefirstrecommendationistoavoidnon-squareand/ornon-power-of-2Texturesaltogether.Iftheimagecanbeplacedwithinasquare,power-of-2Texture,anddoesnotresultintoomuchqualitydegradationduetosqueezing/stretching,thenweshouldapplythosechangesjusttokeeptheCPUandGPUhappy.
However,ifwestillwanttousenon-squareTextures,thereisatrickwecanapplytoachievehigherqualitywithoutcostinganyadditionalspace.Sincethewaynon-squareTexturesarepackedbycompressionalgorithms,wecanoftenincreasethebit-rate(andhencequality)ofthechosencompressionformatforanon-squareTextureandstillachieveanidenticalimportedfilesizeandruntimeoverheadcost.ThisonlycostsusthetimeittakestofindtheseTexturesandtestavarietyofcompressionalgorithmstofindthehighestqualityversion.
SparseTexturesSparseTextures,alsoknownasMega-TexturesorTiled-Textures,provideawayofeffectivelystreamingTexturedatafromdiskatruntime.Relativelyspeaking,iftheCPUperformsoperationsintheorderofseconds,thenthediskwilloperateintheorderofdays.Socommonadviceisthatharddiskaccessduringgameplayshouldbeavoidedatallcosts,sinceanysuchtechniquerisksinflictingmorediskaccessthanavailable,causingourapplicationtogrindtoahalt.
But,SparseTexturingbreaksthisruleandofferssomeinterestingperformancesavingtechniques.TheaimofSparseTexturingistocombinemanyTexturesintoanenormousTexturefile,whichwouldbefartoolargetoloadintographicsmemoryasasingleTexturefile.ThisissimilartotheconceptofAtlasing,exceptthefilecontainingtheTexturesisincrediblylarge(forexample,32,768x32,768resolution)andcontainsconsiderabledetail(32bitsperpixel).Theideaistosavelargeamountsofruntimememoryandmemorybandwidthbyhand-pickingsmallsubsectionsoftheTexturedynamically,andpullthemfromthediskjustbeforetheyareneededinthegame.Themaincostofthistechniqueisthefilesizerequirement(theexampleresolutionfilewouldconsume4GBofdiskspace!).OthercostsforthistechniquecanbeovercomewithagreatdealofScenepreparationwork.
ThegameworldneedstobecreatedinsuchawaythatitminimizestheamountofTextureswappingtakingplace.Inordertoavoidjarring,“texturepopping”problems,Texturesubsectionsmustbepulledfromadiskwithjustenoughtimetosparethattheplayerdoesnotnotice.ThistakesplaceinthedesignoftheTexturefileitself,bykeepingcommonelementsforagivenSceneinthesamegeneralareaoftheTexture,andthedesignoftheScene,bytriggeringnewTexturesubsectionloadingatkeymomentsduringgameplay.Ifitishandledwithgreatcareandattentiontodetail,thenSparseTexturingcanresultinsomeimpressiveScenequalityandequallyimpressivememorysavings.
SparseTexturingwaspreviouslyaProEdition-onlyfeatureinUnity4,butwasmadeavailablewiththePersonalEditionofUnity5.SparseTexturingrequiresspecializedhardwareandplatformsupport,however,sothisoptionisnotavailabletoallgames.Itisahighlyspecializedanduncommontechniquewithinthegamingindustry,whichisreflectedinthelackofdocumentation.TheUnitydocumentationdoesnotprovidemuch
http://freepdf-books.com
informationonSparseTexturing,butitdoesprovideanexampleSceneshowingtheeffectatwork.ItcanbefoundatthefollowingURL:http://docs.unity3d.com/Manual/SparseTextures.html.
ForUnitydeveloperswhoconsiderthemselvesadvancedenoughtofigureitoutontheirown,itmightbeworthtakingthetimetoperformsomeresearchtoseeifSparseTexturingisrightfortheirprojectandwhethertheyarewillingtomaketheappropriateScenechangesnecessarytogaintheperformancebenefitsthatthisfeaturepresents.
ProceduralMaterialsAlsoknownasSubstances,ProceduralMaterialsareameansofprocedurallygeneratingTexturesatruntimebycombiningsmall,high-qualityTexturesampleswithcustommathematicalformulas.ThegoalofProceduralMaterialsistogreatlyminimizetheapplicationfootprintatthecostofadditionalruntimememoryandCPUprocessingduringinitialization.LikeSparseTexturing,thisfeaturewaspreviouslyonlyavailableintheProEditionofUnity4andisnowavailableinUnity5.
ThisgivesmanyusersanopportunitytoviewtheirMaterialsfromadifferentperspective,asProceduralMaterialsareamoremodernapproachtotheirgames.Texturefilesareoftenthebiggestdiskspaceconsumerofagameproject,andit’sfairlycommonknowledgethatdownloadtimeshaveatremendousnegativeimpactonthecompleteddownloadrateandjustgettingpeopletotryourgame(evenifit’sfree!).ProceduralMaterialsofferustheabilitytosacrificesomeinitializationandruntimeprocessingpowerformuchfasterdownloads.ThisisveryimportantforanupcominggenerationofMobilegamesthataretryingtocompeteviagraphicalfidelity.
TheUnitydocumentationonProceduralMaterialsisfarmoreextensivethanforSparseTexturing,soitisrecommendedtoworkthroughthedocumentationforaclearerpictureofhowSubstancesworkandhowtheycanprovideuswithperformancebenefits:
http://docs.unity3d.com/Manual/ProceduralMaterials.html
http://freepdf-books.com
http://freepdf-books.com
MeshandanimationfilesFinally,let’scovermeshandanimationfiles.Thesefiletypesareessentiallylargearraysofvertexandskinnedbonedata,andthereareavarietyoftechniqueswecanapplytominimizefilesize,whilekeepingasimilar,ifnotidentical,appearance.Therearealsosometimeswaystolowerthecostofrenderinglargegroupsoftheseobjectsthroughbatchingtechniques.Let’slookintoaseriesofperformance-enhancingtechniqueswecanapplytosuchfiles.
http://freepdf-books.com
ReducingpolygoncountThisisthemostobviouswaytogainperformance,butweshouldneverdisregardit.Infact,sincewecannotbatchobjectsusingSkinnedMeshRenderers,it’soneoftheonlygoodwaysofreducingCPUandGPUruntimeoverheadforanimatedobjects.
Reducingthepolygoncountissimple,straightforward,andprovidesbothCPUandmemorycostsavingsforthetimerequiredforartiststocleanupthemesh.Muchofanobject’sdetailisprovidedalmostentirelybydetailedTexturingandcomplexShadinginthisdayandage,sowecanoftengetawaywithstrippingawayalotofverticesonmodernmeshesandmostuserswouldbeunabletotellthedifference.
TweakingMeshCompressionUnityoffersfourdifferentMeshCompressionsettingsforimportedmeshfiles:Off,Low,Medium,andHigh.IncreasingthissettingwillstripawaymoreandmorepartsofthemeshthatUnitythinksaren’tneededinordertomakeagoodestimateofthesamemeshwiththeaimofreducingoverallfilesize.Thisisessentiallyanautomatedversionofhavinganartistmanuallyreducingthepolygoncount.
However,automatedmeshoptimizationisaverydifficultproblemtosolvemathematicallyandeventhebestalgorithmstendtogeneratealotofartefactsandirregularities.DifferentlevelsofMeshCompressioncanbeattemptedasaquicksolutiontoreducingpolygoncount,butitwillprobablynevercomparetohavinganartistmakeappropriatepolycountreductionsbyhand.
TipThese3Dtoolsoftenprovidetheirownbuilt-inwaysofautomatedmeshoptimization,andshouldbetestedasameansofoptimizingthemeshbeforeimportingthemintoUnity.
UseRead-WriteEnabledappropriatelyTheRead-WriteEnabledflagallowschangestobemadetothemeshatruntimeeitherviaScriptingorautomaticallybyUnityduringruntime.Internally,thismeansitwillkeeptheoriginalmeshdatainmemoryuntilwewanttoduplicateitandmakechangesdynamically.DisablingthisoptionwillallowUnitytodiscardtheoriginalmeshdatafrommemoryonceithasdeterminedthefinalmeshtouse.
Ifweonlyeveruseauniformlyscaledversionofameshthroughouttheentiregame,thendisablingthisoptionwillsaveruntimememorysincewewillnolongerneedtheoriginalmeshdatatomakefurtherrescaledduplicatesofthemesh(incidentally,thisishowUnityorganizesobjectsbyscalefactorwhenitcomestoDynamicBatching).Unitycan,therefore,discardthisunwanteddataearlysincewewillneverneeditagainuntilthenexttimetheapplicationislaunched.
However,ifthemeshoftenreappearsatruntimewithdifferentscales,thenUnityneedstokeepthisdatainmemorysothatitcanrecalculateanewmeshmorequickly,andsotheRead-WriteEnabledflagshouldbeenabled.DisablingitwillrequireUnitytonotonlyreloadthemeshdata,butalsomaketherescaledduplicateatthesametime,causinga
http://freepdf-books.com
potentialperformancehiccup.
Unitytriestodetectthecorrectbehaviorforthissettingatinitializationtime,butwhenmeshesareinstantiatedandscaledinadynamicfashionatruntime,thenwemustforcetheissuebyenablingthissetting.Thiswillimproveinstantiationspeedoftheobjects,butcostsomememoryoverheadsincetheoriginalmeshdataiskeptarounduntilit’sneeded.
TipNotethatthisalsoapplieswhenusingtheGenerateCollidersoption.
http://freepdf-books.com
Import/calculateonlywhat’sneededThisappearstobeanotherobvioussuggestion,butmeshesdonotonlycontainvertexpositionaldata.TherecouldbeunnecessaryNormalsandTangentsinourmeshthattheShaderswon’tneed,orwecouldbeautogeneratingNormalandTangentcoordinatesthatwewon’tuse,particularlywhentheSmoothingAngleisverylow.Inthesecases,eachvertexrequiresmultiplenormalvectorstocreatethefaceted,flat-shadingstylethatresultsfromit.
Double-checkyourmeshimportsettingsandexaminetheresultantfilesizeandin-gameappearance,bytinkeringwiththeimportsettingstoseeifyoucanmakeanysavingsbystrippingawayunwantedandunnecessarydata.
http://freepdf-books.com
ConsiderbakedanimationsThiswilldependonthe3Driggingandanimationtoolthatweareusing,andtheoverallvertexcountofourmesh;insomecasesbakinganimationscanresultinmuchsmallerfilesizesandmemoryoverheadthanblended/skinnedanimations.Bakedanimationsworkbystoringakeyframedpositionforeachvertexforeachframethatwassampled,andifthemesh’spolygoncountislowenough,thenwemayseesomesignificantsavingsthroughthissimplechange.
Inaddition,howoftenthebakedsampleistakencanusuallybecustomizedbytheexportingapplication.Differentsampleratesshouldbetestedtofindagoodvaluewherethekeymomentsoftheanimationstillshine-throughwhatisessentiallyasimplifiedestimate.
http://freepdf-books.com
LetUnityoptimizemeshesTheOptimizeMeshesoptioninamesh’simportsettingswillreorganizethevertexdataforquickerreadability,andsometimesregeneratethelow-levelrenderingstyle(downtothelevelofpointsversustrisversusstrips)tooptimizetherenderingspeedofthemesh.Simplyput,thisoptionshouldbeenabledinalmostallcases,asthereisverylittlereasontonotletUnitymaketheseadjustmentsforus,unlesswe’vedonesomeprofilingandwe’repositivethatit’ssomehowgeneratingbottlenecks.
Ifwe’regeneratingmeshesprocedurally,thenwecantellUnitytoinvokethisprocessusingtheOptimize()methodonaMeshFilterComponent.Thisprocesscantakesometime,soitshouldbeusedduringinitializationorotherconvenientstoppingpoint.
http://freepdf-books.com
CombinemeshesCombiningmeshesintoalarge,singlemeshcanbeconvenienttoreduceDrawCallsifthemeshesaretoolargeforDynamicBatchinganddon’tplaywellwithotherStaticallyBatchedgroups.ThisisessentiallytheequivalentofStaticBatching,butperformedmanually,sosometimesit’swastedeffortifStaticBatchingcouldtakecareoftheprocessforus.
However,ifwe’reusingtheUnity4FreeEditionwhereStaticBatchingisnotavailabletousorwewishthemeshtomovearoundtheScene,thenthisisagoodoptiontominimizeourDrawCalls.BewarethatitcomeswiththesameriskasStaticBatching.IfanysinglevertexofthemeshisvisibleintheScene,thentheentireobjectwillberenderedtogetherasonewhole.Thiscanleadtoalotofwastedprocessingifthemeshisonlypartiallyvisiblemostofthetime.
ThistechniquealsocomeswiththedrawbackthatitgeneratesawholenewmeshassetfilethatwemustdepositintoourScene,whichmeansanychangeswemaketotheoriginalmesheswillnotbereflectedinthecombinedone.Thisresultsinalotoftediousworkflowefforteverytimechangesneedtobemade,soifStaticBatchingisanoption,itshouldbeusedinstead.
Thereareseveraltoolsavailableonline,whichcancombinemeshfilestogetherforusinUnity.TheyareonlyanAssetStoresearch,orGooglesearchaway.
http://freepdf-books.com
http://freepdf-books.com
SummaryTherearemanydifferentopportunitiesthatwecanexploretoachieveperformancegainsforourapplicationjustbytinkeringwithourimportedassets.Or,fromanotherperspective,thereareplentyofwaystoruinourapplication’sperformancethroughassetmismanagement.
Almosteverysingleopportunityisatrade-offbetweenoneperformancemetricorworkflowtaskandanother.So,wemustremainvigilantandonlypicktherighttechniquesintherightprojectsfortherightreasons.Theworstthingwecandoisimplementsuchchangeswithoutunderstandingtheimpact.It’sexcitingtostumbleonsomebigperformanceenhancingsuggestionoutinthebig,wideworld,butunlessweunderstandhowitworks,andtheresultingcosts,wecaninvitefurtherperformanceproblemsandbottleneckswithoutrealizingit,costingusmoretimeandeffortdowntheroad.
Thisconcludesourexplorationofimprovingperformancethroughartassetmanipulation.Inthenextchapter,wewillbeinvestigatingtheBox2DandPhysXphysicssolutionsprovidedbyUnity,thechangeswecanmaketoourscriptcode,Scene,andprojecttomakethesecomponentsprocessourdatafaster;andbehaviortoavoidthatmightcausethemtostumble.
http://freepdf-books.com
http://freepdf-books.com
Chapter5.FasterPhysicsEachoftheperformance-enhancingsuggestionswe’veexploredthusfarhavebeenprimarilycenteredonreducingsystemrequirementsandavoidingframerateissues.Butatitsmostfundamentallevel,seekingpeakperformancemeansimprovingtheuserexperience.Thisisbecauseeveryframeratehiccup,everycrash,andeverysystemrequirementthatistoocostlyforagivenmarketultimatelydetractsfromthequalityoftheproduct,andleavesuswonderingwhetherweshouldhavetriedhardertotweaksettingsandfixmorebugsbeforerelease.
TherearecertainlyopportunitiestomanipulatePhysicsEnginebehaviorthatimprovealloftheaforementionedissues,butPhysicsEnginesalsofallintoauniquecategoryofhavingadirectimpactongameplayquality.Ifimportantgameplaycollisioneventsgetmissed(suchastheplayerfallingthroughthefloor),orthegamefreezeswhileitcalculatesacomplexsituation,thenthesehaveasignificantimpactongameplayquality.Thisoftenresultsinpullingtheplayeroutoftheexperience,andit’sacoin-tosswhethertheuserfindsitinconvenient,obnoxious,orhilarious.UnlessourgameisspecificallytargetingtheComedyPhysicsgenre(which,incidentally,hasgrowninpopularityinrecentyearswithgameslikeQWOPandGoatSimulator),thesearesituationsweshouldstrivetoavoid.
Forsomegames,thePhysicsEngineisusedtohandleasignificantnumberoftasksduringgameplay,fromcollisiondetectionwithotherobjectsandinvisibletriggerboxestoraycastingandgatheringalistofobjectsinagivenregion.Forexample,itisessentialinplatformerandactiongamestotunethephysicsproperly;howtheplayercharacterreactstoinputandhowtheworldreactstotheplayercharactercanbetwoofthemostimportantaspectsofwhatmakesthegamefeelresponsiveandfun.Othergamesmayonlyusephysicsforsimplegameplayevents,interestingspectacles,andothereye-candy,butthemoreefficientlythePhysicsSystemisused,themoreofaspectaclethatcanbecreated.
Therefore,inthischapter,wewillnotonlycoverwaystoreduceCPUspikes,overhead,andmemoryconsumptionthroughUnity’sPhysicsSystem,butalsoincludewaystoalterphysicsbehaviorwiththeaimofimprovinggameplayquality.Inaddition,becauseUnity’sPhysicsSystemsarea“black-box”,inthatwecan’tdomuchinternaldebugging,itcanbeverytrickytofigureoutexactlywhen,where,andwhycertainphysicsglitchesareplaguingourproject,andwhatweshoulddotopreventthem.Asaresult,themethodscoveredinthischapterwillincludeseveralsuggestionsonhowtoreduceinstabilityandproblematicphysicssituations.
http://freepdf-books.com
PhysicsEngineinternalsUnitytechnicallyfeaturestwodifferentPhysicsEngines:NvidiaPhysXfor3DphysicsandtheOpenSourceprojectBox2Dfor2Dphysics.However,theirimplementationishighlyabstracted,andfromtheperspectiveoftheUnityAPI,bothenginesoperateinanearlyidenticalfashion.
Ineithercase,themoreweunderstandaboutUnity’sPhysicsSystem,themoresensewecanmakeofpossibleperformanceenhancements.So,firstwe’llcoversometheoryaboutUnity’sPhysicsEngines.
http://freepdf-books.com
PhysicsandtimePhysicsEnginesgenerallyoperateundertheassumptionthattimeisiteratinginfixedvaluesoftime,andbothofUnity’sPhysicsEnginesoperateinthismanner.ThePhysicsEnginewillonlycalculateusingveryspecificvaluesoftime,independentofhowmuchtimeittooktorenderthepreviousframe.ThisisknownastheFixedUpdateTimestep,anditissettoavalueof20millisecondsbydefault,or50updatespersecond.
NoteItcanbeverydifficulttogenerateconsistentresultsforcollisionsandforcesbetweentwodifferentcomputersifaPhysicsEngineusesavariabletimestep.Suchenginestendtogenerateinconsistentresultsbetweenmultiplayerclients,andduringrecordedreplays.
Iftoomuchtimehaspassedbetweenframes(alowframerate),thenthePhysicsSystemmayupdatemultipletimesbeforerenderingbeginsagain.Conversely,ifnotenoughtimehaspassedsincethepreviousrender(ahighframerate),thenthephysicsupdatemaybeskippeduntilafterthenextrendercall.
TheFixedUpdate()methodrepresentsthemomentwhenthePhysicsSystemperformssimulationtimestepupdates.ItisoneofseveralimportantUnitycallbackswecandefineinaMonoBehaviourscriptand,ingeneral,FixedUpdate()isusedtodefineframe-rate-independentbehavior.Thiscallbackisusuallyusedforcalculationssuchasartificialintelligence(whicharealsoeasiertoworkwithifweassumeafixedupdatefrequency),butthisisalsowhereweshouldmodifyRigidbodyobjectsduringgameplay.
ThefollowingdiagramshowsanimportantsnippetoftheUnityOrderofExecutiondiagram:
Note
http://freepdf-books.com
ThefullOrderofExecutiondiagramcanbefoundat:http://docs.unity3d.com/Manual/ExecutionOrder.html.
TheFixedUpdateloopAswecansee,FixedUpdate()isinvokedjustpriortothePhysicsSystemperformingitsownupdateandthetwoareinextricablylinked.TheprocessbeginswithdeterminingwhetherenoughtimehaspassedtobeginthenextFixedUpdate.TheoutcomewillvarydependingonhowmuchtimehaspassedsincethelastFixedUpdate.
Ifenoughtimehaspassed,thentheFixedUpdate()methodisinvokedglobally,andanyCoroutinestiedtoFixedUpdates(thatis,yieldstoWaitForFixedUpdate())arehandledimmediatelyafterward,followedbyphysicsupdatesandtrigger/collidercallbacks.
Iflessthan20mshasgonebysincethelastFixedUpdate,thenthecurrentFixedUpdateisskipped.Atthispoint,input,gameplaylogic,andrenderingmusttakeplaceandcompletebeforeUnityperformsthenextFixedUpdatecheck,andsoon,asthisprocessrepeatsitselfduringruntime.ThisdesigngivesbothFixedUpdatesandthePhysicsSystemahigherpriorityoverrendering,butforcesthephysicssimulationintoafixedframerate.
NoteInordertoensuresmoothmotionduringframeswherephysicsupdatesareskipped,somePhysicsEngines(includingUnity’s)interpolatethestatebetweenthepreviousstateandthecurrentstatebasedonhowmuchtimeremainsuntilthenextFixedUpdate.
Thisensuresthat,graphically,objectsappeartomovesmoothlyduringhighframerates,eventhoughtheyareonlybeingupdatedevery20ms.
MaximumAllowedTimestepItisimportanttonotethatifalotoftimehaspassedsincethelastFixedUpdate(forexample,thegamefrozemomentarily),thenphysicsandFixedUpdateswillcontinuetobecalculateduntiltheyhave“caughtup”withthecurrenttime.Forexample,ifthepreviousframetook100mstorender(forexample,asuddenperformancespikedroppingthegameto10FPS),thenthePhysicsSystemwillneedtoupdatefivetimes.TheFixedUpdate()methodwillthereforebecalledfivetimesbeforeUpdate()canbecalledagainduetothedefaultFixedUpdateTimestepof20ms.If,forwhateverreason,theprocessingofthesefiveupdatesconsumes20msormore,thenitwillneedtoinvokeasixthupdate!
Consequently,it’spossibleduringmomentsofheavyphysicsactivitythatthePhysicsEnginecantakemorethan20mstocompleteaphysicsupdate,whichitselftakesanother20ms,andsoon,suchthatitisneverabletoescapeandallowanotherframetorender(thisisoftenknownasthe“spiralofdeath”).TopreventthePhysicsEnginefromlockingupourgameduringthesemoments,thereisamaximumamountoftimethatthePhysicsEngineisallowedtoprocessbetweeneachrender.ThisthresholdiscalledtheMaximumAllowedTimestep,andifthecurrentFixedUpdateistakinglongertoprocessthanthisvalue,thenitwillsimplystopandforgofurtherprocessinguntiltheendofthenextrender.
http://freepdf-books.com
Thisdesignallowstherenderingsystemtoatleastrenderthecurrentstate,andallowforgameplaylogictomakesomedecisionsduringraremomentswherephysicscalculationhasgoneballistic(punintended).
PhysicsupdatesandruntimechangesWhenthePhysicsSystemprocessesthenexttimestep,itmustmoveanyactiveRigidbodyobjects,detectanycollision,andinvokethecollisioncallbacksonthecorrespondingobjects.It’sforexactlythisreasonthattheUnitydocumentationexplicitlywarnsustoonlymakechangestoRigidbodyobjectsinFixedUpdate()andotherphysicscallbacks.Thesemethodsaretightly-coupledwiththeupdatefrequencyofthePhysicsEngine,asopposedtootherpartsofthegameloop,suchasUpdate().
ThismeansthatcallbackssuchasOnTriggerEnter()aresafeplacestomakeRigidbodychanges,whilemethodssuchasUpdate()andtime-basedCoroutinesarenot.NotfollowingthisadvicecouldcauseunexpectedphysicsbehaviorasmultiplechangesaremadetothesameobjectbeforethePhysicsSystemisgivenachancetocatchandprocessallofthem,resultinginsomeespeciallyconfusinggameplaybugs.
ItlogicallyfollowsthatthemoretimewespendinanygivenFixedUpdateiteration,thelesstimewehaveforthenextgameplayandrenderingpass.Mostofthetimethisresultsinminor,unnoticeablebackgroundprocessingtasks,asthePhysicsEnginebarelyhasanyworktodo,andFixedUpdate()callbackshavealotoftimetocompletetheirwork.
But,insomegames,thePhysicsEnginecouldbeperformingalotofcalculationsduringeachandeveryFixedUpdate.Thiskindofbottleneckinginphysicsprocessingtimewillaffectourrenderingframerate,causingittoplummetasthePhysicsSystemistaskedwithgreaterandgreaterworkloads.Essentially,therenderingsystemwillproceedasnormal,butwheneverit’stimeforaFixedUpdate,thenitwouldbegivenverylittletimetogeneratethecurrentdisplay,causingasuddenstutter.ThisisinadditiontothevisualeffectofthePhysicsSystemstoppingearlybecauseithittheMaximumAllowedTimestep.Allofthistogetherwillgenerateapooruserexperience.
Hence,tokeepasmoothandconsistentframerate,thegoalistofreeupasmuchtimeaswecanforrenderingbyminimizingtheamountoftimethePhysicsSystemtakestoprocessanygiventimestep.Thisappliesinboththebest-casescenario(nothingmoving)andworst-casescenario(everythingsmashingintoeverythingelseatonce).Thereareanumberoftime-relatedfeaturesandvalueswecantweakwithinthePhysicsSystemtoavoidperformancepitfallssuchasthese.
http://freepdf-books.com
StaticandDynamicCollidersThereisarathersignificantnamespaceconflictwiththeterm“static”inUnity.WehavealreadycoveredstaticGameObjects,thevariousStaticsubflags,theStaticBatchingfeature,andthenthere’stheuseofstaticvariablesandclassesinC#.Meanwhile,Unity’soriginalphysicsimplementationfor3DobjectshasitsownconceptofStaticColliders.Later,when2Dphysicswasimplemented,itkeptthesameconceptofStaticColliderstokeepthingsconsistentbetweenthem.
So,withthisinminditisveryimportanttorememberthatStaticCollidersarenotobjectswiththeStaticflagenabled,sincethoseflagsareaUnityEngineconcept.StaticCollidersaresimplycollidersthatdonothaveanattachedRigidbody.Meanwhile,colliderswithanattachedRigidbodyarecalledDynamicColliders.
ThePhysicsSystemcombinesStaticCollidersintoadifferent,optimizeddatastructure,whichhelpstosimplifyfutureprocessingtasks.Theseobjectswillnotreacttoimpulsesappliedbyobjectscollidingwiththem,butwillpreventotherobjectsfrommovingthroughthem.ThismakesStaticCollidersidealforworldbarriersandotherobstaclesthatmustnotmove.
http://freepdf-books.com
CollisiondetectionTherearethreesettingsforcollisiondetectioninUnity:Discrete,Continuous,andContinuousDynamic.TheDiscretesettingeffectivelyteleportsobjectsasmalldistanceeverytimestepbasedontheirvelocityandhowmuchtimehaspassed.Afteralltheobjectshavebeenmoved,itthenperformsabounding-volumecheckforanyoverlaps,treatsthemascollisions,andresolvesthembasedontheirphysicalpropertiesandhowtheyoverlap.Thismethodriskscollisionsbeingmissedifsmallobjectsaremovingtooquickly.
Bothofthecontinuouscollisiondetectionmethodsworkbyinterpolatingobjectsfromtheirstartingandendingpositionsforthecurrenttimestepandcheckingforanycollisionsalongtheway.Thisreducestheriskofmissedcollisionsandgeneratesamoreaccuratesimulation,attheexpenseofsignificantlygreaterCPUoverheadcomparedtotheDiscretesetting.
TheContinuoussettingonlyenablescontinuouscollisiondetectionbetweenthegivencolliderandStaticColliders(recallthatStaticCollidersaresimplycolliderswithoutanyattachedRigidbody).ThesameobjectswillbesimultaneouslytreatedasusingtheDiscretesettingwhenitcomestocollisiondetectionwithotherdynamicobjects(thosewithanattachedRigidbody).Meanwhile,theContinuousDynamicsettingisslightlydifferentasitenablesthesamecontinuouscollisiondetection,butdoessobetweenthegivencolliderandallothercolliders,bothStaticandDynamic.
Thefollowingscreenshotshowshowthediscreteandcontinuouscollisiondetectionmethodswouldworkforapairofsmall,fast-movingobjects:
Thisisanextremeexampleforthesakeofillustration.Inthediscretecase,wecanseethattheobjectsare“teleporting”adistancearoundfourtimestheirownsizeinasingletimestep,whichwouldtypicallyonlyhappenwithverysmallobjectswithveryhighvelocities,andishenceveryrareifourgameisrunningoptimally.Inmostcases,thedistancestheobjectstravelinasingle20mstimesteparemuchsmallerrelativetothesizeoftheobject,andsothecollisioniseasilydetected.
http://freepdf-books.com
CollidertypesTherearefivedifferenttypesof3DCollidersinUnity5.Inorderofthelowestperformancecosttothegreatest,theyare:Sphere,Capsule,Cylinder,Box,andMeshColliders.Thefirstfourcollidertypesareconsideredprimitivesandmaintainconsistentshapes,althoughtheycangenerallybescaledindifferentdirectionstomeetcertainneeds.MeanwhileMeshColliderscanbecustomizedtoaparticularshapedependingontheassignedmesh.
NoteTherearealsothreemain2DColliders:Circle,Box,andPolygon,whicharefunctionallysimilartoSphere,Box,andMeshCollidersin3D.Allofthefollowinginformationisessentiallytransferabletotheequivalent2Dshape.
Inaddition,therearetwovarietiesofMeshCollider:convexandconcave.Thedifferenceisthataconcaveshapefeaturesatleastoneinternalangle(ananglebetweentwoedgesinsidetheshape)ofgreaterthan180degrees.Toillustratethis,thefollowingscreenshotshowsthedistinguishingdifferencebetweenconvexandconcaveshapes:
TipAneasywaytorememberthedifferencebetweenconvexandconcaveshapesisthataconcaveshapehasatleastone“cave”withinit.
BothMeshCollidertypesusethesameComponent(aMeshCollider!),andwhichtypeofMeshCollidergetsgeneratedistoggledusingtheConvexcheckbox.EnablingthisoptionwillallowtheobjecttocollidewithotherMeshCollidersmarkedasConvex,aswellasprimitiveshapes(Spheres,Boxes,andsoon.).Inaddition,iftheConvexcheckboxisenabledforaMeshColliderwithaconcaveshape,thenthePhysicsSystemwillautomaticallysimplifytheconcaveshape,generatingacolliderwiththenearestconvexshapeitcan.Intheprecedingexample,ifweimporttheconcavemeshontheright,and
http://freepdf-books.com
enabletheConvexcheckbox,itwouldgenerateacollidershapeclosertotheconvexmeshontheleft.
Ineithercase,thePhysicsSystemwillattempttogenerateacolliderthatmatchestheshapeoftheattachedmesh,withanupperlimitof255vertices.Ifthetargetmeshhasmoreverticesthanthis,thenitwillthrowanerrorduringgenerationofthemesh.NotethatConcaveMeshColliderswithattachedRigidbodyobjectsarenotsupportedinUnity5.ConcaveshapescanonlybeusedasStaticColliders(forexample,acollidableobjectintheworldthatdoesn’tmove),orTriggerVolumes(forexample,anoddly-shapedpoolofacid).
http://freepdf-books.com
TheCollisionMatrixThePhysicsSystemfeaturesaCollisionMatrixthatdefineswhichobjectsareallowedtocollidewithwhichotherobjects.ObjectsthatdonotfitthismatrixareautomaticallyignoredbythePhysicsSystemwhenthetimecomestoresolveboundingvolumeoverlapsandcollisions.Thissavesonphysicsprocessingduringcollisiondetectionstages,andalsoallowstheobjectstomovethroughoneanotherwithoutanycollisionstakingplace.
TheCollisionMatrixsystemworksthroughUnity’sLayersystem.Thematrixrepresentseverypossiblelayer-to-layercombinationthatmightbepossible,andenablingacheckboxmeansthatcollidersinbothofthoselayerswillbecheckedduringthecollisiondetectionphase.Notethatthere’snowaytoallowonlyoneofthetwoobjectstorespondtothecollision.Ifonelayercancollidewithanother,thentheymustbothrespondtothecollision(withtheexceptionofStaticColliders,whicharen’tallowedtorespondtocollisions).
TheCollisionMatrixcanbeaccessedthroughEdit|ProjectSettings|Physics(orPhysics2D)|LayerCollisionMatrix.
Notethatwearelimitedtoonly32totallayersforourentireproject(sincethePhysicsSystemusesa32-bitbitmasktodetermineinter-layercollisionopportunities),sowemustorganizeourobjectsintosensiblelayersthatwillextendthroughouttheentirelifetimeoftheproject.If,forwhateverreason,32layersarenotenoughforourproject,thenwemightneedtofindcunningwaystoreuselayers,orremovelayersthataren’tnecessary.
http://freepdf-books.com
RigidbodyactiveandsleepingstatesEverymodernPhysicsEnginesharesacommonoptimizationtechniquewherebyobjectsthathavecometoresthavetheirinternalstatechangedfromanactivestatetoasleepingstate.Whilesleeping,little-to-noprocessortimewillbespentupdatingtheobjectuntilithasbeenawokenbysomeexternalforceorevent.
Thevalueofmeasurementthatisusedtodetermine“rest”tendstovarybetweenengines;itcouldbecalculatedusinglinearandrotationalspeed,kineticenergy,momentum,orsomeotherphysicalpropertyoftheRigidbody.Inanycase,ifanobjecthasnotexceededsomethresholdvalueinashorttime,thenthePhysicsEnginewillassumetheobjectwillnolongerneedtomoveagainuntilithasundergoneanewcollision,oranewforcehasbeenappliedtoit.Untilthen,thesleepingobjectwillmaintainitscurrentposition.
Inessence,thePhysicsEngineisautomaticallycullingsomeprocessingtasksforobjectsthathaveasmallamountofkineticenergy.Butthisdoesnotremoveitentirelyfromthesimulation.IfamovingRigidbodyapproachesthesleepingobject,thenitmuststillperformcheckstoseewhethernearbyobjectshavecollidedwithit,whichwouldreawakenthesleepingobject,reintroducingittothesimulationforprocessing.ThethresholdvalueforthesleepingstatecanbemodifiedunderEdit|ProjectSettings|Physics|SleepThreshold.WecanalsogetacountofthetotalnumberofactiveRigidbodyobjectsfromthePhysicsareaoftheProfiler.
http://freepdf-books.com
RayandobjectcastingAnothercommonfeatureofPhysicsEnginesistheabilityto“cast”arayfromonepointtoanother,andgatherdataaboutoneormoreoftheobjectsinitspath.Itisprettycommontoimplementimportantgameplaytasksthroughcastingandbounding-volumechecks.Firinggunsistypicallyimplementedbyperformingraycastsfromtheplayertothetargetlocationandfindinganyviabletargetsinitspath(evenifit’sjustawall).
Wecanalsoobtainalistoftargetswithinanexplosionradius,suchasfromagrenadeorfireball,usingaPhysics.OverlapSphere()check,andsothisistypicallyhowsucharea-of-effectabilitiesareimplemented.
Wecanevencastentireobjectsforwardinspace,usingPhysics.SphereCast()andPhysics.CapsuleCast().Thesemethodsareoftenusedifweneedraysoflargersizes,orwewishtoseewhatwouldbeinthepathofamovingcharacter.
http://freepdf-books.com
http://freepdf-books.com
PhysicsperformanceoptimizationsNowthatwehaveanunderstandingofthemostsignificantfeaturesoftheUnityPhysicsEngine,wecancoversomeoptimizationtechniquestoimproveourgame’sphysicsperformance.
http://freepdf-books.com
ScenesetupFirstly,thereareanumberofbestpracticeswecanapplytoourScenestoimproveconsistencyofthephysicssimulation.NotethatthesetechniqueswillnotnecessarilyimproveCPUormemoryusage,buttheywillresultinareducedlikelihoodofinstabilityfromthePhysicsEngine.
ScalingWeshouldtrytokeepallphysicsobjectscalesintheworldascloseto1:1:1aswepossiblycan.Thismeansthatforthedefaultgravityvalueof-9.81,theunitscaleoftheworldisimpliedtobe1meterperunit,sincetheforceofgravityatthesurfaceoftheEarthis9.81m/s²(mostgamesaretryingtosimulatethissituation).Ourobjectsizesshouldreflectourimpliedworldscale,sincescalingthemtoolargewillcausegravitytoappeartomovetheobjectsmuchmoreslowlythanwewouldexpect.Theconverseisalsotrue;scalingobjectstoosmallwillmakethemappeartofalltooquicklyandwillnotseemrealistic.
Wecantweaktheworld’simpliedscalebymodifyingthestrengthofgravityunderEdit|ProjectSettings|Physics(orPhysics2D)|Gravity.However,beawarethatanyfloating-pointarithmeticwillbemoreaccuratewithvaluescloserto0,soifwehavesomeobjectsthathavescalevaluesfarabove(1,1,1),eveniftheymatchtheimpliedworld-scale,thenwecouldstillobserveerraticphysicsbehavior.So,earlyintheprojectweshouldimportandscaleourmostcommonphysicsobjectsaroundascalevalueof(1,1,1),andthenadjustthevalueofgravitytomatch.Thiswillgiveusareferencepointtoworkwithasweintroducenewobjects.
TipBewarnedthatUnity4alsohasavalueforSpeedofSoundinitsAudiosettings,whichisusedduringanyDoppler-basedaudioeffects.Thedefaultvalueis343tomatchthespeedofsoundinairof343ms-1.Changingtheimpliedworldscaleviagravitywillrequirethisvaluetobeadjustedtomaintainconsistency.Unity5calculatestheDopplerEffectdifferentlyandsothisvariablewasremoved,nolongermakingthisissueaconcern.
PositioningSimilarly,keepingallobjectscloseto(0,0,0)inpositionwillresultinbetterfloating-pointaccuracy,improvingtheconsistencyofthesimulation.SpaceSimulatorandFree-Runninggamestrytosimulateincrediblylargespaces,andtheytypicallyusethistechniqueasmuchaspossiblebysecretlyteleporting,(orsimplykeeping)theplayercharactercenteredintheworld.Atthispoint,eithereverythingelseismovedtosimulatetravel,orvolumesofspacearecompartmentalizedsothatphysicscalculationsarealwayscalculatedwithvaluesclosetozero.Thisensuresthatallobjectsremaincloseto(0,0,0)inordertoavoidfloating-pointinaccuraciesastheplayertravelsgreatdistances.
Othertypesofgamesshouldnotriskintroducingfloating-pointinaccuracy,sounlesswe’realreadydeepintoourproject(suchthatchangingandre-testingeverythingatalate
http://freepdf-books.com
stagewouldbetoomuchhassle),weshouldtrytokeepallofourphysicsobjectscloseto(0,0,0).Plus,thisissimplygoodpracticeforourprojectworkflowasitmakesitmuchfastertoaddandpositionobjectsinourgameworld.
MassTheUnitydocumentationrecommendsthatobjectmassvaluesstayaround0.1,withnovaluesexceeding10,duetotheinstabilityitgenerates:http://docs.unity3d.com/ScriptReference/Rigidbody-mass.html.
Thismeansweshouldnotthinkofmassintermsofmeasurementssuchaspoundsorkilograms,butratherarelativevaluebetweenobjects.Weshouldtrytomaintainconsistentandreasonableratiosofmassbetweencollidingobjects.Havingobjectscollidingwithamassratioofgreaterthan1,000willmostcertainlyresultinerraticbehaviorduetothelargemomentumdifferenceandeventuallossoffloatingpointprecision.Weshouldtrytoensureinter-objectcollisionsoccurwithobjectswithsimilarvaluesoftheirmassproperty,andobjectpairsthathaveasignificantscaledifferenceshouldbeculledwiththeCollisionMatrix(moreonthisshortly).
TipImpropermassratiosarethemostcommoncauseforphysicsinstabilityanderraticbehavior.
NotethattheforceofgravityatthecentreoftheEarthaffectsallobjectsequally,regardlessoftheirmass,soitdoesnotmatterifweconsideramasspropertyvalueof1tobethemassofarubberballorthemassofawarship.There’snoneedtoadjusttheforceofgravitytocompensateforanyassumptionswe’remakingwiththeserelativemasspropertyvalues.Whatdoesmatter,however,istheamountofairresistancethegivenobjectundergoeswhilefalling(thisiswhyafeatherfallsslowerthanasolidobjectofidenticalmass).So,tomaintainrealisticbehavior,wemayneedtocustomizethedragpropertyforsuchobjectsorcustomizetheforceofgravityonaper-objectbasis(suchasdisablingtheUseGravitycheckboxandapplyingacustomgravitationalforceviaScriptcode).
http://freepdf-books.com
UseStaticCollidersappropriatelyAspreviouslymentioned,thePhysicsSystemautomaticallygeneratesadatastructurefromthedataofallStaticColliders(colliderswithoutRigidbodyobjects)separatelyfromthestructurethatmanagesDynamicColliders(colliderswithRigidbodyobjects).Unfortunately,ifnewobjectsareintroducedintothedatastructureatruntime,thenitmustberegenerated.ThisislikelytocauseasignificantCPUspike.ThismakesitvitalthatweavoidinstantiatingnewStaticCollidersduringgameplay.
Inaddition,merelymoving,rotating,orscalingStaticCollidersalsotriggersthisregenerationprocessandshouldbeavoided.Ifwehavecollidersthatwewishtomovearoundwithoutreactingtootherobjectscollidingwiththeminaphysicalway,thenweshouldattachaRigidbodytomakeitaDynamicColliderandsettheKinematicflagtotrue.Thisflagpreventstheobjectfromreactingtoexternalimpulsesfrominter-objectcollisions.ThisallowsittobehavesimilartoaStaticCollider,butitisnowinadatastructurethatproperlysupportsmovingobjects,sowecanmoveitaroundfromScriptcode(duringFixedUpdates!),anditwillapplyimpulsestootherobjects.
TipIt’sforthisreasonthattheKinematicflagisoftenusedonobjectscontrolledbyplayers;theycanpushotherobjectsaroundbutshouldn’tbepushedaroundthemselves.
http://freepdf-books.com
OptimizetheCollisionMatrixAsweknow,thePhysicsSystem’sCollisionMatrixdefineswhichobjectsassignedtocertainlayersareallowedtocollidewithobjectsassignedtootherlayers.Ortoputitmoresuccinctly,whichobjectpairsareevenconsideredbythePhysicsSystem.Everyotherobject-layer-pairissimplyignoredbythePhysicsEngine,whichmakesthisanimportantavenueforminimizingPhysicsEngineworkloadsinceitreducesthenumberofbounding-volumechecksthatmustbeperformedateachandeverytimestep.
TipReminder:theCollisionMatrixcanbeaccessedthroughEdit|ProjectSettings|Physics(orPhysics2D)|LayerCollisionMatrix.
ThefollowingscreenshotshowsacommonCollisionMatrixforanarcadeshootergame:
Inthisexample,wehaveminimizedthenumberofpossibleinter-objectcollisionsforthePhysicsSystemtocheck.Sincepowerupscanonlybepickedupbytheplayer,thenthereisnoneedtocomparecollisionsbetweenpowerupsandobjectsfromanyotherlayers.Meanwhile,wedon’twishforprojectilestocollidewiththeobjectthatfiredit,whichexcludesEnemyProjectilesfromcollidingwithenemies,andPlayerProjectilesfromcollidingwiththeplayer.Wewanteverythingtocollidewiththegameworld(wallsandothersurfaces),andperhapswedon’twantprojectilescollidingwithotherprojectiles(althoughsomegamesmightwantthis!).
WeshouldperformlogicalsanitycheckslikethisforalloftheLayercombinationsintheCollisionMatrixtoseewhetherwe’rewastingprecioustimecheckingforinter-objectcollisionsbetweenobject-pairsthataren’tnecessary.
http://freepdf-books.com
PreferdiscretecollisiondetectionWeshouldusetheDiscreteoptionbydefaultforthemajorityofobjects.Teleportingobjectsonceandperformingasingleoverlapcheckbetweennearbyobject-pairsisafairlytrivialamountofwork.However,theamountofcalculationittakestointerpolatetheobjectsbetweentheirstartingandendingpositions,andsimultaneouslyverifyanyslightbounding-volumeoverlapsbetweenthesepointsovertime,issignificantlygreater.
Consequently,theContinuouscollisiondetectionoptionisanorderofmagnitudemoreexpensivethantheDiscretedetectionmethod,andtheContinuousDynamiccollisiondetectionsettingisanorderofmagnitudemoreexpensivethanContinuous!HavingtoomanyobjectsofthecontinuoustypeswillcauseseriousperformancedegradationincomplexScenes.Ineithercase,thecostsaremultipliedbythenumberofobjectsthatneedtobecomparedduringanygivenframeandwhetherornotthecomparisoncolliderisStaticorDynamic.
Ergo,thecontinuousdetectionsettingsshouldonlybeusedinextremecircumstances.TheContinuoussettingshouldbeusedwhenimportantcollisionsarefrequentlymissedwiththestaticworld,forinstance,ifweexpectcertainobjectstomovequickly,andwewishtobecertaintheyneverfallthroughthegameworldorteleportthroughwalls.Finally,theContinuousDynamicsettingshouldonlybeusedifthesamesituationappliesbutwewishtocatchcollisionsbetweenpairsofvery-fastmovingDynamicColliders.Unlesswehavegoodreasontousethem,allothersituationsshouldfavortheDiscretesetting.
But,perhaps,theDiscretesettingisn’tworkingwell-enoughonalargescale.Perhapsourentiregamerevolvesaroundalotofsmallphysicsobjectsanddiscretecollisiondetectionsimplyisn’tcatchingenoughcollisionstomaintainproductquality.Well,we’reinluck,becausewecancustomizethephysicstimesteptogivetheDiscretecollisionoptionabetterchanceofcatchingsuchcollisionsbymodifyinghowfrequentlytheenginechecksforFixedUpdates.
http://freepdf-books.com
ModifytheFixedUpdatefrequencyAsmentionedpreviously,FixedUpdatesandphysicstimestepprocessingarestrongly-coupled,sobymodifyingthefrequencyofFixedUpdatecheckswenotonlychangethefrequencythatthePhysicsSystemwillcalculateandresolvethenextcallback,butwewillalsochangehowfrequentlyFixedUpdate()callbacksarebeinginvoked.Consequently,changingthisvaluecanberiskyifwe’redeepintoourprojectandhavealotofbehaviorthatdependsonthesecallbacks.
AlteringtheFixedUpdatefrequencycanbeaccomplishedthroughtheEdit|ProjectSettings|Time|FixedTimesteppropertyintheEditor,orthroughtheTime.fixedDeltaTimepropertyinscriptcode.
Reducingthisvalue(increasingthefrequency)willforcethePhysicsSystemtoprocessmorefrequently,givingitabetterchanceofcatchingcollisionsbetweenourDynamic,Discreteobjects.Naturally,thiscomeswithaCPUcostsincewe’reinvokingmoreFixedUpdate()callbacks,aswellasaskingthePhysicsEnginetoupdatemorefrequently,havingitmoveobjectsandverifycollisionsmoreoften.
Conversely,increasingthisvalue(decreasingthefrequency)providesmoretimefortheCPUtocompleteothertasksbeforeitmusthandlephysicsprocessingagain,orlookingatitfromanotherperspective,givingthePhysicsSystemmoretimetoprocessthelasttimestepbeforeitbeginsprocessingthenextone.But,loweringtheFixedUpdatefrequencywouldessentiallylowerthemaximumvelocityatwhichobjectscanbemovingbeforethePhysicsSystemcannolongercapturecollisionsbetweendiscreteobjects(dependingontheobjects’sizes).
ThismakesitabsolutelyvitaltoperformasignificantamountoftestingeachtimetheFixedTimestepvalueischanged.Evenwithacompleteunderstandingofhowthisvalueworks,itisdifficulttopredictwhattheoveralloutcomewilllooklikeduringgameplay,
http://freepdf-books.com
andwhethertheresultispassableforqualitypurposes.Hence,changestothisvalueshouldbemadeearlyintheproject’slifecycleandthenmadeinfrequentlyinordertogetasufficientamountoftestingagainstasmanyphysicssituationsaspossible.
ItmighthelptocreateatestScenethatflingssomeofourhigh-velocityobjectsatoneanothertoseeiftheresultsareacceptable,andrunthroughthisScenewheneverFixedTimestepchangesaremade.Butactualgameplaytendstoberathercomplex,withmanybackgroundtasksandunanticipatedplayerbehaviorthatcausesadditionalworkforthePhysicsSystem,orgivesitlesstimetoprocessthecurrentiteration.Actualgameplayconditionsaredifficulttoduplicateinavacuum,andthere’snosubstitutefortherealthing,sothemoretestingwecanaccomplishagainstthecurrentvalueofFixedTimestep,themoreconfidentwecanbethatthechangesmeetacceptablequalitystandards.
Wealwayshavethecontinuouscollisiondetectionoptionsasalastresorttooffsetsomeoftheresultinginstabilitywe’reobserving.Butunfortunately,evenifthechangesaretargeted,itismorelikelythatthiswillcausefurtherperformanceissuesthanwestartedwithduetotheoverheadcostsofcontinuouscollisiondetection.ItwouldbewisetoprofileourScenebeforeandafterenablingcontinuouscollisiondetectiontoverifythatthebenefitsareoutweighingthecosts.
http://freepdf-books.com
AdjusttheMaximumAllowedTimestepIftheMaximumAllowedTimestepvaluegetshitregularly,thenitwillresultinsomeprettybizarre-lookingphysicsbehavior.Rigidbodyobjectswillappeartoslowdownorfreezeinspace,sincethePhysicsEngineneedstokeepexitingearlybeforeithasfullyresolveditsentiretimequota.Inthiscase,itisaclearsignthatweneedtooptimizeourphysicsfromotherangles.Butattheveryleastwecanbeconfidentthethresholdwillpreventthegamefromcompletelylockingupduringaphysicsprocessingspike.
ThissettingcanbeaccessedthroughEdit|ProjectSettings|Time|MaximumAllowedTimestep.Thedefaultsettingistoconsumeamaximumof0.333seconds,whichwouldmanifestitselfasaverynoticeabledropinframerate(amere3FPS)ifitwerebreached.Ifweeverfeeltheneedtochangethissetting,thenweobviouslyhavesomebigproblemswithourphysicsworkload,soitisrecommendedtoonlytweakthisvalueifwehaveexhaustedallotherapproaches.
http://freepdf-books.com
Minimizecastandbounding-volumechecksAlloftheraycastingmethodsareincrediblyuseful,buttheyarerelativelyexpensive(particularlyCapsuleCast()andSphereCast()),requiringustominimizehowoftentheyarecalled.WeshouldavoidcallingthesemethodsregularlywithinUpdatecallbacksorCoroutines,savingthemonlyforkeyeventsinourscriptcode.
Ifweabsolutelymustrelyonpersistentline,ray,orarea-of-effectcollisionareasinourScene(examplesincludesecuritylasers,orcontinuouslyburningfires),thentheywouldbebettersimulatedusingasimpleTriggerCollider,ratherthanperformingcontinuousraycastingoroverlapchecks.
Ifsuchreplacementsarenotpossible,andwetrulyneedpersistentcastingchecksusingthesemethods(suchasared-dotlasersight),thenwecanminimizetheamountofprocessingeachcallmakesbyexploitingtheLayerMaskobjects.
Forexample,alazyraycastwouldlooklikeso:
[SerializeField]float_maxRaycastDistance;
voidPerformRaycast(){
RaycastHithitInfo=newRaycastHit();
if(Physics.Raycast(newRay(transform.position,transform.forward),
outhit,_maxRaycastDistance)){
//handleraycastresulthere
}
}
ButthisoverloadofPhysics.Raycast()willcausetheraytocollidewiththefirstobjectofanylayerinitspath.ThePhysics.RaycastmethodhasmultipleoverloadsthatacceptaLayerMaskobjectforanargument.Wecanusethistocustomizewhichobjectsshouldbecheckedbytheraycast,simplifyingtheworkloadforthePhysicsEngine:
[SerializeField]float_maxRaycastDistance;
[SerializeField]LayerMask_layerMask;
voidPerformRaycast(){
RaycastHithitInfo=newRaycastHit();
if(Physics.Raycast(newRay(transform.position,transform.forward),
outhit,_maxRaycastDistance,_layerMask)){
//handleraycastresulthere
}
}
TheLayerMaskobjectcanthenbeconfiguredthroughtheobject’sInspectorview:
http://freepdf-books.com
TipNotethat,becausetheRaycastHitandRayclassesaremanagedbythenativememoryspaceoftheUnityEngine,theydon’tresultinmemoryallocationsthatdrawtheattentionoftheGarbageCollector.WewilllearnmoreaboutsuchactivityinChapter7,MasterfulMemoryManagement.
http://freepdf-books.com
AvoidcomplexMeshCollidersInorderofefficiency,thevariouscollidersare:Spheres,Capsules,Cylinders,Boxes,ConvexMeshColliders,andfinallyConcaveMeshColliders.However,thefourmainprimitivesareanorderofmagnitudemoreefficientthaneitheroftheMeshColliders,asthemathematicalcalculationsfordetectingandresolvingcollisionsbetweenthemarefairlysuccinctandoptimized.Performingcomparisonsbetweenaconvexshapeandanothercollidercanbeacostlyprocess,whilecomparingbetweenaconcaveshapeandanythingelseisevenmoreexpensive.
NotePerformingruntimebounding-volumechecksbetweenpairsofconcaveshapesisperhapstheclosestthingto“MathematicalArmageddon”thatwemightfindinareal-timephysicssimulation(atleastforafewmoreyears!).Toprotectusfromourownstupidity,Unityeffectivelybansusfromperformingconcave-to-concaveMeshColliderboundingvolumechecks.
Agreatironybetweenphysicsandgraphicsin3Dapplicationsishowdifficultitistohandlesphericalandboxobjectsbetweenthetwoofthem.Theperfectsphericalmeshwouldrequireaninfinitenumberofpolygonstogenerate,buthowasphereisrepresentedinaPhysicsEngineisrelativelytrivialtoresolveforcontactpointsandcollisions.Conversely,asimpleboxtakesaminisculenumberofpolygonsandefforttoproducegraphically,andyettakessignificantlymoremathematicsandprocessingpowertofindcontactpointsandresolvecollisionsfor.Thisimpliesthatgettingthemostoutofbothgraphicsandphysicswouldbetopopulateourworldwithlow-polygongraphicalobjects,representedassphereswithinthePhysicsSystem.However,thiswouldmakeabsolutelynosensetoahumanobserverastheywitnesssharp,pointyobjectsrollingaroundlikeballs.
ItisalwaysimportanttorememberwhenworkingwithPhysicsEnginesthatthephysicalrepresentationofanobjectdoesnotnecessarilyneedtomatchitsgraphicalrepresentation.Thisisbeneficialasagraphicalmeshcanoftenbecondenseddownintoamuchsimplershape,generatingaverysimilarphysicsbehaviorandsparingustheneedtouseanoverly-complexMeshCollider.
Thisseparationofrepresentationsbetweengraphicsandphysicsallowsustooptimizetheperformanceofonesystemwithout(necessarily)negativelyaffectingtheother.Iftherewouldbenonoticeablerepercussionsongameplay,thenwearefreetorepresentcomplexgraphicalobjectswiththesimplestphysicsshapesbehind-the-scenes.Iftheplayernevernotices,thennoharmisdone!
So,wecansolvethisprobleminoneoftwoways:eitherbyapproximatingthephysicsbehaviorofthecomplexshapeusingone(ormore)ofthestandardprimitives,orausingamuchsimplerMeshCollider.
UsesimplerprimitivesMostshapescanbeapproximatedusingoneofthefourprimitivecolliders(inorderof
http://freepdf-books.com
efficiency):Spheres,Capsules,Cylinders,orBoxes.Infact,wedonotneedtorepresenttheobjectusingonlyasinglecollider;wearefreetouseseveralcollidersifitservesourneedsforcreatingacomplexcollisionshapebyattachingadditionalchildGameObjectswiththeirowncolliders.ThisisalmostalwayslesscostlythanusingasingleMeshColliderandshouldbepreferredovermorecomplexsolutions.
Thefollowingimageshowsahandfulofcomplexgraphicalobjects,representedbyoneormoresimplerprimitivesinthePhysicsSystem:
UsingaMeshColliderforanyoneoftheseobjectswouldbesignificantlymorecostlythantheprimitivecollidersshownhere.Itisworthexploringanyandallopportunitiestosimplifyourobjectsdownusingtheseprimitivesasmuchaswecan,astheycanprovidesignificantperformancegains.
Forexample,concavemeshesareuniqueinthattheycanfeaturegaps,orholes,thatallowothermeshesto“fall”into,oreventhroughthem,whichintroducesopportunitiesfortheobjectstofallthroughtheworldifconcaveshapesareusedforworldcollisionareas.ItisoftenbettertoplaceBoxCollidersinstrategiclocationsforthispurpose.
UsesimplerMeshCollidersThemeshassignedtotheMeshColliderdoesnotnecessarilyneedtomatchthegraphicalrepresentationofthesameobject(Unitysimplypicksitasthedefault).ThisgivesusanopportunitytoreplacetheMeshCollider’smeshpropertywithadifferent,simplermeshforanobject’scolliderfromtheoneweuseforitsgraphicalrepresentation.
ThefollowingimageshowsanexampleofacomplexgraphicalmeshthathasbeengivenasimplifiedmeshforitsMeshCollider:
http://freepdf-books.com
Simplifyingtherenderedmeshintoconvexshapeswithlowerpolygoncountsinthiswaywillgreatlyreducetheoverheadneededtodeterminebounding-volumeoverlapswithothercolliders.Dependingonhowwelltheoriginalobjectisestimated,theremaybefewtononoticeablegameplaydifferences,especiallyinthecaseofthisaxe,whichweexpecttobemovingquicklyascreaturesswingitduringattacks,makingitunlikelythatplayerswillnoticethedifferencebetweenthetwomeshesascolliders.
http://freepdf-books.com
AvoidcomplexphysicscomponentsCertainspecialphysicsColliderComponents,suchasTerrain,Cloth,andWheelColliders,areordersofmagnitudemorecostlythanallprimitivecolliders,andevenMeshCollidersinsomecases.WeshouldsimplynotincludesuchComponentsinourScenesunlesstheyareabsolutelynecessary.Forinstance,ifwehaveTerrainobjectsinthedistancethattheplayerwillneverapproach,thenthere’slittlereasontoincludeanattachedTerrainCollider.
GamesfeaturingClothComponentsshouldconsiderinstantiatingdifferentobjectswithoutthemwhenrunninginlower-qualitysettings,orsimplyanimatingclothbehavior(althoughitistotallyunderstandableiftheteamhasgrownattachedandfalleninlovewithhowthestuffmovesaround).
GamesusingWheelCollidersshouldsimplytrytousefewerwheelcolliders!Vehicleswithmorethanfourwheelsmaybeabletouseonlyfourwheelstogeneratethecorrectphysicsbehavior,whilefakingthegraphicalrepresentationofadditionalwheels.
http://freepdf-books.com
LetphysicsobjectssleepThePhysicsEngine’ssleepfeaturecanposeseveralproblemsforourgame.
NoteReminder:thesleepthresholdcanbemodifiedunderEdit|ProjectSettings|Physics|SleepThreshold.
Firstly,somedevelopersdon’trealizethatmanyoftheirRigidbodyobjectsaresleepingduringmostofthelifetimeoftheirapplication.Thistendstoleaddeveloperstoassumethattheycangetawaywith(forexample)doublingthenumberofRigidbodyobjectsintheirgame,andthecostswillsimplydoubletomatchit.Thisisunlikely.Thefrequencyofcollisionsandtotalaccumulatedtimeofactiveobjectsismorelikelytoincreaseinanexponentialfashion,ratherthanalinearone.Thisleadstounexpectedperformancecostswhennewphysicsobjectsareintroducedintothesimulation.WeshouldkeepthisinmindwhenwedecidetoincreasethephysicscomplexityofourScenes.
Secondly,thereisthedangerof“islands”ofsleepingphysicsobjectsbeinggenerated.IslandsarecreatedwhenalargenumberofRigidbodyobjectsaretouchingoneanother,andhavegraduallycometorest—imagineapileofboxesthathavebeenspawnedandformedalargepile.Eventually,alloftheRigidbodyobjectswillfallasleeponceenoughenergyinthesystemislostandtheyallcometorest.However,becausethey’reallstilltouchingoneanother,assoonasoneoftheseobjectsisawoken,itwillstartachainreaction,awakeningallothernearbyRigidbodyobjects.SuddenlywehavealargespikeinCPUusagebecausedozensofobjectshavenowre-enteredthesimulation,andtherearesuddenlymanymorecollisionstoresolveuntiltheobjectsfallasleepagain.
Ifwecouldfindawaytodetectthatislandsareforming,wecouldstrategicallydestroy/despawnsomeofthemtopreventtoomanylargeislandsfrombeinggenerated.Butworkaroundssuchasthesewillbedependentuponthegameitself,asperformingregular,globalchecks,anddistancecomparisonsbetweenallofourRigidbodyobjectsisnotacheaptasktoaccomplish.Forexample,agamethatrequirestheplayertomovelotsofphysicsobjectsintoanarea(forexample,agamethatinvolvesherdingsheepintoapen)couldchoosetodespawntheDynamicColliderobjectassoonastheplayermovesitintoposition,lockingtheobjecttoitsfinaldestination,andeasingtheworkloadonthePhysicsEngine.
Thirdly,changinganyofaRigidbody’spropertiesatruntime,suchasmass,drag,UseGravity,andsoon,willalsoreawakentheobject.Ifwe’reregularlychangingthesevalues(suchasagamewhereobjectsizesandmasseschangeovertime),thentheywillremainactiveforlongerperiodsoftimethanusual.Thisisalsothecaseforapplyingforces,soifwe’reusingacustomgravitysolution(suchassuggestedbackinthesectionentitledMass),weshouldtrytoavoidapplyingthegravitationalforceeveryFixedUpdate,otherwisetheobjectwillbeunabletofallasleep.
Sleepingobjectscanbeablessingandacurse.Theycansaveusalotofprocessingpower,butiftoomanyofthemreawakenatthesametimeoroursimulationistoobusytoallow
http://freepdf-books.com
enoughofthemtofallasleep,thenwecouldbeincurringsomeunfortunateperformancecostsduringgameplay.Weshouldstrivetolimitthesesituationsasmuchaspossiblebylettingourobjectsenterthesleepingstateasmuchaspossible,andavoidgroupingthemtogetherinlargeclusters.
http://freepdf-books.com
ModifySolverIterationCountJoints,Springs,andotherconnectedRigidbodyobjectsarenottrivialtosimulateintheworldofPhysicsEngines.Becauseoftheco-dependentinteractivity(internallyrepresentedasmovementconstraints)thatoccurswithjoiningtwoobjectstogether,thesystemmustoftenmakeseveralattemptsatsolvingthenecessarymathematicalequations.Thismulti-iterationapproachisrequiredtocalculateanaccurateresultwheneverthereisachangeinvelocitytoanypieceoftheobject-chain.
Itthereforebecomesabalancingactoflimitingthemaximumnumberofattemptsthe“Solver”makestoresolveaparticularsituation,versushowaccuratearesultwecangetawaywith.Wedon’twanttheSolvertospendtoomuchtimeonasinglecollision,becausethereisalotofotherworkthePhysicsEnginehastodowithinthesameiteration.But,wealsodon’twanttoreducethemaximumnumberofiterationstoofarasitwillonlyapproximatewhatthefinalsolutionwouldhavebeenifithadbeengivenmoretimetocalculatetheresult.
NoteThesameSolveralsogetsinvolvedwhenresolvinginter-objectcollisionsandcontacts.Itcanalmostalwaysdeterminethecorrectresultwithasingleiteration,withtheexceptionofsomeveryrareandcomplexcollisionsituations.Itisonlywhenthird-partyobjectswillbeaffectedthroughJointsthattheSolverrequiresadditionalefforttomathematicallyintegratethefinalresult.
TheSolverIterationCountcanbemodifiedunderEdit|ProjectSettings|Physics|SolverIterationCount.Inmostcases,thedefaultvalueofsixiterations(seveniterationsinUnity4)isperfectlyacceptable.But,gamesthatincludeverycomplexjointsystemsmaywishtoincreasethiscounttosuppressanyerratic(ordownrightexplosive)CharacterJointbehaviors,whilesomeprojectsmaybeabletogetawaywithreducingthiscount.Testingmustbeperformedafterchangingthisvaluetoseewhethertheprojectstillmaintainstheintendedlevelsofquality.
Incidentally,ifwefindourgameregularlyrunsintojarring,erratic,andphysics-breakingsituationswithcomplexJoint-basedobjects(suchasragdolls),thenweshouldconsidergraduallyincreasingtheSolverIterationCountuntiltheproblemshavebeensuppressed.TheseproblemstypicallyoccurifourragdollsabsorbtoomuchenergyfromcollidingobjectsandtheSolverisunabletoiteratethesolutiondowntosomethingreasonablebeforeitisaskedtogiveup.Atthispoint,oneoftheJointsgoessupernova,draggingtherestofthemintoorbitalongwithit!
Weshouldalsodoublecheckthatourragdoll’sRigidbodymassesareobeyingtherulessetforthearlierinthischapter,sothattheresultantenergyexchangeandvelocitieswillbemorereasonable.
http://freepdf-books.com
OptimizingragdollsSpeakingofCharacterJoints,ragdollsareincrediblypopularfeaturesforgoodreason;they’retonsoffun!Ignoringthemorbidityofflingingcorpsesaroundagameworldforthemoment,there’ssomethingaboutwatchingacomplexchainofobjectsflailaroundandsmashintothingsthathitsalotofpsychological“funbuttons”.
ThismakesitverytemptingtoallowmanyragdollstocoexistwithinourSceneatthesametime,butaswequicklydiscover,thisrisksanenormousperformancehitwhentoomanyragdollsareinmotionand/orcollidewithotherobjectsduetotheamountofiterationstheSolverwouldneedtoresolvethemall.So,let’sexploresomewaystoimprovetheperformanceofanyragdollswewishtouse.
ReduceJointsandCollidersUnityprovidesasimpleragdoll-generationtoolunderGameObject|3DObject|Ragdoll…inUnity5,orGameObject|CreateOther|Ragdoll…inUnity4.Thistoolcanbeusedtocreateragdollsfromagivenobjectbyselectingtheappropriatechildobjectstoattachcolliderstoforanygivenbodypartorlimb.Thistoolalwayscreates11differentcollidersandassociatedJoints(pelvis,chest,head,andtwocollidersperlimb),butwemightwishtoconsiderusingonlysixcolliders(body,head,andonecolliderperlimb)togreatlyreducetheoverheadcostattheexpenseofragdollrealism.ThiscanbeachievedbydeletingunwantedcollidersandreassigningtheCharacterJoint’sConnectedBodypropertiestotheproperparentjoints.
Suchsimplificationscouldbeimplementedasameansofreducingoverheadforweakerhardware/lowerqualitysettings,asasimplecompromisetoallowmoreragdollstocoexistinourScene.Itcouldevenbeuseddynamicallyifaparticularnumberofragdollsarealreadypresent.Agodclasswouldneedtokeeptrackofhowmanyragdollscurrentlyexist,butwhennewragdollsareintroduced,wecouldinstantiateasimplerversioninordertokeepthingsrunningsmoothly.
Avoidinter-ragdollcollisionsUnlesswereallydesireinter-ragdollcollisionsthenweshouldperhapsdisablethemusingtheCollisionMatrix.Theperformancecostofragdollsgrowsexponentiallywhenragdollscollidewithoneanother,sincewewouldbeaskingtheSolvertoworkextrahardandriskingerraticbehaviorduetotheapproximationsitisforcedtomake.
DisableorremoveinactiveragdollsFinally,wecouldconsiderdisallowingragdollsfromre-enteringthephysicssimulationaftertheyhavecometorest.Insomegames,oncearagdollhasreacheditsfinal“destination,”wenolongerneedittoremaininthegameworldasaninteractableobject.
Wecanpollanygivencollider’ssleepstatewiththeIsSleepingmethodand,onceithasreachedthisstate,wehaveanumberofoptionswecanpursue.Wecoulddisablealloftheragdoll’scolliders,preventingitfrombeingreintroducedtothesimulation,wecouldremovetheragdollfromtheSceneforthesakeofcleanup,orwecouldkeeptrackofthis
http://freepdf-books.com
ragdollandonlyremoveitwhenadifferentragdollhasbeenintroducedtotheScene.
Whateverapproachwechoosetoimprovetheperformanceofourragdollswillnodoubtresultinlimitingragdollsasagameplayfeature,eitherbyinstantiatingfewerofthem,givingthemlesscomplexity,orgivingthemashorterlifetime,butthesearereasonablecompromisestomakegiventheperformance-savingopportunities.
http://freepdf-books.com
KnowwhentousephysicsAsalways,thebestmethodofimprovingtheperformanceofafeatureistoavoidusingitasmuchaspossible.Forallmoveableobjectsinourgame,weshouldtakeamomenttoaskourselvesifgettingthePhysicsEngineinvolvedisevennecessary.Ifnot,weshouldlookforopportunitiestoreplacethemwithsomethingsimplerandlesscostly.
Perhapswe’reusingphysicstodetectwhethertheplayerfellintoakill-zone,butourgameissimpleenoughthatweonlyhavekill-zonesataspecificheight.Inthiscase,wecouldavoidphysicscollidersaltogetherandgetawaywithonlycheckingwhethertheplayer’sypositionfallsbelowaparticularvalue.
Asanotherexample,maybewe’retryingtosimulateameteorshower,andourfirstinstinctwastohavemanyfallingobjectsthatmoveviaphysicsRigidbodyobjects,detectcollisionswiththegroundviacolliders,andthengenerateanexplosionatthepointofimpact.ButperhapsthegroundisconsistentlyflatorwehaveaccesstotheTerrain’sHeightMapforsomerudimentarycollisiondetection.Inthiscase,objecttravelcouldbesimplifiedbytweeningtheobjects’transform.positionpropertiesovertimetosimulatethesamebehaviorwithoutrequiringanyphysicscomponents.Inbothcases,wecanreducethephysicsoverheadbysimplifyingthesituationandpushingtheworkintoScriptcode.
TipTweeningisacommonshort-handtermforin-betweening,whichistheactofinterpolatingpropertiesfromonevaluetoanothermathematicallyovertime.Therearemanyuseful(andfree!)tweeninglibraries,availableontheUnityAssetStore,thatprovidealotofusefulfunctionality.
Thereverseisalsopossible;theremightbeoccasionswherewe’reperformingagreatdealofcalculationthroughScriptcodethatcouldbehandledthroughphysicsrelativelysimply.Forexample,wemighthaveimplementedaninventorysystemwithmanyobjectsthatcanbepickedup.WhentheplayerhitsthePickupkey,eachoftheseobjectsmightbecomparedagainsttheplayer’spositiontofigureoutwhichobjectisclosest.WecouldconsiderreplacingalloftheScriptcodewithasinglePhysics.OverlapSphere()calltogetnearbyobjectswhenthekeyispressed,andthenfigureouttheclosestpickupobjectfromtheresult(orjustpickupallofthem!).Thiscouldgreatlyreducethetotalnumberofobjectsthatmustbecomparedeachtimethekeyispressed.
Theopportunitiesareaswideandfar-reachingasourowningenuity.Theabilitytorecognizeopportunitiestoremoveunnecessaryphysicsgrunt-workfromourScenes,and/orusephysicstoreplacebehaviorthatiscostlywhenperformedthroughScriptcode,isavitalskillthatwillserveuswellwhensavingperformanceincurrentandfuturegamedevelopmentprojects.
http://freepdf-books.com
ConsiderupgradingtoUnity5Ifwe’rerunningUnity4,anabsolutelastresorttoimprovephysicsperformancewouldbetoconsiderupgradingtoUnity5.TherewereamultitudeofhugeperformanceenhancementswithUnity5’supgradefromPhysXversion2.8.3toversion3.3.TheseimprovementscannotbeoverstatedastheygrantaboutdoubletheperformanceofthePhysicsSystemascomparedtoUnity4.TheupgradeincludeslessoverheadinmovingStaticColliders,improvedperformanceincontinuouscollisiondetectionmethods,supportformorerigidbodies,improvedClothandWheelCollidercomponents,aswellasmulticorephysicssupport.Inshort,itallowsustoreducetheperformancecostofthesameScene,orcrammorephysicsactivityintoourScenesforthesamecost.
However,thesechangesresultedinsomesignificantAPIchangesforcertaintasks,whichmeansScriptingandComponentsinUnity4maynotbefullycompatiblewithUnity5(andnotjustforphysics-relatedtasks).Consequently,theupgradeitselfisunlikelytobetrivial,andweshouldnotforgettomakeabackupofourprojectbeforeattemptingtodoso.TheamountofworkwillultimatelydependonthecomplexityofourprojectandhowitaffectsanyAssetStorepurchaseswerelyon.Eachassetislikelytoneedupdatesofitsownandanyassetsthathavefallenoutofsupportwillneedtobereplaced.
http://freepdf-books.com
http://freepdf-books.com
SummaryWe’vecoverednumerousmethodstoimproveourgame’sphysicssimulationbothintermsofperformance,andconsistency.ThebesttechniquewhenitcomestocostlysystemssuchasPhysicsEnginesissimplyavoidance.Thelessweneedtousethesystem,thelessweneedtoworryaboutitgeneratingbottlenecks.Intheworstcase,wemayneedtoreducethescopeofourgametocondensephysicsactivitydowntoonlytheessentials,butaswe’velearned,thereareplentyofwaystoreducephysicscomplexitywithoutcausinganynoticeablegameplayeffects.
Inthenextchapter,wewillimmerseourselvesinUnity’sgraphicssystem,discoveringhowtomaximizegraphicalfidelityusingalloftheCPUcycleswe’vefreedupusingtheperformanceenhancementsfromearlierchapters.
http://freepdf-books.com
http://freepdf-books.com
Chapter6.DynamicGraphicsThereisnoquestionthattherenderingsystemofmoderngraphicsdevicesiscomplicated.Evenrenderingasingletriangletothescreenengagesmanyofthesecomponents,sinceGPUsaredesignedforlargeamountsofparallelism,asopposedtoCPUs,whicharedesignedtohandlevirtuallyanycomputationalscenario.Moderngraphicsrenderingisahigh-speeddanceofprocessingandmemorymanagementthatspanssoftware,hardware,multiplememoryspaces,multiplelanguages,multipleprocessors,multipleprocessortypes,andalargenumberofspecial-casefeaturesthatcanbethrownintothemix.
Tomakemattersworse,everygraphicssituationwewillcomeacrossisdifferentinitsownway.Runningthesameapplicationagainstadifferentdevice,evenbythesamemanufacturer,oftenresultsinanapples-versus-orangescomparisonduetothedifferentcapabilitiesandfunctionalitytheyprovide.Itcanbedifficulttodeterminewhereabottleneckresideswithinsuchacomplexchainofdevicesandsystems,anditcantakealifetimeofindustryworkin3Dgraphicstohaveastrongintuitionaboutthesourceofperformanceissuesinmoderngraphicssystems.
Thankfully,Profilingcomestotherescueonceagain.Ifwecangatherdataabouteachcomponent,usemultipleperformancemetricsforcomparison,andtweakourScenestoseehowdifferentgraphicsfeaturesaffecttheirbehavior,thenweshouldhavesufficientevidencetofindtherootcauseoftheissueandmakeappropriatechanges.Sointhischapter,youwilllearnhowtogathertherightdata,digjustdeepenoughintothegraphicssystemtofindthetruesourceoftheproblem,andexplorevarioussolutionstoworkaroundagivenproblem.
Asyoulearnedinearlierchapters,theCPUandGPUworkintandemtodeterminewhattextures,meshes,renderstates,Shaders,andsoon,areneededtorenderourScenesatanygivenmoment.We’vealsocoveredseveraltechniquestoreducesomeoftherenderingworkloadthroughStaticandDynamicBatching,andbymanipulatingourmeshandtexturefilesthroughcompressionandencoding,MipMapping,Atlasing,andevensomeproceduralalternatives.
However,therearestillmanymoretopicstocoverwhenitcomestoimprovingrenderingperformance,sointhischapterwewillbeginwithsomegeneraltechniquesonhowtodeterminewhetherourrenderingislimitedbytheCPUorbytheGPU,andwhatwecandoabouteithercase.WewilldiscussoptimizationtechniquessuchasOcclusionCullingandLevelOfDetail(LOD)andprovidesomeusefuladviceonShaderoptimization,aswellaslarge-scalerenderingfeaturessuchaslightingandshadows.Finally,sincemobiledevicesareacommontargetforUnityprojects,wewillalsocoversometechniquesthatmayhelpimproveperformanceonlimitedhardware.
http://freepdf-books.com
ProfilingrenderingissuesPoorrenderingperformancecanmanifestitselfinanumberofways,dependingonwhetherthedeviceisCPU-bound,orGPU-bound;inthelattercase,therootcausecouldoriginatefromanumberofplaceswithinthegraphicspipeline.Thiscanmaketheinvestigatorystageratherinvolved,butoncethesourceofthebottleneckisdiscoveredandtheproblemisresolved,wecanexpectsignificantimprovementsassmallfixestendtoreapbigrewardswhenitcomestotherenderingsubsystem.
WebrieflytoucheduponthesubjectofbeingCPU/GPU-boundinChapter3,TheBenefitsofBatching.Tosummarizetheearlierdiscussion,weknowthattheCPUsendsrenderinginstructionsthroughthegraphicsAPI,thatfunnelthroughthehardwaredrivertotheGPUdevice,whichresultsincommandsenteringtheGPU’sCommandBuffer.ThesecommandsareprocessedbythemassivelyparallelGPUsystemonebyoneuntilthebufferisempty.Buttherearealotmorenuancesinvolvedinthisprocess.
Thefollowingshowsa(greatlysimplified)diagramofatypicalGPUpipeline(whichcanvarybasedontechnologyandvariousoptimizations),andthebroadrenderingstepsthattakeplaceduringeachstage:
ThetoprowrepresentstheworkthattakesplaceontheCPU,theactofcallingintothegraphicsAPI,throughthehardwaredriver,andpushingcommandsintotheGPU.Ergo,aCPU-boundapplicationwillbeprimarilylimitedbythecomplexity,orsheernumber,ofgraphicsAPIcalls.
Meanwhile,aGPU-boundapplicationwillbelimitedbytheGPU’sabilitytoprocessthosecalls,andemptytheCommandBufferinareasonabletimeframetoallowfortheintendedframerate.Thisisrepresentedinthenexttworows,showingthestepstakingplaceintheGPU.But,becauseofthedevice’scomplexity,theyareoftensimplifiedintotwodifferentsections:thefrontendandthebackend.
http://freepdf-books.com
ThefrontendreferstothepartoftherenderingprocesswheretheGPUhasreceivedmeshdata,adrawcallhasbeenissued,andalloftheinformationthatwasfedintotheGPUisusedtotransformverticesandrunthroughVertexShaders.Finally,therasterizergeneratesabatchoffragmentstobeprocessedinthebackend.ThebackendreferstotheremainderoftheGPU’sprocessingstages,wherefragmentshavebeengenerated,andnowtheymustbetested,manipulated,anddrawnviaFragmentShadersontotheframebufferintheformofpixels.
TipNotethat“FragmentShader”isthemoretechnicallyaccuratetermforPixelShaders.Fragmentsaregeneratedbytherasterizationstage,andonlytechnicallybecomepixelsoncethey’vebeenprocessedbytheShaderanddrawntotheFrameBuffer.
Thereareanumberofdifferentapproacheswecanusetodeterminewheretherootcauseofagraphicsrenderingissuelies:
ProfilingtheGPUwiththeProfilerExaminingindividualframeswiththeFrameDebuggerBruteForceCulling
http://freepdf-books.com
GPUprofilingBecausegraphicsrenderinginvolvesboththeCPUandGPU,wemustexaminetheproblemusingboththeCPUUsageandGPUUsageareasoftheProfilerasthiscantelluswhichcomponentisworkinghardest.
Forexample,thefollowingscreenshotshowstheProfilerdataforaCPU-boundapplication.Thetestinvolvedcreatingthousandsofsimpleobjects,withnobatchingtechniquestakingplace.ThisresultedinanextremelylargeDrawCallcount(around15,000)fortheCPUtoprocess,butgivingtheGPUrelativelylittleworktododuetothesimplicityoftheobjectsbeingrendered:
ThisexampleshowsthattheCPU’s“rendering”taskisconsumingalargeamountofcycles(around30msperframe),whiletheGPUisonlyprocessingforlessthan16ms,indicatingthatthebottleneckresidesintheCPU.
Meanwhile,ProfilingaGPU-boundapplicationviatheProfilerisalittletrickier.Thistime,thetestinvolvescreatingasmallnumberofhighpolycountobjects(foralowDrawCallpervertexratio),withdozensofreal-timepointlightsandanexcessivelycomplexShaderwithatexture,normaltexture,heightmap,emissionmap,occlusionmap,andsoon,(forahighworkloadperpixelratio).
ThefollowingscreenshotshowsProfilerdatafortheexampleScenewhenitisruninastandaloneapplication:
http://freepdf-books.com
Aswecansee,therenderingtaskoftheCPUUsageareamatchescloselywiththetotalrenderingcostsoftheGPUUsagearea.WecanalsoseethattheCPUandGPUtimecostsatthebottomoftheimagearerelativelysimilar(41.48msversus38.95ms).ThisisveryunintuitiveaswewouldexpecttheGPUtobeworkingmuchharderthantheCPU.
TipBeawarethattheCPU/GPUmillisecondcostvaluesarenotcalculatedorrevealedunlesstheappropriateUsageAreahasbeenaddedtotheProfilerwindow.
However,let’sseewhathappenswhenwetestthesameexactScenethroughtheEditor:
ThisisabetterrepresentationofwhatwewouldexpecttoseeinaGPU-boundapplication.WecanseehowtheCPUandGPUtimecostsatthebottomareclosertowhatwewouldexpecttosee(2.74msvs64.82ms).
However,thisdataishighlypolluted.ThespikesintheCPUandGPUUsageareasarethe
http://freepdf-books.com
resultoftheProfilerWindowUIupdatingduringtesting,andtheoverheadcostofrunningthroughtheEditorisalsoartificiallyincreasingthetotalGPUtimecost.
Itisunclearwhatcausesthedatatobetreatedthisway,andthiscouldcertainlychangeinthefutureifenhancementsaremadetotheProfilerinfutureversionsofUnity,butitisusefultoknowthisdrawback.
NoteTryingtodeterminewhetherourapplicationistrulyGPU-boundisperhapstheonlygoodexcusetoperformaProfilertestthroughtheEditor.
http://freepdf-books.com
TheFrameDebuggerAnewfeatureinUnity5istheFrameDebugger,adebuggingtoolthatcanrevealhowtheSceneisrenderedandpiecedtogether,oneDrawCallatatime.WecanclickthroughthelistofDrawCallsandobservehowtheSceneisrendereduptothatpointintime.ItalsoprovidesalotofusefuldetailsfortheselectedDrawCall,suchasthecurrentrendertarget(forexample,theshadowmap,thecameradepthtexture,themaincamera,orothercustomrendertargets),whattheDrawCalldid(drawingamesh,drawingastaticbatch,drawingdepthshadows,andsoon),andwhatsettingswereused(texturedata,vertexcolors,bakedlightmaps,directionallighting,andsoon).
ThefollowingscreenshotshowsaScenethatisonlybeingpartiallyrenderedduetothecurrentlyselectedDrawCallwithintheFrameDebugger.Notetheshadowsthatarevisiblefrombakedlightmapsthatwererenderedduringanearlierpassbeforetheobjectitselfisrendered:
IfweareboundbyDrawCalls,thenthistoolcanbeeffectiveinhelpingusfigureoutwhattheDrawCallsarebeingspenton,anddeterminewhetherthereareanyunnecessaryDrawCallsthatarenothavinganeffectonthescene.Thiscanhelpuscomeupwithwaystoreducethem,suchasremovingunnecessaryobjectsorbatchingthemsomehow.WecanalsousethistooltoobservehowmanyadditionalDrawCallsareconsumedbyrenderingfeatures,suchasshadows,transparentobjects,andmanymore.Thiscouldhelpus,whenwe’recreatingmultiplequalitylevelsforourgame,todecidewhatfeaturestoenable/disableunderthelow,medium,andhighqualitysettings.
http://freepdf-books.com
BruteforcetestingIfwe’reporingoverourProfilingdata,andwe’restillnotsurewecandeterminethesourceoftheproblem,wecanalwaystrythebruteforcemethod:cullaspecificactivityfromtheSceneandseeifitresultsingreatlyincreasedperformance.Ifasmallchangeresultsinabigspeedimprovement,thenwehaveastrongclueaboutwherethebottlenecklies.There’snoharminthisapproachifweeliminateenoughunknownvariablestobesurethedataisleadingusintherightdirection.
Wewillcoverdifferentwaystobruteforcetestaparticularissueineachoftheupcomingsections.
http://freepdf-books.com
CPU-boundIfourapplicationisCPU-bound,thenwewillobserveagenerallypoorFPSvaluewithintheCPUUsageareaoftheProfilerwindowduetotherenderingtask.However,ifVSyncisenabledthedatawilloftengetmuddiedupwithlargespikesrepresentingpausesastheCPUwaitsforthescreenrefreshratetocomearoundbeforepushingthecurrentframebuffer.So,weshouldmakesuretodisabletheVSyncblockintheCPUUsageareabeforedecidingtheCPUistheproblem.
Brute-forcingatestforCPU-boundingcanbeachievedbyreducingDrawCalls.Thisisalittleunintuitivesince,presumably,we’vealreadybeenreducingourDrawCallstoaminimumthroughtechniquessuchasStaticandDynamicBatching,Atlasing,andsoforth.Thiswouldmeanwehaveverylimitedscopeforreducingthemfurther.
Whatwecando,however,isdisabletheDraw-Call-savingfeaturessuchasbatchingandobserveifthesituationgetssignificantlyworsethanitalreadyis.Ifso,thenwehaveevidencethatwe’reeitheralready,orveryclosetobeing,CPU-bound.Atthispoint,weshouldseewhetherwecanre-enablethesefeaturesanddisablerenderingforafewchoiceobjects(preferablythosewithlowcomplexitytoreduceDrawCallswithoutover-simplifyingtherenderingofourscene).Ifthisresultsinasignificantperformanceimprovementthen,unlesswecanfindfurtheropportunitiesforbatchingandmeshcombining,wemaybefacedwiththeunfortunateoptionofremovingobjectsfromoursceneastheonlymeansofbecomingperformantagain.
TherearesomeadditionalopportunitiesforDrawCallreduction,includingOcclusionCulling,tweakingourLightingandShadowing,andmodifyingourShaders.Thesewillbeexplainedinthefollowingsections.
However,Unity’srenderingsystemcanbemultithreaded,dependingonthetargetedplatform,whichversionofUnitywe’rerunning,andvarioussettings,andthiscanaffecthowthegraphicssubsystemisbeingbottleneckedbytheCPU,andslightlychangesthedefinitionofwhatbeingCPU-boundmeans.
MultithreadedrenderingMultithreadedrenderingwasfirstintroducedinUnityv3.5inFebruary2012,andenabledbydefaultonmulticoresystemsthatcouldhandletheworkload;atthetime,thiswasonlyPC,Mac,andXbox360.Gradually,moredeviceswereaddedtothislist,andsinceUnityv5.0,allmajorplatformsnowenablemultithreadedrenderingbydefault(andpossiblysomebuildsofUnity4).
http://freepdf-books.com
MobiledeviceswerealsostartingtofeaturemorepowerfulCPUsthatcouldsupportthisfeature.Androidmultithreadedrendering(introducedinUnityv4.3)canbeenabledthroughacheckboxunderPlatformSettings|OtherSettings|MultithreadedRendering.MultithreadedrenderingoniOScanbeenabledbyconfiguringtheapplicationtomakeuseoftheAppleMetalAPI(introducedinUnityv4.6.3),underPlayerSettings|OtherSettings|GraphicsAPI.
Whenmultithreadedrenderingisenabled,tasksthatmustgothroughtherenderingAPI(OpenGL,DirectX,orMetal),arehandedoverfromthemainthreadtoa“workerthread”.Theworkerthread’spurposeistoundertaketheheavyworkloadthatittakestopushrenderingcommandsthroughthegraphicsAPIanddriver,togettherenderinginstructionsintotheGPU’sCommandBuffer.ThiscansaveanenormousnumberofCPUcyclesforthemainthread,wheretheoverwhelmingmajorityofotherCPUtaskstakeplace.Thismeansthatwefreeupextracyclesforthemajorityoftheenginetoprocessphysics,scriptcode,andsoon.
Incidentally,themechanismbywhichthemainthreadnotifiestheworkerthreadoftasksoperatesinaverysimilarwaytotheCommandBufferthatexistsontheGPU,exceptthatthecommandsaremuchmorehigh-level,withinstructionslike“renderthisobject,withthisMaterial,usingthisShader”,or“drawNinstancesofthispieceofproceduralgeometry”,andsoon.ThisfeaturehasbeenexposedinUnity5toallowdeveloperstotakedirectcontroloftherenderingsubsystemfromC#code.ThiscustomizationisnotaspowerfulashavingdirectAPIaccess,butitisastepintherightdirectionforUnitydeveloperstoimplementuniquegraphicaleffects.
NoteConfusingly,theUnityAPInameforthisfeatureiscalled“CommandBuffer”,sobesurenottoconfuseitwiththeGPU’sCommandBuffer.
ChecktheUnitydocumentationonCommandBuffertomakeuseofthisfeature:http://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.html.
Gettingbacktothetaskathand,whenwediscussthetopicofbeingCPU-boundingraphicsrendering,weneedtokeepinmindwhetherornotthemultithreadedrendererisbeingused,sincetheactualrootcauseoftheproblemwillbeslightlydifferentdependingonwhetherthisfeatureisenabledornot.
Insingle-threadedrendering,whereallgraphicsAPIcallsarehandledbythemainthread,andinanidealworldwherebothcomponentsarerunningatmaximumcapacity,ourapplicationwouldbecomebottleneckedontheCPUwhen50percentormoreofthetimeperframeisspenthandlinggraphicsAPIcalls.However,resolvingthesebottleneckscanbeaccomplishedbyfreeingupworkfromthemainthread.Forexample,wemightfindthatgreatlyreducingtheamountofworktakingplaceinourAIsubsystemwillimproveourrenderingsignificantlybecausewe’vefreedupmoreCPUcyclestohandlethegraphicsAPIcalls.
But,whenmultithreadedrenderingistakingplace,thistaskispushedontotheworkerthread,whichmeansthesamethreadisn’tbeingaskedtomanagebothengineworkand
http://freepdf-books.com
graphicsAPIcallsatthesametime.Theseprocessesaremostlyindependent,andeventhoughadditionalworkmuststilltakeplaceinthemainthreadtosendinstructionstotheworkerthreadinthefirstplace(viatheinternalCommandBuffersystem),itismostlynegligible.Thismeansthatreducingtheworkloadinthemainthreadwillhavelittle-to-noeffectonrenderingperformance.
NoteNotethatbeingGPU-boundisthesameregardlessofwhethermultithreadedrenderingistakingplace.
GPUSkinningWhilewe’reonthesubjectofCPU-bounding,onetaskthatcanhelpreduceCPUworkload,attheexpenseofadditionalGPUworkload,isGPUSkinning.Skinningistheprocesswheremeshverticesaretransformedbasedonthecurrentlocationoftheiranimatedbones.Theanimationsystem,workingontheCPU,onlytransformsthebones,butanotherstepintherenderingprocessmusttakecareofthevertextransformationstoplacetheverticesaroundthosebones,performingaweightedaverageoverthebonesconnectedtothosevertices.
ThisvertexprocessingtaskcaneithertakeplaceontheCPUorwithinthefrontendoftheGPU,dependingonwhethertheGPUSkinningoptionisenabled.ThisfeaturecanbetoggledunderEdit|ProjectSettings|PlayerSettings|OtherSettings|GPUSkinning.
http://freepdf-books.com
http://freepdf-books.com
FrontendbottlenecksWehavealreadycoveredsometechniquesonmeshoptimizationinChapter4,KickstartYourArt,whichcanhelpreduceourmesh’svertexattributes.Asaquickreminder,itisnotuncommontouseameshthatcontainsalotofunnecessaryUVandNormalvectordata,soourmeshesshouldbedouble-checkedforthiskindofsuperfluousfluff.WeshouldalsoletUnityoptimizethestructureforus,whichminimizescachemissesasvertexdataisreadwithinthefrontend.
WewillalsolearnsomeusefulShaderoptimizationtechniquesshortly,whenwebegintodiscussbackendoptimizations,sincemanyoptimizationtechniquesapplytobothFragmentandVertexShaders.
Theonlyattackvectorlefttocoverisfindingwaystoreduceactualvertexcounts.Theobvioussolutionsaresimplificationandculling;eitherhavetheartteamreplaceproblematicmesheswithlowerpolycountversions,and/orremovesomeobjectsfromthescenetoreducetheoverallpolygoncount.Iftheseapproacheshavealreadybeenexplored,thenthelastapproachwecantakeistofindsomekindofmiddlegroundbetweenthetwo.
http://freepdf-books.com
LevelOfDetailSinceitcanbedifficulttotellthedifferencebetweenahighqualitydistanceobjectandalowqualityone,thereisverylittlereasontorenderthehighqualityversion.So,whynotdynamicallyreplacedistantobjectswithsomethingmoresimplified?
LevelOfDetail(LOD),isabroadtermreferringtothedynamicreplacementoffeaturesbasedontheirdistanceorformfactorrelativetothecamera.Themostcommonimplementationismesh-basedLOD:dynamicallyreplacingameshwithlowerandlowerdetailedversionsasthecameragetsfartherandfartheraway.Anotherexamplemightbereplacinganimatedcharacterswithversionsfeaturingfewerbones,orlesssamplingfordistantobjects,inordertoreduceanimationworkload.
TipThebuilt-inLODfeatureisavailableintheUnity4ProEditionandalleditionsofUnity5.However,itisentirelypossibletoimplementitviaScriptcodeinUnity4FreeEditionifdesired.
MakinguseofLODcanbeachievedbyplacingmultipleobjectsintheSceneandmakingthemchildrenofaGameObjectwithanattachedLODGroupcomponent.TheLODGroup’spurposeistogenerateaboundingboxfromtheseobjects,anddecidewhichobjectshouldberenderedbasedonthesizeoftheboundingboxwithinthecamera’sfieldofview.Iftheobject’sboundingboxconsumesalargeareaofthecurrentview,thenitwillenablethemesh(es)assignedtolowerLODgroups,andiftheboundingboxisverysmall,itwillreplacethemesh(es)withthosefromhigherLODgroups.Ifthemeshistoofaraway,itcanbeconfiguredtohideallchildobjects.So,withthepropersetup,wecanhaveUnityreplacemesheswithsimpleralternatives,orcullthementirely,whicheasestheburdenontherenderingprocess.
NoteChecktheUnitydocumentationformoredetailedinformationontheLODfeature:http://docs.unity3d.com/Manual/LevelOfDetail.html.
Thisfeaturecancostusalargeamountofdevelopmenttimetofullyimplement;artistsmustgeneratelowerpolygoncountversionsofthesameobject,andleveldesignersmustgenerateLODgroups,configurethem,andtestthemtoensuretheydon’tcausejarringtransitionsasthecameramovescloserorfartheraway.ItalsocostsusinmemoryandruntimeCPU;thealternativemeshesneedtobekeptinmemory,andtheLODGroupcomponentmustroutinelytestwhetherthecamerahasmovedtoanewpositionthatwarrantsachangeinLODlevel.
Inthiseraofgraphicscardcapabilities,vertexprocessingisoftentheleastofourconcerns.CombinedwiththeadditionalsacrificesneededforLODtofunction,developersshouldavoidpreoptimizingbyautomaticallyassumingLODwillhelpthem.Excessiveuseofthefeaturewillleadtoburdeningotherpartsofourapplication’sperformance,andchewuppreciousdevelopmenttime,allforthesakeofparanoia.Ifithasn’tbeenproventobeaproblem,thenit’sprobablynotaproblem!
http://freepdf-books.com
Scenesthatfeaturelarge,expansiveviewsoftheworld,andlotsofcameramovement,shouldconsiderimplementingthistechniqueveryearly,astheaddeddistanceandmassivenumberofvisibleobjectswillexacerbatethevertexcountenormously.Scenesthatarealwaysindoors,orfeatureacamerawithaviewpointlookingdownattheworld(real-timestrategyandMOBAgames,forexample)shouldprobablysteerclearofimplementingLODfromthebeginning.Gamessomewherebetweenthetwoshouldavoidituntilnecessary.Italldependsonhowmanyverticesareexpectedtobevisibleatanygiventimeandhowmuchvariabilityincameradistancetherewillbe.
TipNotethatsomegamedevelopmentmiddlewarecompaniesofferthird-partytoolsforautomatedLODmeshgeneration.Thesemightbeworthinvestigatingtocomparetheireaseofuseversusqualitylossversuscosteffectiveness.
http://freepdf-books.com
DisableGPUSkinningAspreviouslymentioned,wecouldenableGPUSkinningtoreducetheburdenonaCPU-boundapplication,butenablingthisfeaturewillpushthesameworkloadintothefrontendoftheGPU.SinceSkinningisoneofthose“embarrassinglyparallel”processesthatfitswellwiththeGPU’sparallelarchitecture,itisoftenagoodideatoperformthetaskontheGPU.Butthistaskcanchewupprecioustimeinthefrontendpreparingtheverticesforfragmentgeneration,sodisablingitisanotheroptionwecanexploreifwe’rebottleneckedinthisarea.Again,thisfeaturecanbetoggledunderEdit|ProjectSettings|PlayerSettings|OtherSettings|GPUSkinning.
TipGPUSkinningisavailableinUnity4ProEdition,andalleditionsofUnity5.
http://freepdf-books.com
ReducetessellationThereisonelasttaskthattakesplaceinthefrontendprocessandthatweneedtoconsider:tessellation.TessellationthroughGeometryShaderscanbealotoffun,asitisarelativelyunderusedtechniquethatcanreallymakeourgraphicaleffectsstandoutfromthecrowdofgamesthatonlyusethemostcommoneffects.But,itcancontributeenormouslytotheamountofprocessingworktakingplaceinthefrontend.
Therearenosimpletrickswecanexploittoimprovetessellation,besidesimprovingourtessellationalgorithms,oreasingtheburdencausedbyotherfrontendtaskstogiveourtessellationtasksmoreroomtobreathe.Eitherway,ifwehaveabottleneckinthefrontendandaremakinguseoftessellationtechniques,weshoulddouble-checkthattheyarenotconsumingthelion’sshareofthefrontend’sbudget.
http://freepdf-books.com
http://freepdf-books.com
BackendbottlenecksThebackendisthemoreinterestingpartoftheGPUpipeline,asmanymoregraphicaleffectstakeplaceduringthisstage.Consequently,itisthestagethatissignificantlymorelikelytosufferfrombottlenecks.
Therearetwobruteforcetestswecanattempt:
ReduceresolutionReducetexturequality
Thesechangeswilleasetheworkloadduringtwoimportantstagesatthebackendofthepipeline:fillrateandmemorybandwidth,respectively.Fillratetendstobethemostcommonsourceofbottlenecksinthemoderneraofgraphicsrendering,sowewillcoveritfirst.
http://freepdf-books.com
FillrateByreducingscreenresolution,wehaveaskedtherasterizationsystemtogeneratesignificantlyfewerfragmentsandtransposethemoverasmallercanvasofpixels.Thiswillreducethefillrateconsumptionoftheapplication,givingakeypartoftherenderingpipelinesomeadditionalbreathingroom.Ergo,ifperformancesuddenlyimproveswithascreenresolutionreduction,thenfillrateshouldbeourprimaryconcern.
FillrateisaverybroadtermreferringtothespeedatwhichtheGPUcandrawfragments.But,thisonlyincludesfragmentsthathavesurvivedallofthevariousconditionaltestswemighthaveenabledwithinthegivenShader.Afragmentismerelya“potentialpixel,”andifitfailsanyoftheenabledtests,thenitisimmediatelydiscarded.Thiscanbeanenormousperformance-saverasthepipelinecanskipthecostlydrawingstepandbeginworkonthenextfragmentinstead.
OnesuchexampleisZ-testing,whichcheckswhetherthefragmentfromacloserobjecthasalreadybeendrawntothesamepixelalready.Ifso,thenthecurrentfragmentisdiscarded.Ifnot,thenthefragmentispushedthroughtheFragmentShaderanddrawnoverthetargetpixel,whichconsumesexactlyonedrawfromourfillrate.Nowimaginemultiplyingthisprocessbythousandsofoverlappingobjects,eachgeneratinghundredsorthousandsofpossiblefragments,forhighscreenresolutionscausingmillions,orbillions,offragmentstobegeneratedeachandeveryframe.Itshouldbefairlyobviousthatskippingasmanyofthesedrawsaswecanwillresultinbigrenderingcostsavings.
Graphicscardmanufacturerstypicallyadvertiseaparticularfillrateasafeatureofthecard,usuallyintheformofgigapixelspersecond,butthisisabitofamisnomer,asitwouldbemoreaccuratetocallitgigafragmentspersecond;howeverthisargumentismostlyacademic.Eitherway,largervaluestellusthatthedevicecanpotentiallypushmorefragmentsthroughthepipeline,sowithabudgetof30GPix/sandatargetframerateof60Hz,wecanaffordtoprocess30,000,000,000/60=500millionfragmentsperframebeforebeingbottleneckedonfillrate.Witharesolutionof2560x1440,andabest-casescenariowhereeachpixelisonlydrawnoveronce,thenwecouldtheoreticallydrawtheentiresceneabout125timeswithoutanynoticeableproblems.
Sadly,thisisnotaperfectworld,andunlesswetakesignificantstepstoavoidit,wewillalwaysendupwithsomeamountofredrawoverthesamepixelsduetotheorderinwhichobjectsarerendered.Thisisknownasoverdraw,anditcanbeverycostlyifwe’renotcareful.
TipThereasonthatresolutionisagoodattackvectortocheckforfillrateboundingisthatitisamultiplier.Areductionfromaresolutionof2560x1440to800x600isanimprovementfactorofabouteight,whichcouldreducefillratecostsenoughtomaketheapplicationperformwellagain.
OverdrawDetermininghowmuchoverdrawwehavecanberepresentedvisuallybyrenderingall
http://freepdf-books.com
objectswithadditivealphablendingandaverytransparentflatcolor.Areasofhighoverdrawwillshowupmorebrightlyasthesamepixelisdrawnoverwithadditiveblendingmultipletimes.ThisispreciselyhowtheSceneview’sOverdrawshadingmoderevealshowmuchoverdrawoursceneissuffering.
Thefollowingscreenshotshowsascenewithseveralthousandboxesdrawnnormally,anddrawnusingtheSceneview’sOverdrawshadingmode:
Attheendoftheday,fillrateisprovidedasameansofgaugingthebest-casebehavior.Inotherwords,it’sprimarilyamarketingtermandmostlytheoretical.But,thetechnicalsideoftheindustryhasadoptedthetermasawayofdescribingthebackendofthepipeline:thestagewherefragmentdataisfunneledthroughourShadersanddrawntothescreen.
Ifeveryfragmentrequiredanabsoluteminimumlevelofprocessing(suchasaShaderthatreturnedaconstantcolor),thenwemightgetclosetothattheoreticalmaximum.TheGPUisacomplexbeast,however,andthingsareneversosimple.Thenatureofthedevicemeansitworksbestwhengivenmanysmalltaskstoperform.But,ifthetasksgettoolarge,thenfillrateislostduetothebackendnotbeingabletopushthroughenoughfragmentsintimeandtherestofthepipelineisleftwaitingfortaskstodo.
Thereareseveralmorefeaturesthatcanpotentiallyconsumeourtheoreticalfillratemaximum,includingbutnotlimitedtoalphatesting,alphablending,texturesampling,theamountoffragmentdatabeingpulledthroughourShaders,andeventhecolorformatofthetargetrendertexture(thefinalFrameBufferinmostcases).Thebadnewsisthatthisgivesusalotofsubsectionstocover,andalotofwaystobreaktheprocess,butthegoodnewsisitgivesusalotofavenuestoexploretoimproveourfillrateusage.
OcclusionCullingOneofthebestwaystoreduceoverdrawistomakeuseofUnity’sOcclusionCullingsystem.ThesystemworksbypartitioningScenespaceintoaseriesofcellsandflyingthroughtheworldwithavirtualcameramakingnoteofwhichcellsareinvisiblefrom
http://freepdf-books.com
othercells(areoccluded)basedonthesizeandpositionoftheobjectspresent.
NotethatthisisdifferenttothetechniqueofFrustumCulling,whichcullsobjectsnotvisiblefromthecurrentcameraview.Thisfeatureisalwaysactiveinallversions,andobjectsculledbythisprocessareautomaticallyignoredbytheOcclusionCullingsystem.
TipOcclusionCullingisavailableintheUnity4ProEditionandalleditionsofUnity5.
OcclusionCullingdatacanonlybegeneratedforobjectsproperlylabeledOccluderStaticandOccludeeStaticundertheStaticFlagsdropdown.OccluderStaticisthegeneralsettingforstaticobjectswherewewantittohideotherobjects,andbehiddenbylargeobjectsinitsway.OccludeeStaticisaspecialcasefortransparentobjectsthatallowsobjectsbehindthemtoberendered,butwewantthemtobehiddenifsomethinglargeblockstheirvisibility.
Naturally,becauseoneofthestaticflagsmustbeenabledforOcclusionCulling,thisfeaturewillnotworkfordynamicobjects.
ThefollowingscreenshotshowshoweffectiveOcclusionCullingcanbeatreducingthenumberofvisibleobjectsinourScene:
http://freepdf-books.com
Thisfeaturewillcostusinbothapplicationfootprintandincursomeruntimecosts.ItwillcostRAMtokeeptheOcclusionCullingdatastructureinmemory,andtherewillbeaCPUprocessingcosttodeterminewhichobjectsarebeingoccludedineachframe.
TheOcclusionCullingdatastructuremustbeproperlyconfiguredtocreatecellsoftheappropriatesizeforourScene,andthesmallerthecells,thelongerittakestogeneratethedatastructure.But,ifitisconfiguredcorrectlyfortheScene,OcclusionCullingcanprovidebothfillratesavingsthroughreducedoverdraw,andDrawCallsavingsbycullingnon-visibleobjects.
ShaderoptimizationShaderscanbeasignificantfillrateconsumer,dependingontheircomplexity,howmuchtexturesamplingtakesplace,howmanymathematicalfunctionsareused,andsoon.Shadersdonotdirectlyconsumefillrate,butdosoindirectlybecausetheGPUmustcalculateorfetchdatafrommemoryduringShaderprocessing.TheGPU’sparallelnaturemeansanybottleneckinathreadwilllimithowmanyfragmentscanbepushedintothethreadatalaterdate,butparallelizingthetask(sharingsmallpiecesofthejobbetween
http://freepdf-books.com
severalagents)providesanetgainoverserialprocessing(oneagenthandlingeachtaskoneafteranother).
Theclassicexampleisavehicleassemblyline.Acompletevehiclerequiresmultiplestagesofmanufacturetocomplete.Thecriticalpathtocompletionmightinvolvefivesteps:stamping,welding,painting,assembly,andinspection,andeachstepiscompletedbyasingleteam.Foranygivenvehicle,nostagecanbeginbeforethepreviousoneisfinished,butwhateverteamhandledthestampingforthelastvehiclecanbeginstampingforthenextvehicleassoonasithasfinished.Thisorganizationallowseachteamtobecomemastersoftheirparticulardomain,ratherthantryingtospreadtheirknowledgetoothin,whichwouldlikelyresultinlessconsistentqualityinthebatchofvehicles.
Wecandoubletheoveralloutputbydoublingthenumberofteams,butifanyteamgetsblocked,thenprecioustimeislostforanygivenvehicle,aswellasallfuturevehiclesthatwouldpassthroughthesameteam.Ifthesedelaysarerare,thentheycanbenegligibleinthegrandscheme,butifnot,andonestagetakesseveralminuteslongerthannormaleachandeverytimeitmustcompletethetask,thenitcanbecomeabottleneckthatthreatensthereleaseoftheentirebatch.
TheGPUparallelprocessorsworkinasimilarway:eachprocessorthreadisanassemblyline,eachprocessingstageisateam,andeachfragmentisavehicle.Ifthethreadspendsalongtimeprocessingasinglestage,thentimeislostoneachfragment.Thisdelaywillmultiplysuchthatallfuturefragmentscomingthroughthesamethreadwillbedelayed.Thisisabitofanoversimplification,butitoftenhelpstopaintapictureofhowpoorlyoptimizedShadercodecanchewupourfillrate,andhowsmallimprovementsinShaderoptimizationprovidebigbenefitsinbackendperformance.
Shaderprogrammingandoptimizationhavebecomeaverynicheareaofgamedevelopment.Theirabstractandhighly-specializednaturerequiresaverydifferentkindofthinkingtogenerateShadercodecomparedtogameplayandenginecode.Theyoftenfeaturemathematicaltricksandback-doormechanismsforpullingdataintotheShader,suchasprecomputingvaluesintexturefiles.Becauseofthis,andtheimportanceofoptimization,Shaderstendtobeverydifficulttoreadandreverse-engineer.
Consequently,manydevelopersrelyonprewrittenShaders,orvisualShadercreationtoolsfromtheAssetStoresuchasShaderForgeorShaderSandwich.ThissimplifiestheactofinitialShadercodegeneration,butmightnotresultinthemostefficientformofShaders.Ifwe’rerelyingonpre-writtenShadersortools,wemightfinditworthwhiletoperformsomeoptimizationpassesoverthemusingsometried-and-truetechniques.So,let’sfocusonsomeeasilyreachablewaysofoptimizingourShaders.
ConsiderusingShadersintendedformobileplatformsThebuilt-inmobileShadersinUnitydonothaveanyspecificrestrictionsthatforcethemtoonlybeusedonmobiledevices.Theyaresimplyoptimizedforminimumresourceusage(andtendtofeaturesomeoftheotheroptimizationslistedinthissection).
DesktopapplicationsareperfectlycapableofusingtheseShaders,buttheytendtofeaturealossofgraphicalquality.Itonlybecomesaquestionofwhetherthelossofgraphical
http://freepdf-books.com
qualityisacceptable.So,considerdoingsometestingwiththemobileequivalentsofcommonShaderstoseewhethertheyareagoodfitforyourgame.
Usesmalldatatypes
GPUscancalculatewithsmallerdatatypesmorequicklythanlargertypes(particularlyonmobileplatforms!),sothefirsttweakwecanattemptisreplacingourfloatdatatypes(32-bit,floatingpoint)withsmallerversionssuchashalf(16-bit,floatingpoint),orevenfixed(12-bit,fixedpoint).
NoteThesizeofthedatatypeslistedabovewillvarydependingonwhatfloatingpointformatsthetargetplatformprefers.Thesizeslistedarethemostcommon.Theimportanceforoptimizationisintherelativesizebetweenformats.
Colorvaluesaregoodcandidatesforprecisionreduction,aswecanoftengetawaywithlessprecisecolorvalueswithoutanynoticeablelossincoloration.However,theeffectsofreducingprecisioncanbeveryunpredictableforgraphicalcalculations.So,changessuchasthesecanrequiresometestingtoverifywhetherthereducedprecisioniscostingtoomuchgraphicalfidelity.
NotethattheeffectsofthesetweakscanvaryenormouslybetweenoneGPUarchitectureandanother(forexample,AMDversusNvidiaversusIntel),andevenGPUbrandsfromthesamemanufacturer.Insomecases,wecanmakesomedecentperformancegainsforatrivialamountofeffort.Inothercases,wemightseenobenefitatall.
Avoidchangingprecisionwhileswizzling
SwizzlingistheShaderprogrammingtechniqueofcreatinganewvector(anarrayofvalues)fromanexistingvectorbylistingthecomponentsintheorderinwhichwewishtocopythemintothenewstructure.Herearesomeexamplesofswizzling:
float4input=float4(1.0,2.0,3.0,4.0);//initialtestvalue
float2val1=input.yz;//swizzletwocomponents
float3val2=input.zyx;//swizzlethreecomponentsinadifferentorder
float4val3=input.yyy;//swizzlethesamecomponentmultipletimes
floatsclr=input.w;
float3val4=sclr.xxx//swizzleascalarmultipletimes
Wecanuseboththexyzwandrgbarepresentationstorefertothesamecomponents,sequentially.Itdoesnotmatterwhetheritisacolororvector;theyjustmaketheShadercodeeasiertoread.Wecanalsolistcomponentsinanyorderweliketofillinthedesireddata,repeatingthemifnecessary.
ConvertingfromoneprecisiontypetoanotherinaShadercanbeacostlyoperation,butconvertingtheprecisiontypewhilesimultaneouslyswizzlingcanbeparticularlypainful.Ifwehavemathematicaloperationsthatrelyonbeingswizzledintodifferentprecision
http://freepdf-books.com
types,itwouldbewiserifwesimplyabsorbedthehigh-precisioncostfromtheverybeginning,orreducedprecisionacrosstheboardtoavoidtheneedforchangesinprecision.
UseGPU-optimizedhelperfunctions
TheShadercompileroftenperformsagoodjobofreducingmathematicalcalculationsdowntoanoptimizedversionfortheGPU,butcompiledcustomcodeisunlikelytobeaseffectiveasboththeCglibrary’sbuilt-inhelperfunctionsandtheadditionalhelpersprovidedbytheUnityCgincludedfiles.IfweareusingShadersthatincludecustomfunctioncode,perhapswecanfindanequivalenthelperfunctionwithintheCgorUnitylibrariesthatcandoabetterjobthanourcustomcodecan.
TheseextraincludefilescanbeaddedtoourShaderwithintheCGPROGRAMblocklikeso:
CGPROGRAM
//otherincludes
#include"UnityCG.cginc"
//Shadercodehere
ENDCG
ExampleCglibraryfunctionstouseareabs()forabsolutevalues,lerp()forlinearinterpolation,mul()formultiplyingmatrices,andstep()forstepfunctionality.UsefulUnityCG.cgincfunctionsincludeWorldSpaceViewDir()forcalculatingthedirectiontowardsthecamera,andLuminance()forconvertingacolortograyscale.
NoteCheckthefollowingURLforafulllistofCgstandardlibraryfunctions:http://http.developer.nvidia.com/CgTutorial/cg_tutorial_appendix_e.html.
ChecktheUnitydocumentationforacompleteandup-to-datelistofpossibleincludefilesandtheiraccompanyinghelperfunctions:http://docs.unity3d.com/Manual/SL-BuiltinIncludes.html.
Disableunnecessaryfeatures
PerhapswecanmakesavingsbysimplydisablingShaderfeaturesthataren’tvital.DoestheShaderreallyneedmultiplepasses,transparency,Z-writing,alpha-testing,and/oralphablending?Willtweakingthesesettingsorremovingthesefeaturesgiveusagoodapproximationofourdesiredeffectwithoutlosingtoomuchgraphicalfidelity?Makingsuchchangesisagoodwayofmakingfillratecostsavings.
Removeunnecessaryinputdata
SometimestheprocessofwritingaShaderinvolvesalotofbackandforthexperimentationineditingcodeandviewingitintheScene.ThetypicalresultofthisisthatinputdatathatwasneededwhentheShaderwasgoingthroughearlydevelopmentisnowsurplusfluffoncethedesiredeffecthasbeenobtained,andit’seasytoforgetwhatchangesweremadewhen/iftheprocessdragsonforalongtime.But,theseredundantdatavaluescancosttheGPUvaluabletimeastheymustbefetchedfrommemoryeveniftheyarenotexplicitlyusedbytheShader.So,weshoulddoublecheckourShaderstoensure
http://freepdf-books.com
alloftheirinputgeometry,vertex,andfragmentdataisactuallybeingused.
Onlyexposenecessaryvariables
ExposingunnecessaryvariablesfromourShadertotheaccompanyingMaterial(s)canbecostlyastheGPUcan’tassumethesevaluesareconstant.ThismeanstheShadercodecannotbecompiledintoamoreoptimizedform.ThisdatamustbepushedfromtheCPUwitheverypasssincetheycanbemodifiedatanytimethroughtheMaterial’smethodssuchasSetColor(),SetFloat(),andsoon.Ifwefindthat,towardstheendoftheproject,wealwaysusethesamevalueforthesevariables,thentheycanbereplacedwithaconstantintheShadertoremovesuchexcessruntimeworkload.Theonlycostisobfuscatingwhatcouldbecriticalgraphicaleffectparameters,sothisshouldbedoneverylateintheprocess.
Reducemathematicalcomplexity
Complicatedmathematicscanseverelybottlenecktherenderingprocess,soweshoulddowhateverwecantolimitthedamage.ComplexmathematicalfunctionscouldbereplacedwithatexturethatisfedintotheShaderandprovidesapre-generatedtableforruntimelookup.Wemaynotseeanyimprovementwithfunctionssuchassinandcos,sincethey’vebeenheavilyoptimizedtomakeuseofGPUarchitecture,butcomplexmethodssuchaspow,exp,log,andothercustommathematicalprocessescanonlybeoptimizedsomuch,andwouldbegoodcandidatesforsimplification.Thisisassumingweonlyneedoneortwoinputvalues,whicharerepresentedthroughtheXandYcoordinatesofthetexture,andmathematicalaccuracyisn’tofparamountimportance.
Thiswillcostusadditionalgraphicsmemorytostorethetextureatruntime(moreonthislater),butiftheShaderisalreadyreceivingatexture(whichtheyareinmostcases)andthealphachannelisnotbeingused,thenwecouldsneakthedatainthroughthetexture’salphachannel,costingusliterallynoperformance,andtherestoftheShadercodeandgraphicssystemwouldbenone-the-wiser.Thiswillinvolvethecustomizationofartassetstoincludesuchdatainanyunusedcolorchannel(s),requiringcoordinationbetweenprogrammersandartists,butisaverygoodwayofsavingShaderprocessingcostswithnoruntimesacrifices.
Infact,MaterialpropertiesandtexturesarebothexcellententrypointsforpushingworkfromtheShader(theGPU)ontotheCPU.Ifacomplexcalculationdoesnotneedtovaryonaperpixelbasis,thenwecouldexposethevalueasapropertyintheMaterial,andmodifyitasneeded(acceptingtheoverheadcostofdoingsofromtheprevioussectionOnlyexposenecessaryvariables).Alternatively,iftheresultvariesperpixel,anddoesnotneedtochangeoften,thenwecouldgenerateatexturefilefromscriptcode,containingtheresultsofthecalculationsintheRGBAvalues,andpullingthetextureintotheShader.Lotsofopportunitiesarisewhenweignoretheconventionalapplicationofsuchsystems,andremembertothinkofthemasjustrawdatabeingtransferredaround.
Reducetexturelookups
Whilewe’reonthesubjectoftexturelookups,theyarenottrivialtasksfortheGPUtoprocessandtheyhavetheirownoverheadcosts.Theyarethemostcommoncauseof
http://freepdf-books.com
memoryaccessproblemswithintheGPU,especiallyifaShaderisperformingsamplesacrossmultipletextures,orevenmultiplesamplesacrossasingletexture,astheywilllikelyinflictcachemissesinmemory.SuchsituationsshouldbesimplifiedasmuchaspossibletoavoidsevereGPUmemorybottlenecking.
Evenworse,samplingatextureinarandomorderwouldlikelyresultinsomeverycostlycachemissesfortheGPUtosufferthrough,soifthisisbeingdone,thenthetextureshouldbereorderedsothatitcanbesampledinamoresequentialorder.
Avoidconditionalstatements
InmoderndayCPUarchitecture,conditionalstatementsundergoalotofcleverpredictivetechniquestomakeuseofinstruction-levelparallelism.ThisisafeaturewheretheCPUattemptstopredictwhichdirectionaconditionalstatementwillgoinbeforeithasactuallybeenresolved,andspeculativelybeginsprocessingthemostlikelyresultoftheconditionalusinganyfreecomponentsthataren’tbeingusedtoresolvetheconditional(fetchingsomedatafrommemory,copyingsomefloatsintounusedregisters,andsoon).Ifitturnsoutthatthedecisioniswrong,thenthecurrentresultisdiscardedandtheproperpathistakeninstead.
Solongasthecostofspeculativeprocessinganddiscardingfalseresultsislessthanthetimespentwaitingtodecidethecorrectpath,anditisrightmoreoftenthanitiswrong,thenthisisanetgainfortheCPU’sspeed.
However,thisfeatureisnotpossibleonGPUarchitecturebecauseofitsparallelnature.TheGPU’scoresaretypicallymanagedbysomehigher-levelconstructthatinstructsallcoresunderitscommandtoperformthesamemachine-code-levelinstructionsimultaneously.So,iftheFragmentShaderrequiresafloattobemultipliedby2,thentheprocesswillbeginbyhavingallcorescopydataintotheappropriateregistersinonecoordinatedstep.Onlywhenallcoreshavefinishedcopyingtotheregisterswillthecoresbeinstructedtobeginthesecondstep:multiplyingallregistersby2.
Thus,whenthissystemstumblesintoaconditionalstatement,itcannotresolvethetwostatementsindependently.Itmustdeterminehowmanyofitschildcoreswillgodowneachpathoftheconditional,grabthelistofrequiredmachinecodeinstructionsforonepath,resolvethemforallcorestakingthatpath,andrepeatforeachpathuntilallpossiblepathshavebeenprocessed.So,foranif-elsestatement(twopossibilities),itwilltellonegroupofcorestoprocessthe“true”path,thenasktheremainingcorestoprocessthe“false”path.Unlesseverycoretakesthesamepath,itmustprocessbothpathseverytime.
So,weshouldavoidbranchingandconditionalstatementsinourShadercode.Ofcourse,thisdependsonhowessentialtheconditionalistoachievingthegraphicaleffectwedesire.But,iftheconditionalisnotdependentonperpixelbehavior,thenwewouldoftenbebetteroffabsorbingthecostofunnecessarymathematicsthaninflictingabranchingcostontheGPU.Forexample,wemightbecheckingwhetheravalueisnon-zerobeforeusingitinacalculation,orcomparingagainstsomeglobalflagintheMaterialbeforetakingoneactionoranother.Bothofthesecaseswouldbegoodcandidatesforoptimizationbyremovingtheconditionalcheck.
http://freepdf-books.com
Reducedatadependencies
ThecompilerwilltryitsbesttooptimizeourShadercodeintothemoreGPU-friendlylow-levellanguagesothatitisnotwaitingondatatobefetchedwhenitcouldbeprocessingsomeothertask.Forexample,thefollowingpoorly-optimizedcode,couldbewritteninourShader:
floatsum=input.color1.r;
sum=sum+input.color2.g;
sum=sum+input.color3.b;
sum=sum+input.color4.a;
floatresult=calculateSomething(sum);
IfwewereabletoforcetheShadercompilertocompilethiscodeintomachinecodeinstructionsasitiswritten,thenthiscodehasadatadependencysuchthateachcalculationcannotbeginuntilthelastfinishesduetothedependencyonthesumvariable.But,suchsituationsareoftendetectedbytheShadercompilerandoptimizedintoaversionthatusesinstruction-levelparallelism(thecodeshownnextisthehigh-levelcodeequivalentoftheresultingmachinecode):
floatsum1,sum2,sum3,sum4;
sum1=input.color1.r;
sum2=input.color2.g;
sum3=input.color3.b
sum4=input.color4.a;
floatsum=sum1+sum2+sum3+sum4;
floatresult=CalculateSomething(sum);
Inthiscase,thecompilerwouldrecognizethatitcanfetchthefourvaluesfrommemoryinparallelandcompletethesummationonceallfourhavebeenfetchedindependentlyviathread-levelparallelism.Thiscansavealotoftime,relativetoperformingthefourfetchesoneafteranother.
However,longchainsofdatadependencycanabsolutelymurderShaderperformance.IfwecreateastrongdatadependencyinourShader’ssourcecode,thenithasbeengivennofreedomtomakesuchoptimizations.Forexample,thefollowingdatadependencywouldbepainfulonperformance,asonestepcannotbecompletedwithoutwaitingonanothertofetchdataandperformingtheappropriatecalculation.
float4val1=tex2D(_tex1,input.texcoord.xy);
float4val2=tex2D(_tex2,val1.yz);
float4val3=tex2D(_tex3,val2.zw);
Strongdatadependenciessuchastheseshouldbeavoidedwheneverpossible.
SurfaceShaders
Ifwe’reusingUnity’sSurfaceShaders,whichareawayforUnitydeveloperstogettogripswithShaderprogramminginamoresimplifiedfashion,thentheUnityEnginetakescareofconvertingourSurfaceShadercodeforus,abstractingawaysomeoftheoptimizationopportunitieswehavejustcovered.However,itdoesprovidesomemiscellaneousvaluesthatcanbeusedasreplacements,whichreduceaccuracybut
http://freepdf-books.com
simplifythemathematicsintheresultingcode.SurfaceShadersaredesignedtohandlethegeneralcasefairlyefficiently,butoptimizationisbestachievedwithapersonaltouch.
Theapproxviewattributewillapproximatetheviewdirection,savingcostlyoperations.halfasviewwillreducetheprecisionoftheviewvector,butbewareofitseffectonmathematicaloperationsinvolvingmultipleprecisiontypes.noforwardaddwilllimittheShadertoonlyconsideringasingledirectionallight,reducingDrawCallssincetheShaderwillrenderinonlyasinglepass,butreducinglightingcomplexity.Finally,noambientwilldisableambientlightingintheShader,removingsomeextramathematicaloperationsthatwemaynotneed.
UseShader-basedLOD
WecanforceUnitytorenderdistantobjectsusingsimplerShaders,whichcanbeaneffectivewayofsavingfillrate,particularlyifwe’redeployingourgameontomultipleplatformsorsupportingawiderangeofhardwarecapability.TheLODkeywordcanbeusedintheShadertosettheonscreensizefactorthattheShadersupports.IfthecurrentLODleveldoesnotmatchthisvalue,itwilldroptothenextfallbackShaderandsoonuntilitfindstheShaderthatsupportsthegivensizefactor.WecanalsochangeagivenShaderobject’sLODvalueatruntimeusingthemaximumLODproperty.
Thisfeatureissimilartothemesh-basedLODcoveredearlier,andusesthesameLODvaluesfordeterminingobjectformfactor,soitshouldbeconfiguredassuch.
http://freepdf-books.com
MemorybandwidthAnothermajorcomponentofbackendprocessingandapotentialsourceofbottlenecksismemorybandwidth.MemorybandwidthisconsumedwheneveratexturemustbepulledfromasectionoftheGPU’smainvideomemory(alsoknownasVRAM).TheGPUcontainsmultiplecoresthateachhaveaccesstothesameareaofVRAM,buttheyalsoeachcontainamuchsmaller,localTextureCachethatstoresthecurrenttexture(s)theGPUhasbeenmostrecentlyworkingwith.ThisissimilarindesigntothemultitudeofCPUcachelevelsthatallowmemorytransferupanddownthechain,asaworkaroundforthefactthatfastermemorywill,invariably,bemoreexpensivetoproduce,andhencesmallerincapacitycomparedtoslowermemory.
WheneveraFragmentShaderrequestsasamplefromatexturethatisalreadywithinthecore’slocalTextureCache,thenitislightningfastandbarelyperceivable.But,ifatexturesamplerequestismade,thatdoesnotyetexistwithintheTextureCache,thenitmustbepulledinfromVRAMbeforeitcanbesampled.ThisfetchrequestriskscachemisseswithinVRAMasittriestofindtherelevanttexture.Thetransferitselfconsumesacertainamountofmemorybandwidth,specificallyanamountequaltothetotalsizeofthetexturefilestoredwithinVRAM(whichmaynotbetheexactsizeoftheoriginalfile,northesizeinRAM,duetoGPU-levelcompression).
It’sforthisreasonthat,ifwe’rebottleneckedonmemorybandwidth,thenperformingabruteforcetestbyreducingtexturequalitywouldsuddenlyresultinaperformanceimprovement.We’veshrunkthesizeofourtextures,easingtheburdenontheGPU’smemorybandwidth,allowingittofetchthenecessarytexturesmuchquicker.GloballyreducingtexturequalitycanbeachievedbygoingtoEdit|ProjectSettings|Quality|TextureQualityandsettingthevaluetoHalfRes,QuarterRes,orEighthRes.
Intheeventthatmemorybandwidthisbottlenecked,thentheGPUwillkeepfetchingthenecessarytexturefiles,buttheentireprocesswillbethrottledastheTextureCachewaitsforthedatatoappearbeforeprocessingthefragment.TheGPUwon’tbeabletopushdatabacktotheFrameBufferintimetoberenderedontothescreen,blockingthewholeprocessandculminatinginapoorframerate.
Ultimately,properusageofmemorybandwidthisabudgetingconcern.Forexample,withamemorybandwidthof96GB/secpercoreandatargetframerateof60framespersecond,thentheGPUcanaffordtopull96/60=1.6GBworthoftexturedataeveryframebeforebeingbottleneckedonmemorybandwidth.
TipMemorybandwidthisoftenlistedonapercorebasis,butsomeGPUmanufacturersmaytrytomisleadyoubymultiplyingmemorybandwidthbythenumberofcoresinordertolistabigger,butlesspracticalnumber.Becauseofthis,researchmaybenecessarytoconfirmthememorybandwidthlimitwehaveforthetargetGPUhardwareisgivenonapercorebasis.
Notethatthisvalueisnotthemaximumlimitonthetexturedatathatourgamecan
http://freepdf-books.com
containintheproject,norinCPURAM,noteveninVRAM.Itisametricthatlimitshowmuchtextureswappingcanoccurduringoneframe.ThesametexturecouldbepulledbackandforthmultipletimesinasingleframedependingonhowmanyShadersneedtousethem,theorderthattheobjectsarerendered,andhowoftentexturesamplingmustoccur,sorenderingjustafewobjectscouldconsumewholegigabytesofmemorybandwidthiftheyallrequirethesamehighquality,massivetextures,requiremultiplesecondarytexturemaps(normalmaps,emissionmaps,andsoon),andarenotbatchedtogether,becausetheresimplyisn’tenoughTextureCachespaceavailabletokeepasingletexturefilelongenoughtoexploititduringthenextrenderingpass.
Thereareseveralapproacheswecantaketosolvebottlenecksinmemorybandwidth.
UselesstexturedataThisapproachissimple,straightforward,andalwaysagoodideatoconsider.Reducingtexturequality,eitherthroughresolutionorbitrate,isnotidealforgraphicalquality,butwecansometimesgetawaywithusing16-bittextureswithoutanynoticeabledegradation.
MipMaps(Chapter4,KickstartYourArt)areanotherexcellentwayofreducingtheamountoftexturedatabeingpushedbackandforthbetweenVRAMandtheTextureCache.NotethattheSceneViewhasaMipmapsShadingMode,whichwillhighlighttexturesinoursceneblueorreddependingonwhetherthecurrenttexturescaleisappropriateforthecurrentSceneView’scamerapositionandorientation.Thiswillhelpidentifywhattexturesaregoodcandidatesforfurtheroptimization.
TipMipMapsshouldalmostalwaysbeusedin3DScenes,unlessthecameramovesverylittle.
TestdifferentGPUTextureCompressionformatsTheTextureCompressiontechniquesyoulearnedbackinChapter4,KickstartYourArt,weredescribedinsuchawaythathelpedreduceourapplication’sfootprint(executablefilesize),andruntimeCPUmemoryusage,thatis,thestorageareawherealltextureresourcedataiskeptuntilitisneededbytheGPU.However,oncethedatareachestheGPU,itusesadifferentformofcompressiontokeeptexturedatasmall.ThecommonformatsareDXT,PVRTC,ETC,andASTC.
Tomakemattersmoreconfusing,eachplatformandGPUhardwaresupportsdifferentcompressionformats,andifthedevicedoesnotsupportthegivencompressionformat,thenitwillbehandledatthesoftwarelevel.Inotherwords,theCPUwillneedtostopandrecompressthetexturetothedesiredformattheGPUwants,asopposedtotheGPUtakingcareofitwithaspecializedhardwarechip.
ThecompressionoptionsareonlyavailableifatextureresourcehasitsTextureTypefieldsettoAdvanced.Usinganyoftheothertexturetypesettingswillsimplifythechoices,andUnitywillmakeabestguesswhendecidingwhichformattouseforthetargetplatform,whichmaynotbeidealforagivenpieceofhardwareandthuswillconsumemorememorybandwidththannecessary.
http://freepdf-books.com
ThebestapproachtodeterminingthecorrectformatistosimplytestabunchofdifferentdevicesandTextureCompressiontechniquesandfindonethatfits.Forexample,commonwisdomsaysthatETCisthebestchoiceforAndroidsincemoredevicessupportit,butsomedevelopershavefoundtheirgameworksbetterwiththeDXTandPVRTCformatsoncertaindevices.
Bewarethat,ifwe’reatthepointwhereindividuallytweakingTextureCompressiontechniquesisnecessary,thenhopefullywehaveexhaustedallotheroptionsforreducingmemorybandwidth.Bygoingdownthisroad,wecouldbecommittingtosupportingmanydifferentdeviceseachintheirownspecificway.Manyofuswouldprefertokeepthingssimplewithageneralsolutioninsteadofpersonalcustomizationandtime-consuminghandiworktoworkaroundproblemslikethis.
MinimizetexturesamplingCanwemodifyourShaderstoremovesometexturesamplingoverhead?Didweaddsomeextratexturelookupfilestogiveourselvessomefillratesavingsonmathematicalfunctions?Ifso,wemightwanttoconsiderloweringtheresolutionofsuchtexturesorrevertingthechangesandsolvingourfillrateproblemsinotherways.Essentially,thelesstexturesamplingwedo,thelessoftenweneedtousememorybandwidthandthecloserwegettoresolvingthebottleneck.
OrganizeassetstoreducetextureswapsThisapproachbasicallycomesbacktoBatchingandAtlasingagain.Arethereopportunitiestobatchsomeofourbiggesttexturefilestogether?Ifso,thenwecouldsavetheGPUfromhavingtopullinthesametexturefilesoverandoveragainduringthesameframe.Asalastresort,wecouldlookforwaystoremovesometexturesfromtheentireprojectandreusesimilarfiles.Forinstance,ifwehavefillratebudgettospare,thenwemaybeabletousesomeFragmentShaderstomakeahandfuloftexturesfilesappearinourgamewithdifferentcolorvariations.
http://freepdf-books.com
VRAMlimitsOnelastconsiderationrelatedtotexturesishowmuchVRAMwehaveavailable.MosttexturetransferfromCPUtoGPUoccursduringinitialization,butcanalsooccurwhenanon-existenttextureisfirstrequiredbythecurrentview.Thisprocessisasynchronousandwillresultinablanktexturebeinguseduntilthefulltextureisreadyforrendering.Assuch,weshouldavoidtoomuchtexturevariationacrossourScenes.
TexturepreloadingEventhoughitdoesn’tstrictlyrelatetographicsperformance,itisworthmentioningthattheblanktexturethatisusedduringasynchronoustextureloadingcanbejarringwhenitcomestogamequality.WewouldlikeawaytocontrolandforcethetexturetobeloadedfromdisktothemainmemoryandthentoVRAMbeforeitisactuallyneeded.
AcommonworkaroundistocreateahiddenGameObjectthatfeaturesthetextureandplaceitsomewhereintheSceneontheroutethattheplayerwilltaketowardstheareawhereitisactuallyneeded.Assoonasthetexturedobjectbecomesacandidatefortherenderingsystem(evenifit’stechnicallyhidden),itwillbegintheprocessofcopyingthedatatowardsVRAM.Thisisalittleclunky,butiseasytoimplementandworkssufficientlywellinmostcases.
WecanalsocontrolsuchbehaviorviaScriptcodebychangingahiddenMaterial’stexture:
GetComponent<Renderer>().material.texture=textureToPreload;
TexturethrashingIntherareeventthattoomuchtexturedataisloadedintoVRAM,andtherequiredtextureisnotpresent,theGPUwillneedtorequestitfromthemainmemoryandoverwritetheexistingtexturedatatomakeroom.Thisislikelytoworsenovertimeasthememorybecomesfragmented,anditintroducesariskthatthetexturejustflushedfromVRAMneedstobepulledagainwithinthesameframe.Thiswillresultinaseriouscaseofmemory“thrashing”,andshouldbeavoidedatallcosts.
ThisislessofaconcernonmodernconsolessuchasthePS4,XboxOne,andWiiU,sincetheyshareacommonmemoryspaceforbothCPUandGPU.Thisdesignisahardware-leveloptimizationgiventhefactthatthedeviceisalwaysrunningasingleapplication,andalmostalwaysrendering3Dgraphics.But,allotherplatformsmustsharetimeandspacewithmultipleapplicationsandbecapableofrunningwithoutaGPU.TheythereforefeatureseparateCPUandGPUmemory,andwemustensurethatthetotaltextureusageatanygivenmomentremainsbelowtheavailableVRAMofthetargethardware.
Notethatthis“thrashing”isnotpreciselythesameasharddiskthrashing,wherememoryiscopiedbackandforthbetweenmainmemoryandvirtualmemory(theswapfile),butitisanalogous.Ineithercase,dataisbeingunnecessarilycopiedbackandforthbetweentworegionsofmemorybecausetoomuchdataisbeingrequestedintooshortatimeperiodforthesmallerofthetwomemoryregionstoholditall.
http://freepdf-books.com
NoteThrashingsuchasthiscanbeacommoncauseofdreadfulgraphicsperformancewhengamesareportedfrommodernconsolestothedesktopandshouldbetreatedwithcare.
Avoidingthisbehaviormayrequirecustomizingtexturequalityandfilesizesonaper-platformandper-devicebasis.Bewarnedthatsomeplayersarelikelytonoticetheseinconsistenciesifwe’redealingwithhardwarefromthesameconsoleordesktopGPUgeneration.Asmanyofuswillknow,evensmalldifferencesinhardwarecanleadtoalotofapples-versus-orangescomparisons,buthardcoregamerswillexpectasimilarlevelofqualityacrosstheboard.
http://freepdf-books.com
http://freepdf-books.com
LightingandShadowingLightingandShadowingcanaffectallpartsofthegraphicspipeline,andsotheywillbetreatedseparately.Thisisperhapsoneofthemostimportantpartsofgameartanddesigntogetright.GoodLightingandShadowingcanturnamundanesceneintosomethingspectacularasthereissomethingmagicalaboutprofessionalcoloringthatmakesitvisuallyappealing.Eventhelow-polyartstyle(thinkMonumentValley)reliesheavilyonagoodlightingandshadowingprofileinordertoallowtheplayertodistinguishoneobjectfromanother.But,thisisn’tanartbook,sowewillfocusontheperformancecharacteristicsofvariousLightingandShadowingfeatures.
Unityofferstwostylesofdynamiclightrendering,aswellasbakedlightingeffectsthroughlightmaps.Italsoprovidesmultiplewaysofgeneratingshadowswithvaryinglevelsofcomplexityandruntimeprocessingcost.Betweenthetwo,therearealotofoptionstoexplore,andalotofthingsthatcantripusupifwe’renotcareful.
TheUnitydocumentationcoversallofthesefeaturesinanexcellentamountofdetail(startwiththispageandworkthroughthem:http://docs.unity3d.com/Manual/Lighting.html),sowe’llexaminethesefeaturesfromaperformancestandpoint.
Let’stacklethetwomainlightrenderingmodesfirst.ThissettingcanbefoundunderEdit|ProjectSettings|Player|OtherSettings|Rendering,andcanbeconfiguredonaper-platformbasis.
http://freepdf-books.com
ForwardRenderingForwardRenderingistheclassicalformofrenderinglightsinourscene.EachobjectislikelytoberenderedinmultiplepassesthroughthesameShader.Howmanypassesarerequiredwillbebasedonthenumber,distance,andbrightnessoflightsources.Unitywilltrytoprioritizewhichdirectionallightisaffectingtheobjectthemostandrendertheobjectina“basepass”asastartingpoint.Itwillthentakeuptofourofthemostpowerfulpointlightsnearbyandre-renderthesameobjectmultipletimesthroughthesameFragmentShader.Thenextfourpointlightswillthenbeprocessedonaper-vertexbasis.Allremaininglightsaretreatedasagiantblobbymeansofatechniquecalledsphericalharmonics.
Someofthisbehaviorcanbesimplifiedbysettingalight’sRenderModetovaluessuchasNotImportant,andchangingthevalueofEdit|ProjectSettings|Quality|PixelLightCount.Thisvaluelimitshowmanylightswillbetreatedonaperpixelbasis,butisoverriddenbyanylightswithaRenderModesettoImportant.Itisthereforeuptoustousethiscombinationofsettingsresponsibly.
Asyoucanimagine,thedesignofForwardRenderingcanutterlyexplodeourDrawCallcountveryquicklyinsceneswithalotofpointlightspresent,duetothenumberofrenderstatesbeingconfiguredandShaderpassesbeingreprocessed.CPU-boundapplicationsshouldavoidthisrenderingmodeifpossible.
NoteMoreinformationonForwardRenderingcanbefoundintheUnitydocumentation:http://docs.unity3d.com/Manual/RenderTech-ForwardRendering.html.
http://freepdf-books.com
DeferredShadingDeferredShadingorDeferredRenderingasitissometimesknown,isonlyavailableonGPUsrunningatleastShaderModel3.0.Inotherwords,anydesktopgraphicscardmadeafteraround2004.Thetechniquehasbeenaroundforawhile,butithasnotresultedinacompletereplacementoftheForwardRenderingmethodduetothecaveatsinvolvedandlimitedsupportonmobiledevices.Anti-aliasing,transparency,andanimatedcharactersreceivingshadowsareallfeaturesthatcannotbemanagedthroughDeferredShadingaloneandwemustusetheForwardRenderingtechniqueasafallback.
DeferredShadingissonamedbecauseactualshadingdoesnotoccuruntilmuchlaterintheprocess;thatis,itisdeferreduntillater.Fromaperformanceperspective,theresultsarequiteimpressiveasitcangenerateverygoodperpixellightingwithsurprisinglylittleDrawCalleffort.TheadvantageisthatahugeamountoflightingcanbeaccomplishedusingonlyasinglepassthroughthelightingShader.ThemaindisadvantagesincludetheadditionalcostsifwewishtopileonadvancedlightingfeaturessuchasShadowingandanystepsthatmustpassthroughForwardRenderinginordertocomplete,suchastransparency.
NoteTheUnitydocumentationcontainsanexcellentsourceofinformationontheDeferredShadingtechnique,itsadvantages,anditspitfalls:http://docs.unity3d.com/Manual/RenderTech-DeferredShading.html.
http://freepdf-books.com
VertexLitShading(legacy)Technically,therearemorethantwolightingmethods.Unityallowsustouseacoupleoflegacylightingsystems,onlyoneofwhichmayseeactualuseinthefield:VertexLitShading.Thisisamassivesimplificationoflighting,aslightingisonlyconsideredpervertex,andnotperpixel.Inotherwords,entirefacesarecoloredbasedontheincominglightcolor,andnotindividualpixels.
Itisnotexpectedthatmany,orreallyany,3Dgameswillmakeuseofthislegacytechnique,asalackofshadowsandproperlightingmakevisualizationsofdepthverydifficult.Itismostlyrelegatedto2Dgamesthatdon’tintendtomakeuseofshadows,normalmaps,andvariousotherlightingfeatures,butitisthereifweneedit.
http://freepdf-books.com
Real-timeShadowsSoftShadowsareexpensive,HardShadowsarecheap,andNoShadowsarefree.ShadowResolution,ShadowProjection,ShadowDistance,andShadowCascadesareallsettingswecanfindunderEdit|ProjectSettings|Quality|Shadowsthatwecanusetomodifythebehaviorandcomplexityofourshadowingpasses.ThatsummarizesalmosteverythingweneedtoknowaboutUnity’sreal-timeshadowingtechniquesfromahigh-levelperformancestandpoint.Wewillcovershadowsmoreinthefollowingsectiononoptimizingourlightingeffects.
http://freepdf-books.com
LightingoptimizationWithacursoryglanceatalloftherelevantlightingtechniques,let’srunthroughsometechniqueswecanusetoimprovelightingcosts.
UsetheappropriateShadingModeItisworthtestingbothofthemainrenderingmodestoseewhichonebestsuitsourgame.DeferredShadingisoftenusedasabackupintheeventthatForwardRenderingisbecomingaburdenonperformance,butitreallydependsonwhereelsewe’refindingbottlenecksasitissometimesdifficulttotellthedifferencebetweenthem.
UseCullingMasksALightComponent’sCullingMaskpropertyisalayer-basedmaskthatcanbeusedtolimitwhichobjectswillbeaffectedbythegivenLight.Thisisaneffectivewayofreducinglightingoverhead,assumingthatthelayerinteractionsalsomakesensewithhowweareusinglayersforphysicsoptimization.Objectscanonlybeapartofasinglelayer,andreducingphysicsoverheadprobablytrumpslightingoverheadinmostcases;thus,ifthereisaconflict,thenthismaynotbetheidealapproach.
NotethatthereislimitedsupportforCullingMaskswhenusingDeferredShading.Becauseofthewayittreatslightinginaveryglobalfashion,onlyfourlayerscanbedisabledfromthemask,limitingourabilitytooptimizeitsbehaviorthroughthismethod.
UseBakedLightmapsBakingLightingandShadowingintoaSceneissignificantlylessprocessor-intensivethangeneratingthematruntime.Thedownsideistheaddedapplicationfootprint,memoryconsumption,andpotentialformemorybandwidthabuse.Ultimately,unlessagame’slightingeffectsarebeinghandledexclusivelythroughLegacyVertexLightingorasingleDirectionalLight,thenitshouldprobablyincludeLightmappingtomakesomehugebudgetsavingsonlightingcalculations.Relyingentirelyonreal-timelightingandshadowsisarecipefordisasterunlessthegameistryingtowinanawardforthesmallestapplicationfilesizeofalltime.
OptimizeShadowsShadowingpassesmostlyconsumeourDrawCallsandfillrate,buttheamountofvertexpositiondatawefeedintotheprocessandourselectionfortheShadowProjectionsettingwillaffectthefrontend’sabilitytogeneratetherequiredshadowcastersandshadowreceivers.Weshouldalreadybeattemptingtoreducevertexcountstosolvefrontendbottleneckinginthefirstplace,andmakingthischangewillbeanaddedmultipliertowardsthateffort.
DrawCallsareconsumedduringshadowingbyrenderingvisibleobjectsintoaseparatebuffer(knownastheshadowmap)aseitherashadowcaster,ashadowreceiver,orboth.EachobjectthatisrenderedintothismapwillconsumeanotherDrawCall,whichmakesshadowsahugeperformancecostmultiplier,soitisoftenasettingthatgameswillexpose
http://freepdf-books.com
tousersviaqualitysettings,allowinguserswithweakerhardwaretoreducetheeffectorevendisableitentirely.
ShadowDistanceisaglobalmultiplierforruntimeshadowrendering.Thefewershadowsweneedtodraw,thehappiertheentirerenderingprocesswillbe.Thereislittlepointinrenderingshadowsatagreatdistancefromthecamera,sothissettingshouldbeconfiguredspecifictoourgameandhowmuchshadowingweexpecttowitnessduringgameplay.Itisalsoacommonsettingthatisexposedtotheusertoreducetheburdenofrenderingshadows.
HighervaluesofShadowResolutionandShadowCascadeswillincreaseourmemorybandwidthandfillrateconsumption.Bothofthesesettingscanhelpcurbtheeffectsofartefactsinshadowrendering,butatthecostofamuchlargershadowmapsizethatmustbemovedaroundandofthecanvassizetodrawto.
NoteTheUnitydocumentationcontainsanexcellentsummaryonthetopicofthealiasingeffectofshadowmapsandhowtheShadowCascadesfeaturehelpstosolvetheproblem:http://docs.unity3d.com/Manual/DirLightShadows.html.
It’sworthnotingthatSoftShadowsdonotconsumeanymorememoryorCPUoverheadrelativetoHardShadows,astheonlydifferenceisamorecomplexShader.ThismeansthatapplicationswithenoughfillratetosparecanenjoytheimprovedgraphicalfidelityofSoftShadows.
http://freepdf-books.com
http://freepdf-books.com
OptimizinggraphicsformobileUnity’sabilitytodeploytomobiledeviceshascontributedgreatlytoitspopularityamonghobbyist,small,andmid-sizedevelopmentteams.Assuch,itwouldbeprudenttocoversomeapproachesthataremorebeneficialformobileplatformsthanfordesktopandotherdevices.
Notethatany,andall,ofthefollowingapproachesmaybecomeobsoletesoon,iftheyaren’talready.Themobiledevicemarketismovingblazinglyfast,andthefollowingtechniquesastheyapplytomobiledevicesmerelyreflectconventionalwisdomfromthelasthalfdecade.Weshouldoccasionallytesttheassumptionsbehindtheseapproachesfromtime-to-timetoseewhetherthelimitationsofmobiledevicesstillfitthemobilemarketplace.
http://freepdf-books.com
MinimizeDrawCallsMobileapplicationsaremoreoftenbottleneckedonDrawCallsthanonfillrate.Notthatfillrateconcernsshouldbeignored(nothingshould,ever!),butthismakesitalmostnecessaryforanymobileapplicationofreasonablequalitytoimplementMeshCombining,Batching,andAtlasingtechniquesfromtheverybeginning.DeferredRenderingisalsothepreferredtechniqueasitfitswellwithothermobile-specificconcerns,suchasavoidingtransparencyandhavingtoomanyanimatedcharacters.
http://freepdf-books.com
MinimizetheMaterialcountThisconcerngoeshandinhandwiththeconceptsofBatchingandAtlasing.ThefewerMaterialsweuse,thefewerDrawCallswillbenecessary.ThisstrategywillalsohelpwithconcernsrelatingtoVRAMandmemorybandwidth,whichtendtobeverylimitedonmobiledevices.
http://freepdf-books.com
MinimizetexturesizeandMaterialcountMostmobiledevicesfeatureaverysmallTextureCacherelativetodesktopGPUs.Forinstance,theiPhone3Gcanonlysupportatotaltexturesizeof1024x1024duetorunningOpenGLES1.1withsimplevertexrenderingtechniques.MeanwhiletheiPhone3GS,iPhone4,andiPadgenerationrunOpenGLES2.0,whichonlysupportstexturesupto2048x2048.Latergenerationscansupporttexturesupto4096x4096.Doublecheckthedevicehardwarewearetargetingtobesureitsupportsthetexturefilesizeswewishtouse(therearetoomanyAndroiddevicestolisthere).However,later-generationdevicesareneverthemostcommondevicesinthemobilemarketplace.Ifwewishourgametoreachawideaudience(increasingitschancesofsuccess),thenwemustbewillingtosupportweakerhardware.
NotethattexturesthataretoolargefortheGPUwillbedownscaledbytheCPUduringinitialization,wastingvaluableloadingtime,andleavinguswithunintendedgraphicalfidelity.ThismakestexturereuseofparamountimportanceformobiledevicesduetothelimitedVRAMandTextureCachesizesavailable.
http://freepdf-books.com
Maketexturessquareandpowerof2WehavealreadycoveredthistopicinChapter4,KickstartYourArt,butitisworthrevisitingthesubjectofGPU-levelTextureCompression.TheGPUwillfinditdifficult,orsimplybeunabletocompressthetextureifitisnotinasquareformat,somakesureyousticktothecommondevelopmentconventionandkeepthingssquareandsizedtoapowerof2.
http://freepdf-books.com
UsethelowestpossibleprecisionformatsinShadersMobileGPUsareparticularlysensitivetoprecisionformatsinitsShaders,sothesmallestformatsshouldbeused.Onarelatednote,formatconversionshouldbeavoidedforthesamereason.
http://freepdf-books.com
AvoidAlphaTestingMobileGPUshaven’tquitereachedthesamelevelsofchipoptimizationasdesktopGPUs,andAlphaTestingremainsaparticularlycostlytaskonmobiledevices.InmostcasesitshouldsimplybeavoidedinfavorofAlphaBlending.
http://freepdf-books.com
http://freepdf-books.com
SummaryIfyou’vemadeitthisfarwithoutskippingahead,thencongratulationsareinorder.ThatwasalotofinformationtoabsorbforjustonecomponentoftheUnityEngine,butthenitisclearlythemostcomplicatedofthemall,requiringamatchingdepthofexplanation.Hopefully,you’velearnedalotofapproachestohelpyouimproveyourrenderingperformanceandenoughabouttherenderingpipelinetoknowhowtousethemresponsibly!
Bynowweshouldbeusedtotheideathat,withtheexceptionofalgorithmimprovements,everyperformanceenhancementweimplementwillcomewithsomerelatedcostthatwemustbewillingtobearforthesakeofremovingonebottleneck.Weshouldalsobereadytoimplementmultipletechniquesuntilwe’vesquashedthemall.
We’vejustcoveredaveryabstractsystemingreatdetail,solet’smovethingsalongwithanexplorationofamoreconcretesystem:Unity’sunderlyingEngineandtheC#language.Inthenextchapter,wewilltakealookatourScriptcodeinamoreadvancedlightandinvestigatesomemethodstoimproveourCPUandmemorymanagement.
http://freepdf-books.com
http://freepdf-books.com
Chapter7.MasterfulMemoryManagementUsingmemoryproperlywithintheUnityEnginerequiresagoodamountofunderstandingoftheunderlyingUnityEngineandMonoFramework.Thiscanbeabitofanintimidatingplaceforsomedevelopers,sincemanypickedUnityastheirsolutionprimarilytoavoidthekindoflow-levelgruntworkthatcomesfromenginedevelopmentandmemorymanagement.Theywouldpreferinsteadtofocusonhigher-levelconcernsrelatedtogameplayimplementation,leveldesign,andartassetmanagement.
Manygamesoflimitedscopecangetawaywithfocusingonsuchhigher-levelconcerns,atthecostofwastedresources,andmayneverrunintoanyproblemsrelatedtomemory.Thisisallwellandgooduntilthedayitbecomesaproblem.Atthispoint,theirneglectinunderstandingtheimportantcomponentsoftheengineleadstoascrambletofindsolutionsthatcanbedifficulttounderstandandimplementwithoutproperknowledgetobackitup.
Therefore,understandingwhatishappeningwithmemoryallocationsandC#languagefeatures,howtheyinteractwiththeMonoPlatform,howMonointeractswiththeunderlyingengine,andthevariouslibrarieswehaveavailableareabsolutelyparamounttomakinghigh-quality,efficientscriptcode.So,inthischapter,youwilllearnaboutallofthenutsandboltsoftheunderlyingUnityEngine,MonoPlatform,C#language,and.NETFramework.
Let’sstartbyexploringthefamiliarpartoftheengine,whichhandlesmostoftheworkforourgame’sscriptingcode—theMonoplatform.
http://freepdf-books.com
TheMonoplatformMonoisamagicalsauce,mixedintotheUnityrecipe,whichgivesitalotofitscross-platformcapability.MonoisanopensourceprojectthatbuiltitsownframeworkandlibrariesbasedontheAPI,specifications,andtoolsfromMicrosoft’s.NETFrameworkandcommonlibraries.Essentially,itisarecreationofthe.NETFramework,asitwasaccomplishedwithlittletonoaccesstothesourcecode.Notethat,despiteMono’slibrariesbeinganopensourcerecreationofMicrosoft’sbase.NETclasslibrary,itisfullycompatiblewiththeoriginallibraryfromMicrosoft.
ThegoaloftheMonoprojectistoprovideaframeworktoallowcross-platformcompatibilityusingthe.NETFrameworkasacommonlayer.Itallowsapplicationstobewritteninacommonprogramminglanguageandrunagainstmanydifferenthardwareplatforms,includingLinux,OSX,Windows,ARM,PowerPC,andmore.Monoalsosupportsmanylanguages,notjusttheC#,Boo,andUnityScriptwemaybefamiliarwith.Anylanguagethatcanbecompiledinto.NET’spureCommonIntermediateLanguage(CIL–moreonthislater)issufficienttointegratewiththeMonoplatform.ThisincludesC#,butevenincludeslanguagessuchasF#,Java,VisualBasic.NET,PythonNet,andIronPython.
AcommonmisconceptionabouttheUnityEngineisthatitisbuiltontopoftheMonoplatform.Thisisuntrue,astheMonosidedoesnothandlemanyimportantgametaskssuchasaudio,rendering,physics,andsoon.UnityTechnologiesbuiltanativeC++backendforthesakeofspeed,andallowsitsuserscontroloftheenginethroughMonoasascriptinginterface.Assuch,MonoismerelyacomponentoftheunderlyingUnityEngine.Thisisequivalenttomanyothergameengines,whichrunC++underthehood,handlingimportanttaskssuchasrendering,animation,resourcemanagement,andsoon,whilesimultaneouslyprovidingascriptinglanguageforgameplaylogictobeimplemented.TheMonoplatformwaschosenbyUnityTechnologiesforthistask.
TipNativecodesimplymeanscodethatiscompileddirectlytothetargetOS,andexecuteswithoutadditionallayersofcomplexityintheruntimeenvironment.Thiskeepsoverheadcostslow,butattheexpenseofneedingtomanagememoryandothertaskswithinthecodeinamoredirectfashion.
Scriptinglanguagestypicallyabstractawaycomplexmemorymanagementthroughautomaticgarbagecollection,andprovidevarioussafetyfeatures,whichsimplifytheactofprogrammingattheexpenseofruntimeoverhead.Somescriptinglanguagescanalsobeinterpretedatruntime,meaningthattheydon’tneedtobecompiledbeforeexecution.Therawinstructionsareconverteddynamicallyintomachinecodeandexecutedthemomenttheyarereadduringruntime.Thelastfeature,andprobablythemostimportantone,isthattheyallowsimplersyntaxofprogrammingcommands.Thisusuallyimprovesthedevelopmentworkflowimmensely,asteammemberswithoutmuchexperienceusinglanguagessuchasC++cancontributetothecodebase.Thisenablesthemtoimplementthingssuchasgameplaylogicinasimplerformat,attheexpenseofacertainamountof
http://freepdf-books.com
controlandruntimeexecutionspeed.
Notethatsuchlanguagesareoftencalled“managed”languages,whichfeaturemanagedcode.Technically,thiswasatermcoinedbyMicrosofttorefertoanysourcecodethatmustruninsidetheirCommonLanguageRuntime(CLR)environment(morelater),asopposedtocodethatiscompiledandrunnativelythroughthetargetOperatingSystem(OS).But,becauseoftheprevalenceandcommonfeaturesthatexistbetweentheCLRandotherlanguagesthatfeaturetheirownsimilarlydesignedruntimeenvironments(suchasJava),theterm“managed”hassincebecomealittlevague.Ittendstobeusedtorefertoanylanguageorcodethatdependsonitsownruntimeenvironmentandthatmay,ormaynot,includeautomaticgarbagecollection.Fortherestofthischapter,wewillusetheterm“managed”torefertocodethatbothdependsonaseparateruntimeenvironmentandhasundergoneautomaticgarbagecollection.
Theruntimeperformancecostofmanagedlanguagesisbecominglessandlesssignificanteveryyear.Thisispartlyduetogradualoptimizationsintoolsandruntimeenvironments,andpartlyduetothecomputingpoweroftheaveragedevicegraduallybecominggreater.Butthemainpointofcontroversyinmanagedlanguagesstillremainstheirautomaticmemorymanagement.Managingmemorymanuallycanbeacomplextaskthatcantakemanyyearsofdifficultdebuggingtobeproficientat,butmanydevelopersfeelthatmanagedlanguagessolvethisprobleminwaysthataretoounpredictable,riskingtoomuchproductquality.Suchdevelopersmightcitethatmanagedcodewillneverreachthesamelevelofperformanceasnativecode,anditisfoolhardytobuildhigh-performanceapplicationswiththem.
Thisistruetoanextent,asmanagedlanguagesinvariablyinflictruntimeoverheads,andwelosepartialcontroloverruntimememoryallocations.But,aswithallthings,itbecomesabalancingact,sincenotallresourceusagewillnecessarilyresultinabottleneck,andthebestgamesaren’tnecessarilytheonesthatuseeverysinglebytetotheirfullest.Forexample,imagineauserinterfacethatrefreshesin30microsecondsvianativecodeversus60microsecondsinmanagedcodeduetoanextra100percentoverhead(extremeexample).Themanagedcodeversionisstillfastenoughsuchthattheuserwillneverbeabletonoticethedifference,soistherereallyanyharminusingmanagedcodeforsuchatask?
Inreality,workingwithmanagedlanguagesoftenjustmeansthatdevelopershaveauniquesetofconcernstoworryaboutcomparedtonativecodedevelopers.Assuch,choosingtouseamanagedlanguageispartlyamatterofpreference,andpartlyacompromiseofcontroloverdevelopmentspeed.
http://freepdf-books.com
ThecompilationprocessWhenwemakechangestoourC#code,itistypicallycompiledimmediatelyafterweswitchbackfromourfavoriteIDE(whichistypicallyeitherMonoDevelopor,themuchmorefeature-richVisualStudio)totheUnityEditor.However,theC#codeisnotconverteddirectlyintomachinecode,aswewouldexpecttohappenwithstaticcompilersinthelandofC++.Instead,thecodeisconvertedintoanintermediatelanguagecalledCommonIntermediateLanguage(CIL),whichisanabstractionabovenativecode.CILissimilartoJavabytecode,uponwhichitisbased,butCILcodeisentirelyuselessonitsown,asCPUshavenoideahowtoruntheinstructionsdefinedinthislanguage.
Atruntime,thisintermediatecodeisrunthroughtheMonoVirtualMachine(VM),whichisaninfrastructurecomponentthatallowsthesamecodetorunagainstmultipleplatformswithoutneedingtochangethecodeitself.Thisisanimplementationofthe.NETCommonLanguageRuntimeorCLR.Ifwe’rerunningoniOS,werunontheiOS-basedVirtualMachineinfrastructure,andifwe’rerunningonLinux,thenwesimplyuseadifferentonethatisbettersuitedforLinux.
WithintheCLR,theintermediateCILcodewillactuallybecompiledintonativecodeondemand.Thison-demandnativecompilationcanbeaccomplishedeitherbyanAhead-Of-Time(AOT)orJust-In-Time(JIT)compiler,dependingonwhichplatformisbeingtargeted.Thesecompilersallowcodesegmentstobecompiledintonativecode(thatis,machinecodespecifictotheOSitisrunningagainst),andthemaindifferencebetweenthetwotypesiswhenthecodeiscompiled.
AOTcompilationhappensearly(aheadoftime),eitherduringthebuildprocessorduringinitialization.Ineithercase,thecodehasbeenprecompiledandnofurtherruntimecostsareinflictedduetodynamiccompilation.InthecurrentversionofUnity(Version5.2.2),theonlyplatformsthatsupportAOTcompilationareWebGL(andonlywhenUnityScriptisbeingused)andiOS.
JITcompilationhappensdynamicallyatruntimeinaseparatethreadandbeginsjustpriortoexecution(“justintime”forexecution).Often,thisdynamiccompilationcausesthefirstinvocationofapieceofcodetorunalittle(oralot!)moreslowly,becausethecodemustfinishcompilingbeforeitcanbeexecuted.But,fromthatpointforward,wheneverthesamecodeblockisexecuted,thereisnoneedforrecompilation,andtheinstructionsrunthroughthepreviouslycompilednativecode.
Itiscommoninsoftwarethat90percentoftheworkisbeingdonebyonly10percentofthecode.ThisgenerallymeansthatJITcompilationturnsouttobeanetpositiveonperformancethanifwesimplytriedtointerprettheCILcodedirectly.However,becausetheJITcompilermustcompilecodequickly,itisnotabletomakeuseofmanyoptimizationtechniquesthatstaticcompilersareabletoexploit.
ManualJITcompilationIntheeventthatJITcompilationiscausingaruntimeperformanceloss,beawarethatitisactuallypossibletoforceJITcompilationofamethodatanytimeviareflection.
http://freepdf-books.com
ReflectionisausefulfeatureoftheC#language,thatallowsourcodebasetoexploreitselfintrospectivelyfortypeinformation,methods,values,andmetadata.Usingreflectionisoftenaverycostlyprocess.Itshouldbeavoidedatruntimeor,attheveryleast,onlyusedduringinitializationorotherloadingtimes.NotdoingsocaneasilycausesignificantCPUspikesandgameplayfreezing.
WecanmanuallyforceJITcompilationofamethodusingreflectiontoobtainafunctionpointertoit:
varmethod=typeof(MyComponent).GetMethod("MethodName");
if(method!=null){
method.MethodHandle.GetFunctionPointer();
Debug.Log("JITcompilationcomplete!");
}
Thiscodeonlyworksonpublicmethods.Obtainingnon-publicmethodscanbeaccomplishedthroughtheuseofBindingFlags:
usingSystem.Reflection;
//...
varmethod=typeof(MyComponent).GetMethod("MethodName",
BindingFlags.NonPublic|BindingFlags.Instance);
ThiskindofcodeshouldonlyberunforverytargetedmethodswherewearecertainthatJITcompilationiscausingCPUspikes.Thiscanbeverifiedbyrestartingtheapplicationandprofilingamethod’sfirstinvocationversusallsubsequentinvocations.ThedifferencewilltellustheJITcompilationoverhead.
TipNotethattheofficialmethodforforcingJITcompilationinthe.NETlibraryisRuntimeHelpers.PrepareMethod(),butthisisnotproperlyimplementedinthecurrentversionofMonothatcomeswithUnity(MonoVersion2.6.5).TheaforementionedworkaroundshouldbeuseduntilUnityhaspulledinamorerecentversionoftheMonoproject.
http://freepdf-books.com
http://freepdf-books.com
MemoryusageoptimizationInmostgameengines,wewouldhavetheluxuryofbeingabletoportinefficientscriptcodeintothefasterC++areaifwewerehittingperformanceissues.ThisisnotanoptionunlessweinvestseriouscashinobtainingtheUnitysourcecode,whichisofferedasalicenseseparatefromtheFree/Personal/Prolicensingsystem,andonapercase,pertitlebasis.ThisforcestheoverwhelmingmajorityofusintoapositionofneedingtomakeourC#script-levelcodeasperformantaspossible.So,whatdoesallofthisbackstorywe’vebeencoveringmeanforuswhenitcomestothetaskofperformanceoptimization?
Firstly,wewon’tbecoveringanythingthatisspecifictotheUnityScriptandBoolanguages(althoughmuchoftheknowledgetranslatestothoselanguages).
Secondly,eventhoughallofourscriptcodemightbeinC#,weneedtobeawarethattheoverallUnityEngineisbuiltfrommultiplecomponentsthateachmaintainsitsownmemorydomains.
Thirdly,onlysometasksweperformwillawakenthedreadedgarbagecollector.Therearequiteafewmemoryallocationapproachesthatwecanusetoavoiditentirely.
Finally,thingscanchangequiteabitdependingonthetargetplatformwe’rerunningagainstandeveryassumptionshouldbetestedforvalidityifwe’restumblingintounexpectedmemorybottlenecks.
http://freepdf-books.com
UnitymemorydomainsThememoryspacewithintheUnityEnginecanbeessentiallysplitintothreedifferentmemorydomains.Eachdomainstoresdifferenttypesofdataandtakescareofaverydifferentsetoftasks.
ThefirstdomainistheNativeDomain.ThisistheunderlyingfoundationoftheUnityEngine,whichiswritteninC++andcompiledtonativecodedependingonwhichplatformisbeingtargeted.ThisareatakescareofallocatingmemoryspaceforthingssuchasAssetdata,forexampleTexturesandMeshes,memoryspaceforvarioussubsystems,suchastheRenderingsystem,Physics,Input,andsoon.Finally,itincludesnativerepresentationsofimportantgameplayobjectssuchasGameObjectandComponent.ThisiswherealotofthebaseComponentclasseskeeptheirdata,suchastheTransformandRigidbodyComponents.
Thesecondmemorydomain,theManagedDomain,iswheretheMonoplatformdoesitswork,andistheareaofmemorythatismaintainedbytheGarbageCollector.Anyscriptingobjectsandcustomclassesarestoredwithinthismemorydomain.ItalsoincludeswrappersfortheverysameobjectrepresentationsthatarestoredwithintheNativeDomain.ThisiswherethebridgebetweenMonocodeandNativecodederivesfrom;eachdomainhasitsownrepresentationforthesameentity,andcrossingthebridgebetweenthemtoomuchcaninflictsomefairlysignificantperformancehitsonourgame,aswelearnedinthepreviouschapters.
WhenanewGameObjectorComponentisinstantiated,itinvolvesallocatingmemoryinboththeManagedandNativeDomains.ThisallowssubsystemssuchasPhysicsandRenderingsystemstocontrolandrenderanobjectthroughitstransformdataontheNativeDomain,whiletheTransformComponentfromourscriptcodeismerelyawaytoreferencethroughthebridgeintotheNativememoryspaceandchangetheobject’stransformdata.Crossingbackandforthacrossthisbridgeshouldbeminimizedasmuchaspossible,duetotheoverheadinvolved,aswe’velearnedthroughtechniquessuchascachingposition/rotationchangesbeforeapplyingthem,backinChapter2,ScriptingStrategies.
Thethirdandfinalmemorydomain(s)arethoseofNativeandExternalDLLs,suchasDirectX,OpenGL,andanycustomDLLs,weattachtoourproject.ReferencingfromMonoC#codeintosuchDLLswillcauseasimilarmemoryspacetransitionasthatbetweenMonocodeandNativecode.
NativememoryWehavenodirectcontroloverwhatisgoingonintheNativeDomainwithouttheUnityEnginesourcecode,butwedohavealotofindirectcontrolbymeansofvariousscript-levelfunctions.Therearetechnicallyavarietyofmemoryallocatorsavailable,whichareusedinternallyforthingssuchasGameObjects,Graphicsobjects,andtheProfiler,butthesearehiddenbehindtheNativecodewall.
However,wecanobservehowmuchmemoryhasbeenallocatedandreservedinthis
http://freepdf-books.com
memorydomainviatheMemoryAreaoftheProfiler.Nativememoryallocationsshowupunderthevalueslabeled“Unity”,andwecanevengetmoreinformationusingtheDetailedviewandsamplingthecurrentframe.
UndertheSceneMemorysectionoftheDetailedview,wecanobservethatMonoBehaviourobjectsalwaysconsumeaconstantamountofmemory,regardlessoftheirmemberdata.ThisisthememoryconsumedbytheNativerepresentationoftheobject.Notethat376bytesofmemoryisconsumedbyaMonoBehaviourinEditorMode,whileonly156bytesisconsumedwhenprofilingthroughastandaloneapplication.
TipMemoryconsumptioninEditorModeisalwayswildlydifferenttothatofastandaloneversion,duetovariousdebuggingandeditorhookdatabeingapplied.ThisaddsafurtherincentivetoavoidusingEditorModeforprofilingandbenchmarkingpurposes(althoughitcanstillbeusefulattimes).
WecanalsousetheProfiler.GetRuntimeMemorySize()methodtogettheNativememoryallocationsizeofaparticularobject.
ManagedobjectrepresentationsareintrinsicallylinkedtotheirNativerepresentations.ThebestwaytominimizeourNativememoryallocationsistosimplyoptimizeourManagedmemoryusage.
ManagedmemoryMemoryinmostmodernoperatingsystemssplitsdynamicmemoryintotwocategories:thestackandtheheap.Thestackisaspecialreservedspaceinmemory,dedicatedtosmall,short-liveddatavalues,whichareautomaticallydeallocatedthemomenttheygooutofscope.Thestackcontainslocalvariables,aswellashandlestheloadingandunloadingoffunctionsasthey’recalled,andexpandsandcontractsalongwiththecallstack.Deallocationsinthestackarebasicallyfreebecausethedataisessentiallyinstantlyforgottenaboutandnolongerreferenceable.Newdatasimplyoverwritestheolddata,sincethestartofthenextmemoryallocationisalwaysknown,andthere’snoreasontoperformanyclean-upoperations.
Becausedatainthestackisveryshort-lived,thetotalstacksizeisusuallyverysmall;intheorderofMegabytes.It’spossibletocauseastackoverflowbyallocatingmorespacethanthestackcansupport.Thiscanoccurduringexceptionallylargecallstacks(forexample,infiniteloops),orhavingalargenumberoflocalvariables,butinmostcasescausingastackoverflowshouldnotbeaconcerndespiteitsrelativelysmallsize.
Theheaprepresentsallremainingmemoryspace,anditisusedfortheoverwhelming
http://freepdf-books.com
majorityofdynamicmemoryallocation.Wheneveradatatypeistoobigtofitinthestackormustexistoutsidethefunctionitwasdeclaredin,thenitmustbeallocatedontheheap.Mono’sheapisspecialinthatitismanagedbyaGarbageCollector(itissometimesreferredtoasaManagedHeap).Duringapplicationinitialization,MonowillrequestagivenchunkofmemoryfromtheOSanduseittogeneratetheheap.Theheapstartsofffairlysmall,lessthanoneMegabyte,butwillgrowasnewblocksofmemoryareneededbyourscriptcode.
WecanverifyhowmuchmemoryhasbeenallocatedandreservedfortheheapusingtheMemoryAreaoftheProfiler,butunderthevalueslabeled“Mono”.
WecanalsodeterminethecurrentusedandreservedheapspaceatruntimeusingtheProfiler.GetMonoUsedSize()andProfiler.GetMonoHeapSize()methods,respectively.
Garbagecollection
Whenamemoryrequestismade,andthereisenoughemptyspaceinthereservedheapblocktosatisfytherequest,thenMonoallocatesthespaceandhandsitovertowhoeverrequestedit.But,iftheheapdoesnothaveroomforit,thentheGarbageCollectorwillawakenandscanalltheexistingmemoryallocationsforanythingwhichisnolongerbeingusedandcleansthemupfirst,beforeattemptingtoexpandthecurrentheapspace.
TheGarbageCollectorintheversionofMonothatUnityusesisatypeofTracingGarbageCollector,whichusesaMark-and-Sweepstrategy.Thisalgorithmworksintwophases:eachallocatedobjectistrackedwithanadditionalbit.Thisflagswhethertheobjecthasbeenmarkedornot.Theseflagsstartoffsetto0(orfalse).
Whenthecollectionprocessbegins,itmarks(setstheflagto1ortrue)allobjectsthatarestillreachabletotheprogram.Eitherthereachableobjectisadirectreference,suchasstaticorlocalvariablesonthestack,oritisanindirectreferencethroughthefields(memberdata)ofotherdirectlyorindirectlyaccessibleobjects.Inthisway,itisgatheringasetofobjectsthatarestillreferenceable.
Thesecondphaseinvolvesiteratingthrougheveryobjectreferenceintheheap(whichMonowillhavebeentrackingthroughoutthelifetimeoftheapplication)andverifyingwhetherornottheyaremarked.Ifso,thentheobjectisignored.But,ifitisnotmarked,thenitisacandidatefordeallocation.Duringthisphase,allmarkedobjectsareskippedover,butnotbeforesettingtheirflagbacktofalseforthefirstphaseofthenextgarbagecollection.
Oncethesecondphaseends,allunmarkedobjectsaredeallocatedtofreespace,andthentheinitialrequesttocreatetheobjectisrevisited.Ifthereisenoughspacefortheobject,thenitisallocatedinthatspaceandtheprocessends.But,ifnot,thenitmustallocatea
http://freepdf-books.com
newblockfortheheapbyrequestingitfromtheOperatingSystem,atwhichpointthememoryallocationrequestcanfinallybecompleted.
Inanidealworld,whereweonlykeepallocatinganddeallocatingobjectsbutonlyafinitenumberofthemexistatonce,theheapwouldmaintainaconstantsizebecausethere’salwaysenoughspacetofittheobject.However,allobjectsinanapplicationarerarelydeallocatedinthesameordertheywereallocated,andevenmorerarelydotheyallhavethesamesizeinmemory.Thisleadstomemoryfragmentation.Memoryfragmentation
Fragmentationoccurswhenobjectsareallocatedanddeallocatedindifferentorders.Thisisbestexplainedthroughanexample.Thefollowingshowsfourstagesofmemoryallocationwithinatypicalheapmemoryspace:
Hereishowthememoryallocationtakesplace:
1. Westartwithanemptyheapspace(1).2. Wethenallocatefourobjectsontheheap,A,B,CandD,eachsizedat64bytes(2).3. Atsomelatertime,wedeallocatetwooftheobjectsAandC(3).4. Thistechnicallyfrees128bytesworthofspace,butsincetheobjectswerenot
contiguous(adjoiningneighbors)inmemory,wehavereallyonlydeallocatedtwoseparate64-byteregionsofmemory.If,atsomepointlater,wewishtoallocateanewobjectthatislargerthan64bytes(4),thenwecannotusethespacethatwaspreviouslyfreedbyobjectsAandC,sinceneitherisindividuallylargeenoughtofitthenewobject(objectsmustalwaysconsumecontiguousmemoryspaces).Therefore,thenewobjectmustbeallocatedinthenextavailable128contiguousbytesintheheapspace.
http://freepdf-books.com
Overtime,ourheapmemorywillbecomeriddledwithmoreandmore,smallerandsmalleremptyspacessuchasthese,asobjectsofdifferentsizesaredeallocated,andthenthesystemlatertriestoallocatenewobjectswithinthesmallestavailablespacethatitcanfitwithin.Thesmallertheseregionsbecome,thelessusabletheyarefornewmemoryallocations.Touseananalogy,thememoryspacebeginstoresembleSwisscheesewithmanysmallholesthatbecomeunusabletous.Intheabsenceofbackgroundtechniquesthatautomaticallycleanupthisfragmentation,thiseffectwouldoccurinliterallyanymemoryspace—RAM,heapspace,andevenharddrives—whicharejustlarger,slower,andmorepermanentmemorystorageareas(thisiswhyit’sagoodideatodefragmentourharddrivesfromtime-to-time!).
Memoryfragmentationcausestwoproblems.Firstly,iteffectivelyreducesthetotalusablememoryspacefornewobjectsoverlongperiodsoftime,dependingonthefrequencyofallocationsanddeallocations.Secondly,itmakesnewallocationstakelongertoresolve,duetotheextratimeittakestofindanewmemoryspacelargeenoughtofittheobject.
Thisbecomesimportantwhennewmemoryallocationsaremadeinaheap,sincewherethefreespacesarelocatedbecomesjustasimportantashowmuchfreespaceisavailable.Evenifwetechnicallyhave128bytesoffreespacetofitanewobject,ifitisnotcontiguousspace,thentheheapmusteithercontinuesearchinguntilitfindsalargeenoughspaceortheentireheapsizemustbeincreasedtofitthenewobject,byrequestinganewmemoryallocationfromtheOSinordertoexpandtheheapspace.Garbagecollectionatruntime
So,inaworstcasescenario,whenanewmemoryallocationisbeingrequestedbyourgame,theCPUwouldhavetospendcyclescompletingthefollowingtasksbeforetheallocationisfinallycompleted:
1. Verifyifthereisenoughcontiguousspaceforthenewobject.2. Ifnot,iteratethroughallknowndirectandindirectreferences,markingthemas
reachable.3. Iteratethroughtheentireheap,flaggingunmarkedobjectsfordeallocation.4. Verifyasecondtimeifthereisenoughcontiguousspaceforthenewobject.5. Ifnot,requestanewmemoryblockfromtheOS,inordertoexpandtheheap.6. Allocatethenewobjectatthefrontofthenewlyallocatedblock.
ThiscanbealotofworkfortheCPUtohandle,particularlyifthisnewmemoryallocationisanimportantgameobjectsuchasaparticleeffect,anewcharacterenteringthescene,acutscenetransition,andsoon.UsersarelikelytonotemomentswheretheGarbageCollectorisfreezinggameplaytohandlethesetasks.Tomakemattersworse,thegarbagecollectionworkloadscalesastheallocatedheapspacegrows,sincesweepingthroughafewmegabytesofspacewillbesignificantlyfasterthanscanningseveralgigabytesofspace.
Allofthismakesitabsolutelycriticaltocontrolourheapspaceintelligently.Thelazierourmemoryusagetacticsare,theworsetheGarbageCollectorwillbehaveinanalmostexponentialfashion.So,it’salittleironicthat,despitetheeffortsofmanagedlanguagesto
http://freepdf-books.com
solvethememorymanagementproblem,managedlanguagedeveloperscanstillfindthemselvesbeingjustas,ifnotmore,concernedwithmemoryconsumptionthandevelopersofnativeapplications!Threadedgarbagecollection
TheGarbageCollectorrunsontwoseparatethreads:theMainthreadandtheFinalizerthread.WhentheGarbageCollectorisinvoked,itwillrunontheMainthreadandflagheapmemoryblocksforfuturedeallocation.Thisdoesnothappenimmediately.TheFinalizerthread,controlledbyMono,canhaveadelayofseveralsecondsbeforethememoryisfinallyfreedandavailableforreallocation.
WecanobservethisbehaviorintheTotalAllocatedblock(thegreenlinewithapologiestothat5percentofthepopulationwithdeuteranopia/deuteranomaly)oftheMemoryAreawithintheProfiler.Itcantakeseveralsecondsforthetotalallocatedvaluetodropafteragarbagecollectionhasoccurred.Becauseofthedelay,weshouldnotrelyonmemorybeingavailablethemomentithasbeendeallocated,andassuch,weshouldneverwastetimetryingtoekeouteverylastbyteofmemorythatwebelieveshouldbeavailable.Wemustensurethatthereisalwayssomekindofbufferzoneavailableforfutureallocations.
BlocksthathavebeenfreedbytheGarbageCollectormaysometimesbegivenbacktotheOperatingSystemaftersometime,whichwouldreducethereservedspaceconsumedbytheheapandallowthememorytobeallocatedforsomethingelse,suchasanotherapplication.But,thisisveryunpredictableanddependsontheplatformbeingtargeted,soweshouldn’trelyonit.Theonlysafeassumptiontomakeisthat,assoonasthememoryhasbeenallocatedtoMono,it’sthenreservedandisnolongeravailabletoeithertheNativeDomainoranyotherapplicationrunningonthesamesystem.Garbagecollectiontactics
Onestrategytominimizegarbagecollectionproblemsisconcealment;manuallyinvoketheGarbageCollectoratopportunemoments,whentheplayermaynotnotice.Acollectioncanbeinvokedbysimplycallingthefollowingmethod:
System.GC.Collect();
Goodopportunitiestoinvokeacollectionmaybeduringlevelloading,whengameplayispaused,shortlyafteramenuinterfacehasbeenopened,inthemiddleofcutscenetransitions,orreallyanybreakingameplaythattheplayerwouldnotwitness,orcareaboutasuddenperformancedrop.WecouldevenusetheProfiler.GetMonoUsedSize()andProfiler.GetMonoHeapSize()methodsatruntimetodetermineifagarbagecollectionneedstobeinvokedinthenearfuture.
Wecanalsocausethedeallocationofahandfulofspecificobjects.IftheobjectinquestionisoneoftheUnityobjectwrappers,suchasaGameObjectorMonoBehaviourcomponent,thentheFinalizerwillfirstinvoketheDispose()methodwithintheNativeDomain.Atthispoint,thememoryconsumedbyboththeNativeandManagedDomainswillthenbefreed.Insomerareinstances,iftheMonowrapperimplementstheIDisposableinterface(thatis,ithasaDispose()methodavailablefromscriptcode),thenwecanactuallycontrolthisbehaviorandforcethememorytobefreedinstantly.
http://freepdf-books.com
Theonlyknownandusefulcaseofthis(thatthisauthoriscurrentlyawareof)istheWWWclass.ThisclassismostoftenusedtoconnecttoawebserveranddownloadAssetdataduringruntime.ThisclassneedstoallocateseveralbuffersintheNativeDomaininordertoaccomplishthistask.Itneedstomakeroomforthecompressedfile,adecompressionbuffer,andthefinaldecompressedfile.Ifwekeptallofthismemoryforalongtime,itwouldbeacolossalwasteofpreciousspace.So,bycallingitsDispose()methodfromscriptcode,wecanensurethatthememorybuffersarefreedpromptlyandpreciselywhentheyneedtobe.
AllotherAssetobjectsoffersomekindofunloadingmethodtocleanupanyunusedassetdata,suchasResources.UnloadUnusedAssets().ActualassetdataisstoredwithintheNativeDomain,sotheGarbageCollectortechnicallyisn’tinvolvedhere,buttheideaisbasicallythesame.ItwilliteratethroughallAssetsofaparticulartype,checkifthey’renolongerbeingreferenced,and,ifso,deallocatethem.But,again,thisisanasynchronousprocessandwecannotguaranteewhendeallocationwilloccur.ThismethodisautomaticallycalledinternallyafteraSceneisloaded,butthisstilldoesn’tguaranteeinstantdeallocation.
Attheveryleast,Resources.UnloadAsset()(thatis,unloadingonespecificAssetatatime)isthepreferredwaytocleanupAssetdata,sincetimewillnotbespentiteratingthroughtheentirecollection.However,it’sworthnotingthattheseunloadingmethodswereupgradedtobemultithreadedinUnity5,whichimprovestheperformancecostofcleaningupAssetdatarathersignificantlyonmostplatforms.
However,thebeststrategyforgarbagecollectionwillalwaysbeavoidance;ifweallocateaslittleheapmemoryandcontrolitsusageasmuchaspossible,thenwewon’thavetoworryabouttheGarbageCollectorinflictingperformancecostsasfrequentlyorashard.Youwilllearnmanytacticsforthisduringtheremainderofthechapter,butyoushouldfirstcoversometheoryonhowandwherememoryisallocated.
http://freepdf-books.com
ValuetypesandReferencetypesNotallmemoryallocationswemakewithinMonowillgothroughtheheap.The.NETFramework(andbyextensiontheC#language,whichmerelyimplementsthe.NETspecification)hastheconceptofValuetypesandReferencetypes,andonlythelatterofwhichneedstobemarkedbytheGarbageCollectorwhileitisperformingitsMark-and-Sweepalgorithm.Referencetypesareexpectedto(orneedto)lastalongtimeinmemoryeitherduetotheircomplexity,theirsize,orhowthey’reused.Largedatasets,andanykindofobjectinstantiatedfromaclass,isaReferencetype.Thisalsoincludesarrays(whetheritisofValuetypesorReferencetypes),delegates,allclasses,suchasMonoBehaviour,GameObject,andanycustomclasseswedefine.
Valuetypesarenormallyallocatedonthestack.Primitivedatatypessuchasbools,ints,andfloatsareexamplesofValuetypes,butonlyifthey’restandaloneandnotamemberofaReferencetype.AssoonasaprimitivedatatypesiscontainedwithinaReferencetype,suchasaclassoranarray,thenitisimpliedthatitiseithertoolargeforthestackorwillneedtosurvivelongerthanthecurrentscopeandmustbeallocatedontheheapinstead.
Allofthiscanbebestexplainedthroughexamples.ThefollowingcodewillcreateanintegerasaValuetypethatexistsonthestackonlytemporarily:
publicclassTestComponent:MonoBehaviour{
voidStart(){
intdata=5;//allocatedonthestack
DoSomething(data);
}//integerisdeallocatedfromthestackhere
}
AssoonastheStart()methodends,thentheintegerisdeallocatedfromthestack.Thisisessentiallyafreeoperationsince,asmentionedpreviously,itdoesn’tbotherdoinganycleanup;itjustmovesthestackpointerbacktothepreviousmemorylocationinthecallstack.Anyfuturestackallocationssimplyoverwritetheolddata.Mostimportantly,noheapallocationtookplacetocreatethedata,andso,theGarbageCollectorwouldbecompletelyunawareofitsexistence.
But,ifwecreatedanintegerasamembervariableoftheMonoBehaviourclassdefinition,thenitisnowcontainedwithinaReferencetype(aclass)andmustbeallocatedontheheapalongwithitscontainer:
publicclassTestComponent:MonoBehaviour{
privateint_data=5;
voidStart(){
DoSomething(_data);
}
}
Similarly,ifweputtheintegerintoanindependentclass,thentherulesforReferencetypesstillapply,andtheobjectisallocatedontheheap:
http://freepdf-books.com
publicclassTestData{
publicintdata=5;
}
publicclassTestComponent:MonoBehaviour{
voidStart(){
TestDatadataObj=newTestData();//allocatedontheheap
DoSomething(dataObj.data);
}//'dataObj'isnotdeallocatedhere,butitwillbecomeacandidate
duringthenextgarbagecollection
}
So,thereisabigdifferencebetweentemporarilyallocatingmemorywithinaclassmethodandstoringlong-termdatainaclass’memberdata.Inbothcases,we’reusingaReferencetype(aclass)tostorethedata,whichmeansitcanbereferencedelsewhere.Forexample,imagineDoSomething()storedthereferencetodataObjwithinamembervariable:
privateTestData_testDataObj;
voidDoSomething(TestDatadataObj){
_testDataObj=dataObj;//anewreferencecreated!Thereferenced
objectwillnowbemarkedduringmark-and-sweep
}
Inthiscase,wewouldnotbeabletodeallocatetheobjectpointedtodataObjassoonastheStart()methodendedbecausethetotalnumberofthingsreferencingtheobjectwouldgofrom2to1.Thisisnot0,andhencetheGarbageCollectorwouldstillmarkitduringmark-and-sweep.Wewillalsoneedtoset_testDataObjtonull,ormakeitreferencesomethingelse,beforetheobjectwasnolongerreachable.
NotethataValuetypemusthaveavalue,andcanneverbenull.Ifastack-allocatedValuetypeisassignedtoaReferencetype,thenthedataissimplycopied.ThisistrueevenforarraysoftheValuetypes:
publicclassTestClass{
privateint[]_intArray=newint[1000];//Referencetypefullof
Valuetypes
voidStoreANumber(intnum){
_intArray[0]=num;//storeaValuewithinthearray
}
}
Whentheinitialarrayiscreated(duringobjectinitialization),1,000integerswillbeallocatedontheheapsettoavalueof0.WhentheStoreANumber()methodiscalled,thevalueofnumismerelycopiedintothezerothelementofthearray,ratherthanstoringareferencetoit.
ThesubtlechangeinthereferencingcapabilityiswhatultimatelydecideswhethersomethingisaReferencetypeoraValuetype,andweshouldtrytousestandaloneValuetypeswheneverwehavetheopportunity,sothattheygeneratestackallocationsinsteadofheapallocations.Anysituationwherewe’rejustsendingaroundapieceofdatathatdoesn’tneedtolivelongerthanthecurrentscopeisagoodopportunitytouseaValuetypeinsteadofaReferencetype.Ostensibly,itdoesnotmatterifwepassthedataintoanother
http://freepdf-books.com
methodofthesameclassoramethodofanotherclass;itstillremainsaValuetypethatwillexistonthestackuntilthemethodthatcreateditgoesoutofthescope.
PassbyvalueandpassbyreferenceTechnically,somethingisduplicatedeverytimeadatavalueispassedasanargumentfromonemethodtoanother,andthisistruewhetheritisaValuetypeoraReferencetype.Thisisknownaspassingbyvalue.ThemaindifferenceisthataReferencetypeismerelyapointerwhichconsumesonly4or8bytesinmemory(32-bitor64-bit,dependingonthearchitecture)regardlessofwhatitisactuallypointingto.WhenaReferencetypeispassedasanargumentitisactuallythevalueofthispointerthatgetscopied,whichisveryquicksincethedataisverysmall.
Meanwhile,aValuetypecontainsthefullandcompletebitsofdatastoredwithintheobject.Hence,allofthedataofaValuetypegetscopiedwhenevertheyarepassedbetweenmethods,orstoredinotherValuetypes.Insomecases,itcanmeanthatpassingalargeValuetypeasargumentsaroundtoomuchcanbemorecostlythanjustusingaReferencetype.FormostValuetypes,thisisnotaproblem,sincetheyarecomparableinsizetoapointer.Butthisbecomesimportantwhenwebegintotalkaboutstructs,inthenextsection.
Datacanbepassedaroundbyreferenceaswell,byusingtherefkeyword,butthisisverydifferentfromtheconceptofValueandReferencetypes,anditisveryimportanttokeepthemdistinctinourmindwhenwetrytounderstandwhatisgoingonunderthehood.WecanpassaValuetypebyvalue,orbyreference,andwecanpassaReferencetypebyvalue,orbyreference.Thismeansthattherearefourdistinctdatapassingsituationsthatcanoccurdependingonwhichtypeisbeingpassedandwhethertherefkeywordisbeingusedornot.
Whendataispassedbyreference(evenifitisaValuetype!)thenmakinganychangestothedatawillchangetheoriginal.Forexample,thefollowingcodewouldprintthevalue10:
voidStart(){
intmyInt=5;
DoSomething(refmyInt);
Debug.Log(String.Format("Value={0}",myInt));
}
voidDoSomething(refintval){
val=10;
}
Removingtherefkeywordfrombothplaceswouldmakeitprintthevalue5instead.Thisunderstandingwillcomeinhandywhenwestarttothinkaboutsomeofthemoreinterestingdatatypeswehaveaccessto.Namely,structs,arrays,andstrings.
StructsareValuetypesStructsareaninterestingspecialcaseinC#.IfwecomefromaC++backgroundtoC#,thenwewouldprobablyassumethattheonlydifferencebetweenastructandaclassis
http://freepdf-books.com
thatastructhasadefaultaccessspecifier,public,whileaclassdefaultstoprivate.However,inC#,structsaresimilartoclassesinthattheycancontainotherprivate/protected/publicdata,havemethods,canbeinstantiatedatruntime,andsoon.ThecoredifferencebetweenthetwoisthatstructsareValuetypesandclassesareReferencetypes.
TherearesomeotherimportantdifferencesbetweenhowstructsandclassesaretreatedinC#;structsdon’tsupportinheritance,theirpropertiescannotbegivencustomdefaultvalues(memberdataalwaysdefaultstovaluessuchas0ornull,sinceitisaValuetype),andtheirdefaultconstructorscannotbeoverridden.Thisgreatlyrestrictstheirusagecomparedtoclasses,sosimplyreplacingallclasseswithstructs(undertheassumptionthatitwilljustallocateeverythingonthestack)isnotawisecourseofaction.
However,ifwe’reusingaclassinasituationwhoseonlypurposeistosendablobofdatatosomewhereelseinourapplication,anditdoesnotneedtolastbeyondthecurrentscope,thenweshoulduseastructinstead,sinceaclasswouldresultinaheapallocationfornoparticularlygoodreason:
publicclassDamageResult{
publicCharacterattacker;
publicCharacterdefender;
publicinttotalDamageDealt;
publicDamageTypedamageType;
publicintdamageBlocked;
//etc
}
publicvoidDealDamage(Character_target){
DamageResultresult=CombatSystem.Instance.CalculateDamage(this,
_target);
CreateFloatingDamageText(result);
}
Inthisexample,we’reusingaclasstopassabunchofdatafromonesubsystem(thecombatsystem)toanother(theUIsystem).Theonlypurposeofthisdataistobecalculatedandreadbyvarioussubsystems,sothisisagoodcandidatetoconvertintoastruct.
MerelychangingtheDamageResultdefinitionfromaclasstoastructcouldsaveusquiteafewunnecessarygarbagecollections,sinceitwouldbeallocatedonthestack.
publicstructDamageResult{
//...
}
Thisisnotacatch-allsolution.SincestructsareValuetypes,thismeanssomethingratheruniquewhenitispassedasanargumentbetweenmethods.Aswepreviouslylearned,everytimeaValuetypeispassedasanargumentbetweenonefunctionandanother,itwillbeduplicatedsinceitispassedbyvalue.ThiscreatesaduplicateValuetypeforthenextmethodtouse,whichwillbedeallocatedassoonasthatmethodgoesoutofscope,andsooneachtimeitispassedaround.So,ifastructispassedbyvaluebetweenfivedifferent
http://freepdf-books.com
methodsinalongchain,thenfivedifferentstackcopieswilloccuratthesametime.Recallthatstackdeallocationsarefree,butdatacopyingisnot.
Thecopyingisprettymuchnegligibleforsmallvalues,suchasasingleintegerorfloat,butpassingaroundridiculouslylargedatasetsthroughstructsoverandoveragainisobviouslynotatrivialtaskandshouldbeavoided.Insuchcases,itwouldbewisertopassthestructbyreferenceusingtherefkeywordtominimizetheamountofdatabeingcopiedeachtime(justa32-bitor64-bitintegerforthememoryreference).However,thiscanbedangeroussincepassingbyreferenceallowsanysubsequentmethodstomakechangestothestruct,inwhichcaseitwouldbeprudenttomakeitsdatavaluesreadonly(itcanonlybeinitializedintheconstructor,andneveragain,evenbyitsownmemberfunctions)topreventlaterchanges.
AlloftheaboveisalsotruewhenstructsarecontainedwithinReferencetypes:
publicstructDataStruct{
publicintval;
}
publicclassStructHolder{
publicDataStruct_memberStruct;
publicvoidStoreStruct(DataStructds){
_memberStruct=ds;
}
}
Totheuntrainedeye,theprecedingcodeappearstobeattemptingtostoreastack-allocatedstructwithinaReferencetype.DoesthismeanthataStructHolderobjectontheheapcannowreferenceanobjectonthestack?WhatwillhappenwhentheStoreStruct()methodgoesoutofscopeandthestructiserased?Itturnsoutthatthesearethewrongquestions.
What’sactuallyhappeningisthat,whileaDataStructobject(_memberStruct)hasbeenallocatedontheheapwithintheStructHolderobject,itisstillaValuetypeanddoesnotmagicallytransformintoaReferencetype.So,alloftheusualrulesforValuetypesapply.The_memberStructvariablecannothaveavalueofnullandallofitsfieldswillbeinitializedto0ornullvalues.WhenStoreStruct()iscalled,thedatafromdswillbecopiedinto_memberStruct.Therearenoreferencestostackobjectstakingplace,andthereisnoconcernaboutlostdata.
ArraysareReferencetypesArrayscanpotentiallycontainahugeamountofdatawithinthem,whichmakethemdifficulttotreatasaValuetypesincethere’sprobablynotenoughroomonthestacktosupportthem.Therefore,theyaretreatedasaReferencetypesothattheentiredatasetcanbepassedaroundviaasinglereference,insteadofduplicatingtheentirearrayeverytimeitispassedaround.ThisistrueirrespectiveofwhetherthearraycontainsValuetypesorReferencetypes.
Thismeansthatthefollowingcodewillresultinaheapallocation:
TestStruct[]dataObj=newTestStruct[1000];
http://freepdf-books.com
for(inti=0;i<1000;++i){
dataObj[i].data=i;
DoSomething(dataObj[i]);
}
Thefollowing,functionallyequivalentcode,wouldnotresultinanyheapallocations,sincethestructsareValuetypes,andhencewouldbecreatedonthestack:
for(inti=0;i<1000;++i){
TestStructdataObj=newTestStruct();
dataObj.data=i;
DoSomething(dataObj);
}
Thesubtledifferenceinthesecondcode-blockisthatonlyoneTestStructexistsonthestackatatime(atleastforthisfunctionDoSomething()canpotentiallycreatemore),whereasthefirstblockneedstoallocate1,000ofthemviaanarray.Obviously,thesemethodsarekindofridiculousasthey’rewritten,buttheyillustrateanimportantpointtoconsider.Thecompilerisn’tsmartenoughtoautomaticallyfindthesesituationsforusandmaketheappropriatechanges.OpportunitiestooptimizeourmemoryusagethroughValuetypereplacementswillbeentirelydowntoourabilitytodetectthem,andunderstandwhyachangewillresultinstackallocations,ratherthanheapallocations.
Notethat,whenweallocateanarrayofReferencetypes,we’recreatinganarrayofreferences,whichcaneachreferenceotherlocationsontheheap.However,whenweallocateanarrayofValuetypes,we’recreatingapackedlistofValuetypesontheheap.EachoftheseValuetypeswillbeinitializedwithavalueof0(orequivalent),sincetheycannotbenull,whileeachreferencewithinanarrayofReferencetypeswillalwaysinitializetonull,sincenoreferenceshavebeenassigned,yet.
StringsareimmutableReferencetypesWebrieflytoucheduponthesubjectofstringsbackinChapter2,ScriptingStrategies,butnowit’stimetogointomoredetailaboutwhyproperstringusageisextremelyimportant.
Becausestringsareessentiallyarraysofcharacters(chars),theyareReferencetypes,andfollowallofthesamerulesasotherReferencetypes;thevaluethatisactuallycopiedandpassedbetweenfunctionsismerelyapointer,andtheywillbeallocatedontheheap.
Theconfusingpartreallybeginswhenwediscoverthatstringsareimmutable,meaningtheycannotbechangedafterthey’vebeenallocated.Beinganarrayimpliesthattheentirelistofcharactersmustbecontiguousinmemory,whichcannotbetrueifweallowedstringstoexpandorcontractat-willwithinadynamicmemoryspace(howcouldwequicklyandsafelyexpandthestringifwe’veallocatedsomethingelseimmediatelyafterit?).
Thismeansthat,ifastringismodified,thenanewstringmustbeallocatedtoreplaceit,wherethecontentsoftheoriginalwillbecopiedandmodifiedas-neededintoawholenewcharacterarray.Inwhichcase,theoldversionwillnolongerbereferencedanywhere,willnotbemarkedduringmark-and-sweepandwillthereforeeventuallybegarbage-collected.Asaresult,lazystringprogrammingcanresultinalotofunnecessaryheapallocations
http://freepdf-books.com
andgarbagecollection.
Forexample,ifwebelievedthatstringsworkedjustlikeotherReferencetypes,wemightbeforgivenforassumingthelogoutputofthefollowingtobeWorld!:
voidStart(){
stringtestString="Hello";
DoSomething(testString);
Debug.Log(testString);
}
voidDoSomething(stringlocalString){
localString="World!";
}
However,thisisnotthecase,anditwillstillprintoutHello.WhatisactuallyhappeningisthatthelocalStringvariable,withinthescopeofDoSomething(),startsoffreferencingthesameplaceinmemoryastestString,duetothereferencebeingpassedbyvalue.ThisgivesustworeferencespointingtothesamelocationinmemoryaswewouldexpectifweweredealingwithanyotherReferencetype.Sofar,sogood.
But,assoonaswechangethevalueoflocalString,werunintoalittlebitofaconflict.Stringsareimmutable,andwecannotchangethem,sothereforewemustallocateanewstringcontainingthevalueWorld!andassignitsreferencetothevalueoflocalString;nowthenumberofreferencestotheHellostringreturnsbacktoone.Theoriginalstring(Hello)willremaininmemorybecausethevalueoftestStringhasnotbeenchanged,andthatisstillthevaluewhichwillbeprintedbyDebug.Log().Allwe’vesucceededindoingbycallingDoSomething()iscreatinganewstringontheheapwhichgetsgarbage-collected,anddoesn’tchangeanything.Thisisthetextbookdefinitionofwasteful.
IfwechangethemethoddefinitionofDoSomething()topassthestringbyreference,viatherefkeyword,theoutputwouldindeedchangetoWorld!.ThisiswhatwewouldexpecttohappenwithaValuetype,whichleadsalotofdeveloperstoincorrectlyassumethatstringsareValuetypes.But,thisisanexampleofthefourthandfinaldata-passingcasewhereaReferencetypeisbeingpassedbyreference,whichallowsustochangewhattheoriginalreferenceisreferencing!
NoteSo,torecap;ifwepassaValuetypebyvalue,wecanonlychangethevalueofthecopy.IfwepassaValuetypebyreference,wecanchangetheactualvalueattributedtotheoriginalversion.IfwepassaReferencetypebyvalue,wecanmakechangestotheobjectthattheoriginalreferenceisreferencing.Andfinally,ifwepassaReferencetypebyreference,wecanchangewhichobjecttheoriginalreferenceisreferencing.
Stringconcatenation
Concatenationistheactofappendingstringstooneanothertoformalargerstring.Aswe’velearned,anysuchcasesarelikelytoresultinexcessheapallocations.Thebiggestoffenderinstring-basedmemorywasteisconcatenatingstringsusingthe+and+=operators,becauseoftheallocationchainingeffecttheycause.
http://freepdf-books.com
Forexample,thefollowingcodetriestocombineagroupofstringstogethertoprintsomeinformationaboutacombatresult:
voidCreateFloatingDamageText(DamageResultresult){
stringoutputText=result.attacker.GetCharacterName()+"dealt"+
result.totalDamageDealt.ToString()+""+result.damageType.ToString()+"
damageto"+result.defender.GetCharacterName()+"("+
result.damageBlocked.ToString()+"blocked)";
//...
}
Anexampleoutputofthisfunctionmightbeastringthatreads:
Dwarfdealt15SlashingdamagetoOrc(3blocked)
Thisfunctionfeaturesahandfulofstringliterals(hard-codedstringsthatareallocatedduringapplicationinitialization)suchasdealt,damageto,andblocked.But,becauseoftheusageofvariableswithinthiscombinedstring,itcannotbecompiledawayatbuildtime,andthereforemustbegenerateddynamicallyatruntime.
Anewheapallocationwillbegeneratedeachtimea+,or+=,operatorisexecuted;onlyasinglepairofstringswillbemergedatatime,anditallocatesanewstringeachtime.Then,theresultofonemergerwillbefedintothenext,andmergedwithanotherstring,andsoonuntiltheentirestringhasbeenbuilt.
So,thepreviousexamplewillresultin9differentstringsbeingallocatedallinonego.Allofthefollowingstringswouldbeallocatedtosatisfythisinstruction,andallwouldeventuallyneedtobegarbagecollected(notethattheoperatorsareresolvedfromright-to-left):
"3blocked)"
"(3blocked)"
"Orc(3blocked)"
"damagetoOrc(3blocked)"
"SlashingdamagetoOrc(3blocked)"
"SlashingdamagetoOrc(3blocked)"
"15SlashingdamagetoOrc(3blocked)"
"dealt15SlashingdamagetoOrc(3blocked)"
"Dwarfdealt15SlashingdamagetoOrc(3blocked)"
That’s262charactersbeingused,insteadof49;orbecauseacharisa2-bytedatatype,that’s524bytesofdatabeingallocatedwhenweonlyneed98bytes.Chancesarethat,ifthiscodeexistsinthecodebaseonce,thenitexistsallovertheplace,soforanapplicationthat’sdoingalotoflazystringconcatenationlikethis,thatisatonofmemorybeingwastedongeneratingunnecessarystrings.
TipNotethatbig,constantstringliteralscanbesafelycombinedusingthe+and+=operatorstomakethemmorereadablewithinthecodebase,butonlyiftheywillresultinaconstantstring.Ifso,thecompilerwilltakecareofmergingallofthestringliteralstogetheratcompiletime.
http://freepdf-books.com
BetterapproachesforgeneratingstringsaretouseeithertheStringBuilderclass,oroneofseveralstringclassmethods.
TheStringBuilderclassiseffectivelyamutable(changeable)stringclass.Itworksbyallocatingabuffertocopythetargetstringsintoandallocatesadditionalspacewheneveritisneeded.WecanretrievethestringusingtheToString()methodwhich,naturally,resultsinamemoryallocationfortheresultantstring,butatleastweavoidedalloftheunnecessarystringallocationswewouldhavegeneratedusingthe+or+=operators.
Conventionalwisdomsaysthatifweroughlyknowthefinalsizeoftheresultantstring,thenwecanallocateanappropriatebufferaheadoftimeandsaveourselvesundueallocations.Forourexampleabove,wemightallocateabufferof100characterstomakeroomforlongcharacternamesanddamagevalues:
usingSystem.Text;
//...
StringBuildersb=newStringBuilder(100);
sb.Append(result.attacker.GetCharacterName());
sb.Append("dealt");
sb.Append(result.totalDamageDealt.ToString());
//etc…
stringresult=sb.ToString();
Ifwedon’tknowthefinalsize,thenusingaStringBuilderclassislikelytogenerateabufferthatdoesn’tfitthesizeexactly,orclosely.Wewilleitherendupwithabufferthat’stoolarge(wastedallocationtimeandspace),or,worse,abufferthat’stoosmall,whichmustkeepexpandingaswegeneratethecompletestring.Ifwe’reunsureaboutthetotalsizeofthestring,thenitmightbebesttouseoneofthevariousstringclassmethods.
Therearethreestringclassmethodsavailableforgeneratingstrings;Format(),Join(),andConcat().Eachoperatesslightlydifferently,buttheoveralloutputisthesame;anewstringisallocatedcontainingthecontentsofthestring(s)wepassintothem,anditisalldoneinasingleactionwhichreducesexcessstringallocations.
Itissurprisinglyhardtosaywhichoneofthetwoapproacheswouldbemorebeneficialinagivensituationastherearealotofreallydeepnuancesinvolved.There’salotofdiscussionsurroundingthetopic(justdoaGooglesearchfor"csharpstringconcatenationperformance"andyou’llseewhatImean),sothebestapproachistoimplementoneortheotherusingtheconventionalwisdomdescribedpreviously.Wheneverwerunintobadperformancewithonemethod,weshouldtrytheother,profilethemboth,andpickthebestoptionofthetwo.
BoxingTechnically,everythinginC#isanobject(caveatsapply).Evenprimitivedatatypessuchasints,floats,andboolsarederivedfromSystem.Objectattheirlowestlevel(aReferenceType!),whichallowsthemaccesstohelpermethodssuchasToString(),sothattheycancustomizetheirstringrepresentation.
ButtheseprimitivetypesaretreatedasspecialcasesviabeingtreatedasValuetypes.WheneveraValuetypeisimplicitlytreatedinsuchawaythatitmustactlikeanobject,
http://freepdf-books.com
theCLRautomaticallycreatesatemporaryobjecttostore,or“box”,thevalueinsidesothatitcanbetreatedasatypicalReferencetypeobject.Asweshouldexpect,thisresultsinaheapallocationtocreatethecontainingvessel.
TipNotethatboxingisnotthesamethingasusingValuetypesasmembervariablesofReferencetypes.ItonlytakesplacewhenValuetypesaretreatedlikeobjectsthemselves.
Forexample,thefollowingcodewouldcausethevariableitobeboxedinsideobjectobj:
inti=128;
objectobj=i;
Thefollowingwouldusetheobjectrepresentationobjtoreplacethevaluestoredwithintheinteger,and“unbox”itbackintoaninteger,storingitini.Thefinalvalueofiwouldbe256:
obj=256;
i=(int)obj;
Thesetypescantechnicallybechangeddynamically.ThefollowingisperfectlylegalC#code,whichusesthesameobjectobjasabove,whichwasoriginallyboxedfromanint:
obj=512f;
floatf=(float)obj;
Thefollowingisalsolegal:
obj=false;
boolb=(bool)obj;
Notethatattemptingtounboxobjintoatypethatisn’tthemostrecentlyassignedtypewouldresultinanInvalidCastException.Allofthiscanbealittletrickytowrapourheadarounduntilwerememberthat,attheendoftheday,everythingisjustbitsinmemory.What’simportantisknowingthatwecantreatourprimitivetypesasobjectsbyboxingthem,convertingtheirtypes,andthenunboxingthemintoadifferenttypeatalatertime.
NoteNotethatit’spossibletoconvertaboxedobject’stypeusingoneofthemanySystem.Convert.To…()methods.
Boxingcanbeeitherimplicit,aspertheexamplesabove,orexplicit,bytypecastingtoSystem.Object.Unboxingmustalwaysbeexplicitbytypecastingbacktoitsoriginaltype.WheneverwepassaValuetypeintoamethodwhichusesSystem.Objectasarguments,boxingwillbeappliedimplicitly.
MethodssuchasString.Format(),whichtakeSystem.Objectsasarguments,areonesuchexample.WetypicallyusethembypassinginValuetypessuchasints,floats,boolsandsoon,togenerateastringwith.Boxingisautomaticallytakingplaceinthesesituations,causingadditionalheapallocationswhichweshouldbeawareof.
http://freepdf-books.com
Collections.Generic.ArrayListisanothersuchexample,sinceArrayListsalwayscontainSystem.Objectreferences.
AnytimeweuseafunctiondefinitionthattakesSystem.Objectasarguments,andwe’repassinginValuetypes,weshouldbeawarethatwe’reimplicitlycausingheapallocationsduetoboxing.
http://freepdf-books.com
TheimportanceofdatalayoutTheimportanceofhowourdataisorganizedinmemorycanbesurprisinglyeasytoforgetabout,butcanresultinafairlybigperformanceboostifitishandledproperly.Cachemissesshouldbeavoidedwheneverpossible,whichmeansthatinmostcases,arraysofdatathatarecontiguousinmemoryshouldbeiteratedoversequentially,asopposedtoanyotheriterationstyle.
Thismeansthatdatalayoutisalsoimportantforgarbagecollection,sinceitisdoneinaniterativefashion,andifwecanfindwaystohavetheGarbageCollectorskipoverproblematicareas,thenwecanpotentiallysavealotofiterationtime.
Inessence,wewanttokeeplargegroupsofReferencetypesseparatedfromlargegroupsofValuetypes.IfthereisevenjustoneReferencetypewithinaValuetype,suchasastruct,thentheGarbageCollectorconsiderstheentireobject,andallofitsdatamembers,indirectlyreferenceableobjects.Whenitcomestimetomark-and-sweep,itmustverifyallfieldsoftheobjectbeforemovingon.But,ifweseparatethevarioustypesintodifferentarrays,thenwecanmaketheGarbageCollectorskipthemajorityofthedata.
Forinstance,ifwehaveanarrayofstructscontainingdatalikeso,thentheGarbageCollectorwillneedtoiterateovereverymemberofeverystruct,whichcouldbefairlytimeconsuming:
publicstructMyStruct{
intmyInt;
floatmyFloat;
boolmyBool;
stringmyString;
}
MyStruct[]arrayOfStructs=newMyStruct[1000];
But,ifwereplaceallofthisdatawithsimplearrays,thentheGarbageCollectorwillignorealloftheprimitivedatatypes,andonlycheckthestrings.Thiswouldresultinmuchafastergarbagecollectionsweep:
int[]myInts=newint[1000];
float[]myFloats=newfloat[1000];
bool[]myBools=newbool[1000];
string[]myStrings=newstring[1000];
Thereasonthisworksisbecausewe’regivingtheGarbageCollectorfewerindirectreferencestocheck.Whenthedataissplitintoseparatearrays(Referencetypes),itfindsthreearraysofValuetypes,marksthearrays,andthenimmediatelymovesonbecausethere’snoreasontomarkValuetypes.Itmuststilliteratethroughallofthestringswithinthestringarray,sinceeachisaReferencetypeanditneedstoverifythattherearenoindirectreferenceswithinit.Technically,stringscannotcontainindirectreferences,buttheGarbageCollectorworksatalevelwhereitonlyknowsiftheobjectisaReferencetypeorValuetype.However,wehavestillsparedtheGarbageCollectorfromneedingtoiterateoveranextra3,000piecesofdata(all1,000ints,floats,andbools).
http://freepdf-books.com
TheUnityAPIThereareseveralinstructionswithintheUnityAPIwhichresultinheapmemoryallocations,whichweshouldbeawareof.Thisessentiallyincludeseverythingthatreturnsanarrayofdata.Forexample,thefollowingmethodsallocatememoryontheheap:
GetComponents<T>();//(T[])
Mesh.vertices;//(Vector3[])
Camera.allCameras;//(Camera[])
Suchmethodsshouldbeavoidedwheneverpossible,orattheveryleastcalledonceandcachedsothatwedon’tcausememoryallocationsmoreoftenthannecessary.
NotethatUnityTechnologieshashinteditmightcomeoutwithallocation-lessversionsofthesemethodssometimeinthelifecycleofUnity5.Presumably,itmightlooksomethinglikethewayParticleSystemsallowsaccesstoParticledata,whichinvolvesprovidingaParticle[]arrayreferencetopointtotherequireddata.Thisavoidsallocationsincewereusethesamebufferbetweencalls.
http://freepdf-books.com
TheforeachloopsTheforeachloopkeywordisabitofacontroversialissueinUnitydevelopmentcircles.ItturnsoutthatalotofforeachloopsimplementedinUnityC#codewillincurunnecessaryheapmemoryallocationsduringthesecalls,astheyallocateanEnumeratorobjectasaclassontheheap,insteadofastructonthestack.Italldependsonthegivencollection’simplementationoftheGetEnumerator()method.
ItturnsoutthateverysinglecollectionthathasbeenimplementedintheversionofMonothatcomeswithUnity(Monoversion2.6.5)willcreateclassesinsteadofstructs,whichresultsinheapallocations.Thisincludes,butisnotlimitedto,List<T>,LinkedList<T>,Dictionary<K,V>,ArrayList,andsoon.But,notethatitisactuallysafetouseforeachloopsontypicalarrays!TheMonocompilersecretlyconvertsforeachoverarraysintosimpleforloops.
Thecostisfairlynegligibleastheheapallocationcostdoesnotscalewiththenumberofiterations.OnlyoneEnumeratorobjectisallocated,andreusedoverandoveragain,whichonlycostsahandfulofbytesofmemoryoverall.Sounlessourforeachloopsarebeinginvokedeveryupdate(whichistypicallydangerousinandofitself)thenthecostswillbemostlynegligibleonsmallprojects.Thetimetakentoconverteverythingtoaforloopmaynotbeworththetime.Butit’sdefinitelysomethingtokeepinmindforthenextprojectwebegintowrite.
Ifwe’reparticularlysavvywithC#,VisualStudio,andmanualcompilationoftheMonoassembly,thenwecanhaveVisualStudioperformcodecompilationforus,andcopytheresultingassemblyDLLintotheAssetsfolder,whichwillfixthismistakeforthegenericcollections.
NotethatperformingforeachoveraTransformComponentisatypicalshortcuttoiteratingoveraTransform’schildren.Forexample:
foreach(Transformchildintransform){
//dostuffwith'child'
}
However,thisresultsinthesameheapallocationsmentionedabove.Asaresult,thatcodingstyleshouldbeavoidedinfavorofthefollowing:
for(inti=0;i<transform.childCount;++i){
Transformchild=transform.GetChild(i);
//dostuffwith'child'
}
http://freepdf-books.com
CoroutinesStartingaCoroutinecostsasmallamountofmemorytobeginwith,butnotethatnofurthercostsareincurredwhenthemethodyields.Ifmemoryconsumptionandgarbagecollectionaresignificantconcerns,weshouldtrytoavoidhavingtoomanyshort-livedCoroutines,andavoidcallingStartCoroutine()toomuchduringruntime.
http://freepdf-books.com
ClosuresClosuresareuseful,butdangeroustools.AnonymousmethodsandlambdaexpressionsarenotalwaysClosures,buttheycanbe.Italldependsonwhetherthemethodusesdataoutsideofitsownscopeandparameterlist,ornot.
Forexample,thefollowinganonymousfunctionwouldnotbeaClosure,sinceitisself-containedandfunctionallyequivalenttoanyotherlocallydefinedfunction:
System.Func<int,int>anon=(x)=>{returnx;};
intresult=anon(5);
But,iftheanonymousfunctionpulledindatafromoutsideitself,thenitbecomesaClosure,asit“closestheenvironment”aroundtherequireddata.ThefollowingwouldresultinaClosure:
inti=1024;
System.Func<int,int>anon=(x)=>{returnx+i;};
intresult=anon(5);
Inordertocompletethistransaction,thecompilermustdefineanewclassthatcanreferencetheenvironmentwherethedatavalueiwouldbeaccessible.Atruntimeitcreatesthecorrespondingobjectontheheapandprovidesittotheanonymousfunction.NotethatthisincludesValuetypes(aspertheaboveexample),whichwereoriginallyonthestack,possiblydefeatingthepurposeofthembeingallocatedonthestackinthefirstplace.So,weshouldexpecteachinvocationofthesecondmethodtoresultinheapallocationsandinevitablegarbagecollection.
http://freepdf-books.com
.NETlibraryfunctionsThe.NETlibraryoffersahugeamountofcommonfunctionalitythathelpssolvenumerousproblemsthatprogrammersmaycomeacrossduringday-to-dayimplementation.Mostoftheseclassesandfunctionsareoptimizedforgeneralusecases,whichmaynotbeoptimalforaspecificsituation.Itmaybepossibletoreplaceaparticular.NETlibraryclasswithacustomimplementationthatismoresuitedtoourspecificusecase.
Therearealsotwobigfeaturesinthe.NETlibrarythatoftenbecomebigperformancehogswheneverthey’reused.Thistendstobebecausetheyareonlyincludedasaquick-and-hackysolutiontoagivenproblemwithoutmucheffortputintooptimization.ThesefeaturesareLINQandRegularExpressions.
LINQprovidesawaytotreatarraysofdataasminiaturedatabasesandperformqueriesagainstthemusingSQL-likesyntax.Thesimplicityofitscodingstyle,andcomplexityoftheunderlyingsystem(throughitsusageofClosures),impliesthatithasafairlylargeoverheadcost.LINQisahandytool,butisnotreallyintendedforhigh-performance,real-timeapplicationssuchasgames,anddoesnotevenfunctiononplatformsthatdonotsupportJITcompilation,suchasiOS.
Meanwhile,RegularExpressions,usingtheRegexclass,allowustoperformcomplexstringparsingtofindsubstringsthatmatchaparticularformat,replacepiecesofastring,orconstructstringsfromvariousinputs.RegularExpressionisanotherveryusefultool,buttendstobeoverusedinplaceswhereitislargelyunnecessary,orinseemingly“clever”waystoimplementafeaturesuchastextlocalization,whenstraightforwardstringreplacementwouldbefarmoreefficient.
Specificoptimizationsforbothofthesefeaturesgofarbeyondthescopeofthisbook,astheycouldfillentirevolumesbythemselves.Weshouldeithertrytominimizetheirusageasmuchaspossible,replacetheirusagewithsomethinglesscostly,bringinaLINQorRegexexperttosolvetheproblemforus,ordosomeGooglingonthesubjecttooptimizehowwe’reusingthem.
TipOneofthebestwaystofindthecorrectansweronlineistosimplypostthewronganswer!Peoplewilleitherhelpusoutofkindness,ortakesuchgreatoffensetoourimplementationthattheyconsiderittheircivicdutytocorrectus!Justbesuretodosomekindofresearchonthesubjectfirst.Eventhebusiestofpeoplearegenerallyhappytohelpiftheycanseethatwe’veputinourfairshareofeffortbeforehand.
http://freepdf-books.com
TemporaryworkbuffersIfwegetintothehabitofusinglarge,temporaryworkbuffersforonetaskoranother,thenitjustmakessensethatweshouldlookforopportunitiestoreusethem,insteadofreallocatingthemoverandoveragain,asthislowerstheoverheadinvolvedinallocation,aswellasgarbagecollection(so-called“memorypressure”).Itmightbeworthwhiletoextractsuchfunctionalityfromcase-specificclassesintoagenericgodclassthatcontainsabigworkareaformultipleclassestoreuse.
http://freepdf-books.com
ObjectpoolingSpeakingoftemporaryworkbuffers,objectpoolingisanexcellentwayofbothminimizingandestablishingcontroloverourmemoryusagebyavoidingdeallocationandreallocation.Theideaistoformulateourownsystemforobjectcreation,whichhidesawaywhethertheobjectwe’regettinghasbeenfreshlyallocatedorhasbeenrecycledfromanearlierallocation.Thetypicaltermstodescribethisprocessareto“spawn”and“despawn”theobject,ratherthancreatinganddeletingthem,sinceanytimeanobjectisdespawnedwe’resimplyhidingitfromviewuntilweneeditagain,atwhichpointitisrespawnedandreused.
Let’scoveraquickimplementationofanobjectpoolingsystem.
Thefirstrequirementistoallowthepooledobjecttodecidehowtorecycleitselfwhenthetimecomes.Thefollowinginterfacewillsatisfytherequirementsnicely:
publicinterfaceIPoolableObject{
voidNew();
voidRespawn();
}
Thisinterfacedefinestwomethods;New()andRespawn().Theseshouldbecalledwhentheobjectisfirstcreated,andwhenithasbeenrespawned,respectively.
Thesecondrequirementistoprovideabaseimplementationofthisinterfacethatallowsobjectsofanytypetohandleanybookkeepingrequiredtotakecareoftheinitialcreationandrespawningofobjects.
ThefollowingObjectPoolclassdefinitionisafairlysimpleimplementationoftheobjectpoolingconcept.Itusesgenericstosupportanyobjecttypesolongasitfitstwocriteria;itmustimplementtheIPoolableObjectinterface,andmustallowforaparameter-lessconstructor(thenew()keywordintheclassdeclaration).
publicclassObjectPool<T>whereT:IPoolableObject,new(){
privateStack<T>_pool;
privateint_currentIndex=0;
publicObjectPool(intinitialCapacity){
_pool=newStack<T>(initialCapacity);
for(inti=0;i<initialCapacity;++i){
Spawn();//instantiateapoolofNobjects
}
Reset();
}
publicintCount{
get{return_pool.Count;}
}
publicvoidReset(){
_currentIndex=0;
}
publicTSpawn(){
if(_currentIndex<Count){
Tobj=_pool.Pop();
http://freepdf-books.com
_currentIndex++;
IPoolableObjectip=objasIPoolableObject;
ip.Respawn();
returnobj;
}else{
Tobj=newT();
_pool.Push(obj);
_currentIndex++;
IPoolableObjectip=objasIPoolableObject;
ip.New();
returnobj;
}
}
}
AnexamplePoolableobjectwouldlooklikeso.Itmustimplementtwopublicmethods,New()andRespawn(),whichareinvokedbytheObjectPoolclassattheappropriatetimes:
publicclassTestObject:IPoolableObject{
publicvoidNew(){
//veryfirstinitializationhere
}
publicvoidRespawn(){
//resetdatawhichallowstheobjecttoberecycledhere
}
}
Andfinally,anexampleusagetocreateapoolof100TestObjectobjects:
privateObjectPool<TestObject>_objectPool=newObjectPool<TestObject>
(100);
Thefirst100callstoSpawn()onthe_objectPoolobjectwillcausetheobjectstoberespawnedandprovidedtothecaller.Ifthestackrunsoutofspace,thenitwilladdevenmoreTestObjectobjectstothestack.Finally,ifReset()iscalledon_objectPool,thenitwillbeginagainfromthestart,recyclingobjectsandprovidingthemtothecaller.
Notethatthispoolingsolutionwillnotworkforclasseswehaven’tdefined,andcannotderivefrom,suchasVector3,andQuaternion.Inthesecases,wewouldneedtodefineacontainingclass:
publicclassPoolableVector3:IPoolableObject{
publicVector3vector=newVector3();
publicvoidNew(){
Reset();
}
publicvoidRespawn(){
Reset();
http://freepdf-books.com
}
publicvoidReset(){
vector.x=vector.y=vector.z=0f;
}
}
Wecouldextendthissysteminanumberofways,suchasdefiningaDespawn()methodtohandledestructionoftheobject,makinguseoftheIDisposableinterfaceandusingblockswhenwewishtoautomaticallyspawnanddespawnobjectswithinasmallscope,and/orallowingobjectsinstantiatedoutsidethepooltobeaddedtoit.
http://freepdf-books.com
http://freepdf-books.com
PrefabpoolingThepreviouspoolingsolutionisusefulfortypicalclasses,butitwon’tworkforspecialUnityobjects,suchasGameObjectandMonoBehaviour.Theseobjectstendtoconsumealargechunkofourruntimememory,cancostusagreatdealofCPUusagewhenthey’recreatedanddestroyed,andtendtoriskalargeamountofgarbagecollectionatruntime.Inotherwords,themaingoalofPrefabpoolingistopushtheoverwhelmingmajorityofobjectinstantiationtoSceneinitialization,ratherthanlettingthemgetcreatedatruntime.ThiscanprovidesomebigruntimeCPUsavings,andavoidsalotofspikescausedbyobjectcreation/destructionandgarbagecollection,attheexpenseofSceneloadingtimes,andruntimememoryconsumption.Asaresult,therearequiteafewpoolingsolutionsavailableontheAssetStoreforhandlingthistask,withvaryingdegreesofsimplicity,quality,andfeaturesets.
NoteItisoftenrecommendedthatpoolingshouldbeimplementedinanygamethatintendstodeployonmobiledevices,duetothegreateroverheadcostsinvolvedintheallocationanddeallocationofmemorycomparedtodesktopapplications.
However,creatingapoolingsolutionisaninterestingtopic,andbuildingonefromscratchisagreatwayofgettingtogripswithalotofimportantinternalUnityEnginebehavior.Also,knowinghowsuchasystemisbuiltmakesiteasiertoextendifwewishittomeettheneedsofourparticulargame,ratherthanrelyingonaprebuiltsolution.
ThegeneralideaofPrefabpoolingistocreateasystemthatcontainslistsofactiveandinactiveGameObjectsthatwereallinstantiatedfromthesamePrefabreference.Thefollowingdiagramshowshowthesystemmightlookafterseveralspawns,despawns,andrespawnsofvariousobjectsderivedfromfourdifferentPrefabs(Orc,Troll,Ogre,andDragon):
http://freepdf-books.com
NoteNotethattheHeapMemoryarearepresentstheobjectsastheyexistinmemory,whilethePoolingSystemarearepresentsreferencestothoseobjects.
Inthisexample,severalinstancesofeachPrefabwereinstantiated(11Orcs,8Trolls,5Ogres,and1Dragon).Currentlyonlyelevenoftheseobjectsareactive,whiletheotherfourteenhavepreviouslybeendespawned,andareinactive.Notethatthedespawnedobjectsstillexistinmemory,althoughtheyarenotvisibleandcannotinteractwiththegameworlduntiltheyhavebeenrespawned.Naturally,thiscostsusaconstantamountofheapmemoryatruntimeinordertomaintaintheinactiveobjects,butwhenanewobjectisinstantiated,wecanreuseoneoftheexistinginactiveobjects,ratherthanallocatingmorememoryinordertosatisfytherequest.ThissavessignificantruntimeCPUcostsduringobjectcreationanddestruction,andavoidsgarbagecollection.
ThefollowingdiagramshowsthechainofeventsthatneedstooccurwhenanewOrcisspawned:
ThefirstobjectintheInactiveOrcpool(Orc7)isreactivatedandmovedintotheActivepool.Wenowhave6activeOrcs,and5inactiveOrcs.
ThefollowingfigureshowstheorderofeventswhenanOgreobjectisdespawned:
http://freepdf-books.com
ThistimetheobjectisdeactivatedandmovedfromtheActivepoolintotheInactivepool,leavinguswith1activeOgreand4inactiveOgres.
Finally,thefollowingdiagramshowswhathappenswhenanewobjectisspawned,buttherearenoinactiveobjectstosatisfytherequest:
Inthisscenario,morememorymustbeallocatedtoinstantiatethenewDragonobject,sincetherearenoDragonobjectsinitsInactivepooltoreuse.Therefore,inordertoavoidruntimememoryallocationsforourGameObjects,itiscriticalthatweknowbeforehandhowmanywewillneed.Thiswillvarydependingonthetypeofobjectinquestion,and
http://freepdf-books.com
requiresoccasionaltestinganddebuggingtoensurewehaveasensiblenumberofeachPrefabinstantiatedatruntime.
Withallofthisinmind,let’screateapoolingsystemforPrefabs!
http://freepdf-books.com
PoolableComponentsLet’sfirstdefineaninterfaceforaPoolableComponent:
publicinterfaceIPoolableComponent{
voidSpawned();
voidDespawned();
}
TheapproachforIPoolableComponentwillbeverydifferentfromtheapproachtakenforIPoolableObject.TheobjectsbeingcreatedthistimeareGameObjects,whicharealottrickiertoworkwiththanstandardobjectsbecauseofhowmuchoftheirruntimebehaviorisalreadyhandledthroughtheUnityEngine,andhowlittleaccesswehavetoit.
GameObjectsdonotgiveusaccesstoanequivalentNew()methodthatwecaninvokeanytimetheobjectiscreated,andwecannotderivefromtheGameObjectclassinordertoimplementone.GameObjectsarecreatedeitherbyplacingtheminaScene,orbyinstantiatingthematruntimethroughGameObject.Instantiate(),andtheonlyinputswecanapplyareaninitialpositionandrotation.Ofcourse,theirComponentshaveanAwake()methodwecandefine,whichisinvokedthefirsttimetheComponentisbroughttolife,butthisismerelyacompositionalobject—it’snottheactualparentobjectwe’respawninganddespawning.
So,becauseweonlyhavecontroloveraGameObjectclass’sComponents,itisassumedthattheIPoolableComponentinterfaceisimplementedbyatleastoneoftheComponentsthatisattachedtotheGameObjectwewishtopool.
TheSpawned()methodshouldbeinvokedoneveryimplementingComponenteachtimethepooledGameObjectisrespawned,whiletheDespawned()methodgetsinvokedwheneveritisdespawned.ThisgivesusentrypointstocontrolthedatavariablesandbehaviorduringthecreationanddestructionoftheparentGameObject.
TheactofdespawningaGameObjectistrivial;turnitsactiveflagtofalse(throughSetActive()).ThisdisablestheColliderandRigidbodyforphysicscalculations,removesitfromthelistofrenderableobjects,andessentiallytakescareofdisablinginteractionswithallbuilt-inUnityEnginesubsystemsinasinglestroke.TheonlyexceptionisanyCoroutinesthatarecurrentlyinvokingontheobject,sinceaswelearnedearlierinChapter2,ScriptingStrategies,CoroutinesareinvokedindependentlyofUpdate()andGameObjectactivity.WewillthereforeneedtocallStopCoroutine(),orStopAllCoroutines()duringthedespawningofsuchobjects.
Inaddition,Componentstypicallyhookintoourowncustomgameplaysubsystemsaswell,andsotheDespawn()methodgivesourComponentstheopportunitytotakecareofanycustomcleanupbeforeshuttingdown.Forexample,wewouldprobablywanttouseDespawn()toderegistertheComponentfromtheMessagingSystemwedefinedbackinChapter2,ScriptingStrategies.
Unfortunately,successfullyrespawningtheGameObjectisalotmorecomplicated.Whenwerespawnanobject,therewillbemanysettingsthatwereleftbehindwhentheobject
http://freepdf-books.com
waspreviouslyactive,andthesemustberesetinordertoavoidconflictingbehaviors.AcommonproblemwiththisisRigidbodyvelocity.Ifthisvalueisnotexplicitlyresetbeforetheobjectisreactivated,thenthenewlyrespawnedobjectwillcontinuemovingwiththesamevelocitytheoldversionhadwhenitwasdespawned.
Thisproblembecomesfurthercomplicatedbythefactthatbuilt-inComponentsaresealed,andthereforecannotbederivedfrom.So,toavoidtheseissues,wecancreateacustomComponentthatresetstheattachedRigidbodywhenevertheobjectisdespawned:
publicclassResetPooledRigidbodyComponent:MonoBehaviour,
IPoolableComponent{
Rigidbody_body;
publicvoidSpawned(){}
publicvoidDespawned(){
if(_body==null){
_body=GetComponent<Rigidbody>();
if(_body==null){
//noRigidbody!
return;
}
}
_body.velocity=Vector3.zero;
_body.angularVelocity=Vector3.zero;
}
}
Notethatthebestplacetoperformthistaskisduringdespawning,becausewecannotbecertaininwhatordertheGameObjectclass’sIPoolableComponentinterfaceswillhavetheirSpawned()methodsinvoked.ItisunlikelythatanotherIPoolableComponentwillchangetheobject’svelocityduringdespawning,butitispossiblethatadifferentIPoolableComponentattachedtothesameobjectmightwanttosettheRigidbody’sinitialvelocitytosomeimportantvalueduringitsownSpawned()method.Ergo,performingthevelocityresetduringtheResetPooledRigidbodyComponentclass’sSpawned()methodcouldpotentiallyconflictwithotherComponentsandcausesomeveryconfusingbugs.
TipInfact,creatingPoolableComponentsthatarenotself-contained,andtendtotinkerwithotherComponentslikethis,isoneofthebiggestdangersofimplementingapoolingsystem.Weshouldminimizesuchimplementations,androutinelyverifythemwhenwe’retryingtodebugstrangeissuesinourgame.
Forthesakeofillustration,hereisthedefinitionofasimplePoolableComponentthatreplacestheTestMessageListenerclasswedefinedbackinChapter2,ScriptingStrategies.ThisComponentautomaticallyhandlessomebasictaskseverytimetheobjectisspawnedanddespawned:
publicclassPoolableTestMessageListener:MonoBehaviour,
IPoolableComponent{
publicvoidSpawned(){
MessagingSystem.Instance.AttachListener(typeof(MyCustomMessage),
this.HandleMyCustomMessage);
http://freepdf-books.com
}
boolHandleMyCustomMessage(BaseMessagemsg){
MyCustomMessagecastMsg=msgasMyCustomMessage;
Debug.Log(string.Format("Gotthemessage!{0},{1}",
castMsg._intValue,castMsg._floatValue));
returntrue;
}
publicvoidDespawned(){
if(MessagingSystem.IsAlive){
MessagingSystem.Instance.DetachListener(typeof(MyCustomMessage),
this.HandleMyCustomMessage);
}
}
}
http://freepdf-books.com
ThePrefabpoolingsystemHopefully,wenowhaveanunderstandingofwhatweneedfromourpoolingsystem,soallthat’sleftistoimplementit.Therequirementsareasfollows:
ItmustacceptrequeststospawnaGameObjectfromaPrefab,aninitialposition,andaninitialrotation:
Ifadespawnedversionalreadyexists,itshouldrespawnthefirstavailableoneIfitdoesnotexist,thenitshouldinstantiateanewGameObjectfromthePrefabIneithercase,theSpawned()methodshouldbeinvokedonallIPoolableComponentinterfacesattachedtotheGameObject
ItmustacceptrequeststodespawnaspecificGameObject:
Iftheobjectismanagedbythepoolingsystem,itshoulddeactivateitandcalltheDespawned()methodonallIPoolableComponentinterfacesattachedtotheGameObjectIftheobjectisnotmanagedbythepoolingsystem,itshouldsendanerror
Therequirementsarefairlystraightforward,buttheimplementationrequiressomeinvestigationifwewishtomakethesolutionperformance-friendly.Firstly,atypicalSingletonwouldbeagoodchoiceforthemainentrypoint,sincewewantthissystemtobegloballyaccessiblefromanywhere:
publicstaticclassPrefabPoolingSystem{
}
ThemaintaskforobjectspawninginvolvesacceptingaPrefabreference,andfiguringifwehaveanydespawnedGameObjectsthatwereoriginallyinstantiatedfromthesamereference.Todothis,wewillessentiallywantourpoolingsystemtokeeptrackoftwodifferentlistsforanygivenPrefabreference:alistofactive(spawned)GameObjects,andalistofinactive(despawned)objectsthatwereinstantiatedfromit.Thisdatawouldbebestabstractedintoaseparateclass,whichwewillnamePrefabPool.
Inordertomaximizetheperformanceofthissystem(andhencemakethelargestgainspossible,relativetojustallocatinganddeallocatingobjectsfrommemoryallofthetime),wewillwanttousesomefastdatastructuresinordertoacquirethecorrespondingPrefabPoolobjectswheneveraspawnordespawnrequestcomesin.
BecausespawninginvolvesbeinggivenaPrefab,wewillwantonedatastructurethatcanquicklymapPrefabstothePrefabPoolthatmanagesthem.AndbecausedespawninginvolvesbeinggivenaGameObject,wewillwantanotherdatastructurethatcanquicklymapspawnedGameObjectstothePrefabPoolthatoriginallyspawnedthem.ADictionaryisagoodchoiceforbothoftheseneeds.
Let’sdefinethesemapsinourpoolingsystem:
publicstaticclassPrefabPoolingSystem{
staticDictionary<GameObject,PrefabPool>_prefabToPoolMap=new
Dictionary<GameObject,PrefabPool>();
http://freepdf-books.com
staticDictionary<GameObject,PrefabPool>_goToPoolMap=new
Dictionary<GameObject,PrefabPool>();
}
Nextwe’lldefinewhathappenswhenwespawnanobject:
publicstaticGameObjectSpawn(GameObjectprefab,Vector3position,
Quaternionrotation){
if(!_prefabToPoolMap.ContainsKey(prefab)){
_prefabToPoolMap.Add(prefab,newPrefabPool());
}
PrefabPoolpool=_prefabToPoolMap[prefab];
GameObjectgo=pool.Spawn(prefab,position,rotation);
_goToPoolMap.Add(go,pool);
returngo;
}
TheSpawn()methodwillbegivenaPrefabreference,aninitialposition,andaninitialrotation.WeneedtofigureoutwhichPrefabPoolthePrefabbelongsto(ifany),askittospawnanewGameObjectusingthedataprovided,andthenreturnthespawnedobjecttotherequestor.Wefirstcheckour“Prefab-to-Pool”map,toseeifapoolalreadyexistsforthisPrefab.Ifnot,wequicklycreateone.Ineithercase,wethenaskthePrefabPooltospawnusanewobject.ThePrefabPoolwilleitherenduprespawninganobjectthatwasdespawnedearlier,orinstantiateanewone(iftherearen’tanyinactiveinstancesleft).
Eitherway,thisclassdoesn’tparticularlycare.ItjustwantstheinstancegeneratedbythePrefabPoolclasssothatitcanbeenteredintothe“GameObject-to-Pool”mapandreturnedtotherequestor.
Forconvenience,wecanalsodefineanoverloadwhichplacestheobjectattheworld’scenter(usefulforGameObjectsthataren’tvisible,andjustneedtoexistsomewhere):
publicstaticGameObjectSpawn(GameObjectprefab){
returnSpawn(prefab,Vector3.zero,Quaternion.identity);
}
NoteNotethatnoactualspawninganddespawningaretakingplace,yet.ThistaskwilleventuallybehandledwithinthePrefabPoolclass.
DespawninginvolvesbeinggivenaGameObject,andthenfiguringoutwhichPrefabPoolismanagingit.ThiscouldbeachievedbyiteratingthroughourPrefabPoolclassesandcheckingiftheycontainthegivenGameObject.ButifweendupgeneratingalotofPrefabPools,thenthisiterativeprocesscantakeawhile.WewillalwaysendupwithasmanyPrefabPoolclassesaswehavePrefabs(atleastsolongaswemanageallofthemthroughthepoolingsystem).Mostprojectstendtohavedozens,hundreds,ifnotthousandsofdifferentPrefabs.
So,theGameObject-to-PoolmapismaintainedtoensurethatwealwayshaverapidaccesstothePrefabPoolthatoriginallyspawnedtheobject.ItcanalsobeusedtoquicklyverifyifthegivenGameObjectisevenmanagedbythepoolingsystemtobeginwith.Hereisthemethoddefinitionforthedespawningmethod,whichtakescareofthesetasks:
http://freepdf-books.com
publicstaticboolDespawn(GameObjectobj){
if(!_goToPoolMap.ContainsKey(obj)){
Debug.LogError(string.Format("Object{0}notmanagedbypool
system!",obj.name));
returnfalse;
}
PrefabPoolpool=_goToPoolMap[obj];
if(pool.Despawn(obj)){
_goToPoolMap.Remove(obj);
returntrue;
}
returnfalse;
}
TipNotethattheDespawn()methodofbothPrefabPoolingSystemandPrefabPoolreturnsaBooleanthatcanbeusedtoverifywhetherornottheobjectwassuccessfullydespawned.
Asaresult,thankstothetwomapswe’remaintaining,wecanquicklyaccessthePrefabPoolthatmanagesthegivenreference,andthissolutionwillscaleforanynumberofPrefabthatthesystemmanages.
http://freepdf-books.com
PrefabpoolsNowthatwehaveasystemthatcanhandlemultiplePrefabpoolsautomatically,theonlythingleftistodefinethebehaviorofthepools.Asmentionedpreviously,wewillwantthePrefabPoolclasstomaintaintwodatastructures:oneforactive(spawned)objectsthathavebeeninstantiatedfromthegivenPrefabandanotherforinactive(despawned)objects.
Technically,thePrefabPoolingSystemclassalreadymaintainsamapofwhichPrefabisgovernedbywhichPrefabPool,sowecanactuallysavealittlememorybymakingthePrefabPoolaslavetothePrefabPoolingSystemclass,bynothavingitkeeptrackofwhichPrefabitismanaging.Consequently,thetwodatastructuresaretheonlymembervariablesthePrefabPoolneedstokeeptrackof.
However,foreachspawnedGameObject,itmustalsomaintainalistofallofitsIPoolableComponentreferencesinordertoinvoketheSpawned()andDespawned()methodsonthem.Acquiringthesereferencescanbeacostlyoperationtoperformatruntime,soitwouldbebesttocachethedatainasimplestruct:
publicstructPoolablePrefabData{
publicGameObjectgo;
publicIPoolableComponent[]poolableComponents;
}
ThisstructwillcontainareferencetotheGameObject,andtheprecachedlistofitsIPoolableComponents.
NowwecandefinethememberdataofourPrefabPoolclass:
publicclassPrefabPool{
Dictionary<GameObject,PoolablePrefabData>_activeList=new
Dictionary<GameObject,PoolablePrefabData>();
Queue<PoolablePrefabData>_inactiveList=newQueue<PoolablePrefabData>
();
}
ThedatastructurefortheactivelistshouldbeadictionaryinordertodoaquicklookupforthecorrespondingPoolablePrefabDatafromanygivenGameObjectreference.Thiswillbeusefulduringobjectdespawning.
Meanwhile,theinactivedatastructureisdefinedasaQueue,butitwillworkequallywellasaList,aStack,orreallyanydatastructurethatneedstoregularlyexpandorcontract,andwhereweonlyneedtopopitemsfromoneendofthelist,sinceitdoesnotmatterwhichobjectitis.Itonlymattersthatweretrieveoneofthem.AQueueisusefulinthiscasebecausewecanbothretrieveandremovetheobjectfromthedatastructureinasinglecall.
http://freepdf-books.com
ObjectspawningLet’sdefinewhatitmeanstospawnaGameObjectinthecontextofourpoolingsystem:atsomepoint,PrefabPoolwillgetarequesttospawnaGameObjectfromagivenPrefab,ataparticularpositionandrotation.ThefirstthingweshouldcheckiswhetherornotwehaveanyinactiveinstancesofthePrefab.Ifso,thenwecanpopthenextavailableonefromtheQueueandrespawnit.Ifnot,thenweneedtoinstantiateanewGameObjectfromthePrefabusingGameObject.Instantiate().Atthismoment,weshouldalsocreateaPoolablePrefabDataobjecttostoretheGameObjectreference,andacquirethelistofallIPoolableComponentsthatareattachedtoit.
Eitherway,wecannowactivatetheGameObject,setitspositionandrotation,andcalltheSpawned()methodonallofitsIPoolableComponents.Oncetheobjecthasbeenrespawned,wecanaddittothelistofactiveobjectsandreturnittotherequestor.
HereisthedefinitionoftheSpawn()methodthatdefinesthisbehavior:
publicGameObjectSpawn(GameObjectprefab,Vector3position,Quaternion
rotation){
PoolablePrefabDatadata;
if(_inactiveList.Count>0){
data=_inactiveList.Dequeue();
}else{
//instantiateanewobject
GameObjectnewGO=GameObject.Instantiate(prefab,position,
rotation)asGameObject;
data=newPoolablePrefabData();
data.go=newGO;
data.poolableComponents=newGO.GetComponents<IPoolableComponent>
();
}
data.go.SetActive(true);
data.go.transform.position=position;
data.go.transform.rotation=rotation;
for(inti=0;i<data.poolableComponents.Length;++i){
data.poolableComponents[i].Spawned();
}
_activeList.Add(data.go,data);
returndata.go;
}
http://freepdf-books.com
InstanceprespawningBecauseweareusingGameObject.Instantiate()wheneverthepoolhasrunoutofdespawnedinstances,thissystemdoesnotcompletelyridusofruntimeobjectinstantiationandhence,heapmemoryallocation.It’simportanttoprespawntheexpectednumberofinstancesthatwewillneedduringthelifetimeofthecurrentScene,sothatwedon’tneedtoinstantiatemoreduringruntime.
TipItwouldbewastefultoprespawn100explosionparticleeffects,ifthemostwewilleverexpecttoseeintheSceneatanygiventimeisthreeorfour.Conversely,spawningtoofewinstanceswillcauseexcessiveruntimememoryallocations,andthegoalofthissystemistopushthemajorityofallocationtothestartofaScene’slifetime.Weneedtobecarefulabouthowmanyinstanceswemaintaininmemorysothatwedon’twastemorememoryspacethannecessary.
Let’sdefineamethodinourPrefabPoolingSystemclassthatwecanusetoquicklyprespawnagivennumberofobjectsfromaPrefab.ThisessentiallyinvolvesspawningNobjects,andthenimmediatelydespawningthemall:
publicstaticvoidPrespawn(GameObjectprefab,intnumToSpawn){
List<GameObject>spawnedObjects=newList<GameObject>();
for(inti=0;i<numToSpawn;i++){
spawnedObjects.Add(Spawn(prefab));
}
for(inti=0;i<numToSpawn;i++){
Despawn(spawnedObjects[i]);
}
spawnedObjects.Clear();
}
WewouldusethismethodduringSceneinitialization,toprespawnacollectionofobjectstouseinthelevel.Forexample:
publicclassOrcPreSpawner:MonoBehaviour
[SerializeField]GameObject_orcPrefab;
[SerializeField]int_numToSpawn=20;
voidStart(){
PrefabPoolingSystem.Prespawn(_orcPrefab,_numToSpawn);
}
}
http://freepdf-books.com
ObjectdespawningFinally,thereistheactofdespawningtheobjects.Asmentionedpreviously,thisprimarilyinvolvesdeactivatingtheobject,butwealsoneedtotakecareofvariousbookkeepingtasksandinvokingDespawned()onallofitsIPoolableComponentreferences.
HereisthemethoddefinitionforthePrefabPoolclass’sDespawn()method:
publicboolDespawn(GameObjectobjToDespawn){
if(!_activeList.ContainsKey(objToDespawn)){
Debug.LogError("ThisObjectisnotmanagedbythisobjectpool!");
returnfalse;
}
PoolablePrefabDatadata=_activeList[objToDespawn];
for(inti=0;i<data.poolableComponents.Length;++i){
data.poolableComponents[i].Despawned();
}
data.go.SetActive(false);
_activeList.Remove(objToDespawn);
_inactiveList.Enqueue(data);
returntrue;
}
Firstweverifytheobjectisbeingmanagedbythepool,andthenwegrabthecorrespondingPoolablePrefabDatainordertoaccessthelistofIPoolableComponentreferences.OnceDespawned()hasbeeninvokedonallofthem,wedeactivatetheobject,removeitfromtheactivelist,andpushitintotheinactivequeuesothatitcanberespawnedlater.
http://freepdf-books.com
PrefabpooltestingThefollowingclassdefinitionallowsustoperformasimplehands-ontestwiththePrefabPoolingSystemclass.ItwillsupportthreePrefabs,andprespawnfiveinstancesduringapplicationinitialization.Wecanpressthe1,2,or3keystospawnaninstanceofeachtype,andthenpressQ,W,orEtodespawnarandominstanceofeachtype.
publicclassPoolTester:MonoBehaviour{
[SerializeField]GameObject_prefab1;
[SerializeField]GameObject_prefab2;
[SerializeField]GameObject_prefab3;
List<GameObject>_go1=newList<GameObject>();
List<GameObject>_go2=newList<GameObject>();
List<GameObject>_go3=newList<GameObject>();
voidStart(){
PrefabPoolSystem_AsSingleton.Prespawn(_prefab1,5);
PrefabPoolSystem_AsSingleton.Prespawn(_prefab2,5);
PrefabPoolSystem_AsSingleton.Prespawn(_prefab3,5);
}
voidUpdate(){
if(Input.GetKeyDown(KeyCode.Alpha1)){SpawnObject(_prefab1,
_go1);}
if(Input.GetKeyDown(KeyCode.Alpha2)){SpawnObject(_prefab2,
_go2);}
if(Input.GetKeyDown(KeyCode.Alpha3)){SpawnObject(_prefab3,
_go3);}
if(Input.GetKeyDown(KeyCode.Q)){DespawnRandomObject(_go1);}
if(Input.GetKeyDown(KeyCode.W)){DespawnRandomObject(_go2);}
if(Input.GetKeyDown(KeyCode.E)){DespawnRandomObject(_go3);}
}
voidSpawnObject(GameObjectprefab,List<GameObject>list){
GameObjectobj=PrefabPoolingSystem.Spawn(prefab,
Random.insideUnitSphere*8f,Quaternion.identity);
list.Add(obj);
}
voidDespawnRandomObject(List<GameObject>list){
if(list.Count==0){
//Nothingtodespawn
return;
}
inti=Random.Range(0,list.Count);
PrefabPoolingSystem.Despawn(list[i]);
list.RemoveAt(i);
}
}
OncewespawnmorethanfiveinstancesofanyofthePrefabs,itwillneedtoinstantiatea
http://freepdf-books.com
newoneinmemory,costingussomememoryallocation.But,ifweobservetheMemoryAreaintheProfiler,whileweonlyspawnanddespawninstancesthatalreadyexist,thenwewillnoticethatabsolutelynonewallocationstakeplace.
http://freepdf-books.com
PrefabpoolingandSceneloadingThereisonesubtlecaveattothissystemthathasnotyetbeenmentioned:thePrefabPoolingSystemclasswilloutlastScenelifetimesinceitisastaticclass.Thismeansthat,whenanewSceneisloaded,thepoolingsystem’sdictionarieswillattempttomaintainreferencestoanypooledinstancesfromthepreviousScene,butUnityforciblydestroystheseobjectsregardlessofthefactthatwearestillkeepingreferencestothem(unlesstheyweresettoDontDestroyOnLoad()!),andsothedictionarieswillbefullofnullreferences.ThiswouldcausesomeseriousproblemsforthenextScene.
WeshouldthereforecreateamethodinPrefabPoolingSystemthatresetsthepoolingsysteminpreparationforthislikelyevent.ThefollowingmethodshouldbecalledbeforeanewSceneisloaded,sothatitisreadyforanyearlycallstoPrespawn()inthenextScene:
publicstaticvoidReset(){
_prefabToPoolMap.Clear();
_goToPoolMap.Clear();
}
Notethat,ifwealsoinvokeagarbagecollectionduringScenetransitions,there’snoneedtoexplicitlyemptythePrefabPoolsthesedictionarieswerereferencing.SincetheseweretheonlyreferencestothePrefabPoolobjects,theywillbedeallocatedduringthenextgarbagecollection.Ifwearen’tinvokinggarbagecollectionbetweenScenes,thenthePrefabPoolandPooledPrefabDataobjectswillremaininmemoryuntilthattime.
http://freepdf-books.com
PrefabpoolingsummaryWehavefinallysolvedtheproblemofruntimememoryallocationsforGameObjectsandPrefabsbut,asaquickreminder,weneedtobeawareofthefollowingcaveats:
Weneedtobecarefulaboutproperlyresettingimportantdatainrespawnedobjects(suchasRigidbodyvelocity)Wemustensurewedon’tprespawntoofew,ortoomany,instancesofaPrefabWeshouldbecarefuloftheorderofexecutionofSpawned()andDespawned()methodsonIPoolableComponentsWemustcallReset()onPrefabPoolingSystembeforeSceneloading
Thereareseveralotherfeatureswecouldimplement.Thesewillbeleftasacademicexercisesifwewishtoextendthissysteminthefuture:
AnyIPoolableComponentsaddedtotheGameObjectafterinitializationwillnotbeinvoked.WecouldfixthisbychangingPrefabPooltokeepacquiringIPoolableComponentseverytimeSpawned()andDespawned()areinvoked,atthecostofadditionaloverheadduringspawning/despawning.IPoolableComponentsattachedtochildrenofthePrefab’srootwillnotbecounted.ThiscouldbefixedbychangingPrefabPooltouseGetComponentsInChildren<T>,atthecostofadditionaloverheadifwe’reusingPrefabswithdeephierarchies.PrefabinstancesthatalreadyexistintheScenewillnotbemanagedbythepoolingsystem.WecouldcreateaComponentthatneedstobeattachedtosuchobjectsandthatnotifiesthePrefabPoolingSystemclassofitsexistenceandpassesthereferenceintothecorrespondingPrefabPool.WecouldimplementawayforIPoolableComponentstosetapriorityduringacquisition,anddirectlycontroltheorderofexecutionfortheirSpawned()andDespawned()methods.WecouldaddcountersthatkeeptrackofhowlongobjectshavebeensittingintheInactivelistrelativetototalScenelifetime,andprintoutthedataduringshutdown.Thiscouldtelluswhetherornotwe’represpawningtoomanyinstancesofagivenPrefab.ThissystemwillnotinteractkindlywithPrefabinstancesthatsetthemselvestoDontDestroyOnLoad().ItmightbewisetoaddaBooleantoeverySpawn()calltosaywhethertheobjectshouldpersistornot,andkeeptheminaseparatedatastructurethatisnotclearedoutduringReset().WecouldchangeSpawn()toacceptanargumentthatallowstherequestortopasscustomdatatotheSpawned()functionofIPoolableObjectforinitializationpurposes.ThiscoulduseasystemsimilartohowcustommessageobjectswerederivedfromtheBaseMessageclassforourMessagingSystembackinChapter2,ScriptingStrategies.
http://freepdf-books.com
http://freepdf-books.com
ThefutureofMonoandUnityAsweknow,UnitydoesnotusethelatestandgreatestMonoprojectcodefromhttp://www.mono-project.com,butaninternally-customizedversionwithsomeinternalbugfixes.
NoteTheactualMonotweaksmadebyUnityTechnologiescanbefoundinthefollowingGitHubrepository:
https://github.com/Unity-Technologies/mono/
AsanunfortunateconsequenceofhowvariouscomponentsoftheMonoFrameworkarelicensed,UnityTechnologieshasonlybeenabletoupdateMonoonaninfrequentbasis.TheoccasionsonwhichthistaskwereaccomplishedwaswiththereleaseofUnity4,whentheyupgradedtoMono2.6,andshortlyafterwardsversion2.6.5backinmid-2010,whichsupports.NET2.0/3.5features.But,atthetimeofpublication,thelatestversionofMono,version4.0,wasreleasedinMay2015,andsupports.NET4.5features.ThisputsUnity’simplementationabout5yearsbehindintermsofC#languageand.NETframeworkfeatures,whichhasdrawntheireofmanyUnitydevelopers.
UnityTechnologieshassuggestedtheremightbeaMonoupgradesometimeinthelifecycleofUnity5,butthelastofficialupdateonthissubjectwasbackinAugust2014.TheUnityroadmap(https://unity3d.com/unity/roadmap)placesitinthe“LongandUncertain”timeline,andUnityv5.2wasreleasedinearlySeptember2015,whichdidnotincludethisupgrade.So,itisdifficulttosaywhenMonowillbereceivingitsmuch-neededupgrade.UnityTechnologieshasalsobeenworkingwithMicrosofttobringreplacementstosomeMonoComponents(suchasupgradedversionsofthestatic,JIT,andAOTcompilers,aswellastheCLR).
NoteMicrosoft’sannouncementonthefutureof.NET:
http://blogs.msdn.com/b/dotnet/archive/2014/04/03/the-next-generation-of-net.aspx
Meanwhile,UnityTechnologieshasbeenworkingontheproblemoflong-termindependencefromthesethird-partydependenciesforawhile.WiththereleaseofUnity5theyunveiledanewapproachforscriptcodecompilation,whichstartedasawaytoprovideimprovedscriptingsupportforWebGL-basedUnityapplications,buthasalsobeenadoptedasthemainsolutiontothesewoes:IL2CPP.
NoteUnityTechnologies’IL2CPPannouncement:
http://blogs.unity3d.com/2014/05/20/the-future-of-scripting-in-unity/
IL2CPPisshorthandforIntermediateLanguageToC++,andcomeswithitsown.NETruntimethatcanberolledouttomultipleplatforms.ThebasicideaisthatC#scriptcode
http://freepdf-books.com
willbeconvertedintoanintermediatelanguageandthenconvertedagaintoC++duringthebuildprocess.TheresultingC++willbepushedthroughoneofseveralavailableplatform-specificcompilerstosupportcross-platformcapability,takingawaytheburdenofhavingtocreateandmanagetheirowncompilers.
Thisprocesswillbemostlydisguisedfromtheuser,andnaturallytherewillbealossofcontrolasthecodeispushedthroughmultiple“codefilters”withvaryinglevelsofoptimizations.Itremainstobeseeniftheyallowsomehookstocontrolthecompilationprocessforadvanceddevelopers.TheEditorisstillexpectedtorunontheC#.NETruntimeforfasterdevelopmentiteration.
Thesuggestedbenefitsofthisapproachincludeperformanceenhancements(sinceevennear-nativecodegeneratedbytheJITcompilerstillpalesincomparisontostatically-compilednativeC++),fasterportingandfeaturedevelopmentfortheUnityEngine,andimprovedgarbagecollection.ThefirstplatformtogettheIL2CPPtreatmentinUnity5isWebGL,andwilleventuallybepushedtootherplatformsasthesystemmatures,andbecomesmorereliable.
NoteFormoreinformationonIL2CPPcheckoutthevariousblogpostsfromUnityTechnologiesonthesubject.Thefollowingpostcontainslotsofinformation,aswellasfurtherlinksonimportanttopics:
http://blogs.unity3d.com/2015/05/06/an-introduction-to-ilcpp-internals/
Whydoesn’tUnityTechnologiesjustprovideaC++APIforUnity?Onecanonlyspeculate,butit’saprettysafeassumptionthatUnitysupportsaverylargeuserbaseofdeveloperswhowouldbeuncomfortableworkinginC++directly.LosingtheaccessibilityofC#andUnityScriptwouldresultinaverydifferentproduct.Long-term,itwouldlikelysplitthecustomerbaseintotwocamps,whichrarelybodeswellsincewhicheveronebringsinthemostrevenuewillbecometheonethatissupportedtoagreaterdegree,leavingtheothertorot(asaninterestinganalogy,gamestypicallysufferfromthesameproblem,asexpansionsandmappackstendtosegregatethemultiplayeruserbase).
Inaddition,therearemany.NETlanguagesthatsharethesameintermediatecodeaftercompilation(CIL),andtheyhaveacommonbinaryinterface,whichmakesitordersofmagnitudeeasiertosupportcross-platformdevelopmentandmultiplelibrariesthanwithC++.Presumably,IL2CPPisacompromisefortheseconcerns.
So,tomakealongstoryshort,thereareagreatmanychangesgoingonwiththeunderlyingUnityEngineandit’stooearlytosaywhethertheIL2CPPapproachwillworksufficientlywellonallplatformstokeepfeatureparityandeaseofdeployment.Onethingisforsure;thenextcoupleofyearsofUnitydevelopmentwillbringsomeinterestingtransitions!
http://freepdf-books.com
http://freepdf-books.com
SummaryWe’vecoveredahumungousamountoftheoryandlanguageconceptsinthischapter,whichhavehopefullyshedsomelightonhowtheinternalsoftheUnityEngineandC#languagework.Thesetoolstrytheirbesttospareusfromtheburdenofcomplexmemorymanagement,butthereisstillawholehostofconcernsweneedtokeepinmindaswedevelopourgame.Betweenthecompilationprocesses,multiplememorydomains,thecomplexitiesofValuetypesversusReferencetypes,passingbyvalueversuspassingbyreference,boxing,objectpooling,andvariousquirkswithintheUnityAPI,wehavealotofthingstoworryabout.But,withenoughpractice,wewilllearntoovercomethemwithoutneedingtokeepreferringtogianttomessuchasthis!
Thischaptereffectivelyconcludesallofthetechniqueswecanbestowthatexplicitlyaimtoimproveapplicationperformance.Workflowoptimizationsarealwaysusefulthingstokeepinmind,however,astherearealotofneatlittlenuancestotheUnityEnginethataren’twellknownorclearlydocumented,andthatonlybecomeapparentthroughexperienceandcommunityinvolvement.Assuch,thenextchapterwillbefullofhintsandtipsforimprovinghowtomanageourprojectandScenesmoreeffectively,howtomakethemostoftheEditor,andhopefullysaveourselvesenoughdevelopmenttimetoactuallyimplementalloftheoptimizationtechniqueswe’vetalkedaboutthroughthisentirebook.
http://freepdf-books.com
http://freepdf-books.com
Chapter8.TacticalTipsandTricksTherearealotoflittlenuancestousingtheUnityEnginethatcanhelpimproveourprojectworkflow.However,quitealotoftheEditor’sfunctionalityisnotwelldocumented,wellknown,orjustnotsomethingwethinkaboutuntilafterthefactthatitcouldhavebeenappliedperfectlytosolveaparticularproblemwewerehaving6monthsago.
TheInternetiscrammedfullofblogsandforumpoststhattrytohelpotherUnitydeveloperslearnabouttheseusefulfeatures,buttheyonlytendtofocusonahandfuloftipsatatime.Theredon’tseemtobeanyonlineresourcesthatgrouptogethermanyoftheminoneplace.Asaresult,intermediateandadvancedusersprobablyhavebookmarkedmanagersburstingattheseamswithlinkstothesetipsthattheyrunintoatonepointoranother,butwhichsitandrotuntilitcomestimetodosomespringcleaning.
So,becausethisbookisprimarilyforintermediateandadvancedusers,itfeltlikeitwasworththrowinginashortchaptertobringtonsofthesetipsandtrickstogetherinonelocation.Itworksasareferencelistinthehopeofsavingusalotoffuturedevelopmenteffort.
http://freepdf-books.com
EditorhotkeytipsTheEditorisrifewithhotkeysthatcanaidrapiddevelopment.It’sworthcheckingoutthedocumentation.Butlet’sbehonest,nobodyreadsthemanualuntiltheyneedsomethingfromit.Herearesomeofthemostuseful,yetlesser-knownhotkeysavailablewhenplayingwiththeUnityEditor.
NoteInallcases,theWindowshotkeyislisted.IftheOSXhotkeyrequiresadifferentsetofkeystrokes,thenitwillbeshowninparentheses.
http://freepdf-books.com
GameObjectsGameObjectscanbeduplicatedbyselectingtheminthehierarchyandpressingCtrl+D(Cmd+D).
New,emptyGameObjectscanbecreatedusingCtrl+Shift+N(Cmd+Shift+N).
PressCtrl+Shift+A(Cmd+Shift+A)toquicklyopentheAddComponentmenu.Fromthere,youcantypeinthenameoftheComponentyouwishtoadd.
http://freepdf-books.com
SceneViewPressingShift+Fordouble-tappingtheFkeywillfollowanobjectintheSceneView,whichcanbehelpfulfortrackinghigh-velocityobjectsorfiguringoutwhyobjectsmightbefallingoutofourScene.
HoldingAltandleft-clickdraggingwiththemousewillmaketheSceneViewcameraorbitthecurrentlyselectedobject(asopposedtolookingaroundit).HoldingAltandright-clickdraggingwillzoomthecamerain/out.
HoldingCtrlandleft-clickdraggingwillcausetheselectedobjecttosnaptothegridasitmoves.ThesamecanbedoneforrotationbyholdingCtrlasweadjusttherotationwidgetsaroundtheobject.SelectingEdit|SnapSettings…opensawindowwherewecaneditthegridthatobjectssnaptoonaper-axisbasis.
Wecanforceobjectstosnapbyvertex,holdingtheVkeyaswemovetheobjectaround.Theselectedobjectwillattachitselftothenearestvertex,tothecursorofthenearestobject.Thisisveryusefulforaligninglevelpiecesintoplace,suchasplatformsandothertile-basedsystems,withoutneedingtohand-adjustpositionvectors.
NoteAtonepoint,inUnityversions4.2to4.6,itwaspossibletoholdShiftwithaColliderobjectselectedtoreveallittlehooksthroughwhichwecouldadjusttheColliderthroughtheSceneView.ThiswasremovedinrecentversionsofUnityduetoconflictswithothercontrols.WemustusetheEditColliderbuttonwithintheCollidercomponenttoaccessthisfeaturegoingforward.
http://freepdf-books.com
ArraysWecanduplicatearrayelementsthathavebeenexposedintheInspectorViewbyselectingthemandpressingCtrl+D(Cmd+D).Thiswillcopytheelementandinsertitintothearrayimmediatelyafterthecurrentselection.
Wecanremoveentriesfromanarrayofreferences(forexample,anarrayofGameObjects)bypressingShift+Delete(Cmd+Delete).Thiswillstripawaytheelementandcondensethearray.Notethatthefirstpresswillclearthereferencesettingittonull,butthesecondpresswillremovetheelement.Removingelementsinarraysofprimitivetypes(ints,floats,andsoforth)canbeaccomplishedbysimplypressingDeletewithouttheShiftkey(Cmd)modifier.
WecanusetheW,A,S,Dkeyswhileright-clickdraggingontheSceneViewtoflyaroundwiththecamera,inatypicalfirst-personcameracontrolstyle.TheQandEkeyscanbeusedtotranslatethecameraontheverticalaxis,respectively.
http://freepdf-books.com
InterfaceWecanholdAltandclickonanyhierarchyarrow(thesmallgreyarrowtotheleftofanyparentobjectname)toexpandtheobject’sfullhierarchyandnotjustthenextlayer.ThisworksonGameObjectsintheHierarchyView,foldersandPrefabswithintheProjectView,listsintheInspectorView,andsoon.
WecansaveandrestoreselectionsfromobjectsintheHierarchyorProjectViewsintypicalRTSgamestyle!MaketheselectionandpressCtrl+Alt+<0-9>(Cmd+Alt+<0-9>)tosavetheselection.PressCtrl+Shift+<0-9>(Cmd+Shift+<0-9>)torestoreit.Thisisexceptionallyusefulifwefindourselvesselectingthesamehandfulofobjectsoverandoveragainwhilewemakeadjustments.
PressingShift+SpacebarwillexpandthecurrentwindowtofilltheentireEditorscreen.Pressingitagainwillshrinkthewindowandrestoreittoitspreviouslocation.
PressingCtrl+Shift+P(Cmd+Shift+P)willtogglethePausebuttonwhileinPlayMode.
http://freepdf-books.com
OtherWecanquicklyaccessthedocumentationofanyUnitykeywordorclass,byhighlightingitinMonoDevelopandpressingCtrl+‘(Cmd+‘).ThiswillopenthedefaultbrowserandperformasearchontheUnitydocumentationforthegivenkeywordorclass.
TipNotethatuserswithEuropeankeyboardsmayalsoneedtoholddowntheShiftkey.
WiththerecentreleaseofVisualStudioToolsforUnity(VSTU),itispossibletoaccessthedocumentationinthesamewaythroughVisualStudiobypressingCtrl+Alt+M,followedbyCtrl+H(noequivalentOSXhotkey,obviously).
http://freepdf-books.com
http://freepdf-books.com
EditorinterfacetipsThefollowingcollectionoftipsrelatestotheEditoranditsinterfacecontrols.
http://freepdf-books.com
GeneralWecanprioritizewhichScriptswillhavetheirUpdateandFixedUpdatemethodscalledbeforeothers,bynavigatingtoEdit|ProjectSettings|ScriptExecutionOrder.Withtheexceptionofsometime-sensitivesystems,suchasaudioprocessing,ifwefindourselvestryingtosolvecomplexproblemsusingthisfeature,itimpliesthatwe’vegotsomefragileandtightcouplingbetweenourComponents.Fromasoftwaredesignperspective,thiscanbeawarningsignthatwemightneedtoapproachtheproblemfromanotherangle.However,itcanbehelpfultohaveparticularobjectsgettheirUpdate()andLateUpdate()functionscalledbeforeotherobjects,inordertodosomebookkeeping.
IntegratingUnityprojectswithaSourceControlsolutioncanbealittletricky.Thefirststepistoforcetheprojecttogenerate.metafilesforassets;ifwedon’tdothis,thenanyonepullingdataintotheirlocalUnityprojectmustregeneratetheirownmetadatafiles.Thiscaneasilycauseconflicts,soitisessentialthateveryoneusesthesameversions.VisiblemetadatafilescanbeenabledbynavigatingtoEdit|ProjectSettings|Editor|VersionControl|Mode|VisibleMetaFiles.Allofthe.metafileswillnowbevisiblewithinthefilestructureandavailableforuploadintoSourceControl.
ItcanalsobehelpfultoconvertcertainassetdataintoaText-onlyformat,ratherthanbinarydata,toallowmanualeditingofdatafiles.Thisturnsmanydatafilesintothemuchmorehuman-readableYAMLformat.Forinstance,ifwe’reusingScriptableObjectstostorecustomdata,wecanuseatexteditortosearchandeditthesefileswithouthavingtodoitallthroughtheUnityEditorandserializationsystem.Thiscansavealotoftime,especiallywhenhuntingforaparticulardatavalueorwhenmultieditingacrossdifferentderivedtypes.ThisoptioncanbeenabledbynavigatingtoEdit|ProjectSettings|Editor|AssetSerialization|Mode|ForceText.
TheEditorhasalogfile,whichcanbeaccessedbyopeningtheConsolewindow(wherelogmessagesareprintedoutto),clickingonthe“hamburgericon”(madefromthreehorizontallines)atthetop-right,andselectingOpenEditorLog.Ifwerecentlybuiltourproject,itwillcontainabreakdownofcompressedfilesizesofallassetsthatwerepackedintotheexecutableandorderedbysize.Thisisanextremelyhelpfulwayoffiguringoutwhichassetsareconsumingthemajorityofourapplicationfootprint(hint:it’salmostalwaysTexturefiles),andwhichfilesaretakingupmorespacethanwewouldexpect.
http://freepdf-books.com
AdditionalwindowscanbeaddedtotheEditorbyright-clickingonthetitleofanexistingwindowandselectingAddTab.Thisalsoallowsustoaddduplicatewindows,suchashavingmorethanoneInspectorViewopenatatime:
Havingduplicateviewscanbekindofredundant,unlessweusethe“lockicon”tolockthegivenviewtoitscurrentselection.Whenweselectanobject,allInspectorViewswillupdatetoshowtheobject’sdata,exceptforanylockedInspectorViews,whichcontinuetoshowthedataoftheobjecttheywerelockedto.
Commontricksthatmakeuseofwindowlockingincludethefollowing:
UsingtwoofthesameView(Inspector,Animation,andsoforth)tocomparetwoobjectsside-by-sideoreasilycopydatafromonetoanother
http://freepdf-books.com
UsingaduplicateProjectViewtomovelargedatasetsaroundTestingwhathappenstoanydependentobjectsifanobjectistweakedduringruntimeSelectingmultipleobjectsintheProjectView,thendragging-and-droppingthemintoaserializedarrayintheInspectorViewwithoutlosingtheoriginalselection
http://freepdf-books.com
TheInspectorViewWecanentercalculationsintonumericinspectorfields.Forexample,typing4*128intoanintfieldwillresolvethevalueto512,sparingusfromhavingtopulloutacalculatorordothemathinourhead.
Arrayelementscanbeduplicatedanddeletedfromalist(inthesamefashionasthehotkeysmentionedpreviously)byright-clickingontherootelementandselectingDuplicateArrayElementorDeleteArrayElement.
AComponent’scontextmenucanbeaccessedthroughboththesmallcogiconintheupper-rightorbyright-clickingonthenameoftheComponent.EveryComponent’scontextmenucontainsaResetoption,whichresetsallvaluesbacktotheirdefault,sparingusfromhavingtoresetvaluesmanually.ThisisusefulwhenworkingwithTransformComponents,asthisoptionwillsettheobject’spositionandrotationto(0,0,0)anditsscaleto(1,1,1).
It’scommonlyknownthat,ifaGameObjectwasspawnedfromaPrefab,thentheentireobjectcanberevertedbacktoitsinitialPrefabstateusingtheRevertbuttonatthetopoftheInspectorView.However,it’slesswellknownthatindividualvaluescanberevertedbyright-clickingonthenameofthevalueandselectingRevertValuetoPrefab.Thisrestorestheselectedvalue,leavingtherestuntouched.
TheInspectorViewhasadebugmodethatcanbeaccessedbyclickingonthehamburgericonnexttothelockiconandselectingDebug.ThiswilldisableallcustomInspectordrawingandrevealallrawdatawithinthegivenGameObjectanditscomponents,evenprivatedatafields.Privatefieldsaregrayed-outandcannotbemodifiedthroughtheInspectorView,butthisgivesusausefulwayofexaminingprivatedataandotherhiddenvaluesduringPlayMode.TheDebugviewalsorevealsinternalObjectIDs,whichcanbeusefulifwe’redoing“interesting”thingswithUnity’sserializationsystemandwanttoresolveconflicts.
IfwehaveanarrayofdataelementsserializedintheInspectorView,thentheyaretypicallylabeledElement<N>where<N>isthearrayindex.Thiscanmakeittrickytofindaspecificelementifourarrayelementsareaseriesofserializedclassesorstructs,whichtendtohavemultiplechildrenthemselves.However,iftheveryfirstfieldintheobjectisastring,thentheelementswillbenamedafterthevalueofthestringfield.
Whenameshobjectisselected,thePreviewwindowatthebottomoftheInspectorViewisoftenfairlysmall,makingithardtoseedetailsinthemeshandhowitwilllookwhenit
http://freepdf-books.com
appearsinourScene.But,ifweright-clickonthetopbarofthePreviewwindow,itwillbedetachedandenlarged,makingitmucheasiertoseeourmesh.Wedon’thavetoworryaboutsettingthedetachedwindowbacktoitsoriginalhomebecause,ifthedetachedwindowisclosed,thenthePreviewwindowwillreturntothebottomoftheInspectorView.
http://freepdf-books.com
TheProjectViewTheProjectView’ssearchbarallowsustofilterforobjectsofaparticulartypebyclickingonthesmallicontotherightofthesearchbar.Thisprovidesalistofdifferenttypeswecanfilterby,revealingallobjectsofthattypewithintheentireproject.However,selectingtheseoptionssimplyfillsthesearchbarwithastringofthet:<type>format,whichappliestheappropriatefilter.
Thus,wecansimplytypetheequivalentstringsintothesearchbarforthesakeofspeed.Forinstance,typingt:prefabwillfilterforallPrefabs,nomatterwheretheycanbefoundinthehierarchy;t:texturewillrevealtextures,t:scenewillrevealScenes,andsoon.Addingmultiplesearchfiltersinthesearchbarwillincludeobjectsofalltypes(itdoesnotrevealobjectswhichonlysatisfybothfilters).Thesefiltersaremodifiersinadditiontoname-basedfiltering,soaddingaplaintextstringwillcauseaname-basedsearchthroughthefilteredobjects.Forexample,t:texturenormalmapwillfindalltexturefilesthatincludethewordnormalmapintheirname.
Ifwe’remakinguseofAssetBundlesandthebuilt-inlabelingsystem,theProjectView’ssearchbaralsoallowsustohuntdownbundledobjectsbytheirlabelusingl:<labeltype>.
IfaMonoBehaviourscriptcontainsserializedreferences(using[SerializeField]orpublic)toUnityAssets,suchasMeshesandTextures,thenwecanassigndefaultvaluesdirectlyintothescriptitself.SelectthescriptfileintheProjectViewandtheInspectorViewshouldcontainafieldfortheassetforustodrag-and-dropthedefaultassignmentinto.
http://freepdf-books.com
Bydefault,theProjectViewsplitsfilesandfoldersintotwocolumnsandtreatsthemseparately.IfweprefertheProjectViewtohaveatypicalhierarchyfolderandfilestructure,thenwecansetittoOneColumnLayoutinitscontextmenu(thehamburgericonatthetopright).ThiscanbeagreatspacesaverinsomeEditorlayouts.
Right-clickingonanyobjectintheProjectViewandselectingSelectDependencieswillrevealallobjectsuponwhichthisassetreliesinordertoexist,suchasTextures,Meshes,MonoBehaviourscriptfiles,andsoon.ForScenefiles,itwilllistallentitiesreferencedwithinthatScene.Thisishelpfulifwe’retryingtoperformsomeassetcleanup.
http://freepdf-books.com
TheHierarchyViewAlesser-knownfeatureoftheHierarchyViewistheabilitytoperformcomponent-basedfilteringwithinthecurrentlyactiveScene.Confusingly,itusesthesamesyntaxasperformingtype-basedfilteringintheProjectViewandcanthereforebeaccomplishedbytypingt:<componentname>.Forexample,typingt:lightintotheHierarchyViewsearchbarwillrevealallobjectsintheScenethatcontainaLightcomponent.
Upper-orlower-casecharactersareunimportant,butthestringmustmatchthefullcomponentnameinorderforthesearchtocomplete.Componentsthatderivefromthegiventypewillalsoberevealed,sotypingt:rendererwillrevealallobjectswithderivedcomponentssuchasMeshRenderers,SkinnedMeshRenderers,andsoon.
http://freepdf-books.com
TheSceneandGameViewsTheSceneViewcameraisnotvisiblefromtheGameView,butitisgenerallyaloteasiertomovearoundandplacethroughtheuseofthehotkeysmentionedpreviously.TheEditorallowsustoaligntheselectedobjecttothesamepositionandrotationoftheScenecamerabynavigatingtoGameObject|AlignwithView(Ctrl+Shift+F/Cmd+Shift+F).ThismeansthatwecanusethecameracontrolstoplacetheScenecamerawherewewouldlikeourobjecttobe,andplacetheobjecttherebyaligningittothecamera.
Similarly,wecanaligntheSceneviewtotheselectedobjectbynavigatingtotheGameObject|AlignViewtoSelectedoption.Thisisusefulforcheckingifthegivenobjectispointingintherightdirection.
Wecanperformsimilarcomponent-basedfilteringontheSceneView,aswecanwiththeHierarchyView,usingthet:<component>syntaxwithinitssearchbar.
AttheverytoprightoftheUnityEditorisadropdownlabeledLayers.ThiscontainsaLayer-basedfilteringandlockingsystemfortheSceneView.Togglingonthe“eye”iconwillshow/hideallobjectsofthatLayerwithintheSceneView.Togglingthelockiconwillalloworpreventobjectsofthegivenlayerfrombeingselected.Thisishelpfulforthingssuchaspreventingsomeonefromaccidentallyselectingandmovingbackgroundobjectsthathavealreadybeensituatedintheperfectlocation.
AcommonlyknownandusefulfeatureoftheEditoristhatGameObjectscanbegivenspecialiconsorlabelstomakethemeasiertofindintheSceneView.Thisisparticularlyhelpfulforobjectswithnorendererbutthatwewishtofindeasily.Forinstance,objectssuchasLightsandCamerashavebuilt-iniconsthatidentifytheminourSceneViewmoreeasily.
However,thesamegizmoscanberevealedwithintheGameViewbyclickingontheGizmosbuttonatthetoprightoftheGameView.Thedropdownforthisoptiondetermineswhatgizmoswillbevisiblewhenthisoptionisenabled.
http://freepdf-books.com
PlayModeSincePlayModechangesarenotautomaticallysaved,itiswisetomodifythetintcolorappliedduringPlayModetomakeitblatantlyobviouswhichmodewe’recurrentworkingwith.ThisvaluecanbesetbynavigatingtoEdit|Preferences|Colors|Playmodetint.
ChangescanbesavedfromPlayModebysimplyusingtheclipboard.Ifwe’retweakinganobjectinPlayModeandwe’rehappywithitssettings,thenwecancopytheobjectintotheclipboardusingCtrl+C(Cmd+C),andpasteitbackintotheSceneoncePlayModeendswithCtrl+V(Cmd+V).Allsettingsontheobjectatthetimeofthecopywillbekept.ThesamecanbedonewithindividualvaluesorentirecomponentsusingtheCopyComponentandPasteComponentoptionsinthecomponent’scontextmenu.However,theclipboardcanonlycontaindataforoneobject,component,orvalue,atatime.
Anotherapproach,whichallowsustosavethedataofmultipleobjectsduringPlayMode,istocreatePrefabsfromthembydragginganddroppingthemintotheProjectWindowatruntime,oncewe’rehappywiththesettings.IftheoriginalobjectwasderivedfromaPrefab,andwewishtoupdateitacrossallinstances,thenweonlyneedtooverwritetheoldPrefabwiththenewonewecreatedbydragginganddroppingthecopyontopoftheoriginal.NotethatthisalsoworksduringPlayModeruntime,butitcanbedangeroussincethereisnodialogpop-uptoconfirmtheoverwrite.BeverycarefulnottooverwritethewrongPrefab.
WecanusetheFrameSkipbutton(thebuttontotherightofthePausebuttonintheEditor)toiterateoneframeatatime.Thiscanbeusefulforwatchingframe-by-framephysicsorgameplaybehavior.KeepinmindthatthiscausesbothoneFixedUpdateandoneUpdatetobecalledeachstep,inequalcounts,whichmaynotexactlyreflectactualruntimebehaviorwherewetendtohaveunequalcallstothesemethods.
IfthePausebuttonisenabledwhenPlayModebegins,thenthegamewillbepausedjustaftertheveryfirstframe,givingusachancetoobserveanyanomaliesthatoccurredfrominitializationofourScene.
http://freepdf-books.com
http://freepdf-books.com
ScriptingtipsThefollowingtipsareusefulfeaturestoknowwhenscripting.
http://freepdf-books.com
GeneralWecanmodifyvarioustemplatesofnewScript,Shader,andComputeShaderfiles.ThiscanbehelpfultoremovetheemptyUpdatestubswhich,aswelearned,cancauseunnecessaryruntimeoverhead.Thesefilescanbefoundinthefollowinglocations:
Windows:<Unityinstall>\Editor\Data\Resources\ScriptTemplates\OSX:/Applications/Unity/Editor/Data/Resources/ScriptTemplates/
TherecentreleaseofUnityVersion5.1introducedtheAssertclassandallowsforassert-baseddebugging,whichsomedevelopersaremorecomfortablewithasopposedtoexception-baseddebugging.ChecktheUnitydocumentationformoreinformationonAsserts:http://docs.unity3d.com/ScriptReference/Assertions.Assert.html
CallingDebug.Break()isfunctionallyequivalenttopausingtheEditorduringPlayMode,whichcanbeusefulforcatchingawkwardgraphicalbehavior,orasamoreconvenientalternativetotheabsurdhotkeyrequiredtopausetheScene(Ctrl+Shift+P).
http://freepdf-books.com
AttributesAttributesareveryusefulmeta-leveltagsthatcanbegiventoalmostanytargetinC#.Theyaremostcommonlyusedonmemberdata(fields)andclasses,allowingustoflagthemwithspecialpropertiessothattheycanbeprocesseddifferently.IntermediateandadvancedUnitydeveloperswillfinditworthwhiletoreadtheC#documentationonattributesandusetheirimaginationtocomeupwiththeirownattributesthathelpacceleratetheirworkflow.TherearequiteafewattributesbuiltintotheUnityenginethatcanbeexceptionallyusefulwhenusedintherightplace.
NoteAdvanceduserswillnotethatattributescanalsobegiventoenums,delegates,methods,parameters,events,modules,andevenassemblies.
VariableattributesPublicvariablesarefairlydangerousthingstoaddtoourcomponents,asanythingcancomealongandchangethevalueatruntime,makingithardtotracebugs,aswellasrequiringspecialhandholdingtopreventthevariablefrombeinggivenaninvalidvalue.However,publicvariablesareusuallythefirstwaythatUnitydeveloperslearntoexposevariablesintheInspectorView.Insomecases,thepublicvariableisabsolutelyintendedtobepublic,butwedon’twishittobeseenintheInspector.Insuchacase,the[HideInInspector]attributecanbeusedtohidethevariablefromtheInspector,whenevernecessary.
However,thepreferredapproachistomakeourvariablesprivateorprotectedandallowEditor-baseddevelopmentbyexposingvaluesthroughthe[SerializeField]attribute.ThisattributeallowsprivateandprotectedvariablestoberevealedintheInspectorfordesignerstomanipulate,withoutriskingothercomponentsaccidentallychangingthevariableatruntime.
The[Range]attributecanbeaddedtoanintegerorfloating-pointfieldtoconvertitintoasliderintheInspectorView.Wecangiveminimumandmaximumvalues,limitingtherangethatthevaluecancontain.
Normally,ifavariableisrenamed,evenifwedoarefactorthroughourIDE(whetheritsMonoDeveloporVisualStudio)thenthevaluesarelostassoonasUnityrecompilestheMonoBehaviourandmakestheappropriatechangestoanyinstancesofthecomponent.However,the[FormerlySerializedAs]attributeisincrediblyhelpfulifwewishtorenameavariablethathasbeenpreviouslyserialized,asitwillcopythedatafromthevariablenamedwithintheattributeintothegivenvariableduringcompilationtime.Nomorelostdataduetorenamingstuff!
Notethatitisnotsafetoremovethe[FormerlySerializedAs]attributeaftertheconversioniscompleted,unlessthevariablehasbeenmanuallychangedandresavedsincecompletion.The“.prefab”datafilewillstillcontaintheoldvariablename,andsoitstillneedsthe[FormerlySerializedField]attributetofigureoutwheretoplacethedatathenexttimethefileisloaded(forexample,whentheEditorisclosedandreopened).Thus,
http://freepdf-books.com
thisisahelpfulattribute,butextendedusedoestendtoclutterupourcodebasealot.
ClassattributesThe[SelectionBase]attributewillmarkanyGameObjectthecomponentisattachedtoastherootofselectionfortheSceneView.Thisisespeciallyusefulifwehavemeshesthatarechildrenofotherobjects,aswemightwanttheparentobjecttobeselectedwiththefirstclick,insteadoftheobjectwiththeMeshRenderercomponent.
Wecanusethe[RequireComponent]attributetoforcedesignerstoattachvitalcomponentstothesameGameObjectiftheyattempttoattachthiscomponent.Thisensuresanydependenciesthatourcodebasereliesonwillbesatisfiedbydesigners,withouthavingtowriteoutawholebunchofdocumentationforthem.
The[ExecuteInEditMode]attributewillforcetheobject’sUpdate(),OnGUI(),andOnRenderObject()methodstobecalledevenduringEditMode.However,therearecaveats:
TheUpdate()methodisonlycalledifsomethingchangesintheSceneOnGUI()isonlycalledduringGameViewevents,notforotherviewssuchastheSceneViewOnRenderObject()iscalledduringanyrepainteventfortheSceneandGameViews
However,thisgivessuchobjectsadifferentsetofeventhooksandentrypointscomparedtotypicalEditorscripts,sothisattributestillhasitsuses.
http://freepdf-books.com
LoggingWecanaddrichtexttagstodebugstrings.Tagssuchas<size>,<b>(bold),<i>(italics),and<color>allworkondebugstrings.Thiscanbehelpfulfordifferentiatingthedifferentkindsoflogmessagesandhighlightingspecificelements.
Debug.Log("<color=red>[ERROR]</color>Thisisa<i>very</i><size=14>
<b>specific</b></size>kindoflogmessage");
TheMonoBehaviourclasshasaprint()methodforconvenience,whichdoesthesamethingasDebug.Log().
Itcanhelptocreateacustomloggerclass,whichautomaticallyappends\n\ntotheendofeverylogmessage.ThiswillpushandhideawaytheunnecessaryUnityEngine.Debug:Log(Object)clutterthattendstofilltheConsolewindow.
http://freepdf-books.com
UsefullinksUnitytechnologiesprovidemanyusefultutorialsontheusageofvariousscriptingfeatures,whichareprimarilytargetedatbeginnerandintermediate-leveldevelopers.Thetutorialscanbefoundathttps://unity3d.com/learn/tutorials/topics/scripting.
There’sahelpfulpostonUnityAnswers,whichprovidesareferencelistthatcoversmanyofthedifferentscriptingandcompilationerrorswemightrunacrossduringdevelopment,whichcanbefoundathttp://answers.unity3d.com/questions/723845/what-are-the-c-error-messages.html.
ScriptableObjectsareveryusefulobjectsandanexcellentwayofstoringgamedatainaformthatdoesnotneedtobeinstantiatedatruntime.Theyworklikeanyotherclassinthattheycancontainmethodsandvariables,canbeserialized,allowpolymorphism,andsoon.Theonlytrickypartistheycanonlybecreatedthroughscripting,andmustbeloadedintomemoryatanytimeusingResources.Load().ButthisallowsustocontrolwhichScriptableObjectsarepresentinmemoryatanygiventime,givingusmorecontroloverruntimememoryconsumption.ExplainingthenuancesofScriptableObjectsherewouldtaketoomuchspace,butUnitytechnologieshaveprovidedagoodintroductoryexaminationofScriptableObjectsinthefollowingtutorialvideo:
https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/scriptable-objects
NoteNotethat,despitethecategoryoftheScriptableObjectvideo,it’sgenerallyconsideredmoreofanintermediate-leveltopic.BeginnerswouldbebestservedbyfocusingonbecomingcomfortablewithPrefabs,beforeturningthingsontheirheadthroughScriptableObjectsandtheimportantserializationtopicsthatneedtobeunderstood.
NestedCoroutinesareanotherinterestingandusefulareaofscriptingthatisnotwelldocumented.But,thefollowingthird-partyblogpost,whichcoversalotoftheinterestingdetails,shouldbeconsideredwhenworkingwithNestedCoroutines:
http://www.zingweb.com/blog/2013/02/05/unity-coroutine-wrapper
WecanfigureoutwhenaparticularfeaturewasaddedtotheUnityAPIbycheckingtheAPIhistorypageathttp://docs.unity3d.com/ScriptReference/40_history.html.
http://freepdf-books.com
http://freepdf-books.com
Customeditors/menustipsWecansetcustomhotkeysforMenuItems.Forexample,wecanmaketheKkeytriggerourMenuitemmethod,bydefiningtheMenuItemattributeasfollows:
[MenuItem("MyMenu/MenuItem_k")]
WecanalsoincludemodifierkeyssuchasCtrl(Cmd),Shift,andAltusingthe%,#,and&characters,respectively.
MenuItemsalsohavetwooverloads,whichallowsustosettwoadditionalparameters:aBooleanthatdetermineswhetherthemenuitemrequiresavalidationmethod,andanintegerthatdeterminesthemenuitem’spriorityinthehierarchy.
CheckthedocumentationforMenuItemsforacompletelistofavailablehotkeymodifiers,specialkeys,andhowtocreatevalidationmethods:
http://docs.unity3d.com/ScriptReference/MenuItem.html
Itispossibleto“ping”anobjectintheHierarchy,similartowhathappenswhenweclickonaGameObjectreferenceintheInspectorView,bycallingEditorGUIUtility.PingObject().
TheoriginalimplementationoftheEditorclass,andthewaythatmostpeoplelearnedhowtowriteEditorscripts,originallyinvolvedwritingalllogicandcontentdrawinginthesameclass.However,PropertyDrawersareaneffectivewayofdelegatingInspectordrawingtoadifferentclassfromthemainEditorclass.Thiseffectivelyseparatesinputandvalidationbehaviorfromdisplaybehavior,allowingmorefine-tunedcontrolofrenderingonaper-fieldbasisandmoreeffectivereuseofcode.WecanevenusePropertyDrawerstooverridedefaultUnitydrawingforbuilt-inobjects,suchasVectorsandQuaternions.
PropertyDrawersmakeuseofSerializedPropertiestoaccomplishserializationofindividualfields,andtheyshouldbepreferredwhenwritingeditorscripts,sincetheymakeuseofbuilt-inundo,redo,andmultieditfunctionality.Datavalidationcanbealittleproblematic,andthebestsolutionistouseOnValidate()callsonsetterpropertiesforfields.AsessionatUnite2013byUnityTechnologiesdeveloperTimCooper,whichexplainsthebenefitsandpitfallsofvariousserializationandvalidationapproachesingreatdetailathttps://www.youtube.com/watch?v=Ozc_hXzp_KU.
WecanaddentriestoComponentcontextmenusandeventhecontextmenusofindividualfieldswiththe[ContextMenu]and[ContextMenuItem]attributes.ThisallowsaneasywaytocustomizeInspectorbehaviorforourComponentswithoutneedingtowritebroadEditorclassesorcustomInspectors.
AdvancedusersmayfinditusefultostorecustomdatawithinUnitymetadatafilesthroughtheAssetImporter.userDatavariable.TherearealsoamultitudeofopportunitiestomakeuseofReflectionoftheUnitycodebase.RyanHipple’ssessionatUnite2014outlinesahugenumberofneatlittlehacksandtricksoneachievewithReflectionintheUnityEditor:
http://freepdf-books.com
https://www.youtube.com/watch?v=SyR4OYZpVqQ
AnundocumentedfeaturewasintroducedinUnityv4.5,ReorderableLists.TheseallowustohaveanInspectorViewofagenericList<T>,whichcanbeeasilyreorderedbydragginganddroppingtheelementsaround.However,thisfeatureappearstobeunfinished,asitrequiresacustomEditorclasstomakeuseofthemproperly.ThefollowingpostonUnityAnswersexplainshowtouseReorderableListsfairlysuccinctly:
http://answers.unity3d.com/questions/826062/re-orderable-object-lists-in-inspector.html
http://freepdf-books.com
http://freepdf-books.com
ExternaltipsThefollowingtipsandtricksrelatetotopicsoutsidetheUnityEditoritselfthatcanhelpUnitydevelopmentworkflowenormously.
GooglingUnity-relatedproblemsorconcernscangoalotfasterifwestartthesearchwith“site:unity3d.com“.
IftheUnityEditorcrashes,forwhateverreason,thenwecanpotentiallyrestoreourScenebyrenamingthefollowingfiletoincludethe.unityextension(forScenefiles),andcopyingitintoourAssetsfolder:
\<projectfolder>\Temp\_EditModeScene
Ifwe’redevelopingonWindows,thenthere’sverylittlereasonnottouseVisualStudioatthispoint.MonoDevelophasbeendraggedalongkickingandscreamingformanyyears,andmanydevelopershavebeenswitchingovertothemorefeature-richVisualStudioCommunityeditionformostoftheirdevelopmentworkflowneeds,particularlywithincrediblyhelpfulpluginssuchasResharper.
Forsomedevelopers,theonlyreasontobootupMonoDevelophasbeenforruntimedebuggingofcode,butwiththerecentreleaseofVisualStudioToolsforUnity(VSTU),VisualStudionowoffersbetterintegrationwiththeUnityEditor.ItevenallowsourC#codetoberuntime-debuggedthroughVisualStudioitself.Unlesswehaveparticularhangupsabouttheinterfaceorthefactthatit’smadebythebig,badMicrosoft,weshouldwanttogiveVisualStudioCommunityatryasitaccelerateourscriptcodedevelopmentinwayswehadn’texpected.
CheckoutthefollowingvideoformoreinformationonVisualStudioanditsintegrationwithUnitythroughVSTU:
https://channel9.msdn.com/Events/Visual-Studio/Visual-Studio-2015-Final-Release-Event/Building-Unity-games-in-Visual-Studio
Thereisagreatresourceforgameprogrammingpatterns(orrather,typicalprogrammingpatternsexplainedinawaythatispertinenttogamedevelopment)anditiscompletelyfreeandavailableonline:
http://gameprogrammingpatterns.com/contents.html
KeepaneyeonanysessionvideosthatcomefromUniteconferences,whenevertheyhappen(orbetteryet,trytoattendthem).There’susuallyacoupleofpanelsateachconferenceheldbyexperienceddeveloperssharinglotsofcoolandinterestingthingsthey’vebeenabletoaccomplishwiththeEngineandEditor.Inadditiontothis,makesuretokeepinvolvedintheUnitycommunity,eitherthroughtheforumsonunity3d.com,Twitter,reddit,StackOverflowandUnityAnswers,oratwhateversocialgatheringplacespopoutofthewoodworkinthecomingyears.
Everysingletipthatwasincludedinthisbookstartedoutasanideaortidbitofknowledgethatsomeonesharedsomewhereatsomepoint.So,thebestwaytokeepup-to-dateonthe
http://freepdf-books.com
besttips,tricks,andtechniquesistokeepourfingersonthepulseofwhereUnityisheadingbystayinginvolvedinitscommunity.
http://freepdf-books.com
OthertipsFinally,thefollowingsectioncontainstipsthatdidn’tquitefitintoothercategories.
It’salwaysagoodideatoorganizeourScenesusingemptyGameObjectsandnamethemsomethingsensible.Theonlydrawbacktothismethodisthattheemptyobject’sTransformisincludedduringpositionorrotationchangesandgetsincludedduringrecalculations.Properobjectreferencing,Transformchangecaching,and/oruseoflocalPosition/localRotationsolvestheproblemadequately.Inalmostallcases,thebenefitstoworkflowfromSceneorganizationaresignificantlymorevaluablethansuchtrivialperformancelosses.
AnimatorOverrideControllerswereintroducedwaybackinUnityv4.3,buttendtobeforgottenorrarelymentioned.TheyareanalternativetostandardAnimationControllersthatallowustoreferenceanexistingAnimationController,andthenoverridespecificstatestousedifferentanimationfiles.Thisallowsformuchfasterworkflowssincewedon’tneedtoduplicateandtweakAnimationControllersmultipletimes;weonlyneedtochangeahandfulofanimationstates.
WhenUnity5islaunched,itautomaticallyopenstheProjectWizard,allowingustoopenarecentproject.However,ifwepreferthedefaultbehaviorfromUnity4,whichistoautomaticallyopenthepreviousproject,wecaneditthisbehaviorbynavigatingtoEdit|Preferences|General|LoadPreviousProjectonstartup.NotethatthissettinghasadifferentnameunderUnity4andworksintheoppositefashion.YoucanseethisbynavigatingtoEdit|Preferences|General|AlwaysShowProjectWizard.NotethatiftheProjectWizardisenabled,wecanalsoopenmultipleinstancesofUnityEditorsimultaneously.
TheamazingcustomizabilityoftheUnityEditoranditsever-growingfeaturesetmeansthereareabsolutelytonsoflittleopportunitiestoimproveworkflowsandmorearebeingdiscoveredorinventedeverysingleday.TheAssetStoremarketplaceisabsolutelyrifewithassets,whichtrytosolvesomekindofproblemthatmoderndevelopersarehavingtroublewith,whichmakesitagreatplacetobrowseifwe’relookingforideasor,ifwe’rewilling,dropsomemoneytosaveusatonofhassle.Becausetheseassetstendtoselltoabroadaudience,thistendstokeeppriceslow,andwecanpickupsomeamazinglyusefultoolsandscriptsforsurprisinglylittlecost.Inalmostallcases,itwouldtakeusasignificantnumberofhourstodevelopthesamesolutionourselves.Ifweconsiderourtimeasvaluable,thenscanningtheAssetStoreonoccasioncanbeaverycost-effectiveapproachtodevelopment.
http://freepdf-books.com
http://freepdf-books.com
SummaryThisbringsustothebook’sconclusion,andhopefullyyouenjoyedtheride.Toreiterateperhapsthemostimportanttipinthisbook,alwaysmakesuretoverifythesourceoftheperformancebottleneckviaprofilingbeforemakingasinglechange.Thelastthingwewanttowastetimeonischasingghostsinthecodebase,whenfiveminutesofprofilertestingcansaveusanentiredayofwork.Also,inalotofcases,thesolutionrequiresacost-benefittinganalysistodetermineifwe’renotsacrificingtoomuchinanyotherareaattheriskofaddingfurtherbottlenecks.Makesuretohaveareasonableunderstandingoftherootcauseofthebottleneck,toavoidputtingotherperformancemetricsatrisk.
Performanceenhancementcanbealotoffunsince,duetothecomplexityofmoderncomputerhardware,smalltweakscanyieldbigrewards.Therearemanytechniquesthatcanbeimplementedtoimproveapplicationperformanceorspeedupourworkflows.Someofthesearehardtofullyrealizewithouttheexperienceandskillsnecessarytospendareasonableamountoftimeimplementingthem.Inmostcasesthefixesarerelativelysimple,oncewefindthesourceoftheproblem.So,goforthanduseyourrepositoryofknowledgetomakeyourgamesthebesttheycanbe!
http://freepdf-books.com
IndexA
Ahead-Of-Time(AOT)/ThecompilationprocessAndroidDebugBridge(ADB)tool/RemoteconnectiontoanAndroiddeviceanimationfiles
about/MeshandanimationfilesAPIhistorypage
URL/Usefullinksapproaches,performanceanalysis
about/Bestapproachestoperformanceanalysisscriptpresence,verifying/Verifyingscriptpresencescriptcount,verifying/Verifyingscriptcountongoingcodechanges,minimizing/Minimizingongoingcodechangesinternaldistractions,minimizing/Minimizinginternaldistractionsexternaldistractions,minimizing/Minimizingexternaldistractions
artefacts/Manageresolutiondownscalingexternallyattributes
variableattributes/Variableattributesclassattributes/Classattributes
audioabout/Audiofiles,loading/Loadingaudiofilesprofiling/Profilingaudioformats,encoding/Encodingformatsandqualitylevelsqualitylevels,encoding/Encodingformatsandqualitylevelsperformanceenhancements/Audioperformanceenhancements
AudioClips/TheAudioAreaaudiofiles
loading/Loadingaudiofilesadditionalloadingoptions/Additionalloadingoptions
AudioMixersURL/ApplyFiltereffectsthroughMixergroupstoreduceduplication
audioperformanceenhancementsabout/AudioperformanceenhancementsactiveAudioSourcecount,minimizing/MinimizeactiveAudioSourcecountAudioClipreferences,minimizing/MinimizeAudioClipreferencesforce,enablingtoMonofor3Dsounds/EnableForcetoMonofor3Dsoundslowerfrequencies,resampling/Resampletolowerfrequenciesencodingformats,considering/Considerallencodingformatsstreaming,preventing/Bewareofstreamingfiltereffects,applying/ApplyFiltereffectsthroughMixergroupstoreduceduplication
http://freepdf-books.com
WWW.audioClip,using/Use“WWW.audioClip”responsiblyAudioModulefiles,consideringforbackgroundmusic/ConsiderAudioModulefilesforbackgroundmusic
AudioSources/TheAudioArea
http://freepdf-books.com
Bbackendbottlenecks
about/Backendbottlenecksfillrate/Fillratememorybandwidth/MemorybandwidthVRAMlimits/VRAMlimits
boxing/Boxingbruteforcetesting/Bruteforcetesting
http://freepdf-books.com
Ccachecomponent
references/CacheComponentreferencesobtaining,withfastestmethod/ObtainingComponentsusingthefastestmethod
caveats,StaticBatchingabout/StaticBatchingcaveatsEditModedebugging/EditModedebuggingofStaticBatchingstaticmeshesinstantiationatruntime,avoiding/Avoidinginstantiatingstaticmeshesatruntimerendering/Visibilityandrenderingvisibility/Visibilityandrendering
CgstandardlibraryfunctionsURL/UseGPU-optimizedhelperfunctions
Closures/Closurescodesegments,targetedprofiling
about/TargetedprofilingofcodesegmentsProfilerscriptcontrol/ProfilerscriptcontrolcustomCPUProfiling/CustomCPUProfiling
CollisionMatrix/TheCollisionMatrixCommandBuffer
URL/MultithreadedrenderingCommonIntermediateLanguage(CIL)/TheMonoplatformCommonLanguageRuntime(CLR)/TheMonoplatformcompilationprocess,Monoplatform
about/ThecompilationprocessmanualJITcompilation/ManualJITcompilation
complexMeshCollidersavoiding/AvoidcomplexMeshColliderssimplerprimitives,using/UsesimplerprimitivessimplerMeshColliders,using/UsesimplerMeshCollidersragdolls,optimizing/OptimizingragdollsJointsandcolliders,reducing/ReduceJointsandCollidersinter-ragdollcollisions,avoiding/Avoidinter-ragdollcollisionsinactiveragdolls,disabling/Disableorremoveinactiveragdollsinactiveragdolls,removing/Disableorremoveinactiveragdolls
controls,UnityProfilerwindowabout/Controls,CPUAreaAddProfiler/ControlsRecord/ControlsDeepProfile/ControlsProfileEditor/ControlsActiveProfiler/ControlsClear/Controls
http://freepdf-books.com
FrameSelection/ControlsTimelineView/ControlsCPUArea/CPUAreaGPUArea/TheGPUAreaRenderingArea/TheRenderingAreaMemoryArea/TheMemoryAreaMemoryArea,simplemode/TheMemoryAreaMemoryArea,detailedmode/TheMemoryAreaAudioArea/TheAudioAreaPhysics3D/2DArea/ThePhysics3D/2DArea
coroutineabout/SavingProfilerdataURL/SavingProfilerdatausing/Update,Coroutines,andInvokeRepeating
Coroutines/CoroutinesCPU-boundapplication
about/CPU-boundmultithreadedrendering/MultithreadedrenderingGPUSkinning/GPUSkinning
CustomEditors/Menustips/Customeditors/menustips
http://freepdf-books.com
D2DColliders
circle/CollidertypesPolygon/Collidertypesbox/Collidertypes
3DCollidersMeshColliders/CollidertypesCapsule/CollidertypesCylinder/CollidertypesBox/Collidertypes
DeferredShadingURL/DeferredShading
Dispose()method/CustomCPUProfilingdistance-squared
considering,overdistance/Considerusingdistance-squaredoverdistanceDrawCall
about/DrawCallsRenderState,modifying/DrawCalls
DynamicBatchingabout/DynamicBatchingrequirements,URL/DynamicBatchingvertexattributes/Vertexattributesuniformscaling/Uniformscalingsummary/DynamicBatchingsummaryapplying/DynamicBatchingsummary
DynamicCollidersabout/StaticandDynamicColliders
http://freepdf-books.com
EEditor
hotkeytips/Editorhotkeytipsabout/Editorhotkeytipsinterfacetips/Editorinterfacetips
emptycallbackdeclarationsremoving/Removingemptycallbackdeclarations
ExecutionOrderURL/SavingProfilerdata
externaltipsabout/Externaltipsothertips/Othertips
http://freepdf-books.com
Ffillrate,backendbottlenecks
about/Fillrateoverdraw/OverdrawOcclusionCulling/OcclusionCullingshaderoptimization/ShaderoptimizationShadersintendedformobileplatforms,using/ConsiderusingShadersintendedformobileplatforms
Find()methodavoiding,atruntime/AvoidingtheFind()andSendMessage()methodsatruntime
FirstInFirstOut(FIFO)queue/DrawCallsFixedUpdate()method/MaximumAllowedTimestepFixedUpdateTimestep/Physicsandtimeforeachloops/TheforeachloopsForwardRendering
URL/ForwardRenderingfragmentShader/ProfilingrenderingissuesFrameDebugger/TheFrameDebuggerfront-endbottlenecks
about/FrontendbottlenecksLevelOfDetail(LOD)/LevelOfDetailGPUSkinning,disabling/DisableGPUSkinningtessellation,reducing/Reducetessellation
http://freepdf-books.com
GGameObjectnullreferencecheck
performing/FasterGameObjectnullreferencechecksgameprogrammingpatterns
URL/Externaltipsgarbagecollection,managedmemory
about/Garbagecollectionmemoryfragmentation/Memoryfragmentationatruntime/GarbagecollectionatruntimethreadedGarbagecollection/Threadedgarbagecollectiontactics/Garbagecollectiontactics
GarbageCollectormainthread/Threadedgarbagecollectionfinalizerthread/Threadedgarbagecollection
globalmessagingsystemabout/Aglobalmessagingsystemgloballyaccessibleobject/Agloballyaccessibleobjectregistration/Registrationmessageprocessing/Messageprocessingimplementing/Implementingthemessagingsystemmessage,queuing/Messagequeuingandprocessingmessage,processing/Messagequeuingandprocessingcustommessage,implementing/Implementingacustommessagemessageregistration/Messageregistrationmessage,sending/Messagesendingmessagecleanup/Messagecleanupwrappingup/Wrappingupthemessagingsystem
GPUProfiling/GPUprofilinggreedymethods/CPUArea
http://freepdf-books.com
Hheap/Managedmemoryhotkeytips,Editor
about/EditorhotkeytipsGameObjects/GameObjectsSceneView/SceneViewarrays/Arraysinterface/InterfaceUnitykeyword,accessing/Other
http://freepdf-books.com
IimmutableReferencetypes
strings/StringsareimmutableReferencetypesabout/StringsareimmutableReferencetypesstringconcatenation/Stringconcatenation
inter-objectcommunicationissuestaticclassapproach/StaticclassesSingletonComponents/SingletonComponentsreferences,assigningtopre-existingobjects/Assigningreferencestopre-existingobjectsglobalmessagingsystem/Aglobalmessagingsystem
interfacetips,Editorabout/Editorinterfacetipsgeneral/GeneralInspectorView/TheInspectorViewProjectView/TheProjectViewHierarchyView/TheHierarchyViewSceneView/TheSceneandGameViewsGameView/TheSceneandGameViewsPlayMode/PlayMode
IntermediateLanguageToC++(IL2CPP)about/ThefutureofMonoandUnityURL/ThefutureofMonoandUnity
InvokeRepeatingusing/Update,Coroutines,andInvokeRepeating
IsAliveproperty/Messagecleanupissue
focusingon/Focusingontheissue
http://freepdf-books.com
JJust-In-Time(JIT)/Thecompilationprocess
http://freepdf-books.com
LLevelOfDetail(LOD)
about/LevelOfDetailURL/LevelOfDetail
LightingandShadowingabout/LightingandShadowingURL/LightingandShadowingForwardRendering/ForwardRenderingDeferredShading/DeferredShadingVertexLitShading(legacy)/VertexLitShading(legacy)real-timeShadows/Real-timeShadows
lightingoptimizationabout/LightingoptimizationappropriateShadingMode,using/UsetheappropriateShadingModeCullingMasks,using/UseCullingMaskslightmapping,using/UseBakedLightmapsshadows,optimizing/OptimizeShadows
http://freepdf-books.com
MManagedDomain/UnitymemorydomainsManagedHeap/Managedmemorymassvalues
URL/MassMaterials
about/MaterialsandShadersMaximumAllowedTimestep/MaximumAllowedTimestep
adjusting/AdjusttheMaximumAllowedTimestepmeaninglessdata(noise)
reducing/Reducingnoisememorybandwidth,backendbottlenecks
about/Memorybandwidthlesstexturedata,using/UselesstexturedataGPUTextureCompressionformats,testing/TestdifferentGPUTextureCompressionformatstexturesampling,minimizing/Minimizetexturesamplingassetsorganization,forreducingtextureswaps/Organizeassetstoreducetextureswaps
memoryusageoptimizationabout/MemoryusageoptimizationUnitymemorydomains/Unitymemorydomainsvaluetypes/ValuetypesandReferencetypesreferencetypes/ValuetypesandReferencetypespassingbyvalue/Passbyvalueandpassbyreferencedatalayout/TheimportanceofdatalayoutUnityAPI/TheUnityAPIforeachloops/TheforeachloopsCoroutines/CoroutinesClosures/Closures.NETlibraryfunctions/.NETlibraryfunctionstemporaryworkbuffers/Temporaryworkbuffersobjectpooling/Objectpooling
meshabout/Meshandanimationfiles
MeshColliderconcave/Collidertypesconvex/Collidertypes
mobilegraphicsoptimizationabout/OptimizinggraphicsformobileDrawCalls,minimizing/MinimizeDrawCallsMaterialCount,minimizing/MinimizetheMaterialcounttexturesize,minimizing/MinimizetexturesizeandMaterialcount
http://freepdf-books.com
power-of-2,creating/Maketexturessquareandpowerof2Texturessquare,creating/Maketexturessquareandpowerof2lowestpossibleprecisionformats,usinginShaders/UsethelowestpossibleprecisionformatsinShadersAlphaTesting,allowing/AvoidAlphaTesting
Monoabout/TheMonoplatformfuture/ThefutureofMonoandUnityURL/ThefutureofMonoandUnity
MonoBehaviourUnitydocumentationURL/Removingemptycallbackdeclarations
Monoplatformabout/TheMonoplatformcompilationprocess/Thecompilationprocess
http://freepdf-books.com
N.NET
URL/ThefutureofMonoandUnity.NETlibraryfunctions/.NETlibraryfunctionsnameproperty
retrieving,avoiding/AvoidretrievingstringpropertiesfromGameObjectsNativeDomain/UnitymemorydomainsNestedCoroutines
URL/Usefullinks
http://freepdf-books.com
OOnGUI()method/LoadingProfilerdataOperatingSystem(OS)/TheMonoplatformOrderofExecution
URL/Physicsandtimeoverdraw/Fillrate
http://freepdf-books.com
Ppassbyreference/Passbyvalueandpassbyreferencepassingbyvalue/Passbyvalueandpassbyreferenceperformance-enhancingtechniques
polygoncount,reducing/Reducingpolygoncountnecessarydata,importing/Import/calculateonlywhat’sneedednecessarydata,calculating/Import/calculateonlywhat’sneededbakedanimations,considering/ConsiderbakedanimationsOptimizeMeshesoption/LetUnityoptimizemeshesmeshes,combining/Combinemeshes
performanceanalysisapproaches/Bestapproachestoperformanceanalysis
PhysicsEngineinternals/Physicsandtimeabout/PhysicsEngineinternalstime/Physicsandtimephysics/PhysicsandtimeFixedUpdateloop/TheFixedUpdateloopMaximumAllowedTimestep/MaximumAllowedTimestepphysicsupdates/Physicsupdatesandruntimechangesruntimechanges/PhysicsupdatesandruntimechangesDynamicColliders/StaticandDynamicCollidersStaticColliders/StaticandDynamicColliderscollisiondetection/CollisiondetectionCollidertypes/CollidertypesCollisionMatrix/TheCollisionMatrixRigidbodyactivestate/RigidbodyactiveandsleepingstatesRigidbodysleepingstates/Rigidbodyactiveandsleepingstatesraycasting/Rayandobjectcastingobjectcasting/Rayandobjectcasting
physicsperformanceoptimizationsabout/Physicsperformanceoptimizationsscenesetup/ScenesetupStaticColliders,using/UseStaticCollidersappropriatelyCollisionMatrix,optimizing/OptimizetheCollisionMatrixdiscretecollisiondetection,preferring/PreferdiscretecollisiondetectionFixedUpdatefrequency,modifying/ModifytheFixedUpdatefrequencyMaximumAllowedTimestep,adjusting/AdjusttheMaximumAllowedTimestepcastandbounding-volumechecks,minimizing/Minimizecastandbounding-volumecheckscomplexMeshColliders,avoiding/AvoidcomplexMeshCollidersphysicsobjects,allowingtosleep/LetphysicsobjectssleepSolverIterationCount,modifying/ModifySolverIterationCount
http://freepdf-books.com
ragdolls,optimizing/Optimizingragdollsphysics,using/Knowwhentousephysicsupgrading,toUnity5/ConsiderupgradingtoUnity5
polygoncountreducing/ReducingpolygoncountTweakMeshCompression/TweakingMeshCompressionRead-WriteEnabledflag,using/UseRead-WriteEnabledappropriately
prefabpoolingabout/Prefabpooling,PrefabpoolsPoolableComponent/PoolableComponentssystemrequirements/ThePrefabpoolingsystemobjectspawning/Objectspawninginstanceprespawning/Instanceprespawningobjectdespawning/Objectdespawningtesting/Prefabpooltestingandsceneloading/PrefabpoolingandSceneloadingsummary/Prefabpoolingsummary
ProceduralMaterialsabout/ProceduralMaterialsURL/ProceduralMaterials
Profiler.enableBinaryLogmethod/SavingandloadingProfilerdataProfiler.enabledmethod/SavingandloadingProfilerdataProfiler.logFilemethod/SavingandloadingProfilerdataProfilingandAnalysis
about/FinalthoughtsonProfilingandAnalysis
http://freepdf-books.com
RReferencetypes
about/ValuetypesandReferencetypesarrays/ArraysareReferencetypes
reflection/ManualJITcompilationrenderingissues
profiling/Profilingrenderingissuesrenderingissues,profiling
GPUProfiling/GPUprofilingFrameDebugger/TheFrameDebuggerbruteforcetesting/BruteforcetestingCPU-bound/CPU-bound
ReorderableListsabout/Customeditors/menustipsURL/Customeditors/menustips
rigidbodyproperty/ObtainingComponentsusingthefastestmethodRuntimeHelpers.PrepareMethod()method/ManualJITcompilation
http://freepdf-books.com
Sscenesetup
about/Scenesetupscaling/Scalingpositioning/Positioningmassvalues/Mass
ScriptableObjectsURL/Usefullinks
scriptingtipsabout/Scriptingtipsgeneral/Generalattributes/Attributeslogging/Loggingusefullinks/Usefullinks
SendMessage()methodavoiding,atruntime/AvoidingtheFind()andSendMessage()methodsatruntime
Shaderabout/MaterialsandShaders
Shaders,intendedformobileplatformsusing/ConsiderusingShadersintendedformobileplatformssmalldatatypes,using/Usesmalldatatypeschangingprecision,avoiding/Avoidchangingprecisionwhileswizzlingswizzling/AvoidchangingprecisionwhileswizzlingGPU-optimizedhelperfunctions,using/UseGPU-optimizedhelperfunctionsunnecessaryfeatures,disabling/Disableunnecessaryfeaturesunnecessaryinputdata,removing/Removeunnecessaryinputdatanecessaryvariables,exposing/Onlyexposenecessaryvariablesmathematicalcomplexity,reducing/Reducemathematicalcomplexity,Reducetexturelookupsconditionalstatements,avoiding/Avoidconditionalstatementsdatadependencies,reducing/ReducedatadependenciesSurfaceShaders/SurfaceShadersShader-basedLOD,using/UseShader-basedLOD
ShadowCascadesfeatureURL/OptimizeShadows
skinning/GPUSkinningSparseTexturing
about/SparseTexturesURL/SparseTextures
sphericalharmonics/ForwardRenderingstack/ManagedmemoryStaticBatching
http://freepdf-books.com
about/StaticBatchingrequirements/StaticBatchingStaticflag/TheStaticflagmemoryrequirements/MemoryrequirementsMaterialreferences/Materialreferencescaveats/StaticBatchingcaveatssummary/StaticBatchingsummary
StaticCollidersabout/StaticandDynamicCollidersusing/UseStaticCollidersappropriately
http://freepdf-books.com
Ttagproperty
retrieving,avoiding/AvoidretrievingstringpropertiesfromGameObjectstemporaryworkbuffers/TemporaryworkbuffersTexture/Texturefilestexturefiles
about/Texturefilescompressionformats/Compressionformatsperformanceenhancements/Textureperformanceenhancements
textureperformanceenhancementsabout/Textureperformanceenhancementsfilesize,reducing/ReduceTexturefilesizeMipMaps,using/UseMipMapswiselyresolutiondownscaling,managing/ManageresolutiondownscalingexternallyAnisotropicFilteringlevels,adjusting/AdjustAnisotropicFilteringlevelsatlasing,considering/ConsiderAtlasingcompressionratesfornon-squaretextures,adjusting/Adjustcompressionratesfornon-squareTexturesSparseTexturing/SparseTexturesProceduralMaterials/ProceduralMaterials
theMSDNC#ProgrammingGuideURL/Registration
TotalAllocatedblock/ThreadedgarbagecollectionTransformchanges
caching/ConsidercachingTransformchanges
http://freepdf-books.com
UUnity
URL/SavingProfilerdata,ThefutureofMonoandUnityfuture/ThefutureofMonoandUnity
Unity3D/TheUnityProfilerUnity5.0/TheUnityProfilerUnityAPI/TheUnityAPIUnitydocumentation
URL/ConsiderAtlasingUnityEditor
profiling/Editorprofilingreflection,URL/Customeditors/menustips
UnityEditor;about/TheUnityProfilerUnitymemorydomains
about/Unitymemorydomainsnativememory/Nativememorymanagedmemory/Managedmemory
UnityProfilerabout/TheUnityProfiler,UnderstandingtheProfilerlaunching/LaunchingtheProfilerUnityEditor/EditororstandaloneinstancesStandaloneInstances/EditororstandaloneinstancesUnityWebplayerconnection,connecting/TheUnityWebplayerconnectionconnecting,toiOSdevice/RemoteconnectiontoaniOSdeviceconnecting,toAndroiddevice/RemoteconnectiontoanAndroiddevicewindow/TheProfilerwindow
UnityProfilerdatasaving/SavingandloadingProfilerdata,SavingProfilerdataloading/SavingandloadingProfilerdata,LoadingProfilerdata
UnityProfilerwindowabout/TheProfilerwindowcontrols/Controls
UnityroadmapURL/ThefutureofMonoandUnity
UnityWebplayer/LaunchingtheProfilerUnloadAudioData()method/Additionalloadingoptionsunusedscriptsandobjects
disabling/Disablingunusedscriptsandobjectsdisabling,byvisibility/Disablingobjectsbyvisibilitydisabling,bydistance/Disablingobjectsbydistance
http://freepdf-books.com
Vvaluetypes
about/ValuetypesandReferencetypesstructs/StructsareValuetypes
VerticalSync(VSync)/MinimizinginternaldistractionsVisualStudio
URL/ExternaltipsVisualStudioToolsforUnity(VSTU)/OtherVRAMlimits,backendbottlenecks
about/VRAMlimitstexturepreloading/Texturepreloadingtexturethrashing/Texturethrashing
http://freepdf-books.com
Top Related