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

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)

除此之外,一旦解决,我敢肯定,这里还有很多其他工作是不可行的。但是我只是从这里开始。谢谢您的帮助!

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。

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秒,然后等待帧结束,然后再截屏:

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;
}

关于c# - ReadPixels被调用来从系统帧缓冲区读取像素,而不是在绘图帧内部。 UnityEngine.Texture2D:ReadPixels,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46595055/

10-10 05:36