Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

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

Discussion in 'iOS and tvOS' started by DeepShader, Oct 6, 2012.

  1. DeepShader

    DeepShader

    Joined:
    May 29, 2009
    Posts:
    682
    Hi there,
    I'm on Unity iOS Pro and don't understand, why this simple lines of code generates a compiler error:

    Code (csharp):
    1.  
    2. var tx2d = Texture2D(go.renderer.material.mainTexture.width,go.renderer.material.mainTexture.height,TextureFormat.RGB24, false);
    3. tx2d.SetPixels(go.renderer.material.mainTexture.GetPixels());
    4.  
    The compiler says:
    'GetPixels' is not a member of 'UnityEngine.Texture'

    Maybe I'm to stupid, to see the fault :D

    Please help me :)


    BTW: As Desktop-Version this code works perfect!
     
  2. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,352
    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?
     
  3. DeepShader

    DeepShader

    Joined:
    May 29, 2009
    Posts:
    682
    This is not the problem..
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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.

    Code (csharp):
    1. tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());
    --Eric
     
  5. DeepShader

    DeepShader

    Joined:
    May 29, 2009
    Posts:
    682
    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?
     
  6. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It casts renderer.material.mainTexture, which returns Texture, to Texture2D.

    --Eric
     
  7. DeepShader

    DeepShader

    Joined:
    May 29, 2009
    Posts:
    682
    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:

    Code (csharp):
    1. #pragma strict
    2.  
    3. import System;
    4. import System.IO;
    5. import HutongGames.PlayMaker;
    6.  
    7.  
    8.  
    9.  
    10.  
    11. @ActionCategory("Webcam")
    12. public class PNGSave extends FsmStateAction{
    13.  
    14.     @UIHint(UIHint.Variable)
    15.     public var gameobject : FsmOwnerDefault;
    16.  
    17.     public var filePath : FsmString;
    18.     public var fileName : FsmString;
    19.        
    20.     @UIHint(UIHint.Variable)
    21.     @ObjectTypeAttribute(typeof(WebCamTexture))
    22.     public var webCamTexture : FsmObject;
    23.    
    24.    
    25.    
    26.     public function Reset()
    27.     {
    28.         gameobject = null;
    29.         filePath = null;
    30.         fileName = null;
    31.     }
    32.  
    33.    
    34.    
    35.    
    36.  
    37.     public function OnEnter()
    38.     {
    39.         var go : GameObject = Fsm.GetOwnerDefaultTarget(gameobject);
    40.         var tx2d = Texture2D(go.renderer.material.mainTexture.width,go.renderer.material.mainTexture.height,TextureFormat.RGB24, false);
    41.    
    42.    
    43.         tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());
    44.  
    45.         tx2d.Apply();
    46.        
    47.         if (filePath != null) filePath = "/" + filePath;
    48.  
    49.         File.WriteAllBytes(Application.persistentDataPath + filePath + "/" + fileName + ".png",tx2d.EncodeToPNG());
    50.     }
    51. }
    52.  
    53.  
    54.  
    55.  
    At runtime I get this error:
    NullReferenceException: Object reference not set to an instance of an object
    PNGSave.OnEnter () (at Assets/PNGSave.js:43)
     
  8. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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
     
  9. DeepShader

    DeepShader

    Joined:
    May 29, 2009
    Posts:
    682
    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 -.-


    Code (csharp):
    1. public function OnEnter()
    2.     {
    3.         var go : GameObject = Fsm.GetOwnerDefaultTarget(gameobject);
    4.         var tx2d = Texture2D(go.renderer.material.mainTexture.width,go.renderer.material.mainTexture.height,TextureFormat.DXT5, false);
    5.    
    6.         var ren : Renderer = go.renderer;
    7.         var mat : Material = go.renderer.material;
    8.         var tex : Texture = go.renderer.material.mainTexture;
    9.         var tex2 : Texture2D = go.renderer.material.mainTexture as Texture2D;
    10.    
    11.         tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());
    12.  
    13.         tx2d.Apply();
    14.        
    15.         if (filePath != null) filePath = "/" + filePath;
    16.  
    17.         File.WriteAllBytes(Application.persistentDataPath + filePath + "/" + fileName + ".png",tx2d.EncodeToPNG());
    18.     }
    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

    Code (csharp):
    1. tx2d.SetPixels(go.renderer.material.mainTexture.GetPixels());
    it works fine on desktop, but not on iOS

    with
    Code (csharp):
    1. tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());
    it breaks on every system!? oO
     
    Last edited: Oct 7, 2012
  10. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    There is no TextureFormat.DXT5 on iOS.

    --Eric
     
  11. DeepShader

    DeepShader

    Joined:
    May 29, 2009
    Posts:
    682
    Yes, I know - this was for testing on desktop. I modified my code again, to find what's null:

    Code (csharp):
    1.     public function OnEnter()
    2.     {
    3.         var go : GameObject = Fsm.GetOwnerDefaultTarget(gameobject);
    4.         var tx2d = Texture2D(go.renderer.material.mainTexture.width,go.renderer.material.mainTexture.height,TextureFormat.RGB24, false);
    5.    
    6.         Debug.Log("Test Start");
    7.         var ren : Renderer = go.renderer;
    8.         if (ren == null) Debug.Log("1 failed"); else Debug.Log("1 passed");
    9.        
    10.         var mat : Material = go.renderer.material;
    11.         if (mat == null) Debug.Log("2 failed"); else Debug.Log("2 passed");
    12.  
    13.  
    14.         var tex : Texture = go.renderer.material.mainTexture;
    15.         if (tex == null) Debug.Log("3 failed"); else Debug.Log("3 passed");
    16.  
    17.  
    18.         var tex2 : Texture2D = go.renderer.material.mainTexture as Texture2D;
    19.         if (tex2 == null) Debug.Log("4 failed"); else Debug.Log("4 passed");   
    20.    
    21.    
    22.         tx2d.SetPixels((go.renderer.material.mainTexture as Texture2D).GetPixels());
    23.  
    24.         tx2d.Apply();
    25.        
    26.         if (filePath != null) filePath = "/" + filePath;
    27.  
    28.         File.WriteAllBytes(Application.persistentDataPath + filePath + "/" + fileName + ".png",tx2d.EncodeToPNG());
    29.     }
    And the result:

    This line of code produce the error
    Code (csharp):
    1. var tex2 : Texture2D = go.renderer.material.mainTexture as Texture2D;
    So this means, that the convertion to Texture2D does not work, because one line above
    Code (csharp):
    1. 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:

    Code (csharp):
    1. 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
    Code (csharp):
    1. tx2d.SetPixels(go.renderer.material.mainTexture.GetPixels());
    and it could not be
    Code (csharp):
    1. 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).
     
    Last edited: Oct 7, 2012
  12. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    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:

    Code (csharp):
    1. #pragma strict
    2.  
    3. var go : GameObject;
    4.  
    5. function Start () {
    6.     var tex = go.renderer.material.mainTexture as Texture2D;
    7.     var tx2d = Texture2D(tex.width, tex.height, TextureFormat.RGB24, false);
    8.     tx2d.SetPixels32(tex.GetPixels32());
    9.     tx2d.Apply();
    10.     renderer.material.mainTexture = tx2d;
    11. }
    --Eric
     
  13. DeepShader

    DeepShader

    Joined:
    May 29, 2009
    Posts:
    682
    Ok, that's fine. But I still don't understand why this line with dynamic typing works:

    Code (csharp):
    1. tx2d.SetPixels(go.renderer.material.mainTexture.GetPixels());
    and this line with #pragma strik doesn't:

    Code (csharp):
    1. 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.
     
    Last edited: Oct 8, 2012
  14. DeepShader

    DeepShader

    Joined:
    May 29, 2009
    Posts:
    682
    No one can/will help?
     
  15. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,352
    Atleast on a pc it doesnt give any errors if you use:

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

    DeepShader

    Joined:
    May 29, 2009
    Posts:
    682
    OMG!!! I'm soooo stupid :D

    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?
     
  17. pixel_fiend

    pixel_fiend

    Joined:
    Jun 16, 2014
    Posts:
    4
    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());
     
  18. soni_619

    soni_619

    Joined:
    Mar 30, 2015
    Posts:
    3
    I am building the project for Wp8 it throws :
    Exception: External component has thrown an exception.
    Type: System.Runtime.InteropServices.SEHException
    Module: UnityEngine
    InnerException: <No Data>
    AdditionalInfo:<No Data>
    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)