I have a problem with a camera, I want to take a screenshot but I get this error:
Flare renderer to update not found UnityEngine.Camera:Render()
c__Iterator4:MoveNext() (at
Assets/Scripts/ActionCam.cs:43)
My code:
public IEnumerator TakeScreenshot() {
yield return new WaitForEndOfFrame();
Camera camOV = _Camera;
RenderTexture currentRT = RenderTexture.active;
RenderTexture.active = camOV.targetTexture;
camOV.Render(); // here is the problem...
Texture2D imageOverview = new Texture2D(camOV.targetTexture.width, camOV.targetTexture.height, TextureFormat.RGB24, false);
imageOverview.ReadPixels(new Rect(0, 0, camOV.targetTexture.width, camOV.targetTexture.height), 0, 0);
imageOverview.Apply();
RenderTexture.active = currentRT;
byte[] bytes = imageOverview.EncodeToPNG();
string path = ScreenShotName(Convert.ToInt32(imageOverview.width), Convert.ToInt32(imageOverview.height));
System.IO.File.WriteAllBytes(path, bytes);
}
There are my camera settings:
If I deactivate the "Flare Layer" I don't get this error, but my screenshots are more or less empty, only the skybox:
any idea?
I Use 3 types of screenshot in unity:
Application.CaptureScreenshot(ScreenSgotFile): Not using anymore because I prefer methods that stores the screenshots in memory. (I don't need the file because it is attached to a MailMessage and sended by an SmtpClient)
OnPostRender (it must be attached to a camera):
void OnPostRender(){
Texture2D ScreenShot=new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
RenderTexture.active=null;
ScreenShot.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
ScreenShot.Apply();
byte[] PngData=ScreenShot.EncodeToPNG();
PngStream = new MemoryStream(PngData);
//File.WriteAllBytes(FileShot, PngData);
// Preview on a sprite
Sprite Spr=Sprite.Create(ScreenShot, new Rect(0, 0, ScreenShot.width, ScreenShot.height),Vector2.zero, 100);
Preview.sprite=Spr;
Preview.gameObject.SetActive(true);
}
The same code but at the end of frame:
void Update(){
...
StartCoroutine(ScreenShotAtEndOfFrame());
}
public IEnumerator ScreenShotAtEndOfFrame(){
yield return new WaitForEndOfFrame();
Texture2D ScreenShot=new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
RenderTexture.active=null; `enter code here`
ScreenShot.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
ScreenShot.Apply();
byte[] PngData=ScreenShot.EncodeToPNG();
PngStream = new MemoryStream(PngData);
//File.WriteAllBytes(FileShot, PngData);
// Preview on a sprite
Sprite Spr=Sprite.Create(ScreenShot, new Rect(0, 0, ScreenShot.width, ScreenShot.height),Vector2.zero, 100);
Preview.sprite=Spr;
Preview.gameObject.SetActive(true);
}
Related
I'm working on a code where I basically have to take a low quality screenshot about every 30 milliseconds. The script is attached to a camara.
What I want to do is reduce the render texture size. The way the code is right now changing either W or H basically gets me a SECTION of of all that is being seen by the camara instead of a reduced size version. So my question is how can I resized or downsample what is read into the screenshot (Texture2D) but that it still is a representation of the entire screen.
public class CameraRenderToImage : MonoBehaviour
{
private RemoteRenderServer rrs;
void Start(){
TimeStamp.SetStart();
Camera.onPostRender += OnPostRenderCallback;
}
void OnPostRenderCallback(Camera cam){
if (TimeStamp.HasMoreThanThisEllapsed(30)){
TimeStamp.SetStart();
int W = Screen.width;
int H = Screen.height;
Texture2D screenshot = new Texture2D(W,H, TextureFormat.RGB24, false);
screenshot.ReadPixels( new Rect(0, 0, W,H), 0, 0);
byte[] bytes = screenshot.EncodeToPNG();
System.IO.File.WriteAllBytes("check_me_out.png", bytes);
TimeStamp.Tok("Encode to PNG and Save");
}
}
// Remove the onPostRender callback
void OnDestroy()
{
Camera.onPostRender -= OnPostRenderCallback;
}
}
If you need to resize your render texture from script you can refer to the next code snippet
void Resize(RenderTexture renderTexture, int width, int height) {
if (renderTexture) {
renderTexture.Release();
renderTexture.width = width;
renderTexture.height = height;
}
}
To make it possible to resize the render texture you first need to make sure it is released.
To get Texture2d:
private Texture2D ToCompressedTexture(ref RenderTexture renderTexture)
{
var texture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false);
var previousTarget = RenderTexture.active;
RenderTexture.active = renderTexture;
texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
RenderTexture.active = previousTarget;
texture.Compress(false);
texture.Apply(false, true);
renderTexture.Release();
renderTexture = null;
return texture;
}
Sprite SpriteModding(string path)
{
byte[] bytes = File.ReadAllBytes(Application.dataPath + "/Resources/fgsoftwarestudio.png");
Texture2D texture = new Texture2D(512, 512, TextureFormat.RGB24, false);
texture.filterMode = FilterMode.Trilinear;
texture.LoadImage(bytes);
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, 512, 512), new Vector2(0.5f, 0.0f), 1.0f);
sprite_bg.GetComponent<SpriteRenderer>().sprite = sprite;
return null;
}
`
]1]1
i open game and sprite don't render
If you are loading a file from resources folder try Resources.Load more information here: Information about Resources folder
I am trying to pass the render texture from Unity into a C++ plugin to then use CUDA on the texture. This works fine in DirectX in editor and build, and also OpenGL in editor. But when I build in OpenGL it gives me a blank texture. I've also noticed that if I try and save said texture it also saves as a blank texture. I call my plugin using GL.IssuePluginEvent(PluginFunction(), 1), and this happens in a coroutine after yield return new WaitForEndOfFrame(). Any ideas on how to fix it?
private IEnumerator CallPlugin()
{
while (enabled) {
yield return new WaitForEndOfFrame();
//Attempt to save image to file, only works in editor
// Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
// RenderTexture.active = _renderTexture;
// tex.ReadPixels(new Rect(0, 0, width, height), 0, 0);
// tex.Apply();
// byte[] bytes = tex.EncodeToPNG();
// System.IO.File.WriteAllBytes("takeScreenshot.png", bytes);
GL.IssuePluginEvent(GetRenderEventFunc(), 1);
}
}
void OnRenderImage(RenderTexture src, RenderTexture dest)
{
if (shader != null)
{
Graphics.Blit(src, dest, material);
}
}
I'm using Intel Real Sense as camera device to capture picture. The capture result is displayed as a RenderTexture. Since I need to sent it via UDP, I need to convert it to byte[], but it only work for Texture2D. Is it possible to convert RenderTexture into Texture2D in unity 2019?
Edit:
Right now, I'm using this code to convert RenderTexture to Texture2D:
Texture2D toTexture2D(RenderTexture rTex)
{
Texture2D tex = new Texture2D(rTex.width, rTex.width, TextureFormat.ARGB32, false);
RenderTexture.active = rTex;
tex.ReadPixels(new Rect(0, 0, rTex.width, rTex.height), 0, 0);
tex.Apply();
return tex;
}
I got this code from here, which doesn't work anymore for unity 2019 since if I display the texture it only give me white texture.
Edit 2:
Here how i called that function:
//sender side
Texture2D WebCam;
public RawImage WebCamSender;
public RenderTexture tex;
Texture2D CurrentTexture;
//receiver side
public RawImage WebCamReceiver;
Texture2D Textur;
IEnumerator InitAndWaitForWebCamTexture()
{
WebCamSender.texture = tex;
CurrentTexture = new Texture2D(WebCamSender.texture.width,
WebCamSender.texture.height, TextureFormat.RGB24, false, false);
WebCam = toTexture2D(tex);
while (WebCamSender.texture.width < 100) //WebCam
{
yield return null;
}
StartCoroutine(SendUdpPacketVideo());
}
then i'll send it via network like this :
IEnumerator SendUdpPacketVideo()
{
...
CurrentTexture.SetPixels(WebCam.GetPixels());
byte[] PNGBytes = CurrentTexture.EncodeToPNG();
...
}
On receiver side, i'm gonna decode it and display on raw image:
....
Textur.LoadImage(ReceivedVideo);
WebCamReceiver.texture = Textur;
...
The most optimized way to do this is:
public Texture2D toTexture2D(RenderTexture rTex)
{
Texture2D dest = new Texture2D(rTex.width, rTex.height, TextureFormat.RGBA32, false);
dest.Apply(false);
Graphics.CopyTexture(rTex, dest);
return dest;
}
I'm trying to build a program that takes your photo and places it with a different background, like a monument or so. So far, I was able to turn the camera on when I start the project with this code
webcamTexture = new WebCamTexture();
rawImage.texture = webcamTexture;
rawImage.material.mainTexture = webcamTexture;
webcamTexture.Play();
Texture2D PhotoTaken = new Texture2D (webcamTexture.width, webcamTexture.height);
PhotoTaken.SetPixels (webcamTexture.GetPixels ());
PhotoTaken.Apply ();
However, I can't take a screenshot or photo because it always ends up all black. I've tried different codes but nothing is working. Can someone please help? Thanks
EDIT
After some tries, this is the code I have:
WebCamTexture webcamTexture;
public RawImage rawImage;
void Start () {
webcamTexture = new WebCamTexture();
rawImage.texture = webcamTexture;
rawImage.material.mainTexture = webcamTexture;
webcamTexture.Play();
RenderTexture texture= new RenderTexture(webcamTexture.width, webcamTexture.height,0);
Graphics.Blit(webcamTexture, texture);
Button btn = yourButton.GetComponent<Button>();
btn.onClick.AddListener(OnClick);
}
public IEnumerator Coroutine(){
yield return new WaitForEndOfFrame ();
}
public void OnClick() {
var width = 767;
var height = 575;
Texture2D texture = new Texture2D(width, height);
texture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
texture.Apply();
// Encode texture into PNG
var bytes = texture.EncodeToPNG();
//Destroy(texture);
File.WriteAllBytes (Application.dataPath + "/../SavedScreen.png", bytes);
}
and with this next code the screenshot is taken, but it takes a photo of the whole thing, and not just a bit of the screen.
void Start()
{
// Set the playback framerate!
// (real time doesn't influence time anymore)
Time.captureFramerate = frameRate;
// Find a folder that doesn't exist yet by appending numbers!
realFolder = folder;
int count = 1;
while (System.IO.Directory.Exists(realFolder))
{
realFolder = folder + count;
count++;
}
// Create the folder
System.IO.Directory.CreateDirectory(realFolder);
}
void Update()
{
// name is "realFolder/shot 0005.png"
var name = string.Format("{0}/shot {1:D04}.png", realFolder, Time.frameCount);
// Capture the screenshot
Application.CaptureScreenshot(name, sizeMultiplier);
}
}
You can take a screenshot like this in Unity
Application.CaptureScreenshot("Screenshot.png");
Reference
EDIT 1
To take a screenshot on a specific part of the screen use the following script:
var width = 400;
var height = 300;
var startX = 200;
var startY = 100;
var tex = new Texture2D (width, height, TextureFormat.RGB24, false);
tex.ReadPixels (Rect(startX, startY, width, height), 0, 0);
tex.Apply ();
// Encode texture into PNG
var bytes = tex.EncodeToPNG();
Destroy(tex);
File.WriteAllBytes(Application.dataPath + "/../SavedScreen.png", bytes);
Reference