|
|
|
|
|
|
public class PreviewManager : IDisposable |
|
|
|
{ |
|
|
|
AbstractMaterialGraph m_Graph; |
|
|
|
Dictionary<Guid, PreviewData> m_Previews = new Dictionary<Guid, PreviewData>(); |
|
|
|
Dictionary<Guid, PreviewRenderData> m_RenderDatas = new Dictionary<Guid, PreviewRenderData>(); |
|
|
|
Dictionary<Guid, PreviewShaderData> m_ShaderDatas = new Dictionary<Guid, PreviewShaderData>(); |
|
|
|
PreviewRenderData m_MasterRenderData; |
|
|
|
HashSet<Guid> m_DirtyPreviews = new HashSet<Guid>(); |
|
|
|
HashSet<Guid> m_DirtyShaders = new HashSet<Guid>(); |
|
|
|
HashSet<Guid> m_TimeDependentPreviews = new HashSet<Guid>(); |
|
|
|
|
|
|
|
|
|
|
public PreviewRate previewRate { get; set; } |
|
|
|
|
|
|
|
public PreviewRenderData masterRenderData |
|
|
|
{ |
|
|
|
get { return m_MasterRenderData; } |
|
|
|
} |
|
|
|
|
|
|
|
public PreviewManager(AbstractMaterialGraph graph) |
|
|
|
{ |
|
|
|
m_Graph = graph; |
|
|
|
|
|
|
m_UberShader = ShaderUtil.CreateShaderAsset(k_EmptyShader); |
|
|
|
m_UberShader.hideFlags = HideFlags.HideAndDontSave; |
|
|
|
m_UberShaderIds = new Dictionary<Guid, int>(); |
|
|
|
m_MasterRenderData = new PreviewRenderData |
|
|
|
{ |
|
|
|
renderTexture = new RenderTexture(400, 400, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default) { hideFlags = HideFlags.HideAndDontSave } |
|
|
|
}; |
|
|
|
public PreviewData GetPreview(INode node) |
|
|
|
public PreviewRenderData GetPreview(INode node) |
|
|
|
return m_Previews[node.guid]; |
|
|
|
return m_RenderDatas[node.guid]; |
|
|
|
var previewData = new PreviewData |
|
|
|
PreviewShaderData shaderData; |
|
|
|
if (!m_ShaderDatas.TryGetValue(node.guid, out shaderData)) |
|
|
|
{ |
|
|
|
shaderData = new PreviewShaderData |
|
|
|
{ |
|
|
|
node = node |
|
|
|
}; |
|
|
|
m_ShaderDatas[node.guid] = shaderData; |
|
|
|
} |
|
|
|
var previewData = new PreviewRenderData |
|
|
|
node = node, |
|
|
|
shaderData = shaderData, |
|
|
|
if (m_Previews.ContainsKey(node.guid)) |
|
|
|
if (m_RenderDatas.ContainsKey(node.guid)) |
|
|
|
m_Previews.Add(node.guid, previewData); |
|
|
|
m_RenderDatas.Add(node.guid, previewData); |
|
|
|
|
|
|
|
var masterNode = node as IMasterNode; |
|
|
|
if (masterRenderData.shaderData == null && masterNode != null) |
|
|
|
{ |
|
|
|
masterRenderData.shaderData = shaderData; |
|
|
|
} |
|
|
|
m_Previews.Remove(node.guid); |
|
|
|
m_RenderDatas.Remove(node.guid); |
|
|
|
|
|
|
|
if (masterRenderData.shaderData != null && masterRenderData.shaderData.node == node) |
|
|
|
masterRenderData.shaderData = m_ShaderDatas.Values.FirstOrDefault(x => x.node is IMasterNode); |
|
|
|
} |
|
|
|
|
|
|
|
void OnNodeModified(INode node, ModificationScope scope) |
|
|
|
|
|
|
m_DirtyShaders.Add(edge.inputSlot.nodeGuid); |
|
|
|
} |
|
|
|
|
|
|
|
List<PreviewData> m_RenderList2D = new List<PreviewData>(); |
|
|
|
List<PreviewData> m_RenderList3D = new List<PreviewData>(); |
|
|
|
List<PreviewRenderData> m_RenderList2D = new List<PreviewRenderData>(); |
|
|
|
List<PreviewRenderData> m_RenderList3D = new List<PreviewRenderData>(); |
|
|
|
HashSet<Guid> m_NodesWith3DPreview = new HashSet<Guid>(); |
|
|
|
|
|
|
|
public void RenderPreviews() |
|
|
|
|
|
|
|
|
|
|
foreach (var node in uberNodes) |
|
|
|
{ |
|
|
|
PreviewData previewData; |
|
|
|
if (!m_Previews.TryGetValue(node.guid, out previewData)) |
|
|
|
PreviewShaderData shaderData; |
|
|
|
if (!m_ShaderDatas.TryGetValue(node.guid, out shaderData)) |
|
|
|
previewData.previewMode = m_NodesWith3DPreview.Contains(node.guid) ? PreviewMode.Preview3D : PreviewMode.Preview2D; |
|
|
|
previewData.shader = m_UberShader; |
|
|
|
shaderData.previewMode = m_NodesWith3DPreview.Contains(node.guid) ? PreviewMode.Preview3D : PreviewMode.Preview2D; |
|
|
|
shaderData.shader = m_UberShader; |
|
|
|
} |
|
|
|
i++; |
|
|
|
EditorUtility.DisplayProgressBar("Shader Graph", string.Format("Compiling preview shaders ({0}/{1})", i, count), 0f); |
|
|
|
|
|
|
|
|
|
|
foreach (var nodeGuid in m_DirtyPreviews) |
|
|
|
{ |
|
|
|
PreviewData previewData; |
|
|
|
if (!m_Previews.TryGetValue(nodeGuid, out previewData)) |
|
|
|
PreviewRenderData renderData; |
|
|
|
if (!m_RenderDatas.TryGetValue(nodeGuid, out renderData)) |
|
|
|
if (previewData.shader == null) |
|
|
|
if (renderData.shaderData.shader == null) |
|
|
|
previewData.texture = null; |
|
|
|
renderData.texture = null; |
|
|
|
if (MaterialGraphAsset.ShaderHasError(previewData.shader)) |
|
|
|
if (MaterialGraphAsset.ShaderHasError(renderData.shaderData.shader)) |
|
|
|
previewData.texture = m_ErrorTexture; |
|
|
|
renderData.texture = m_ErrorTexture; |
|
|
|
if (previewData.previewMode == PreviewMode.Preview2D) |
|
|
|
m_RenderList2D.Add(previewData); |
|
|
|
if (renderData.shaderData.previewMode == PreviewMode.Preview2D) |
|
|
|
m_RenderList2D.Add(renderData); |
|
|
|
m_RenderList3D.Add(previewData); |
|
|
|
m_RenderList3D.Add(renderData); |
|
|
|
|
|
|
|
if (masterRenderData.shaderData != null && m_DirtyPreviews.Contains(masterRenderData.shaderData.node.guid)) |
|
|
|
m_RenderList3D.Add(masterRenderData); |
|
|
|
|
|
|
|
var time = Time.realtimeSinceStartup; |
|
|
|
EditorUtility.SetCameraAnimateMaterialsTime(m_SceneResources.camera, time); |
|
|
|
|
|
|
m_SceneResources.camera.transform.rotation = Quaternion.identity; |
|
|
|
m_SceneResources.camera.orthographicSize = 1; |
|
|
|
m_SceneResources.camera.orthographic = true; |
|
|
|
foreach (var previewData in m_RenderList2D) |
|
|
|
foreach (var renderData in m_RenderList2D) |
|
|
|
if (m_UberShaderIds.TryGetValue(previewData.node.guid, out outputId)) |
|
|
|
if (m_UberShaderIds.TryGetValue(renderData.shaderData.node.guid, out outputId)) |
|
|
|
m_PreviewMaterial.shader = previewData.shader; |
|
|
|
m_SceneResources.camera.targetTexture = previewData.renderTexture; |
|
|
|
m_PreviewMaterial.shader = renderData.shaderData.shader; |
|
|
|
m_SceneResources.camera.targetTexture = renderData.renderTexture; |
|
|
|
RenderTexture.active = previewData.renderTexture; |
|
|
|
RenderTexture.active = renderData.renderTexture; |
|
|
|
Graphics.Blit(Texture2D.whiteTexture, previewData.renderTexture, m_SceneResources.checkerboardMaterial); |
|
|
|
Graphics.Blit(Texture2D.whiteTexture, renderData.renderTexture, m_SceneResources.checkerboardMaterial); |
|
|
|
Graphics.DrawMesh(m_SceneResources.quad, Matrix4x4.identity, m_PreviewMaterial, 1, m_SceneResources.camera, 0, m_PreviewPropertyBlock, ShadowCastingMode.Off, false, null, false); |
|
|
|
var previousUseSRP = Unsupported.useScriptableRenderPipeline; |
|
|
|
Unsupported.useScriptableRenderPipeline = false; |
|
|
|
|
|
|
previewData.texture = previewData.renderTexture; |
|
|
|
renderData.texture = renderData.renderTexture; |
|
|
|
m_RenderList2D.Clear(); |
|
|
|
|
|
|
|
// Render 3D previews
|
|
|
|
m_SceneResources.camera.transform.position = -Vector3.forward * 5; |
|
|
|
|
|
|
{ |
|
|
|
int outputId; |
|
|
|
if (m_UberShaderIds.TryGetValue(previewData.node.guid, out outputId)) |
|
|
|
if (m_UberShaderIds.TryGetValue(previewData.shaderData.node.guid, out outputId)) |
|
|
|
m_PreviewMaterial.shader = previewData.shader; |
|
|
|
m_PreviewMaterial.shader = previewData.shaderData.shader; |
|
|
|
m_SceneResources.camera.targetTexture = previewData.renderTexture; |
|
|
|
var previousRenderTexure = RenderTexture.active; |
|
|
|
RenderTexture.active = previewData.renderTexture; |
|
|
|
|
|
|
Graphics.DrawMesh(mesh, Matrix4x4.TRS(-mesh.bounds.center, Quaternion.identity, Vector3.one), m_PreviewMaterial, 1, m_SceneResources.camera, 0, m_PreviewPropertyBlock, ShadowCastingMode.Off, false, null, false); |
|
|
|
var previousUseSRP = Unsupported.useScriptableRenderPipeline; |
|
|
|
Unsupported.useScriptableRenderPipeline = previewData.node is IMasterNode; |
|
|
|
Unsupported.useScriptableRenderPipeline = previewData.shaderData.node is IMasterNode; |
|
|
|
m_RenderList3D.Clear(); |
|
|
|
foreach (var nodeGuid in m_DirtyPreviews) |
|
|
|
foreach (var previewRenderData in m_RenderList2D.Union(m_RenderList3D)) |
|
|
|
PreviewData previewData; |
|
|
|
if (!m_Previews.TryGetValue(nodeGuid, out previewData)) |
|
|
|
continue; |
|
|
|
|
|
|
|
if (previewData.onPreviewChanged != null) |
|
|
|
previewData.onPreviewChanged(); |
|
|
|
if (previewRenderData.onPreviewChanged != null) |
|
|
|
previewRenderData.onPreviewChanged(); |
|
|
|
m_RenderList2D.Clear(); |
|
|
|
m_RenderList3D.Clear(); |
|
|
|
m_DirtyPreviews.Clear(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
if (node == null) |
|
|
|
return; |
|
|
|
PreviewData previewData; |
|
|
|
if (!m_Previews.TryGetValue(nodeGuid, out previewData)) |
|
|
|
PreviewShaderData shaderData; |
|
|
|
if (!m_ShaderDatas.TryGetValue(nodeGuid, out shaderData)) |
|
|
|
previewData.previewMode = m_NodesWith3DPreview.Contains(nodeGuid) ? PreviewMode.Preview3D : PreviewMode.Preview2D; |
|
|
|
shaderData.previewMode = m_NodesWith3DPreview.Contains(nodeGuid) ? PreviewMode.Preview3D : PreviewMode.Preview2D; |
|
|
|
previewData.shaderString = null; |
|
|
|
shaderData.shaderString = null; |
|
|
|
previewData.shaderString = m_Graph.GetPreviewShader(node, out mode); |
|
|
|
shaderData.shaderString = m_Graph.GetPreviewShader(node, out mode); |
|
|
|
File.WriteAllText(Application.dataPath + "/../GeneratedShader.shader", (previewData.shaderString ?? "null").Replace("UnityEngine.MaterialGraph", "Generated")); |
|
|
|
File.WriteAllText(Application.dataPath + "/../GeneratedShader.shader", (shaderData.shaderString ?? "null").Replace("UnityEngine.MaterialGraph", "Generated")); |
|
|
|
if (string.IsNullOrEmpty(previewData.shaderString)) |
|
|
|
if (string.IsNullOrEmpty(shaderData.shaderString)) |
|
|
|
if (previewData.shader != null) |
|
|
|
Object.DestroyImmediate(previewData.shader, true); |
|
|
|
previewData.shader = null; |
|
|
|
if (shaderData.shader != null) |
|
|
|
Object.DestroyImmediate(shaderData.shader, true); |
|
|
|
shaderData.shader = null; |
|
|
|
if (previewData.shader != null && MaterialGraphAsset.ShaderHasError(previewData.shader)) |
|
|
|
if (shaderData.shader != null && MaterialGraphAsset.ShaderHasError(shaderData.shader)) |
|
|
|
ShaderUtil.ClearShaderErrors(previewData.shader); |
|
|
|
Object.DestroyImmediate(previewData.shader, true); |
|
|
|
previewData.shader = null; |
|
|
|
ShaderUtil.ClearShaderErrors(shaderData.shader); |
|
|
|
Object.DestroyImmediate(shaderData.shader, true); |
|
|
|
shaderData.shader = null; |
|
|
|
if (previewData.shader == null) |
|
|
|
if (shaderData.shader == null) |
|
|
|
previewData.shader = ShaderUtil.CreateShaderAsset(previewData.shaderString); |
|
|
|
previewData.shader.hideFlags = HideFlags.HideAndDontSave; |
|
|
|
shaderData.shader = ShaderUtil.CreateShaderAsset(shaderData.shaderString); |
|
|
|
shaderData.shader.hideFlags = HideFlags.HideAndDontSave; |
|
|
|
ShaderUtil.ClearShaderErrors(previewData.shader); |
|
|
|
ShaderUtil.UpdateShaderAsset(previewData.shader, previewData.shaderString); |
|
|
|
ShaderUtil.ClearShaderErrors(shaderData.shader); |
|
|
|
ShaderUtil.UpdateShaderAsset(shaderData.shader, shaderData.shaderString); |
|
|
|
var message = "RecreateShader: " + node.GetVariableNameForNode() + Environment.NewLine + previewData.shaderString; |
|
|
|
if (MaterialGraphAsset.ShaderHasError(previewData.shader)) |
|
|
|
var message = "RecreateShader: " + node.GetVariableNameForNode() + Environment.NewLine + shaderData.shaderString; |
|
|
|
if (MaterialGraphAsset.ShaderHasError(shaderData.shader)) |
|
|
|
void DestroyPreview(Guid nodeGuid, PreviewData previewData) |
|
|
|
void DestroyPreview(Guid nodeGuid, PreviewRenderData previewRenderData) |
|
|
|
if (m_Previews.Remove(nodeGuid)) |
|
|
|
if (m_RenderDatas.Remove(nodeGuid)) |
|
|
|
if (previewData.shader != null) |
|
|
|
Object.DestroyImmediate(previewData.shader, true); |
|
|
|
if (previewData.renderTexture != null) |
|
|
|
Object.DestroyImmediate(previewData.renderTexture, true); |
|
|
|
if (previewRenderData.shaderData.shader != null) |
|
|
|
Object.DestroyImmediate(previewRenderData.shaderData.shader, true); |
|
|
|
if (previewRenderData.renderTexture != null) |
|
|
|
Object.DestroyImmediate(previewRenderData.renderTexture, true); |
|
|
|
var node = m_Graph.GetNodeFromGuid(nodeGuid); |
|
|
|
if (node != null) |
|
|
|
node.onModified -= OnNodeModified; |
|
|
|
|
|
|
previewData.shader = null; |
|
|
|
previewData.renderTexture = null; |
|
|
|
previewData.texture = null; |
|
|
|
previewData.onPreviewChanged = null; |
|
|
|
previewRenderData.shaderData.shader = null; |
|
|
|
previewRenderData.renderTexture = null; |
|
|
|
previewRenderData.texture = null; |
|
|
|
previewRenderData.onPreviewChanged = null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
if (m_SceneResources != null) |
|
|
|
m_SceneResources.Dispose(); |
|
|
|
m_SceneResources = null; |
|
|
|
var previews = m_Previews.ToList(); |
|
|
|
var previews = m_RenderDatas.ToList(); |
|
|
|
foreach (var kvp in previews) |
|
|
|
DestroyPreview(kvp.Key, kvp.Value); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
public delegate void OnPreviewChanged(); |
|
|
|
|
|
|
|
public class PreviewData |
|
|
|
public class PreviewShaderData |
|
|
|
public Mesh mesh { get; set; } |
|
|
|
} |
|
|
|
|
|
|
|
public class PreviewRenderData |
|
|
|
{ |
|
|
|
public PreviewShaderData shaderData { get; set; } |
|
|
|
public Mesh mesh { get; set; } |
|
|
|
public RenderTexture renderTexture { get; set; } |
|
|
|
public Texture texture { get; set; } |
|
|
|
public OnPreviewChanged onPreviewChanged; |