日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

【Unity】使用RenderTexture为物体生成快照

發(fā)布時(shí)間:2023/12/13 综合教程 23 生活家
生活随笔 收集整理的這篇文章主要介紹了 【Unity】使用RenderTexture为物体生成快照 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。

作者:Jimm 郵箱:junmingz@foxmail.com


RenderTexture的定義和作用

RenderTexture are textures that can be rendered to.

RenderTexture(下文簡(jiǎn)稱RTT)是可以被渲染的紋理,簡(jiǎn)稱渲染紋理。一般來說,RTT可以應(yīng)用在制作動(dòng)態(tài)陰影,反射以及監(jiān)視攝像機(jī)(車輛后視鏡)等,另一方面可以應(yīng)用到游戲截圖,背景模糊等方面,用途十分廣泛。以后這些技術(shù)都會(huì)慢慢分享到博客上,敬請(qǐng)期待!


RTT的用法

Camera(攝像機(jī))是Unity中非常重要的一個(gè)組件,其中有一個(gè)屬性叫做targetTexture,在設(shè)置了targetTexture后,Camera會(huì)在渲染時(shí)將其屏幕上的圖像渲染到targetTexture上。在相機(jī)渲染完成后可以讀取屏幕像素內(nèi)的緩存來使用。其中,相機(jī)渲染完成有三種調(diào)用方式:

1.OnPostRender()

OnPostRender is called after a camera finished rendering the scene.

OnPostRender在相機(jī)完成渲染場(chǎng)景時(shí)調(diào)用。這次遇到的需求是需要為物體生成快照,做法是另外創(chuàng)建一個(gè)相機(jī),在另一個(gè)位置完成渲染工作,代碼如下:

//快照相機(jī)
public Camera shotCam;
public UITexture texture;
void OnPostRender()
{
    //設(shè)定當(dāng)前RenderTexture為快照相機(jī)的targetTexture 
    RenderTexture rt = shotCam.targetTexture;
    RenderTexture.active = rt;
    Texture2D tex = new Texture2D(rt.width, rt.height);
    //讀取緩沖區(qū)像素信息 
    tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
    tex.Apply();
    texture.mainTexture = tex;
    Texture2D.Destroy(tex);
    tex = null;
}
//這里刪除的時(shí)機(jī)有問題,會(huì)導(dǎo)致不顯示相機(jī)渲染的圖像問題
//謝謝一位好心讀者提醒,改正后的代碼在下方

修正后的代碼:

public Camera shotCam;
public UITexture texture;
private Texture2D tex = null;
void OnPostRender()
{
//在每次相機(jī)渲染完成時(shí)再刪除上一幀的texture if(tex != null) { Destroy(tex); } //設(shè)定當(dāng)前RenderTexture為快照相機(jī)的targetTexture RenderTexture rt = shotCam.targetTexture; RenderTexture.active = rt; tex = new Texture2D(rt.width, rt.height); //讀取緩沖區(qū)像素信息 tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); tex.Apply(); texture.mainTexture = tex; }

場(chǎng)景中的效果如下:

2.使用協(xié)程(yield return new WaitForEndOfFrame())

yield return new WaitForEndOfFrame()

等待當(dāng)前幀結(jié)束。類似于OnPostRender(),可以使用for循環(huán)來依次對(duì)多個(gè)物體進(jìn)行快照,代碼如下:

public GameObject[] gos;
void Start()
{
    StartCoroutine(RenderGoTexCR());
}
IEnumerator RenderGoTexCR()
{
    int length = textures.Length;
    for (int i = 0; i < length; i++)
    {
        GameObject go = Instantiate(gos[i]);
        go.SetActive(true);
        yield return new WaitForEndOfFrame();
        RenderTexture rt = shotCam.targetTexture;
        RenderTexture.active = rt;
        Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
        tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
        tex.Apply();
        textures[i].mainTexture = tex;
        GameObject.Destroy(go);
    }
}

PS:yield語(yǔ)句要放在設(shè)置RenderTexture.active之前,因?yàn)橹挥性趲Y(jié)束時(shí)shotCam的targetTexture才被正確渲染,才可以通過ReadPixels取得正確的圖像。tex在使用過后最好使用Destroy()銷毀,或者在設(shè)置mainTexture之前銷毀之前的Texture,否則就會(huì)像博主一樣寫著寫著博客發(fā)現(xiàn)Unity運(yùn)行了一段時(shí)間就把內(nèi)存吃光了。

場(chǎng)景效果如下:

3.使用Camera.Render()

我們發(fā)現(xiàn)當(dāng)要對(duì)多個(gè)物體進(jìn)行快照時(shí)OnPostRender()就沒那么好用了,因?yàn)槲覀冃枰谙鄼C(jī)渲染前將物體展示出來(OnPreRender()),在相機(jī)渲染后取得像素信息,對(duì)于兩個(gè)函數(shù)分別處理GameObject我們是拒絕的(程序員就喜歡簡(jiǎn)單粗暴!)。那么使用協(xié)程又有什么問題呢?細(xì)心的同學(xué)會(huì)發(fā)現(xiàn),每次渲染一個(gè)物體都需要等到幀結(jié)束,那么當(dāng)需要渲染的物體較多時(shí)渲染時(shí)間會(huì)明顯變長(zhǎng),這顯然也不是我們想要的,那么有沒有能在很短時(shí)間內(nèi)完成大量物體的渲染呢?Camera.Render()給了我們福音。

Camera.Render()

手動(dòng)渲染相機(jī)。廢話不多說,貼代碼:

public GameObject[] gos;
void Start()
{
    for (int i = 0; i < textures.Length; i++)
    {
        GameObject go = Instantiate(gos[i]);
        go.SetActive(true);
        textures[i].mainTexture = RenderGoTex();
        GameObject.Destroy(go);
    }
}
Texture2D RenderGoTex()
{
    RenderTexture rt = shotCam.targetTexture;
    shotCam.Render();
    RenderTexture.active = rt;
    Debug.Log(RenderTexture.active);
    Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
    tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
    tex.Apply();
    return tex;
}

Camera.Render()無(wú)需等待幀結(jié)束,它在調(diào)用時(shí)強(qiáng)制渲染相機(jī),通過返回的tex進(jìn)行操作即可,同樣不要忘了Texture的內(nèi)存問題,場(chǎng)景中效果如下:

咦,怎么會(huì)發(fā)生重疊現(xiàn)象呢,明明在取得tex之后調(diào)用了Destroy()函數(shù)呀!這個(gè)也困擾了我一段時(shí)間,后來發(fā)現(xiàn)是Destroy函數(shù)的延遲問題。Destroy()函數(shù)對(duì)實(shí)際物體的銷毀會(huì)延遲到當(dāng)前循環(huán)更新后,在渲染前完成的,所以我們?cè)谶@一幀執(zhí)行for循環(huán)時(shí),雖然每次循環(huán)都調(diào)用了Destroy()來銷毀物體,但是實(shí)際上它們是在for循環(huán)結(jié)束后才一起銷毀的,所以為了避免此問題,我們改用DestroyImmediate(),或者先調(diào)用gameObject.SetActive(false)后再Destroy(),后者是比較推薦的做法,原因請(qǐng)看官方文檔

https://docs.unity3d.com/ScriptReference/Object.DestroyImmediate.html


結(jié)尾語(yǔ)

博主只是初入江湖的小菜,最近萌生寫博客的想法,希望能將自己在學(xué)習(xí)和工作中遇到的問題以及所感所想與大家分享,同時(shí)也是對(duì)自我的總結(jié)。最后感謝大家的支持,你們的支持就是我的動(dòng)力!


總結(jié)

以上是生活随笔為你收集整理的【Unity】使用RenderTexture为物体生成快照的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。