固定视角的特效优化方式(1)

我们有个游戏需要在特定的角度下进行。但游戏的特效非常的多和复杂,例如其中一些小道具的dc就达到6个。

其中一个优化方法当然是从源头优化,就是美术制作时就减少,但这样有几个问题,第一是美术可能需要重新做,时间上不可控。第二就是减少也很难,而且可能有些特效是公用的,这个情况下合并多个特效一起也并不是好事。

粒子特效的特点就是透明度粒子比较普通,同时发射得比较集中,所以overdraw普遍比较高。

如果不改变其他得前提下要优化粒子就是把所有同一材质和mesh的放在同一个“Order in layer”,当然要注意这个值不要跟其他mesh重叠了,不然会打乱批次。

这可能是最简单的优化方案了。但是他是基于我们设计上也清楚这个数值作用的前提下。

一开始已经说明了是固定视角,说明他的角度不变。这个情况下有个特点,就是你走到哪,怎么玩,看到的一种特效都是恒定的循环表现。这个做法不适合随机特效和拖尾特效等不确定的特效

那么我们可以考虑把他做成序列帧的方式播放,分两个阶段:

1.录制阶段:录制阶段是创建摄像机,把特效每帧渲染到摄像机的targetrender上,然后这个rt保存起来,形成了rt列表。

2.播放阶段:隐藏特效,播放rt列表。

 

录制状态大体代码:

public class RecordFxState : BaseState
{
    private List<RenderTexture> mFxRTs;

    private int cameraLayer;
    private const float currentFrameRate = 60;
    private int realDuration = 0;

    public override void Init(FxRTData data)
    {
        base.Init(data);
        //currentFrameRate = Application.targetFrameRate;
        realDuration = (int)(mFxrtData.duration* currentFrameRate);
        cameraLayer = data.CameraLayer;
        modifyCameraProperty();
        //SfxMgr.instance.ReleaseFxCamRT();
    }

    public override void OnUpdate()
    {
        base.OnUpdate();
        if (!FxRTData.HasRT(mFxrtData.FXName) && mFxrtData.RootTransform)
        {
            mFxRTs = FxRTData.GetRTs(mFxrtData.FXName);
            if (mFxRTs.Count < realDuration)
            {
                RenderTexture rt = RenderTexture.GetTemporary(fxCam.targetTexture.descriptor);
                fxCam.targetTexture = rt;
                mFxRTs.Add(rt);
            }
            else
            {
                ReleaseFxCamRT();
                AddDicBool(FxRTData.FxHasRTList, mFxrtData.FXName, true);
                ALUGUICommon.setGameObjDisable(mFxrtData.RootTransform.gameObject);
            }
        }
    }

    private void AddDicBool(Dictionary<string, bool> dic, string str, bool val)
    {
        if (dic.ContainsKey(str))
        {
            dic[str] = val;
        }
        else
        {
            dic.Add(str, val);
        }
    }

    private Camera fxCam = null;

    public void ReleaseFxCamRT()
    {
        if (fxCam != null)
        {
            //RenderTexture.ReleaseTemporary(fxCam.targetTexture);
            ALUGUICommon.setGameObjDisable(fxCam.gameObject);
            GameObject.Destroy(fxCam.gameObject);
        }
    }

    private void CreateCamera(Transform parent)
    {
        if (fxCam != null)
        {
            return;
        }
        GameObject go = new GameObject("fxCamera");
        fxCam = go.AddComponent<Camera>();
        if (cameraLayer == 0)
        {
            cameraLayer = LayerMask.NameToLayer("Item");
        }
        fxCam.cullingMask = 1 << cameraLayer;
        fxCam.farClipPlane = 10;
        fxCam.nearClipPlane = -5;
        fxCam.orthographic = true;
        fxCam.clearFlags = CameraClearFlags.SolidColor;
        fxCam.backgroundColor = new Color(0, 0, 0, 0);
        go.transform.SetParent(parent);
        go.transform.localRotation = Quaternion.Euler(mFxrtData.CameraRotation);
        RenderTexture rt = RenderTexture.GetTemporary((int)mFxrtData.RTSize.x, (int)mFxrtData.RTSize.y, 1, RenderTextureFormat.ARGB32);
        rt.useMipMap = false;
        rt.autoGenerateMips = false;
        fxCam.targetTexture = rt; 
    }

    private void modifyCameraProperty()
    {

        if (FxRTData.HasRT(mFxrtData.FXName))
        {
            return;
        }
        CreateCamera(mFxrtData.RootTransform);

        fxCam.orthographicSize = mFxrtData.CameraOrthographicSize;
        fxCam.rect = mFxrtData.CameraViewPortRect;
        fxCam.transform.localPosition = mFxrtData.CameraPosition;
    }
}

播放状态大体代码:

using UnityEngine;

public class PlayRTState : BaseState
{
    private bool canPlay = false;
    private int index = 0;
    protected MeshRenderer mMeshRenderer = null;
    private bool hasHideItem = false;

    private void CreateQuad()
    {
        if (mMeshRenderer != null)
        {
            return;
        }
        GameObject go = GameObject.CreatePrimitive(PrimitiveType.Quad);
        go.name = "fx_rt";
        Component.Destroy(go.GetComponent<MeshCollider>());
        go.transform.SetParent(mFxrtData.RootTransform);
        //var pos = fxCam.transform.localPosition;
        //go.transform.localPosition = new Vector3(-pos.x, -pos.y, -pos.z);
        go.transform.localPosition = mFxrtData.QuadPosition;
        go.transform.localRotation = Quaternion.Euler(mFxrtData.QuadRotation);
        go.transform.localScale = mFxrtData.QuadScale;//new Vector3(4, 4, 1);
        mMeshRenderer = go.GetComponent<MeshRenderer>();
        if (FxRTData.FxMaterialsList.ContainsKey(mFxrtData.FXName))
        {
            mMeshRenderer.sharedMaterial = FxRTData.FxMaterialsList[mFxrtData.FXName];
            mMeshRenderer.sortingOrder = FxRTData.FxMeshDepthList[mFxrtData.FXName];
        }
        else
        {
            mMeshRenderer.sharedMaterial = new Material(Shader.Find("D_Shader/D_Shader_RT_Particle"));
            mMeshRenderer.sharedMaterial.enableInstancing = true;
            FxRTData.FxMaterialsList.Add(mFxrtData.FXName, mMeshRenderer.sharedMaterial);
            FxRTData.FxMeshDepthList.Add(mFxrtData.FXName, FxRTData.FxMeshDepth);
            mMeshRenderer.sortingOrder = FxRTData.FxMeshDepth;
            FxRTData.FxMeshDepth++;
        }
        mMeshRenderer.sharedMaterial.mainTexture = null;

        mFxrtData.mMeshRenderer = mMeshRenderer;
    }

    public override void Init(FxRTData data)
    {
        base.Init(data);
        if (mFxrtData.FxRTs != null &&
            mFxrtData.FxRTs.Count > 0)
        {
            canPlay = true;
        }

        if (!canPlay)
        {
            return;
        }

        CreateQuad();
        if (!hasHideItem)
        {
            hasHideItem = true;
            if (mFxrtData.childTransforms.Length >= 2)
            {
                for (int i = 1; i < mFxrtData.childTransforms.Length; i++)
                {
                    bool isSetDisable = true;
                    var thisName = mFxrtData.childTransforms[i].name;
                    for (int j = 0; j < FxRTData.ExceptFXs.Length; j++)
                    {
                        string eFx = FxRTData.ExceptFXs[j];
                        if (thisName.Equals(eFx))
                        {
                            mFxrtData.childTransforms[i].SetParent(mFxrtData.RootTransform);
                            mFxrtData.childTransforms[i].localPosition = mFxrtData.QuadPosition;
                            isSetDisable = false;
                            break;
                        }
                    }
                    if (isSetDisable)
                        ALUGUICommon.setGameObjDisable(mFxrtData.childTransforms[i].gameObject);
                }
            }
        }
        
        index = 0;
    }

    int cuTime = 0;
    const int tTime = 2;
    public override void OnUpdate()
    {
        base.OnUpdate();

        if (!canPlay)
        {
            return;
        }
        cuTime++;
        if (cuTime >= tTime)
        {
            cuTime = 0;
            return;
        }
        var rts = mFxrtData.FxRTs;
        var count = rts.Count;
        if (index < count)
        {
            mFxrtData.FxMPR.SetTexture("_MainTex", rts[index]);
            mFxrtData.mMeshRenderer.SetPropertyBlock(mFxrtData.FxMPR);
            //mFxrtData.mMeshRenderer.material.mainTexture = rts[index];
        }

        mFxrtData.RootTransform.localRotation = Quaternion.identity;
        //mFxrtData.RootTransform.transform.localScale = vec;
        index++;
        if (index >= rts.Count - 1)
        {
            index = 1;
        }
    }
}

最后效果是没什么区别的,如果不介意像素,还可以减少rt的像素,减少内存消耗。

然后dc在rt下当然就只有一个了,而且overdraw也没了。而且我们把gpuinstance打开也可以把所有同类型的合成一个。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值