Created
February 12, 2023 02:26
-
-
Save NanyiJiang/d11828eb09e3cf00155deceef7f6e986 to your computer and use it in GitHub Desktop.
Unity Streaming Virtual Texture Request improvement
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEngine; | |
#if ENABLE_VIRTUALTEXTURES | |
using VT = UnityEngine.Rendering.VirtualTexturing; | |
#endif | |
// [ExecuteInEditMode] | |
public class VTRequester : MonoBehaviour | |
{ | |
#if ENABLE_VIRTUALTEXTURES | |
List<VTProperty> m_Stacks = new List<VTProperty>(); | |
//The standard texture tile size is 128 pixels. | |
const int k_TileSizeInPxl = 128; | |
public struct VTProperty | |
{ | |
public Material mat; | |
public int stackId; | |
public int topMip; | |
} | |
public void CacheVTProperties() | |
{ | |
Debug.Log("caching VT properties"); | |
m_Stacks.Clear(); | |
Renderer[] meshRenderers = FindObjectsOfType<MeshRenderer>(true); | |
var skinnedMeshRenderers = FindObjectsOfType<SkinnedMeshRenderer>(true); | |
var renderers = meshRenderers.Concat(skinnedMeshRenderers); | |
Dictionary<int, Material> materials = new Dictionary<int, Material>(); | |
//find all unique materials | |
foreach (Renderer r in renderers) | |
{ | |
var materialsOfRenderer = r.sharedMaterials; | |
foreach(var mat in materialsOfRenderer) { | |
if (mat == null) continue; | |
if( !materials.ContainsKey(mat.GetInstanceID()) ) | |
{ | |
materials.Add(mat.GetInstanceID(), mat); | |
} | |
} | |
} | |
foreach (var m in materials) | |
{ | |
//We use the stack ID to request a mip map of this stack to be streamed | |
//We use the max Dimension to calculate the top mip | |
var stackIDandMaxDimensions = GetAllStackIDAndMaxDimensions(m.Value); | |
var tailMips = (int)Mathf.Log(k_TileSizeInPxl, 2); | |
if (stackIDandMaxDimensions.Count != 0) | |
{ | |
foreach (var item in stackIDandMaxDimensions) | |
{ | |
var stackId = item.Key; | |
var stackSize = item.Value; | |
if (stackSize != 0) { | |
//Calculate the lowest resolution mip available. A stack does not have mips smaller than the tile size. | |
//a texture of 128x128 has 1 mip level, 256x256 has 2 mip levels, etc... | |
int topMip = (int)Mathf.Log(stackSize, 2) - tailMips ; | |
VTProperty s; | |
s.mat = m.Value; | |
s.stackId = stackId; | |
s.topMip = topMip; | |
m_Stacks.Add(s); | |
} | |
} | |
} | |
} | |
//Debug.Log("found materials " + materials.Count); | |
} | |
void Update() | |
{ | |
var i = Random.Range(0, m_Stacks.Count); | |
var s = m_Stacks[i]; | |
VT.Streaming.RequestRegion(s.mat, s.stackId, new Rect(0, 0, 1, 1), s.topMip, 1); | |
} | |
//In the future there might be better ways to do this. | |
Dictionary<int, int> GetAllStackIDAndMaxDimensions(Material mat) | |
{ | |
Shader shader = mat.shader; | |
var stackIDandMaxDimensions = new Dictionary<int, int>(); | |
int count = shader.GetPropertyCount(); | |
for (int i = 0; i < count; i++) | |
{ | |
if (shader.GetPropertyType(i) == UnityEngine.Rendering.ShaderPropertyType.Texture) | |
{ | |
string stackName; | |
int layerIndex; | |
//check if textures on a material are part of a stack. | |
if (shader.FindTextureStack(i, out stackName, out layerIndex)) | |
{ | |
var stackId = Shader.PropertyToID(stackName); | |
if (!stackIDandMaxDimensions.ContainsKey(stackId)) | |
{ | |
int w = 0, h = 0; | |
VT.Streaming.GetTextureStackSize(mat, stackId, out w, out h); | |
if (w == 0 || h == 0) { | |
// TODO: resolve invalid streaming requests | |
// Debug.Log($"Invalid stack {mat.name}"); | |
} | |
stackIDandMaxDimensions[stackId] = Mathf.Max(w, h); | |
} | |
} | |
} | |
} | |
return stackIDandMaxDimensions; | |
} | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment