浏览代码

prep work for high-end mobile support

prep work for high-end mobile support. Most mobile doesn't support
textureCubeArray so built-in to TextureCacheCubemap we allow a special
path which converts to panorama on the fly upon texture cache population
(only at the very moment when the cube map is injected and cached).
/main
mmikk 8 年前
当前提交
c9bc3369
共有 2 个文件被更改,包括 194 次插入31 次删除
  1. 143
      Assets/ScriptableRenderLoop/common/TextureCache.cs
  2. 82
      Assets/ScriptableRenderLoop/common/CubeToSpherical.shader

143
Assets/ScriptableRenderLoop/common/TextureCache.cs


{
private CubemapArray m_Cache;
// alternative panorama path intended for mobile
// the member variables below are only in use when m_IsNoCubeArray is true.
private bool m_IsNoCubeArray = false;
private Texture2DArray m_CacheNoCubeArray;
private RenderTexture[] m_StagingRTs;
private int m_NumPanoMipLevels;
private int m_PanoWidthTop;
private int m_PanoHeightTop;
private Material m_CubeBlitMaterial;
private int m_CubeMipLevelPropName;
private int m_dstPanoWidthPropName;
private int m_dstPanoHeightPropName;
private int m_cubeSrcTexPropName;
// alternative panorama path intended for mobile
// the member variables below are only in use when m_IsNoCubeArray is true.
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height);
if (texture is Cubemap)
if(m_IsNoCubeArray)
TransferToPanoCache(sliceIndex, texture);
else
mismatch |= (m_Cache.format != (texture as Cubemap).format);
}
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height);
if (mismatch)
{
bool failed = false;
if (texture is Cubemap)
{
mismatch |= (m_Cache.format != (texture as Cubemap).format);
}
for (int f = 0; f < 6; f++)
if (mismatch)
if (!Graphics.ConvertTexture(texture, f, m_Cache, 6 * sliceIndex + f))
bool failed = false;
for (int f = 0; f < 6; f++)
failed = true;
break;
if (!Graphics.ConvertTexture(texture, f, m_Cache, 6 * sliceIndex + f))
{
failed = true;
break;
}
}
if (failed)
{
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})",
texture.name, m_Cache.width, m_Cache.height, m_Cache.format);
if (failed)
else
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})",
texture.name, m_Cache.width, m_Cache.height, m_Cache.format);
for (int f = 0; f < 6; f++)
Graphics.CopyTexture(texture, f, m_Cache, 6 * sliceIndex + f);
else
{
for (int f = 0; f < 6; f++)
Graphics.CopyTexture(texture, f, m_Cache, 6 * sliceIndex + f);
}
return m_Cache;
return m_IsNoCubeArray ? (Texture) m_CacheNoCubeArray : m_Cache;
var res = AllocTextureArray(6 * numCubeMaps);
m_NumMipLevels = GetNumMips(width, width);
var res = AllocTextureArray(numCubeMaps);
m_NumMipLevels = GetNumMips(width, width); // will calculate same way whether we have cube array or not
if(m_IsNoCubeArray)
{
if(!m_CubeBlitMaterial) m_CubeBlitMaterial = new Material(Shader.Find("Hidden/CubeToPano"));
m_PanoWidthTop = 4*width;
m_PanoHeightTop = 2*width;
m_Cache = new CubemapArray(width, numCubeMaps, format, isMipMapped)
// create panorama 2D array. Hardcoding the render target for now when m_IsNoCubeArray is true. No convenient way atm. to
// map from TextureFormat to RenderTextureFormat and don't want to deal with sRGB issues for now.
m_CacheNoCubeArray = new Texture2DArray(m_PanoWidthTop, m_PanoHeightTop, numCubeMaps, TextureFormat.RGBAHalf, isMipMapped)
{
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Repeat
};
m_NumPanoMipLevels = isMipMapped ? GetNumMips(m_PanoWidthTop, m_PanoHeightTop) : 1;
m_StagingRTs = new RenderTexture[m_NumPanoMipLevels];
for(int m=0; m<m_NumPanoMipLevels; m++)
{
m_StagingRTs[m] = new RenderTexture(Mathf.Max(1,m_PanoWidthTop>>m), Mathf.Max(1,m_PanoHeightTop>>m), 0, RenderTextureFormat.ARGBHalf);
}
if(m_CubeBlitMaterial)
{
m_CubeMipLevelPropName = Shader.PropertyToID("_cubeMipLvl");
m_dstPanoWidthPropName = Shader.PropertyToID("_dstPanoWidth");
m_dstPanoHeightPropName = Shader.PropertyToID("_dstPanoHeight");
m_cubeSrcTexPropName = Shader.PropertyToID("_srcCubeTexture");
}
}
else
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Trilinear,
anisoLevel = 0 // It is important to set 0 here, else unity force anisotropy filtering
};
m_Cache = new CubemapArray(width, numCubeMaps, format, isMipMapped)
{
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Trilinear,
anisoLevel = 0 // It is important to set 0 here, else unity force anisotropy filtering
};
}
return res;
}

Texture.DestroyImmediate(m_Cache); // do I need this?
if(m_IsNoCubeArray)
{
Texture.DestroyImmediate(m_CacheNoCubeArray);
for(int m=0; m<m_NumPanoMipLevels; m++)
{
m_StagingRTs[m].Release();
}
m_StagingRTs=null;
if(m_CubeBlitMaterial) Material.DestroyImmediate(m_CubeBlitMaterial);
}
else Texture.DestroyImmediate(m_Cache);
}
private void TransferToPanoCache(int sliceIndex, Texture texture)
{
m_CubeBlitMaterial.SetTexture(m_cubeSrcTexPropName, texture);
for(int m=0; m<m_NumPanoMipLevels; m++)
{
m_CubeBlitMaterial.SetInt(m_CubeMipLevelPropName, Mathf.Min(m_NumMipLevels-1,m) );
m_CubeBlitMaterial.SetInt(m_dstPanoWidthPropName, m_StagingRTs[m].width);
m_CubeBlitMaterial.SetInt(m_dstPanoHeightPropName, m_StagingRTs[m].height);
Graphics.SetRenderTarget(m_StagingRTs[m]);
Graphics.Blit(null, m_CubeBlitMaterial, 0);
}
for(int m=0; m<m_NumPanoMipLevels; m++)
Graphics.CopyTexture(m_StagingRTs[m], 0, 0, m_CacheNoCubeArray, sliceIndex, m);
}
}

82
Assets/ScriptableRenderLoop/common/CubeToSpherical.shader


Shader "Hidden/CubeToPano" {
Properties {
_SrcBlend ("", Float) = 1
_DstBlend ("", Float) = 1
}
SubShader {
Pass
{
ZWrite Off
ZTest Always
Cull Off
Blend Off
CGPROGRAM
#pragma target 4.5
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
UNITY_DECLARE_TEXCUBE(_srcCubeTexture);
uniform int _cubeMipLvl;
uniform int _dstPanoWidth;
uniform int _dstPanoHeight;
struct v2f {
float4 vertex : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
v2f vert (float4 vertex : POSITION, float2 texcoord : TEXCOORD0)
{
v2f o;
o.vertex = UnityObjectToClipPos(vertex);
o.texcoord = texcoord.xy;
return o;
}
half2 DirectionToSphericalTexCoordinate(half3 dir) // use this for the lookup
{
// coordinate frame is (-Z,X) meaning negative Z is primary axis and X is secondary axis.
float recipPi = 1.0/3.1415926535897932384626433832795;
return half2( 1.0-0.5*recipPi*atan2(dir.x, -dir.z), asin(dir.y)*recipPi+0.5 );
}
half3 SphericalTexCoordinateToDirection(half2 sphTexCoord)
{
float pi = 3.1415926535897932384626433832795;
float theta = (1-sphTexCoord.x) * (pi*2);
float phi = (sphTexCoord.y-0.5) * pi;
float csTh, siTh, csPh, siPh;
sincos(theta, siTh, csTh);
sincos(phi, siPh, csPh);
// theta is 0 at negative Z (backwards). Coordinate frame is (-Z,X) meaning negative Z is primary axis and X is secondary axis.
return float3(siTh*csPh, siPh, -csTh*csPh);
}
half4 frag (v2f i) : SV_Target
{
uint2 pixCoord = ((uint2) i.vertex.xy);
half3 dir = SphericalTexCoordinateToDirection(i.texcoord.xy);
half3 res = UNITY_SAMPLE_TEXCUBE_LOD(_srcCubeTexture, dir, (float) _cubeMipLvl).xyz;
return half4(res,1.0);
}
ENDCG
}
}
Fallback Off
}
正在加载...
取消
保存