游戏中特效加载原理和优化方法

游戏项目中一般会用到一些优化手段,大部分优化的是资源的大小对内存的影响,比如项目中特效的加载会拥有两个类:photoFactoryEffect和photoMutilEffect

photoFactory与photoMutil的区别

photoFactory是一个优化类,作用就是减轻通过photoMutil生成的特效克隆go的大小,优化的是内存

photoMutil生成一个挂载特效rt的go,真正管理特效的是photoProducer。

特效加载原理

特效的gameObject通过camaro和rt映射到其他的gameObject上,一个特效只会加载一次,利用rt分发多份。

// PhotoEffectFactory.lua module(“logic.common.ugui.PhotoEffectFactory”,package.seeall) local PhotoEffectFactory = class(“PhotoEffectFactory”) function PhotoEffectFactory:ctor() self._factoryContainer = goutil.create(“PHOTOFACTORYROOT”, false) GameUtils.setPos(self._factoryContainer, -2500, 0, 0) – 所有生效的特效 self._effects={} – 池化 self._pool=ObjectPool.New(20,PhotoEffectFactory._createEffect, PhotoEffectFactory._disposeEffect, PhotoEffectFactory._resetEffect ) end function PhotoEffectFactory._createEffect() local effect = {} local container = goutil.create(“eff”, true) container.layer = Framework.LayerUtil.NameToLayer(SceneLayer.UI) effect.container = container effect.photoEff = Framework.LuaComponentContainer.Add(container, PhotoMultiEffect) effect.photoEff:setEffectLoadedCallback(PhotoEffectFactory._onEffectLoaded, PhotoEffectFactory.instance) –克隆的特效 effect.clones={} – 引用数 effect.count=0 return effect end function PhotoEffectFactory._resetEffect(effect) effect.count=0 effect.clones={} effect.photoEff:clear() end function PhotoEffectFactory._disposeEffect(effect) if not goutil.isNil(effect.container) then goutil.destroy(effect.container) end end – 外部接口:提供256 * 144规格的RT特效克隆体 –uiWidth, uiHeight 需要显示的ui尺寸,请根据具体界面情况传入 function PhotoEffectFactory:getSmallClonePhotoEffect(url, uiWidth, uiHeight) return self:getClonePhotoEffect(url, PhotoUtil.SmallRTWidth, PhotoUtil.SmallRTHeight, uiWidth, uiHeight) end – 外部接口:重新播放RT特效 function PhotoEffectFactory:rePlayPhotoEffect(url) local photoData = url and self._effects[url] if photoData then if not goutil.isNil(photoData.orgGoInst) then goutil.setActive(photoData.orgGoInst, false) goutil.setActive(photoData.orgGoInst, true) end end end – 获取克隆的RT特效预制物 –uiWidth, uiHeight 需要显示的ui尺寸,请根据具体界面情况传入 function PhotoEffectFactory:getClonePhotoEffect(url, rtWidth, rtHeight, uiWidth, uiHeight) if GameUtils.isEmptyString(url) then return end – 如果未生成 local eff=self._effects[url] if eff==nil then eff=self._pool:fetchObject() local container=eff.container rtWidth = rtWidth or PhotoUtil.PartRTWidth rtHeight = rtHeight or PhotoUtil.PartRTHeight goutil.setWidth(container.transform, uiWidth or rtWidth)–ui尺寸默认是rt大小 goutil.setHeight(container.transform, uiHeight or rtHeight) – 放在factory root 下 goutil.addChildToParent(eff.container, self._factoryContainer) – rename eff.container.name=url self._effects[url]=eff –临时处理,后续优化 if rtWidth == PhotoUtil.SmallRTWidth and rtHeight == PhotoUtil.SmallRTHeight then eff.photoEff:showSmallEffect(url) else eff.photoEff:showPartEffect(url) end end eff.count = eff.count + 1 –只是克隆rawImage,transform local objClone = goutil.create(tostring(eff.count),true) objClone.layer = Framework.LayerUtil.NameToLayer(SceneLayer.UI) GameUtils.copyRectTransform(objClone:GetComponent(goutil.Type_RectTransform), eff.container:GetComponent(goutil.Type_RectTransform)) GameUtils.copyRawImage(objClone:AddComponent(typeof(UnityEngine.UI.RawImage)), eff.container:GetComponent(typeof(UnityEngine.UI.RawImage))) – local objClone = goutil.clone(self._urlToPhotoDict[url].container, tostring(self._urlToPhotoDict[url].count)) —————————– – 判断当前特效是否已经加载完成,是则直接显示 if eff.photoEff:checkIsFinishLoadByUrl(url) then local rawImageComp = objClone:GetComponent(typeof(UnityEngine.UI.RawImage)) if rawImageComp then rawImageComp.enabled = true end end table.insert(eff.clones, objClone) return objClone end – 判断创建出来的GameObject的RT与复制品的RT是否指向同一张RT,如果不是,则需要将复制品指向的RT修改过来 function PhotoEffectFactory:_pointToSameRT(url) local photoData = self._effects[url] if photoData and photoData.photoEff then local orgRawImage = photoData.photoEff:getRawImage() if orgRawImage then local goCopy = photoData.clones and photoData.clones[1] if not goutil.isNil(goCopy) then local copyRawImage = goCopy:GetComponent(typeof(UnityEngine.UI.RawImage)) if copyRawImage and orgRawImage.texture ~= copyRawImage.texture then for i = 1, #photoData.clones do goCopy = photoData.clones[i] if not goutil.isNil(goCopy) then copyRawImage = goCopy:GetComponent(typeof(UnityEngine.UI.RawImage)) if copyRawImage then copyRawImage.texture = orgRawImage.texture end end end end end end end end function PhotoEffectFactory:turnOn(url) if self._effects and self._effects[url] then if self._effects[url].photoEff then self._effects[url].photoEff:turnOn() self:_pointToSameRT(url) end end end function PhotoEffectFactory:turnOff(url) if self._effects and self._effects[url] then if self._effects[url].photoEff then self._effects[url].photoEff:turnOff() end end end function PhotoEffectFactory:_onEffectLoaded(goInst, res) if res and res.ResPath then local data = self._effects and self._effects[res.ResPath] if data then data.orgGoInst = goInst if data.clones then local rawImageComp for i = 1, #data.clones do if not goutil.isNil(data.clones[i]) then rawImageComp = data.clones[i]:GetComponent(typeof(UnityEngine.UI.RawImage)) if rawImageComp then rawImageComp.enabled = true end end end end end end end function PhotoEffectFactory:destroyClonePhotoEffect(url,justclear) local photoEffect=self._effects and self._effects[url] if photoEffect then photoEffect.count = photoEffect.count - 1 if photoEffect.count <= 0 then self._pool:returnObject(photoEffect) self._effects[url]=nil end end end – 预留接口:清除所有的PhotoEffect function PhotoEffectFactory:destroy() if self._effects then self._pool:clear() self._effects={} end end PhotoEffectFactory.instance = PhotoEffectFactory.New() return PhotoEffectFactory

// photoMultiEffect.lua module(“logic.common.ugui.PhotoMultiEffect”, package.seeall) local PhotoMultiEffect = class(“PhotoMultiEffect”) function PhotoMultiEffect:ctor(compContainer) self._compContainer = compContainer self._go = self._compContainer.gameObject self._multiLoader = MultiResLoader.New() –资源的引用都在这里引用 self._photo = Framework.PhotoBase.Add(self._go) self._rtWidth = PhotoUtil.PartRTWidth self._rtHeight = PhotoUtil.PartRTHeight self._effectLoadedCallback = nil self._effectLoadedCallbackObj = nil self._effectOnePlayFinishCallback = nil self._effectOnePlayFinishCallbackObj = nil self._bInitUVRect = true self._urls = {} self._goInstList = {} PhotoUtil.initPhotoSetting() self:_initRawImage() end function PhotoMultiEffect:_initRawImage() if not goutil.isNil(self._go) then self._rawImage = self._go:GetComponent(typeof(UnityEngine.UI.RawImage)) if self._rawImage == nil then self._rawImage = self._go:AddComponent(typeof(UnityEngine.UI.RawImage)) end self._rawImage.enabled = false self._rawImage.raycastTarget = false self._rawImage.material = PhotoUtil.getEffMaterial() end end function PhotoMultiEffect:_setRawImageUVRect(rtWidth, rtHeight) if self._bInitUVRect and self._rawImage then self._rtWidth = rtWidth self._rtHeight = rtHeight PhotoUtil.setRTCapacity(rtWidth, rtHeight) –计算RawImage的大小以及偏移 local uvRectW = math.min(1, goutil.getWidth(self._go.transform) / rtWidth) local uvRectH = math.min(1, goutil.getHeight(self._go.transform) / rtHeight) local uvRectX = (1 - uvRectW) * 0.5 local uvRectY = (1 - uvRectH) * 0.5 self._rawImage.uvRect = UnityEngine.Rect.New(uvRectX, uvRectY, uvRectW, uvRectH) self._bInitUVRect = false end end – 该接口只提供给PhotoEffectFactory使用,其他地方不允许调用 function PhotoMultiEffect:getRawImage() return self._rawImage end function PhotoMultiEffect:setEffectLoadedCallback(callback, callbackObj) self._effectLoadedCallback = callback self._effectLoadedCallbackObj = callbackObj end function PhotoMultiEffect:setEffectOnePlayFinishCallback(callback, callbackObj) self._effectOnePlayFinishCallback = callback self._effectOnePlayFinishCallbackObj = callbackObj end function PhotoMultiEffect:setClickEnable(bRaycastTarget) if self._rawImage then self._rawImage.raycastTarget = bRaycastTarget end end function PhotoMultiEffect:setClickCallback(callback, callbackObj) if callback == nil then return end if goutil.isNil(self._go) then return end if not self._btnClick then local compButton = self._go:GetComponent(typeof(UnityEngine.UI.Button)) if compButton == nil then self._go:AddComponent(typeof(UnityEngine.UI.Button)) end self._btnClick = Framework.ButtonAdapter.Get(self._go) self._btnClick:AddClickListener(callback, callbackObj) end end – 小图标规格的RT特效 256 * 144 function PhotoMultiEffect:showSmallEffect(…) local urls = {…} if not urls or #urls == 0 then return end self:loadRes(urls, PhotoUtil.SmallRTWidth, PhotoUtil.SmallRTHeight) end – 中等规格的RT特效 512 * 288 function PhotoMultiEffect:showPartEffect(…) local urls = {…} if not urls or #urls == 0 then return end self:loadRes(urls, PhotoUtil.PartRTWidth, PhotoUtil.PartRTHeight) end – 全屏规格的RT特效 1280 * 720 function PhotoMultiEffect:showFullScreneEffect(…) local urls = {…} if not urls or #urls == 0 then return end self:loadRes(urls, PhotoUtil.RTWidth, PhotoUtil.RTHeight) end – 最大全屏规格的RT特效 1560 * 720,不能再接受更大的尺寸规格 function PhotoMultiEffect:showMaxScreneEffect(…) local urls = {…} if not urls or #urls == 0 then return end self:loadRes(urls, PhotoUtil.MaxRTWidth, PhotoUtil.MaxRTHeight) end function PhotoMultiEffect:loadRes(urls, rtWidth, rtHeight) if self._photo == nil then return end self:_setRawImageUVRect(rtWidth, rtHeight) self._photo:TurnOn(rtWidth, rtHeight) self._isOn = true local renderTexture = self._photo and self._photo.producer and self._photo.producer.renderTexture if renderTexture == nil then printError(“renderTexture is nil, self._go=”, self._go.name) self._rawImage.enabled = false return – 重复 photobase.turnOn里已经做了 – else – self._rawImage.texture = renderTexture end local len = #urls for i = 1, len do if not self._urls then self._urls = {} end table.insert(self._urls, urls[i]) self._multiLoader:addResPath(urls[i]) end PhotoUtil.addUsingRTCount(self, rtWidth, rtHeight) –暂时没有全部加载完毕逻辑回调 self._multiLoader:load(_, self._onSingleResLoaded, self) end function PhotoMultiEffect:_onSingleResLoaded(res) if res.IsSuccess then if goutil.isNil(self._go) or self._photo == nil then self:clear() return end –9/4修改:self._isOn为false表示有两种情况,一种是在特效加载完成之前调用了turnOff接口,一种是调用了clear接口; –按道理调用clear接口并不会回调到这里,所以处理第一种情况就好 if not self._isOn then if self._urls == nil or #self._urls == 0 then self:turnOff() return end end local goInst if self._urls then for i = #self._urls, 1, -1 do if res.ResPath == self._urls[i] then table.remove(self._urls, i) goInst = goutil.clone(res:GetAsset(nil, nil)) goInst.layer = Framework.LayerUtil.NameToLayer(PhotoUtil.LayerName) table.insert(self._goInstList, goInst) break end end end if goInst then if self._photo then –检查当前是turnOff还是turnOn – goutil.setActive(goInst, self._isOn) self._rawImage.enabled = self._isOn if self._isOn then self._photo:ShowTarget(goInst, true) else goutil.addChildToParent(goInst, self._go) end end if self._effectLoadedCallback then if self._effectLoadedCallbackObj then self._effectLoadedCallback(self._effectLoadedCallbackObj, goInst, res) else self._effectLoadedCallback(goInst, res) end end –检查美术是否有挂载EffectPlayer的组件 local _effectCSComp = goInst:GetComponent(typeof(Pjg.EffectPlayer)) if _effectCSComp and not goutil.isNil(_effectCSComp) then –参数默认以组件的,暂不支持外部设置参数 _effectCSComp:AddFinishListener(self._onEffectOnePlayFinish, self) –加载好就立即执行play _effectCSComp:Play() end end end end –暂时没有全部播放完毕逻辑回调 function PhotoMultiEffect:_onEffectOnePlayFinish() if goutil.isNil(self._go) then return end if self._effectOnePlayFinishCallback then if self._effectOnePlayFinishCallbackObj then self._effectOnePlayFinishCallback(self._effectOnePlayFinishCallbackObj) else self._effectOnePlayFinishCallback() end end end function PhotoMultiEffect:getFirstUrl() return self._urls and self._urls[1] end function PhotoMultiEffect:getUrlString() return table.concat(self._urls, “#”) end – 根据传入的路径判断该特效是否已经加载完成 function PhotoMultiEffect:checkIsFinishLoadByUrl(url) local bLoaded = false if self._multiLoader and self._multiLoader:getResource(url) then return true end end – bReplay:是否重播,有些特效需要再次打开的时候调用 – 注意:重播只针对本身是显示状态的特效,如果本身特效由于功能需要自己被隐藏,bReplay传入true也是没法重播 function PhotoMultiEffect:turnOn(bReplay) if not self._isOn then if self._rawImage then self._rawImage.enabled = true end if self._goInstList and self._photo then self._photo:TurnOn(self._rtWidth, self._rtHeight) PhotoUtil.addUsingRTCount(self, self._rtWidth, self._rtHeight) local goInst for i = 1, #self._goInstList do goInst = self._goInstList[i] if not goutil.isNil(goInst) then if bReplay and goInst.activeSelf then goutil.setActive(goInst, false) goutil.setActive(goInst, true) end –检查美术是否有挂载EffectPlayer的组件 local _effectCSComp = goInst:GetComponent(typeof(Pjg.EffectPlayer)) if _effectCSComp and not goutil.isNil(_effectCSComp) then _effectCSComp:Stop() _effectCSComp:RemoveFinishListener() –参数默认以组件的,暂不支持外部设置参数 _effectCSComp:AddFinishListener(self._onEffectOnePlayFinish, self) _effectCSComp:Play() end self._photo:ShowTarget(goInst, true) end end end self._isOn = true end end function PhotoMultiEffect:turnOff() if goutil.isNil(self._go) then return end if self._isOn then if self._rawImage then self._rawImage.enabled = false end if self._goInstList and self._photo then for i = 1, #self._goInstList do if not goutil.isNil(self._goInstList[i]) then –goutil.setActive(self._goInstList[i], false) goutil.addChildToParent(self._goInstList[i], self._go) end end end if self._photo then self._photo:TurnOff() PhotoUtil.reduceUsingRTCount(self, self._rtWidth, self._rtHeight) end self._isOn = false end end function PhotoMultiEffect:clear() self._urls = {} if self._multiLoader then self._multiLoader:clear() end if self._goInstList then for i = 1, #self._goInstList do if not goutil.isNil(self._goInstList[i]) then –检查美术是否有挂载EffectPlayer的组件 local _effectCSComp = self._goInstList[i]:GetComponent(typeof(Pjg.EffectPlayer)) if _effectCSComp and not goutil.isNil(_effectCSComp) then _effectCSComp:Stop() _effectCSComp:RemoveFinishListener() end goutil.destroy(self._goInstList[i]) end end self._goInstList = {} end if self._photo then self._photo:TurnOff() PhotoUtil.reduceUsingRTCount(self, self._rtWidth, self._rtHeight) end self._isOn = false if goutil.isNil(self._go) then return end if self._rawImage then self._rawImage.enabled = false end self._bInitUVRect = true end function PhotoMultiEffect:OnDestroy() self:clear() self._multiLoader=nil self._compContainer = nil self._go = nil self._photo = nil self._rawImage = nil self._effectLoadedCallback = nil self._effectLoadedCallbackObj = nil self._effectOnePlayFinishCallback = nil self._effectOnePlayFinishCallbackObj = nil self._urls = nil self._goInstList = nil if self._btnClick then self._btnClick:RemoveClickListener() self._btnClick = nil end end – 判断是否是空闲,需要加载特效 function PhotoMultiEffect:isFree() return not self._isOn and self._multiLoader.totalCount==0 end return PhotoMultiEffect

// PhotoBase.cs using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace Framework { public class PhotoBase : MonoBehaviour { protected PhotoProducer _producer; protected RawImage _rawImg; public static PhotoBase Add(GameObject go) { return go.AddComponentOnce(); } void Awake() { //2018/8/8修改,防止gameObject或父节点被隐藏,lua已经初始化RawImage后显示gameObject的时候Awake接口被调用 _rawImg = gameObject.GetComponent (); if (_rawImg == null) { _rawImg = gameObject.AddComponentOnce(); _rawImg.raycastTarget = false; _rawImg.texture = null; _rawImg.material = PhotoProducerCache.Instance.GetPhotoMaterial(); } } protected virtual void OnEnable() { if(_producer != null) { _producer.producerContainer.SetActive(true); } } protected virtual void OnDisable() { if(_producer != null && _producer.producerContainer != null) { _producer.producerContainer.SetActive(false); } } public void EnableClick(bool isEnable) { if(isEnable) { _rawImg.raycastTarget = true; } else { _rawImg.raycastTarget = false; } } //在turn on的时候才有值 public PhotoProducer producer { get{ return _producer;} } //在turn on的时候才能调用 public void SetCameraPosition(float x,float y,float z) { GlobalObject.gVec3.x = x; GlobalObject.gVec3.y = y; GlobalObject.gVec3.z = z; _producer.rtCamera.transform.localPosition = GlobalObject.gVec3; } //在turn on的时候才能调用 public void SetCameraRotation(float x,float y,float z) { _producer.rtCamera.transform.localRotation = Quaternion.Euler(x,y,z); } /** * 将一个物体放入拍摄空间内 * */ public void ShowTarget(GameObject go,bool allSameLayer) { if(allSameLayer) go.SetLayerRecursively(PhotoProducerCache.Instance.GetCullingLayer()); else go.layer = PhotoProducerCache.Instance.GetCullingLayer(); go.transform.SetParent(_producer.targetContainer.transform,false); } /** * 把拍摄目标全部移除 * */ public void RemoveAllTargets() { GameObjectUtil.ClearChildren(_producer.targetContainer); } public void TurnOn() { if(_producer == null) { Rect size = (gameObject.transform as RectTransform).rect; _producer = PhotoProducerCache.Instance.Fetch(Mathf.CeilToInt(size.width),Mathf.CeilToInt(size.height)); _rawImg.texture = _producer.renderTexture; } if(this.gameObject.activeInHierarchy) { _producer.producerContainer.SetActive(true); } else { _producer.producerContainer.SetActive(false); } } ///

/// 重载TurnOn接口,支持外部传入需要创建的RT大小 /// public void TurnOn(float width, float height) { if(_producer == null) { if (_rawImg == null) { _rawImg = gameObject.GetComponent (); } _producer = PhotoProducerCache.Instance.Fetch(Mathf.CeilToInt(width),Mathf.CeilToInt(height)); _rawImg.texture = _producer.renderTexture; } if(this.gameObject.activeInHierarchy) { _producer.producerContainer.SetActive(true); } else { _producer.producerContainer.SetActive(false); } } public bool IsOn { get{ return _producer != null;} } public void TurnOff() { if(_producer != null) { PhotoProducerCache.Instance.Return(_producer); _producer = null; } } void OnDestroy() { TurnOff(); } } }

// photoProducer.cs using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Framework { public class PhotoProducer { private GameObject _rtContainer; private GameObject _targetContainer; private Camera _rtCamera; private RenderTexture _rt; public GameObject producerContainer { get { return _rtContainer;} } public GameObject targetContainer { get {return _targetContainer;} } public Camera rtCamera { get {return _rtCamera;} } public RenderTexture renderTexture { get {return _rt;} } public PhotoProducer(int width,int height,int cullingMask,int rtDepth,RenderTextureFormat rtFormat,int antiAliasing) { _rtContainer = new GameObject(“PhotoProducer_“ + PhotoProducerCounter.GetCounter()); _targetContainer = new GameObject(“TargetContainer”); _targetContainer.transform.SetParent(_rtContainer.transform,false); _rtContainer.transform.position = PhotoProducerCounter.GenPosition(); GameObject.DontDestroyOnLoad(_rtContainer); GameObject cameraObj = new GameObject(“Camera”); cameraObj.transform.SetParent(_rtContainer.transform, false); this._rtCamera = cameraObj.AddComponent(); this._rtCamera.useOcclusionCulling = false; _rtCamera.enabled = true; _rtCamera.clearFlags = CameraClearFlags.SolidColor; _rtCamera.backgroundColor = new Color(0, 0, 0, 0); _rtCamera.cullingMask = cullingMask; _rtCamera.targetTexture = _rt; _rtCamera.farClipPlane = 1000; _rt = new RenderTexture(width, height,rtDepth,rtFormat); if(antiAliasing > 0) _rt.antiAliasing = antiAliasing; _rtCamera.targetTexture = _rt; } public void Dispose() { if (_rtCamera != null) { _rtCamera.targetTexture = null; } if(_rt != null) { GameObject.Destroy(_rt); _rt = null; } GameObjectUtil.Destroy(_rtContainer); } } }

// photoProducerCache.cs using System.Collections.Generic; using UnityEngine; namespace Framework { /** * UI特效公用的RenderTexture缓存 以及 用于绘制的Camera和GameObject * RenderTexture的大小 有若干种规格,游戏项目中规划好预定的几种规格规范 * 规格1 1136 640 * 规格2 200*200 * */ public class PhotoProducerCache : Singleton { //一些设置 private int _photoCullingLayer = 0; private int _photoCullingMask = 0; private int _rtDepth = 32; private RenderTextureFormat _rtFormat = RenderTextureFormat.ARGB32; private int _antiAliasing = 2; private Material _photoMat; //每种规格 对应的 缓存RenderTexture列表 private Dictionary<int,List> _cache = new Dictionary<int,List>(); private Dictionary<int,int> _capacityDict = new Dictionary<int, int>(); public void SetAALevel(int aaLevel) { this._antiAliasing = aaLevel; } public void SetCullingLayer(int mask) { _photoCullingLayer = mask; _photoCullingMask = 1<<_photoCullingLayer; } public int GetCullingLayer() { return _photoCullingLayer; } public void SetRenderTextureDepth(int depth) { _rtDepth = depth; } public void SetRenderTextureFormat(RenderTextureFormat format) { _rtFormat = format; } public void SetCapacity(int width,int height,int capacity) { int key = (width << 16) + height; _capacityDict[key] = capacity; } public void SetPhotoMaterial(Material mat) { _photoMat = mat; } public Material GetPhotoMaterial() { return _photoMat; } public PhotoProducer Fetch(int width,int height) { if(width <= 0 || height <= 0) return null; int key = (width << 16) + height; PhotoProducer producer; if(_cache.ContainsKey(key)) { List producers = _cache[key]; if(producers.Count > 0) { producer = producers[producers.Count-1]; producer.targetContainer.SetActive(true); producers.RemoveAt(producers.Count-1); } else { producer = new PhotoProducer(width,height,_photoCullingMask,_rtDepth,_rtFormat,_antiAliasing); } } else { producer = new PhotoProducer(width,height,_photoCullingMask,_rtDepth,_rtFormat,_antiAliasing); } return producer; } public void Return(PhotoProducer producer) { if(producer == null) return; RenderTexture rt = producer.renderTexture; int key = (rt.width << 16) + rt.height; int capacity; _capacityDict.TryGetValue(key,out capacity); if(capacity > 0) { List producers; _cache.TryGetValue(key,out producers); if(producers == null) { producers = new List(); _cache[key] = producers; } if(producers.Count < capacity) { if (producer.producerContainer) { producer.producerContainer.SetActive(false); } producers.Add(producer); } else //剩余容量不够了,销毁掉 { producer.Dispose(); } } else //不需要缓存的 { producer.Dispose(); } } } }