Unity 6.3
0 онлайн 3 гостей 3 в системе
Вход

Разреженные текстуры

Разреженные текстуры (также известные как "тюльпановые текстуры" или "мега-тексты") представляют собой текстуры, которые слишком большие, чтобы помещаться в графическую память в целом. Для их обработки Unity разбивает основную текстуру на более мелкие прямоугольные секции, известные как "тюльпаны". Отдельные тюльпаны могут затем загружаться по мере необходимости. Например, если камера может видеть только небольшую область разреженной текстуры, то в памяти должны находиться только те тюльпаны, которые в данный момент видны.

За исключением плитки, редкая текстура ведет себя как любая другая текстура в использовании. Шейдеры могут использовать их без особых изменений и они могут иметь mipmaps, использовать все режимы фильтрации текстуры и т.д. Если определенная плитка не может быть загружена по какой-либо причине, то результат не определен; некоторые GPUs показывают черную область, где отсутствующая плитка должна быть, но это поведение не стандартизировано.

Не все аппаратные средства и платформы поддерживают редкие текстуры. Например, на системах DirectX они требуют поддержки DX11.2 (Windows 8.1) и относительно недавнего GPU. На OpenGL они требуют поддержки расширения ARB_sparse_texture. Редкие текстуры поддерживают только несжатые форматы текстур.

См. страницу справки по скриптам SparseTexture для более подробной информации об обработке редких текстур из скриптов.

Пример

Следующий пример загружает только текстуру для плитки прямо под камерой. Пример работает только в том случае, если ваше оборудование и платформа поддерживают редкие текстуры. Чтобы использовать пример:

  1. Создание сцены с большой плоскостью GameObject. Дополнительную информацию см. в Примитивные и замещающие объекты.
  2. Прикрепите скрипт к GameObject.
  3. Введите режим воспроизведения.
  4. Измените положение камеры по осям x и y. Вид Scene показывает загрузку и разгрузку плиток.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class SparseTextureExample : MonoBehaviour {

    private int tileCountX;
    private int tileCountY;
    private Bounds bounds;
    private SparseTexture texture;
    private Color32[] colorForSingleTile;
    private Vector2 lastTileVisible;

    void Awake()
    {
        if (!SystemInfo.supportsSparseTextures)
        {
            Debug.Log("Sparse textures are not supported on this platform.");
        }

        bounds = GetComponent<Renderer>().bounds;
        lastTileVisible = new Vector2(0f, 0f);

        // Create the sparse texture
        DestroyImmediate(texture);
        texture = new SparseTexture(1024, 1024, TextureFormat.RGBA32, 1, false);

        // Set the texture on the material
        GetComponent<Renderer>().sharedMaterial.mainTexture = texture;

        // Get the number of tiles from the sparse texture
        tileCountX = (texture.width + texture.tileWidth - 1) / texture.tileWidth;
        tileCountY = (texture.height + texture.tileHeight - 1) / texture.tileHeight;
        Debug.Log("Tile size: " + texture.tileWidth + " x " + texture.tileHeight + " pixels");
        Debug.Log("Tile count: " + tileCountX + " x " + tileCountY);

        // Fill the color array for a single tile with red
        colorForSingleTile = new Color32[texture.tileWidth * texture.tileHeight];
        for(int i = 0; i < colorForSingleTile.Length; i++)
        {
            colorForSingleTile[i] = new Color32(255, 0, 0, 255);
        }
    }

    void LateUpdate()
    {
        // Get camera position
        Vector3 camPos = Camera.main.transform.position;

        // Get tile index x and y under the camera position
        float px = Mathf.Clamp(Mathf.InverseLerp (bounds.min.x, bounds.max.x, camPos.x), 0.0f, 0.9999f);
        float py = Mathf.Clamp(Mathf.InverseLerp (bounds.min.z, bounds.max.z, camPos.z), 0.0f, 0.9999f);
        int tileX = (int)(px * 1024 / texture.tileWidth);
        int tileY = (int)(py * 1024 / texture.tileHeight);

        // Update the tile with the red color
        // In a real project, you might load the texture from disk or generate it procedurally
        texture.UpdateTile(tileX, tileY, 0, colorForSingleTile);

        // Use the SparseTexture API to unload the texture of the previous tile under the camera
        Vector2 tileVisible = new Vector2(tileX, tileY);
        if(lastTileVisible != tileVisible)
        {           
            Debug.Log("Tile under camera: " + tileX + ", " + tileY);

            texture.UnloadTile((int)lastTileVisible.x, (int)lastTileVisible.y, 0);
            Debug.Log("Unloaded: " + (int)lastTileVisible.x + ", " + (int)lastTileVisible.y);

            lastTileVisible = tileVisible;
        }
    }

    void OnDisable ()
    {
        GetComponent<Renderer>().sharedMaterial.mainTexture = null;
        DestroyImmediate(texture);
    }
}