调用ReadPixels从系统帧缓冲区读取像素,而不是在绘图帧内部. UnityEngine.Texture2D:ReadPixels [英] ReadPixels was called to read pixels from system frame buffer, while not inside drawing frame. UnityEngine.Texture2D:ReadPixels

查看:1569
本文介绍了调用ReadPixels从系统帧缓冲区读取像素,而不是在绘图帧内部. UnityEngine.Texture2D:ReadPixels的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用统一性创建一个小的测试应用程序.我正在构建该应用程序的一个实例,并将其设置为充当主机,然后在统一编辑器中作为客户端运行另一个实例.在当前的迭代中,我只有一个按钮,当按下该按钮时,请截取屏幕截图,然后将该屏幕截图发送给所有客户端.但是似乎没有任何作用.我遇到的第一个问题是ReadPixels错误:

I'm trying to create a little test app, using unity. I'm building out one instance of the app and setting it to function as a Host and then running another instance within the unity editor as a client. In this current iteration I have a single button that SHOULD, when pressed is take a screenshot and then send that screenshot to all clients. But nothing seems to to be working. The initial issue that I'm hitting is a ReadPixels error:

ReadPixels was called to read pixels from system frame buffer, while not inside drawing frame. UnityEngine.Texture2D:ReadPixels(Rect, Int32, Int32) UNETChat:OnPostRender() (at Assets/Scripts/UNETChat.cs:50) <TakeSnapshot>c__Iterator0:MoveNext() (at Assets/Scripts/UNETChat.cs:42) UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr).

ReadPixels was called to read pixels from system frame buffer, while not inside drawing frame. UnityEngine.Texture2D:ReadPixels(Rect, Int32, Int32) UNETChat:OnPostRender() (at Assets/Scripts/UNETChat.cs:50) <TakeSnapshot>c__Iterator0:MoveNext() (at Assets/Scripts/UNETChat.cs:42) UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr).

除此之外,一旦解决,我确定这里还有很多其他工作是不合时宜的.但是我只是从这里开始.感谢您的帮助!

Beyond that, once solved I'm sure that there is a lot of additional work in here that's off the mark. But I'm just starting here. Thanks for the help!

using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Networking.NetworkSystem;

public class MyMsgType
{
    public static short texture = MsgType.Highest + 1;
};

//Create a class that holds a variables to send
public class TextureMessage : MessageBase
{
    public byte[] textureBytes;
    public string message = "Test Received Message"; //Optional
}

public class UNETChat : Chat
{
    NetworkClient myClient;
    public Texture2D previewTexture;
    string messageToSend = "Screen Short Image";

    private void Start()
    {
        //if the client is also the server
        if (NetworkServer.active) 
        {
            // Register to connect event
            myClient.RegisterHandler(MsgType.Connect, OnConnected);
            // Register to texture receive event
            myClient.RegisterHandler(MyMsgType.texture, OnTextureReceive);
        }
        setupClient();
    }

    public IEnumerator TakeSnapshot(int width, int height)
    {
        yield return new WaitForSeconds(0.1F);
        Texture2D texture = new Texture2D(800, 800, TextureFormat.RGB24, true);
        texture.ReadPixels(new Rect(0, 0, 800, 800), 0, 0);
        texture.LoadRawTextureData(texture.GetRawTextureData());
        texture.Apply();

        sendTexture(texture, messageToSend);

        // gameObject.renderer.material.mainTexture = TakeSnapshot;

    }

    public void DoSendTexture()
    {
        StartCoroutine(TakeSnapshot(Screen.width, Screen.height));
    }

    // SERVER //////////////////////////

    //Call to send the Texture and a simple string message
    public void sendTexture(Texture2D texture, string message)
    {
        TextureMessage msg = new TextureMessage();

        //Convert Texture2D to byte array
        msg.textureBytes = texture.GetRawTextureData();
        msg.message = message;

        NetworkServer.SendToAll(MyMsgType.texture, msg);

        Debug.Log("Texture Sent!!");
    }

    // CLIENT //////////////////////////

    // Create a client and connect to the server port
    public void setupClient()
    {
        //Create new client
        myClient = new NetworkClient();
        //Register to connect event
        myClient.RegisterHandler(MsgType.Connect, OnConnected);
        //Register to texture receive event
        myClient.RegisterHandler(MyMsgType.texture, OnTextureReceive);
        //Connect to server
        myClient.Connect("localhost", 4444);
    }

    //Called when texture is received
    public void OnTextureReceive(NetworkMessage netMsg)
    {
        TextureMessage msg = netMsg.ReadMessage<TextureMessage>();

        //Your Received message
        string message = msg.message;
        Debug.Log("Texture Messsage " + message);

        //Your Received Texture2D
        Texture2D receivedtexture = new Texture2D(4, 4);
        receivedtexture.LoadRawTextureData(msg.textureBytes);
        receivedtexture.Apply();
    }

    public void OnConnected(NetworkMessage netMsg)
    {
        Debug.Log("Connected to server");
    }
}

推荐答案

在截屏之前或调用Texture2D.ReadPixels函数之前,请等待直到当前帧的结尾.这可以通过WaitForEndOfFrame类完成.请注意我是如何缓存它的,以避免每次调用TakeSnapshot函数时都创建新的Object.

Wait until the end of the current frame before taking the screenshot or before calling the Texture2D.ReadPixels function. This can be done with the WaitForEndOfFrame class. Notice how I cached it to avoid creating new Object each time the TakeSnapshot function is called.

WaitForEndOfFrame frameEnd = new WaitForEndOfFrame();

public IEnumerator TakeSnapshot(int width, int height)
{
    yield return frameEnd;

    Texture2D texture = new Texture2D(800, 800, TextureFormat.RGB24, true);
    texture.ReadPixels(new Rect(0, 0, 800, 800), 0, 0);
    texture.LoadRawTextureData(texture.GetRawTextureData());
    texture.Apply();
    sendTexture(texture, messageToSend);

    // gameObject.renderer.material.mainTexture = TakeSnapshot;
}


我注意到您的脚本中包含yield return new WaitForSeconds(0.1F),该脚本会等待0.2秒,然后再截取屏幕截图.如果必须等待0.2秒,请先等待0.2秒,然后等待帧结束,然后再截屏:


I noticed you have yield return new WaitForSeconds(0.1F) in your script which waits for 0.2 seconds before taking the screenshot. If you must wait for 0.2 seconds, then first wait for 0.2 seconds and then wait for end of frame before taking the screenshot:

WaitForSeconds waitTime = new WaitForSeconds(0.1F);
WaitForEndOfFrame frameEnd = new WaitForEndOfFrame();

public IEnumerator TakeSnapshot(int width, int height)
{
    yield return waitTime;
    yield return frameEnd;

    Texture2D texture = new Texture2D(800, 800, TextureFormat.RGB24, true);
    texture.ReadPixels(new Rect(0, 0, 800, 800), 0, 0);
    texture.LoadRawTextureData(texture.GetRawTextureData());
    texture.Apply();
    sendTexture(texture, messageToSend);

    // gameObject.renderer.material.mainTexture = TakeSnapshot;
}

这篇关于调用ReadPixels从系统帧缓冲区读取像素,而不是在绘图帧内部. UnityEngine.Texture2D:ReadPixels的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆