浏览代码

HDRenderLoop; General cleanup pass around OnDisable/Cleanup

/main
Sebastien Lagarde 8 年前
当前提交
4a757643
共有 11 个文件被更改,包括 182 次插入195 次删除
  1. 40
      Assets/ScriptableRenderLoop/HDRenderLoop/Editor/HDRenderLoopInspector.cs
  2. 63
      Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs
  3. 57
      Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.cs
  4. 4
      Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.hlsl
  5. 155
      Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.cs
  6. 5
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.cs
  7. 4
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/AtmosphericParameters.cs
  8. 4
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyRenderer.cs
  9. 10
      Assets/ScriptableRenderLoop/HDRenderLoop/Utilities.cs
  10. 29
      Assets/ScriptableRenderLoop/common/TextureSettings.cs
  11. 6
      Assets/ScriptableRenderLoop/fptl/FptlLighting.cs

40
Assets/ScriptableRenderLoop/HDRenderLoop/Editor/HDRenderLoopInspector.cs


public readonly GUIContent tileLightLoopDebugMode = new GUIContent("Enable Debug mode", "Toggle overheat map mode");
public readonly GUIContent directIndirectSinglePass = new GUIContent("Enable direct and indirect lighting in single pass", "Toggle");
public readonly GUIContent bigTilePrepass = new GUIContent("Enable big tile prepass", "Toggle");
public readonly GUIContent clustered = new GUIContent("Enable clusted", "Toggle");
public readonly GUIContent clustered = new GUIContent("Enable clustered", "Toggle");
public readonly GUIContent textureSettings = new GUIContent("texture Settings");
public readonly GUIContent spotCookieSize = new GUIContent("spotCookie Size");
public readonly GUIContent pointCookieSize = new GUIContent("pointCookie Size");
public readonly GUIContent reflectionCubemapSize = new GUIContent("reflectionCubemap Size");
}
private static Styles s_Styles = null;

EditorGUI.indentLevel++;
EditorGUI.BeginChangeCheck();
shadowParameters.enabled = EditorGUILayout.Toggle(styles.shadowsEnabled, shadowParameters.enabled);
shadowParameters.shadowAtlasWidth = Mathf.Max(0, EditorGUILayout.IntField(styles.shadowsAtlasWidth, shadowParameters.shadowAtlasWidth));
shadowParameters.shadowAtlasHeight = Mathf.Max(0, EditorGUILayout.IntField(styles.shadowsAtlasHeight, shadowParameters.shadowAtlasHeight));

shadowParameters.directionalLightCascades[i] = Mathf.Max(0, EditorGUILayout.FloatField(shadowParameters.directionalLightCascades[i]));
}
EditorGUI.indentLevel--;
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(renderLoop); // Repaint
}
EditorGUI.indentLevel--;
EditorGUILayout.Space();
var textureParameters = renderLoop.textureSettings;
EditorGUILayout.LabelField(styles.textureSettings);
EditorGUI.indentLevel++;
EditorGUI.BeginChangeCheck();
textureParameters.spotCookieSize = Mathf.NextPowerOfTwo(Mathf.Clamp(EditorGUILayout.IntField(styles.spotCookieSize, textureParameters.spotCookieSize), 16, 1024));
textureParameters.pointCookieSize = Mathf.NextPowerOfTwo(Mathf.Clamp(EditorGUILayout.IntField(styles.pointCookieSize, textureParameters.pointCookieSize), 16, 1024));
textureParameters.reflectionCubemapSize = Mathf.NextPowerOfTwo(Mathf.Clamp(EditorGUILayout.IntField(styles.reflectionCubemapSize, textureParameters.reflectionCubemapSize), 64, 1024));
EditorGUILayout.Space();
EditorGUILayout.LabelField(styles.tileLightLoopSettings);

renderLoop.tilePassLightLoop.debugViewTilesFlags = (TilePass.DebugViewTilesFlags)EditorGUILayout.EnumMaskField("DebugView Tiles", renderLoop.tilePassLightLoop.debugViewTilesFlags);
renderLoop.tilePassLightLoop.enableDirectIndirectSinglePass = EditorGUILayout.Toggle(styles.directIndirectSinglePass, renderLoop.tilePassLightLoop.enableDirectIndirectSinglePass);
renderLoop.tilePassLightLoop.enableBigTilePrepass = EditorGUILayout.Toggle(styles.bigTilePrepass, renderLoop.tilePassLightLoop.enableBigTilePrepass);
renderLoop.tilePassLightLoop.enableClustered = EditorGUILayout.Toggle(styles.clustered, renderLoop.tilePassLightLoop.enableClustered);
if (renderLoop.tilePassLightLoop != null)
{
renderLoop.tilePassLightLoop.debugViewTilesFlags = (TilePass.DebugViewTilesFlags)EditorGUILayout.EnumMaskField("DebugView Tiles", renderLoop.tilePassLightLoop.debugViewTilesFlags);
renderLoop.tilePassLightLoop.enableDirectIndirectSinglePass = EditorGUILayout.Toggle(styles.directIndirectSinglePass, renderLoop.tilePassLightLoop.enableDirectIndirectSinglePass);
renderLoop.tilePassLightLoop.enableBigTilePrepass = EditorGUILayout.Toggle(styles.bigTilePrepass, renderLoop.tilePassLightLoop.enableBigTilePrepass);
renderLoop.tilePassLightLoop.enableClustered = EditorGUILayout.Toggle(styles.clustered, renderLoop.tilePassLightLoop.enableClustered);
}
if (EditorGUI.EndChangeCheck())
{

63
Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs


[SerializeField]
TextureSettings m_TextureSettings = TextureSettings.Default;
public TextureSettings textureSettings
{
get { return m_TextureSettings; }
}
// Various set of material use in render loop
Material m_FinalPassMaterial;
Material m_DebugViewMaterialGBuffer;

private void OnValidate()
{
// Calling direction Rebuild() here cause this warning:
// "SendMessage cannot be called during Awake, CheckConsistency, or OnValidate UnityEngine.Experimental.ScriptableRenderLoop.HDRenderLoop:OnValidate()"
// Workaround is to declare this dirty flag and call REbuild in Render()
m_CameraColorBuffer = Shader.PropertyToID("_CameraColorTexture");
// We call Cleanup() here because Rebuild() can be call by OnValidate(), i.e when inspector is touch
// Note that module don't need to do the same as the call here is propagated correctly
Cleanup();
m_CameraColorBuffer = Shader.PropertyToID("_CameraColorTexture");
m_CameraDepthBuffer = Shader.PropertyToID("_CameraDepthTexture");
m_CameraColorBufferRT = new RenderTargetIdentifier(m_CameraColorBuffer);

m_LitRenderLoop.Rebuild();
m_CookieTexArray = new TextureCache2D();
m_CookieTexArray.AllocTextureArray(8, (int)m_TextureSettings.spotCookieSize, (int)m_TextureSettings.spotCookieSize, TextureFormat.RGBA32, true);
m_CookieTexArray.AllocTextureArray(8, m_TextureSettings.spotCookieSize, m_TextureSettings.spotCookieSize, TextureFormat.RGBA32, true);
m_CubeCookieTexArray.AllocTextureArray(4, (int)m_TextureSettings.pointCookieSize, TextureFormat.RGBA32, true);
m_CubeCookieTexArray.AllocTextureArray(4, m_TextureSettings.pointCookieSize, TextureFormat.RGBA32, true);
m_CubeReflTexArray.AllocTextureArray(32, (int)m_TextureSettings.reflectionCubemapSize, TextureFormat.BC6H, true);
m_CubeReflTexArray.AllocTextureArray(32, m_TextureSettings.reflectionCubemapSize, TextureFormat.BC6H, true);
// Init various light loop
m_SinglePassLightLoop = new SinglePass.LightLoop();

public override void Cleanup()
{
m_LitRenderLoop.OnDisable();
m_SinglePassLightLoop.OnDisable();
tilePassLightLoop.OnDisable();
if (m_LitRenderLoop != null)
{
m_LitRenderLoop.Cleanup();
m_LitRenderLoop = null;
}
if (m_SinglePassLightLoop != null)
{
m_SinglePassLightLoop.Cleanup();
m_SinglePassLightLoop = null;
}
if (m_TilePassLightLoop != null)
{
m_TilePassLightLoop.Cleanup();
m_TilePassLightLoop = null;
}
m_CubeReflTexArray.Release();
m_CookieTexArray.Release();
m_CubeCookieTexArray.Release();
if (m_CubeReflTexArray != null)
{
m_CubeReflTexArray.Release();
m_CubeReflTexArray = null;
}
if (m_CookieTexArray != null)
{
m_CookieTexArray.Release();
m_CookieTexArray = null;
}
if (m_CubeCookieTexArray != null)
{
m_CubeCookieTexArray.Release();
m_CubeCookieTexArray = null;
}
m_SkyRenderer.OnDisable();
if (m_SkyRenderer != null)
{
m_SkyRenderer.Cleanup();
}
#if UNITY_EDITOR
UnityEditor.SupportedRenderingFeatures.active = UnityEditor.SupportedRenderingFeatures.Default;

57
Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.cs


}
// Static keyword is required here else we get a "DestroyBuffer can only be call in main thread"
static ComputeBuffer s_DirectionalLights;
static ComputeBuffer s_PunctualLightList;
static ComputeBuffer s_EnvLightList;
static ComputeBuffer s_AreaLightList;
static ComputeBuffer s_PunctualShadowList;
static ComputeBuffer s_DirectionalShadowList;
static ComputeBuffer s_DirectionalLights = null;
static ComputeBuffer s_PunctualLightList = null;
static ComputeBuffer s_EnvLightList = null;
static ComputeBuffer s_AreaLightList = null;
static ComputeBuffer s_PunctualShadowList = null;
static ComputeBuffer s_DirectionalShadowList = null;
Material m_DeferredMaterial;
void ClearComputeBuffers()
{
if (s_DirectionalLights != null)
s_DirectionalLights.Release();
if (s_DirectionalShadowList != null)
s_DirectionalShadowList.Release();
if (s_PunctualLightList != null)
s_PunctualLightList.Release();
if (s_AreaLightList != null)
s_AreaLightList.Release();
if (s_PunctualShadowList != null)
s_PunctualShadowList.Release();
if (s_EnvLightList != null)
s_EnvLightList.Release();
}
Material m_DeferredMaterial = null;
ClearComputeBuffers();
s_DirectionalLights = new ComputeBuffer(HDRenderLoop.k_MaxDirectionalLightsOnSCreen, System.Runtime.InteropServices.Marshal.SizeOf(typeof(DirectionalLightData)));
s_DirectionalShadowList = new ComputeBuffer(HDRenderLoop.k_MaxCascadeCount, System.Runtime.InteropServices.Marshal.SizeOf(typeof(DirectionalShadowData)));
s_PunctualLightList = new ComputeBuffer(HDRenderLoop.k_MaxPunctualLightsOnSCreen, System.Runtime.InteropServices.Marshal.SizeOf(typeof(LightData)));

m_DeferredMaterial.EnableKeyword("LIGHTLOOP_SINGLE_PASS");
}
public void OnDisable()
public void Cleanup()
s_DirectionalLights.Release();
s_DirectionalLights = null;
s_DirectionalShadowList.Release();
s_DirectionalShadowList = null;
s_PunctualLightList.Release();
s_PunctualLightList = null;
s_AreaLightList.Release();
s_AreaLightList = null;
s_EnvLightList.Release();
s_EnvLightList = null;
s_PunctualShadowList.Release();
s_PunctualShadowList = null;
Utilities.SafeRelease(s_DirectionalLights);
Utilities.SafeRelease(s_DirectionalShadowList);
Utilities.SafeRelease(s_PunctualLightList);
Utilities.SafeRelease(s_AreaLightList);
Utilities.SafeRelease(s_EnvLightList);
Utilities.SafeRelease(s_PunctualShadowList);
Utilities.Destroy(m_DeferredMaterial);
}

4
Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.hlsl


StructuredBuffer<LightData> _AreaLightList;
StructuredBuffer<EnvLightData> _EnvLightList;
//TEXTURE2D_ARRAY(_ShadowArray);
//SAMPLER2D_SHADOW(sampler_ShadowArray);
//SAMPLER2D(sampler_ManualShadowArray); // TODO: settings sampler individually is not supported in shader yet...
// Use texture atlas for shadow map
//TEXTURE2D(_ShadowAtlas);
//SAMPLER2D_SHADOW(sampler_ShadowAtlas);

155
Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/TilePass/TilePass.cs


public const int MaxNumDirLights = 2;
public const float FltMax = 3.402823466e+38F;
static ComputeShader buildScreenAABBShader;
static ComputeShader buildPerTileLightListShader; // FPTL
static ComputeShader buildPerBigTileLightListShader;
static ComputeShader buildPerVoxelLightListShader; // clustered
static ComputeShader buildScreenAABBShader = null;
static ComputeShader buildPerTileLightListShader = null; // FPTL
static ComputeShader buildPerBigTileLightListShader = null;
static ComputeShader buildPerVoxelLightListShader = null; // clustered
private static ComputeBuffer s_LightShapeDataBuffer;
private static ComputeBuffer s_ConvexBoundsBuffer;
private static ComputeBuffer s_AABBBoundsBuffer;
private static ComputeBuffer s_LightList;
private static ComputeBuffer s_LightShapeDataBuffer = null;
private static ComputeBuffer s_ConvexBoundsBuffer = null;
private static ComputeBuffer s_AABBBoundsBuffer = null;
private static ComputeBuffer s_LightList = null;
private static ComputeBuffer s_BigTileLightList; // used for pre-pass coarse culling on 64x64 tiles
private static ComputeBuffer s_BigTileLightList = null; // used for pre-pass coarse culling on 64x64 tiles
private static int s_GenListPerBigTileKernel;
// clustered light list specific buffers and data begin

const int k_Log2NumClusters = 6; // accepted range is from 0 to 6. NumClusters is 1<<g_iLog2NumClusters
const float k_ClustLogBase = 1.02f; // each slice 2% bigger than the previous
float m_ClustScale;
private static ComputeBuffer s_PerVoxelLightLists;
private static ComputeBuffer s_PerVoxelOffset;
private static ComputeBuffer s_PerTileLogBaseTweak;
private static ComputeBuffer s_GlobalLightListAtomic;
private static ComputeBuffer s_PerVoxelLightLists = null;
private static ComputeBuffer s_PerVoxelOffset = null;
private static ComputeBuffer s_PerTileLogBaseTweak = null;
private static ComputeBuffer s_GlobalLightListAtomic = null;
// clustered light list specific buffers and data end
SFiniteLightBound[] m_boundData;

}
// Static keyword is required here else we get a "DestroyBuffer can only be call in main thread"
static ComputeBuffer s_DirectionalLights;
static ComputeBuffer s_PunctualLightList;
static ComputeBuffer s_EnvLightList;
static ComputeBuffer s_AreaLightList;
static ComputeBuffer s_PunctualShadowList;
static ComputeBuffer s_DirectionalShadowList;
static ComputeBuffer s_DirectionalLights = null;
static ComputeBuffer s_PunctualLightList = null;
static ComputeBuffer s_EnvLightList = null;
static ComputeBuffer s_AreaLightList = null;
static ComputeBuffer s_PunctualShadowList = null;
static ComputeBuffer s_DirectionalShadowList = null;
Material m_DeferredDirectMaterial;
Material m_DeferredIndirectMaterial;
Material m_DeferredAllMaterial;
Material m_DebugViewTilesMaterial;
Material m_DeferredDirectMaterial = null;
Material m_DeferredIndirectMaterial = null;
Material m_DeferredAllMaterial = null;
Material m_DebugViewTilesMaterial = null;
const int k_TileSize = 16;

return (camera.pixelHeight + (k_TileSize - 1)) / k_TileSize;
}
// Local function
void ClearComputeBuffers()
{
ReleaseResolutionDependentBuffers();
if (s_AABBBoundsBuffer != null)
s_AABBBoundsBuffer.Release();
if (s_ConvexBoundsBuffer != null)
s_ConvexBoundsBuffer.Release();
if (s_LightShapeDataBuffer != null)
s_LightShapeDataBuffer.Release();
if (enableClustered)
{
if (s_GlobalLightListAtomic != null)
s_GlobalLightListAtomic.Release();
}
if (s_DirectionalLights != null)
s_DirectionalLights.Release();
if (s_DirectionalShadowList != null)
s_DirectionalShadowList.Release();
if (s_PunctualLightList != null)
s_PunctualLightList.Release();
if (s_AreaLightList != null)
s_AreaLightList.Release();
if (s_PunctualShadowList != null)
s_PunctualShadowList.Release();
if (s_EnvLightList != null)
s_EnvLightList.Release();
}
ClearComputeBuffers();
buildScreenAABBShader = Resources.Load<ComputeShader>("scrbound");
buildPerTileLightListShader = Resources.Load<ComputeShader>("lightlistbuild");
buildPerBigTileLightListShader = Resources.Load<ComputeShader>("lightlistbuild-bigtile");

m_DeferredAllMaterial.DisableKeyword("LIGHTLOOP_TILE_INDIRECT");
m_DeferredAllMaterial.EnableKeyword("LIGHTLOOP_TILE_ALL");
public void OnDisable()
public void Cleanup()
// TODO: do something for Resources.Load<ComputeShader> ?
s_AABBBoundsBuffer.Release();
s_ConvexBoundsBuffer.Release();
s_LightShapeDataBuffer.Release();
if (enableClustered)
{
s_GlobalLightListAtomic.Release();
}
Utilities.SafeRelease(s_AABBBoundsBuffer);
Utilities.SafeRelease(s_ConvexBoundsBuffer);
Utilities.SafeRelease(s_LightShapeDataBuffer);
s_DirectionalLights.Release();
s_DirectionalLights = null;
s_DirectionalShadowList.Release();
s_DirectionalShadowList = null;
s_PunctualLightList.Release();
s_PunctualLightList = null;
s_AreaLightList.Release();
s_AreaLightList = null;
s_EnvLightList.Release();
s_EnvLightList = null;
s_PunctualShadowList.Release();
s_PunctualShadowList = null;
// enableClustered
Utilities.SafeRelease(s_GlobalLightListAtomic);
Utilities.SafeRelease(s_DirectionalLights);
Utilities.SafeRelease(s_DirectionalShadowList);
Utilities.SafeRelease(s_PunctualLightList);
Utilities.SafeRelease(s_AreaLightList);
Utilities.SafeRelease(s_EnvLightList);
Utilities.SafeRelease(s_PunctualShadowList);
Utilities.Destroy(m_DeferredDirectMaterial);
Utilities.Destroy(m_DeferredIndirectMaterial);

public bool NeedResize()
{
return s_LightList == null || (s_BigTileLightList == null && enableBigTilePrepass) || (s_PerVoxelLightLists == null && enableClustered);
return s_LightList == null ||
(s_BigTileLightList == null && enableBigTilePrepass) ||
(s_PerVoxelLightLists == null && enableClustered);
if (s_LightList != null)
s_LightList.Release();
if (enableClustered)
{
if (s_PerVoxelLightLists != null)
s_PerVoxelLightLists.Release();
Utilities.SafeRelease(s_LightList);
if (s_PerVoxelOffset != null)
s_PerVoxelOffset.Release();
// enableClustered
Utilities.SafeRelease(s_PerVoxelLightLists);
Utilities.SafeRelease(s_PerVoxelOffset);
Utilities.SafeRelease(s_PerTileLogBaseTweak);
if (k_UseDepthBuffer && s_PerTileLogBaseTweak != null)
s_PerTileLogBaseTweak.Release();
}
if (enableBigTilePrepass)
{
if (s_BigTileLightList != null)
s_BigTileLightList.Release();
}
// enableBigTilePrepass
Utilities.SafeRelease(s_BigTileLightList);
}
int NumLightIndicesPerClusteredTile()

var cmd = new CommandBuffer();
cmd.SetGlobalBuffer("g_vLightListGlobal", bUseClusteredForDeferred ? s_PerVoxelLightLists : s_LightList); // opaques list (unless MSAA possibly)
cmd.name = bUseClusteredForDeferred ? "Clustered pass" : "Tiled pass";
// In case of bUseClusteredForDeferred disable toggle option since we're using m_perVoxelLightLists as opposed to lightList
if (bUseClusteredForDeferred)

5
Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.cs


isInit = false;
}
public void OnDisable()
public void Cleanup()
if (m_InitPreFGD) DestroyImmediate(m_InitPreFGD);
Utilities.Destroy(m_InitPreFGD);
// TODO: how to delete RenderTexture ?
isInit = false;
}

4
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/AtmosphericParameters.cs


if (instance == this)
{
// TODO: what's the point of doing this?
OnDisable();
Cleanup();
OnEnable();
}

instance = this;
}
void OnDisable()
void Cleanup()
{
// Undefine all preprocessor symbols.
UpdateKeywords(false);

4
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyRenderer.cs


if ((m_SkyboxCubemapRT != null) && (m_SkyboxCubemapRT.width != (int)skyParameters.skyResolution))
{
Utilities.Destroy(m_SkyboxCubemapRT);
m_SkyboxCubemapRT = null;
m_SkyboxGGXCubemapRT = null;
}
if (m_SkyboxCubemapRT == null)

}
}
public void OnDisable()
public void Cleanup()
{
Utilities.Destroy(m_StandardSkyboxMaterial);
Utilities.Destroy(m_SkyHDRIMaterial);

10
Assets/ScriptableRenderLoop/HDRenderLoop/Utilities.cs


#else
UnityObject.Destroy(obj);
#endif
obj = null;
}
}
public static void SafeRelease(ComputeBuffer buffer)
{
if (buffer != null)
{
buffer.Release();
buffer = null;
}
}

29
Assets/ScriptableRenderLoop/common/TextureSettings.cs


[System.Serializable]
public struct TextureSettings
namespace UnityEngine.Experimental.ScriptableRenderLoop
public uint spotCookieSize;
public uint pointCookieSize;
public uint reflectionCubemapSize;
[System.Serializable]
public struct TextureSettings
{
public int spotCookieSize;
public int pointCookieSize;
public int reflectionCubemapSize;
public static TextureSettings Default
{
get
public static TextureSettings Default
TextureSettings settings;
settings.spotCookieSize = 128;
settings.pointCookieSize = 512;
settings.reflectionCubemapSize = 128;
return settings;
get
{
TextureSettings settings = new TextureSettings();
settings.spotCookieSize = 128;
settings.pointCookieSize = 512;
settings.reflectionCubemapSize = 128;
return settings;
}
}
}
}

6
Assets/ScriptableRenderLoop/fptl/FptlLighting.cs


m_CookieTexArray = new TextureCache2D();
m_CubeCookieTexArray = new TextureCacheCubemap();
m_CubeReflTexArray = new TextureCacheCubemap();
m_CookieTexArray.AllocTextureArray(8, (int)m_TextureSettings.spotCookieSize, (int)m_TextureSettings.spotCookieSize, TextureFormat.RGBA32, true);
m_CubeCookieTexArray.AllocTextureArray(4, (int)m_TextureSettings.pointCookieSize, TextureFormat.RGBA32, true);
m_CubeReflTexArray.AllocTextureArray(64, (int)m_TextureSettings.reflectionCubemapSize, TextureFormat.BC6H, true);
m_CookieTexArray.AllocTextureArray(8, m_TextureSettings.spotCookieSize, m_TextureSettings.spotCookieSize, TextureFormat.RGBA32, true);
m_CubeCookieTexArray.AllocTextureArray(4, m_TextureSettings.pointCookieSize, TextureFormat.RGBA32, true);
m_CubeReflTexArray.AllocTextureArray(64, m_TextureSettings.reflectionCubemapSize, TextureFormat.BC6H, true);
//m_DeferredMaterial.SetTexture("_spotCookieTextures", m_cookieTexArray.GetTexCache());
//m_DeferredMaterial.SetTexture("_pointCookieTextures", m_cubeCookieTexArray.GetTexCache());

正在加载...
取消
保存