HELP, why does GetPixels() not work for iOS?

Hi there,
I’m on Unity iOS Pro and don’t understand, why this simple lines of code generates a compiler error:

var tx2d = Texture2D(go.renderer.material.mainTexture.width,go.renderer.material.mainTexture.height,TextureFormat.RGB24, false);
tx2d.SetPixels(go.renderer.material.mainTexture.GetPixels());

The compiler says:
‘GetPixels’ is not a member of ‘UnityEngine.Texture’

Maybe I’m to stupid, to see the fault :smile:

Please help me :slight_smile:

BTW: As Desktop-Version this code works perfect!

No idea, but sometimes unity seems to change texture settings when loading unity windows project on mac…
So have you checked your maintexture settings in inspector?

This is not the problem…

Which is completely correct…it’s a member of Texture2D, not Texture. The only reason it would work on the desktop is because of using dynamic typing, which you can (and should, if you’re going to have iOS be a publishing target) disable by using #pragma strict on all your scripts.

tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());

–Eric

Perfect! You saved my night! Thank you!!

So just to be sure (go.renderer.material.mainTexture as Texture2D) converts it to Texture2D and so .GetPixels() works?

It casts renderer.material.mainTexture, which returns Texture, to Texture2D.

–Eric

Oh, I think I was a lil bit to happy… it still doesn’t work. Maybe it would be easier, if I post the compete script:

#pragma strict

import System;
import System.IO;
import HutongGames.PlayMaker;

 
 
 

@ActionCategory("Webcam")
public class PNGSave extends FsmStateAction{

    @UIHint(UIHint.Variable)
    public var gameobject : FsmOwnerDefault;

    public var filePath : FsmString;
    public var fileName : FsmString;
        
	@UIHint(UIHint.Variable)
	@ObjectTypeAttribute(typeof(WebCamTexture))
	public var webCamTexture : FsmObject;
    
    
    
    public function Reset()
    {
        gameobject = null;
        filePath = null;
        fileName = null;
    }

    
    
    

	public function OnEnter()
	{
		var go : GameObject = Fsm.GetOwnerDefaultTarget(gameobject);
		var tx2d = Texture2D(go.renderer.material.mainTexture.width,go.renderer.material.mainTexture.height,TextureFormat.RGB24, false);
	
	
		tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());

		tx2d.Apply();
		
		if (filePath != null) filePath = "/" + filePath;

    	File.WriteAllBytes(Application.persistentDataPath + filePath + "/" + fileName + ".png",tx2d.EncodeToPNG());
    }
}

At runtime I get this error:
NullReferenceException: Object reference not set to an instance of an object
PNGSave.OnEnter () (at Assets/PNGSave.js:43)

Do some checks to see what’s null. It’s either the “go” variable, or it doesn’t have a renderer, or the shader doesn’t have _MainTex so mainTexture doesn’t work, or it doesn’t have anything in the texture. Probably better to split it up into multiple lines so everything can be checked as needed.

–Eric

I tried everything I know and I can’t still find what’s null. As Desktop-Version it runs fine, only as iOS it breaks -.-

public function OnEnter()
	{
		var go : GameObject = Fsm.GetOwnerDefaultTarget(gameobject);
		var tx2d = Texture2D(go.renderer.material.mainTexture.width,go.renderer.material.mainTexture.height,TextureFormat.DXT5, false);
	
		var ren : Renderer = go.renderer;
		var mat : Material = go.renderer.material;
		var tex : Texture = go.renderer.material.mainTexture;
		var tex2 : Texture2D = go.renderer.material.mainTexture as Texture2D;
	
		tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());

		tx2d.Apply();
		
		if (filePath != null) filePath = "/" + filePath;

    	File.WriteAllBytes(Application.persistentDataPath + filePath + "/" + fileName + ".png",tx2d.EncodeToPNG());
    }

Is there another way to find, what’s null?

EDIT: No, I’m wrong. After I changed the line as you suggest above, it doesn’t run any longer as desktop-version. Now I’m really confused.

With

tx2d.SetPixels(go.renderer.material.mainTexture.GetPixels());

it works fine on desktop, but not on iOS

with

tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());

it breaks on every system!? oO

There is no TextureFormat.DXT5 on iOS.

–Eric

Yes, I know - this was for testing on desktop. I modified my code again, to find what’s null:

	public function OnEnter()
	{
		var go : GameObject = Fsm.GetOwnerDefaultTarget(gameobject);
		var tx2d = Texture2D(go.renderer.material.mainTexture.width,go.renderer.material.mainTexture.height,TextureFormat.RGB24, false);
	
		Debug.Log("Test Start");
	    var ren : Renderer = go.renderer;
		if (ren == null) Debug.Log("1 failed"); else Debug.Log("1 passed");
		
        var mat : Material = go.renderer.material;
		if (mat == null) Debug.Log("2 failed"); else Debug.Log("2 passed");


        var tex : Texture = go.renderer.material.mainTexture;
		if (tex == null) Debug.Log("3 failed"); else Debug.Log("3 passed");


        var tex2 : Texture2D = go.renderer.material.mainTexture as Texture2D;
		if (tex2 == null) Debug.Log("4 failed"); else Debug.Log("4 passed");	
	
	
		tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());

		tx2d.Apply();
		
		if (filePath != null) filePath = "/" + filePath;

    	File.WriteAllBytes(Application.persistentDataPath + filePath + "/" + fileName + ".png",tx2d.EncodeToPNG());
    }

And the result:

This line of code produce the error var tex2 : Texture2D = go.renderer.material.mainTexture as Texture2D;

So this means, that the convertion to Texture2D does not work, because one line above var tex : Texture = go.renderer.material.mainTexture; passes fine, without result null - so there must be a texture.

But why it won’t convert to Texture2D?


EDIT:
I also tried it via ReadPixels:

tx2d.ReadPixels(new Rect(0,0,go.renderer.material.mainTexture.width,go.renderer.material.mainTexture.height),0,0);

This brings me another error:
ReadPixels was called to read pixels from system frame buffer, while not inside drawing frame.

–.–

BTW:
Is there a way to see, what the compiler changes on ‘wrong’ code, if dynamic typing is on? So I could look up, what the compiler makes with this line of code, which works great on desktop with dynamic typing tx2d.SetPixels(go.renderer.material.mainTexture.GetPixels());

and it could not be tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels()); because if I switch the line to this, my App breaks at this line (with the ‘wrong’ syntaxline, which will be fixed via dynamic typing it works, so it would be great to see, what the compiler changes to it).

Dynamic typing happens at runtime; it’s not something the compiler is changing. Use #pragma strict to disable dynamic typing. Casting to Texture2D works fine, as shown by this example, assuming the object used for “go” has a material which uses a shader that has _MainTex:

#pragma strict

var go : GameObject;

function Start () {
	var tex = go.renderer.material.mainTexture as Texture2D;
	var tx2d = Texture2D(tex.width, tex.height, TextureFormat.RGB24, false);
	tx2d.SetPixels32(tex.GetPixels32());
	tx2d.Apply();
	renderer.material.mainTexture = tx2d;
}

–Eric

Ok, that’s fine. But I still don’t understand why this line with dynamic typing works:

tx2d.SetPixels(go.renderer.material.mainTexture.GetPixels());

and this line with #pragma strik doesn’t:

tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());

Do you have any idea, what at runtime happens, that the texture on go.renderer.material.maintexture will found?

In another script I apply a WebCamTexture to this Cube-Material and I can see it on screen, so it is there.

This error makes me ill -.-

Would it easier to help me, if I would upload an example? (attached)

EDIT:
Now I’m pretty sure it’s because of the assigned WebCamTexture to the Material of the Cube, but I’m definitely don’t know, how to get the texture as Texture2D from a material with an assigned WCT. Please look in my attached demo and maybe you can help me.

No one can/will help?

Atleast on a pc it doesnt give any errors if you use:

tx2d.SetPixels((go.renderer.material.mainTexture as WebCamTexture).GetPixels());

OMG!!! I’m soooo stupid :smile:

Thank you so much! This works great!!

I think I don’t really understand what ‘as …’ means. Does it tells the compiler which kind of texture is assigned to mainTexture?

how to get the texture as Texture2D from a material with an assigned WCT

In case anyone is wondering how to convert a WCT to Tex2D… You have to point the Tex2D to the native texture pointer.

tx2d.UpdateExternalTexture(webcamTexture.GetNativeTexturePtr());

I am building the project for Wp8 it throws :
Exception: External component has thrown an exception.
Type: System.Runtime.InteropServices.SEHException
Module: UnityEngine
InnerException:
AdditionalInfo:
at UnityEngine.Internal.$Calli.Invoke62(Int32 arg0, Int32 arg1, Int32 arg2, Int32 arg3, Int32 arg4, Int32 arg5, IntPtr method)
at UnityEngine.Texture2D.GetPixels(Int32 x, Int32 y, Int32 blockWidth, Int32 blockHeight, Int32 miplevel)
at UnityEngine.Texture2D.GetPixels(Int32 x, Int32 y, Int32 blockWidth, Int32 blockHeight)
at MaterialCreator.ExtractTextureFromMaterial(Int32 num, Texture2D sourceText, Int32 row, Int32 col, List`1& textureList)
at MaterialCreator.LoadAtlas()
at MaterialCreator.Awake()
at MaterialCreator.$Invoke0(Int64 instance, Int64* args)
at UnityEngine.Internal.$MethodUtility.InvokeMethod(Int64 instance, Int64* args, IntPtr method)