Плагин Unity Текстура неизменна - PullRequest
3 голосов
/ 14 мая 2019

У меня довольно сложный вопрос.В Unity WebGL загрузка текстур (с использованием LoadImage) приводит к зависанию движка на несколько миллисекунд, что вызывает заикание в игре, что еще хуже при загрузке большой текстуры.Это известная проблема.

Чтобы избежать зависания, я решил попробовать браузеру загрузить текстуру и применить эту текстуру к игровому объекту.Таким образом, не должно быть замораживания, потому что браузер делает это в потоке.

Сделать это немного сложно, поэтому я основал это решение на WebGLMovieTexture, который является бесплатным активом в хранилище ресурсов, который позволяетВы можете воспроизводить фильмы с помощью встроенных в проигрыватель браузеров (вместо VideoPlayer для Unities), применяя их к текстуре, а затем к объекту gameObject.Я использую это часто, и это работает, поэтому я решил попробовать то же самое с изображениями.

Для этого нужно создать плагин в Javascript, интерфейсный класс для этого плагина в c #, а затем создать класс, которыйиспользует этот интерфейсный класс.

Сначала вот плагин Javascript, я включил здесь только важные биты

var LibraryWebGLImageTexture = {

$imageInstances: [],

WebGLImageTextureCreate: function(url)
{
  var str = Pointer_stringify(url);
  var img = document.createElement('img');
  img.onload=function() {
      console.log("image load completed"); <<<-------------
  }
  img.style.display = 'none';
  img.src = str;
  return imageInstances.push(img) - 1;
},

WebGLImageTextureRefresh: function(img, tex)
{
  GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[tex]);
  GLctx.pixelStorei(GLctx.UNPACK_FLIP_Y_WEBGL, true);
  GLctx.texImage2D(GLctx.TEXTURE_2D, 0, GLctx.RGBA, GLctx.RGBA,GLctx.UNSIGNED_BYTE, imageInstances[img]);
  GLctx.pixelStorei(GLctx.UNPACK_FLIP_Y_WEBGL, false);
}

Вот класс интерфейса C # для плагина, опять же включил только важные части

public class WebGLImageTexture 
{
[DllImport("__Internal")]
private static extern int WebGLImageTextureCreate (string url);

[DllImport("__Internal")]
private static extern void WebGLImageTextureRefresh (int img, int texture);

public Texture2D m_Texture=null;
int m_Instance; 
bool m_Loop;

public WebGLImageTexture (string url)
{
    Debug.Log("creating image element");
    m_Instance = WebGLImageTextureCreate(url);
    imgInfo();
    Debug.Log("image element created:"+m_Instance);
}

public void imgInfo()
{
    Debug.Log("trying to get width and height...=" + m_Instance);
    var width = 672;
    var height = 420;
    m_Texture = new Texture2D(width, height, TextureFormat.ARGB32, false);
    m_Texture.wrapMode = TextureWrapMode.Clamp;
    Debug.Log("IMAGE:"+m_Texture);
}
public void Refresh()
{
    Debug.Log("Image Update IN");
    WebGLImageTextureRefresh(m_Instance, m_Texture.GetNativeTextureID());
}

static public implicit operator Texture2D(WebGLImageTexture tex)
{
    Debug.Log("IMPLICIT TEXTURE 2D");
    return tex.m_Texture;
}   

Класс, представленный ниже, использует вышеуказанный интерфейс к плагину для создания экземпляра плагина, передавая URL-адрес изображения.Затем он ждет короткое время загрузки изображения, а затем вызывает функцию обновления плагинов для передачи текстуры в gameObject.

WebGLImageTexture it;   // plugin interface

void Start () {
    it = new WebGLImageTexture("http://interfacelift.com/wallpaper/previews/04194_pagview_672x420.jpg");
    gameObject.GetComponent<Renderer>().material.mainTexture = it;
    Invoke("loaded", 20); // wait for image to load then invoke this
} 


public void loaded()
{
    it.Refresh();
}

//Spin the cube

void Update () {
    transform.Rotate(new Vector3(1, 2, 3) * Time.deltaTime * 10);
}

Как видно из кода плагина javascript в самом верху, когдаизображение загружается, оно печатает на консоль "загрузка изображения завершена".Это работает!

Через некоторое время время ожидания истекает, и вызывается функция обновления плагинов, которая делает что-то для помещения изображения в текстуру, но в функции обновления она вылетает с ошибкой

* 1021.*

Кажется, что функция обновления плагинов использует OpenGL, чего я не знаю, и дает эту ошибку в функции обновления, которая является ключом к этой работе.

Кто-нибудь знает, как решить эту ошибку

1 Ответ

2 голосов
/ 14 мая 2019

Единственная причина, по которой я могу подумать, чтобы получить эту ошибку, заключается в том, что текстура была выделена с gl.texStorage2D, что означает, что вы можете использовать gl.texSubImage2D только для обновления текстуры.

gl.texStorage2D выделяет текстуру и весь ее уровень в один вызов. С этого момента размер текстуры не может быть изменен. gl.texImage2D перераспределяет отдельные уровни MIP, где вы не можете использовать это для обновления текстуры, выделенной с помощью gl.texStorage2D, но вы можете обновить содержимое существующей текстуры с помощью gl.texSubImage2D

Другими словами, измените эту строку

GLctx.texImage2D(GLctx.TEXTURE_2D, 0, GLctx.RGBA, GLctx.RGBA,GLctx.UNSIGNED_BYTE, imageInstances[img]);

к этому

GLctx.texSubImage2D(GLctx.TEXTURE_2D, 0, 0, 0, GLctx.RGBA, GLctx.UNSIGNED_BYTE, imageInstances[img]);

Кстати, ваш код будет иметь проблемы, не дожидаясь фактической загрузки текстуры. Просто ожидания "некоторое время" будет недостаточно, если пользователь находится на медленном соединении. Вам нужно будет выполнить рефакторинг, чтобы вы могли либо получить событие из JavaScript в C #, когда изображение загрузилось, либо время от времени опрашивать игру

Просто угадал что-то вроде

var LibraryWebGLImageTexture = {

$imageInstances: [],

WebGLImageTextureCreate: function(url)
{
  var str = Pointer_stringify(url);
  var img = new Image();
  img.src = str;
  return imageInstances.push(img) - 1;
},

WebGLImageTextureLoaded: function(img)
{
  return imageInstances[img].complete;
},

WebGLImageTextureWidth: function(img)
{
  return imageInstances[img].width;
},

WebGLImageTextureHeight: function(img)
{
  return imageInstances[img].height;
},

WebGLImageTextureRefresh: function(img, tex)
{
  GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[tex]);
  GLctx.pixelStorei(GLctx.UNPACK_FLIP_Y_WEBGL, true);
  GLctx.texSubImage2D(GLctx.TEXTURE_2D, 0, 0, 0, GLctx.RGBA, GLctx.UNSIGNED_BYTE, imageInstances[img]);
  GLctx.pixelStorei(GLctx.UNPACK_FLIP_Y_WEBGL, false);
}
public class WebGLImageTexture 
{
[DllImport("__Internal")]
private static extern int WebGLImageTextureCreate (string url);

[DllImport("__Internal")]
private static extern bool WebGLImageTextureLoaded (int img);

[DllImport("__Internal")]
private static extern int WebGLImageTextureWidth (int img);

[DllImport("__Internal")]
private static extern int WebGLImageTextureHeight (int img);

[DllImport("__Internal")]
private static extern void WebGLImageTextureRefresh (int img, int texture);

...

Я дам вам выяснить, хотите ли вы проверить в обновлении, загружено ли изображение, или использовать сопрограмму, чтобы проверить, загружено ли изображение или нет

Если вы хотите также проверить на наличие ошибок, то, возможно, что-то вроде

var LibraryWebGLImageTexture = {

$imageInstances: [],

WebGLImageTextureCreate: function(url)
{
  var str = Pointer_stringify(url);
  var img = new Image();
  var info = {img: img, error: false}
  img.onerror = function() {
    info.error = true;
  };
  img.src = str;
  return imageInstances.push(info) - 1;
},

WebGLImageTextureLoaded: function(img)
{
  return imageInstances[img].img.complete;
},

WebGLImageTextureError: function(img)
{
  return imageInstances[img].error;
},


WebGLImageTextureWidth: function(img)
{
  return imageInstances[img].img.width;
},

WebGLImageTextureHeight: function(img)
{
  return imageInstances[img].img.height;
},

WebGLImageTextureRefresh: function(img, tex)
{
  GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[tex]);
  GLctx.pixelStorei(GLctx.UNPACK_FLIP_Y_WEBGL, true);
  GLctx.texSubImage2D(GLctx.TEXTURE_2D, 0, 0, 0, GLctx.RGBA, GLctx.UNSIGNED_BYTE, imageInstances[img].img);
  GLctx.pixelStorei(GLctx.UNPACK_FLIP_Y_WEBGL, false);
}
public class WebGLImageTexture 
{
[DllImport("__Internal")]
private static extern int WebGLImageTextureCreate (string url);

[DllImport("__Internal")]
private static extern bool WebGLImageTextureLoaded (int img);

[DllImport("__Internal")]
private static extern bool WebGLImageTextureError (int img);

[DllImport("__Internal")]
private static extern int WebGLImageTextureWidth (int img);

[DllImport("__Internal")]
private static extern int WebGLImageTextureHeight (int img);

[DllImport("__Internal")]
private static extern void WebGLImageTextureRefresh (int img, int texture);

...

Теперь вы можете проверить свой опрос, если WebGLImageTextureError вернет true, тогда вы получили ошибку, и если WebGLImageTextureLoaded вернет true, изображение завершено загрузка.

...