オブジェクトに適用されているマテリアルをテクスチャを変更して変更していますが、問題は、これを実行しているときにラグが発生することです。
unity3dの一時的な遅延を回避するために、メモリにいくつかのテクスチャをプリロードするにはどうすればよいですか?
オブジェクトに適用されているマテリアルをテクスチャを変更して変更していますが、問題は、これを実行しているときにラグが発生することです。
unity3dの一時的な遅延を回避するために、メモリにいくつかのテクスチャをプリロードするにはどうすればよいですか?
追加する直前にテクスチャをロードしていますか? 新しいテクスチャはどのように保存されますか? 通常、事前キャッシュは Awake() または Start() ループ中に行われます。
Renderer objectRenderer;
public Texture2D replacementTextureAsset;
Texture2D runtimeTextureReplacement;
void Awake()
{
objectRenderer = (Renderer)GetComponent(typeof(Renderer));
// Either have the texture assigned via the inspector (replacementTextureAsset above)
// or else get a reference to it at runtime. Either way, the texture will be loaded into memory by the end of this loop.
runtimeTextureReplacement = Resources.Load("myReplacementAsset");
}
void TextureReplace() // Called whenever
{
objectRenderer.material.texture = replacementTextureAsset;
OR
objectRenderer.material.texture = runtimeTextureReplacement;
}
これが既に実行されていて、まだ「ラグ」がある場合は、グラフィック カードのフレーム バッファにテクスチャを送信するという避けられない結果を経験している可能性があります。その場合は、テクスチャを小さくするしかありません。
クールではないかもしれませんが、Unity 5.3 で動作します。テクスチャをプリロードしたいすべてのゲームオブジェクトで、この拡張メソッドを awake/start scene/monobehaviour で呼び出します。
public static class GameObjectExtension
{
public static void PreloadTexture( this GameObject go )
{
var render = go.GetComponentInChildren<Renderer>();
if ( render && render.sharedMaterial && render.sharedMaterial.mainTexture )
{
int dd = render.sharedMaterial.mainTexture.width;
}
}
}
発想はここから。
私はあなたの質問をもう少し考えました。これが私の提案です。これはハックであり、このコードを私の名前に関連付ける必要がなかったらいいのにと思います。
public bool TextureCached = false;
public bool TextureLoaded = false;
public bool TextureLoadReady = false;
public string TexturePath = "";
public int MaxPixelConvert = 1000;
Texture2D cached_texture = null;
public Vector2 last_pixel = new Vector2(0,0);
// Use this for initialization
void Start () {
SwapMainTexture();
StartWorker();
}
void StartWorker(){
Thread t1 = new Thread (new ThreadStart (this.ListenForUpdate));
t1.Start();
}
/// <summary>
/// Reads new texture from TexturePath
/// </summary>
IEnumerator ReadNewTexture(){
UnityEngine.WWW urltexture = new WWW(TexturePath);
yield return urltexture;
cached_texture = urltexture.texture;
TextureLoadReady = false;
TextureCached = true;
}
void ListenForUpdate(){
// Simulate waiting for an asynchronous update notifying us of the updated texture.
Thread.Sleep(1000);
// ...Receive some notification image is ready load.
// In my case, I'm just loading a local file for testing.
TexturePath = @"file://C:\Users\Public\Pictures\LargeAssPicture.jpg";
TextureLoadReady = true;
}
/// <summary>
/// Create a temporary copy of maintexture so that SetPixel doesn't overwrite the original
/// </summary>
void SwapMainTexture(){
Texture2D texture = (Texture2D)Instantiate(renderer.material.mainTexture);
renderer.material.mainTexture = texture;
}
/// <summary>
/// Update the main texture in small chunks (<MaxPixelConvert)
/// </summary>
void ImABadIdea(){
int count = 0;
Texture2D main_texture = (Texture2D)renderer.sharedMaterial.mainTexture;
for(int x = (int)last_pixel.x; x <= cached_texture.width; x++){
for(int y = (int)last_pixel.y; y <= cached_texture.height; y++){
main_texture.SetPixel(x,y,cached_texture.GetPixel(x,y));
last_pixel = new Vector2(x,y);
if(y+1>=cached_texture.height)last_pixel.y = 0;
count += 1;
if(count >= MaxPixelConvert)break;
}
if(count >= MaxPixelConvert)break;
}
main_texture.Apply();
if(last_pixel.x == cached_texture.width && last_pixel.y == cached_texture.height){
TextureLoaded = true;
}
}
void Update () {
if(TextureLoadReady){ //trigger when new texture ready to load
TextureLoadReady = false;
StartCoroutine(ReadNewTexture());
}
if(TextureCached && !TextureLoaded){ //trigger when new texture is loaded and start streaming it
ImABadIdea();
}
}
テクスチャの読み込みは、単純なワーカー スレッドによってトリガーされます。スレッドがロードする新しいテクスチャの通知を「受け取る」と、適切なフラグが設定されます (共有リソースをロックしていないことはわかっていますが、私の例は十分に単純です)。その後、テクスチャがキャッシュに取り込まれ、メイン スレッド内の各フレーム ティックごとに小さな 1000 ピクセルのチャンクでオブジェクトのテクスチャに徐々に適用されます。
私のテスト シーンでは、メイン オブジェクトと、そのオブジェクトのクローンを画面外に隠したままにしました。クローンにはスクリプトがあり、新しいテクスチャをロードします。テクスチャがロードされたら、それをメイン オブジェクトと交換しました。
コードは 3000x3000 ピクセルの画像でテストされました。
何らかの方法でテクスチャを使用すると、グラフィック カードにアップロードされます。そのため、ゲームのロード画面で、「プリロード」したいすべてのテクスチャをループして、何らかの方法で使用するだけです。たとえば、RenderTexture にレンダリングするか、GUI.DrawTexture を使用してそれらを画面(そして、ロード画面の背景を一番上に描画します)。