浏览代码

New preview system and master node preview in inspector

/main
Peter Bay Bastian 7 年前
当前提交
bec6cdbb
共有 14 个文件被更改,包括 555 次插入488 次删除
  1. 12
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/AbstractMaterialGraphEditWindow.cs
  2. 32
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Inspector/GraphInspectorPresenter.cs
  3. 31
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Inspector/GraphInspectorView.cs
  4. 89
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/MaterialGraphPreviewGenerator.cs
  5. 32
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/GraphEditorPresenter.cs
  6. 96
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialGraphPresenter.cs
  7. 47
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialNodePresenter.cs
  8. 29
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/MaterialNodeView.cs
  9. 33
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Resources/Styles/MaterialGraph.uss
  10. 16
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Testing/IntegrationTests/ShaderGenerationTest.cs
  11. 355
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/PreviewSystem.cs
  12. 3
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/PreviewSystem.cs.meta
  13. 12
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/NodePreviewPresenter.cs.meta
  14. 256
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/NodePreviewPresenter.cs

12
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/AbstractMaterialGraphEditWindow.cs


set
{
if (m_GraphEditorView != null)
{
if (m_GraphEditorView.presenter != null)
m_GraphEditorView.presenter.Dispose();
}
m_GraphEditorView = value;
}
}

{
if (graphEditorView.presenter == null)
CreatePresenter();
graphEditorView.presenter.graphPresenter.UpdateTimeDependentNodes();
if (graphEditorView.presenter != null)
graphEditorView.presenter.UpdatePreviews();
}
}

void OnDisable()
{
rootVisualContainer.Clear();
graphEditorView = null;
}
void OnDestroy()

UpdateAsset();
}
graphEditorView.Dispose();
graphEditorView = null;
}
void OnGUI()

void CreatePresenter()
{
if (graphEditorView.presenter != null)
graphEditorView.presenter.Dispose();
var presenter = CreateInstance<GraphEditorPresenter>();
presenter.Initialize(inMemoryAsset, this, selected.name);
graphEditorView.presenter = presenter;

32
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Inspector/GraphInspectorPresenter.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.MaterialGraph;
public class GraphInspectorPresenter : ScriptableObject
public class GraphInspectorPresenter : ScriptableObject, IDisposable
PreviewHandle m_PreviewHandle;
public Texture previewTexture { get; private set; }
[Flags]
public enum ChangeType

AssetName = 1 << 2,
PreviewTexture = 1 << 3,
All = -1
}

public void Initialize(string assetName, IGraph graph)
public void Initialize(string assetName, IGraph graph, PreviewSystem previewSystem)
var masterNode = graph.GetNodes<AbstractMasterNode>().FirstOrDefault();
if (masterNode != null)
{
m_PreviewHandle = previewSystem.GetPreviewHandle(masterNode.guid);
m_PreviewHandle.onPreviewChanged += OnPreviewChanged;
}
}
void OnPreviewChanged()
{
previewTexture = m_PreviewHandle.texture;
Change(ChangeType.PreviewTexture);
}
public void UpdateSelection(IEnumerable<INode> nodes)

{
if (onChange != null)
onChange(changeType);
}
public void Dispose()
{
if (m_PreviewHandle != null)
{
m_PreviewHandle.Dispose();
m_PreviewHandle = null;
};
}
}
}

31
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Inspector/GraphInspectorView.cs


using System;
using System;
using System.Linq;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEditor.Graphing.Util;

AbstractNodeEditorView m_EditorView;
TypeMapper m_TypeMapper;
Image m_Preview;
var headerContainer = new VisualElement { name = "header" };
var topContainer = new VisualElement { name = "top" };
m_Title = new VisualElement() { name = "title" };
headerContainer.Add(m_Title);
var headerContainer = new VisualElement { name = "header" };
{
m_Title = new VisualElement() { name = "title" };
headerContainer.Add(m_Title);
}
topContainer.Add(headerContainer);
m_ContentContainer = new VisualElement { name = "content" };
topContainer.Add(m_ContentContainer);
Add(headerContainer);
Add(topContainer);
m_ContentContainer = new VisualElement { name = "contentContainer" };
Add(m_ContentContainer);
var bottomContainer = new VisualElement { name = "bottom" };
{
m_Preview = new Image { name = "preview", image = Texture2D.blackTexture};
bottomContainer.Add(m_Preview);
}
Add(bottomContainer);
// Nodes missing custom editors:
// - PropertyNode

m_ContentContainer.Add(view);
}
}
}
if ((changeType & GraphInspectorPresenter.ChangeType.PreviewTexture) != 0)
{
m_Preview.image = presenter.previewTexture ?? Texture2D.blackTexture;
}
}

89
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/MaterialGraphPreviewGenerator.cs


{
internal class MaterialGraphPreviewGenerator : IDisposable
{
private bool m_AllowSRP;
private RenderTexture m_RenderTexture;
private static readonly Mesh[] s_Meshes = {null, null, null, null, null};
private static readonly Mesh[] s_Meshes = { null, null, null, null, null };
private static readonly GUIContent[] s_MeshIcons = {null, null, null, null, null};
private static readonly GUIContent[] s_LightIcons = {null, null};
private static readonly GUIContent[] s_TimeIcons = {null, null};
private static readonly GUIContent[] s_MeshIcons = { null, null, null, null, null };
private static readonly GUIContent[] s_LightIcons = { null, null };
private static readonly GUIContent[] s_TimeIcons = { null, null };
protected static GameObject CreateLight()
{

return lightGO;
}
public MaterialGraphPreviewGenerator(bool allowSRP)
public MaterialGraphPreviewGenerator()
m_AllowSRP = allowSRP;
m_Scene = EditorSceneManager.NewPreviewScene();
var camGO = EditorUtility.CreateGameObjectWithHideFlags("Preview Scene Camera", HideFlags.HideAndDontSave, typeof(Camera));
SceneManager.MoveGameObjectToScene(camGO, m_Scene);

var l1 = CreateLight();
SceneManager.MoveGameObjectToScene(l1, m_Scene);
//previewScene.AddGameObject(l1);
Light1 = l1.GetComponent<Light>();

if (s_Meshes[0] == null)
{
var handleGo = (GameObject)EditorGUIUtility.LoadRequired("Previews/PreviewMaterials.fbx");
// @TODO: temp workaround to make it not render in the scene
handleGo.SetActive(false);
foreach (Transform t in handleGo.transform)

}
}
public Texture DoRenderPreview(Material mat, PreviewMode mode, Rect size)
{
return DoRenderPreview(mat, mode, size, Time.realtimeSinceStartup);
}
public static Mesh quad
{
get

var vertices = new[]
{
new Vector3(-1f, -1f, 0f),
new Vector3(1f, 1f, 0f),
new Vector3(1f, 1f, 0f),
new Vector3(-1f, 1f, 0f)
new Vector3(-1f, 1f, 0f)
};
var uvs = new[]

}
}
public Texture DoRenderPreview(Material mat, PreviewMode mode, Rect size, float time)
public void DoRenderPreview(RenderTexture renderTexture, Material mat, PreviewMode mode, bool allowSRP, float time, MaterialPropertyBlock properties = null)
return Texture2D.blackTexture;
return;
int rtWidth = (int)(size.width);
int rtHeight = (int)(size.height);
if (!m_RenderTexture || m_RenderTexture.width != rtWidth || m_RenderTexture.height != rtHeight)
{
if (m_RenderTexture)
{
UnityEngine.Object.DestroyImmediate(m_RenderTexture);
m_RenderTexture = null;
}
// Do not use GetTemporary to manage render textures. Temporary RTs are only
// garbage collected each N frames, and in the editor we might be wildly resizing
// the inspector, thus using up tons of memory.
RenderTextureFormat format = m_Camera.allowHDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;
m_RenderTexture = new RenderTexture(rtWidth, rtHeight, 16, format, RenderTextureReadWrite.Default);
m_RenderTexture.hideFlags = HideFlags.HideAndDontSave;
m_Camera.targetTexture = m_RenderTexture;
}
m_Camera.targetTexture = renderTexture;
RenderTexture.active = m_RenderTexture;
RenderTexture.active = renderTexture;
Graphics.Blit(Texture2D.whiteTexture, m_RenderTexture, m_CheckerboardMaterial);
Graphics.Blit(Texture2D.whiteTexture, renderTexture, m_CheckerboardMaterial);
if (mode == PreviewMode.Preview3D)
{
m_Camera.transform.position = -Vector3.forward * 5;

m_Camera.orthographic = true;
}
m_Camera.targetTexture = m_RenderTexture;
m_Camera.targetTexture = renderTexture;
EditorUtility.SetCameraAnimateMaterialsTime(m_Camera, time);
Light0.enabled = true;

Light1.intensity = 1.0f;
m_Camera.clearFlags = CameraClearFlags.Depth;
DrawMesh(
Graphics.DrawMesh(
Vector3.zero,
Quaternion.identity,
Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one),
0);
1,
m_Camera,
0,
properties,
ShadowCastingMode.Off,
false,
null,
false);
Unsupported.useScriptableRenderPipeline = m_AllowSRP;
Unsupported.useScriptableRenderPipeline = allowSRP;
m_Camera.Render();
Unsupported.useScriptableRenderPipeline = oldAllowPipes;

Light1.enabled = false;
return m_RenderTexture;
if (m_RenderTexture == null)
{
UnityEngine.Object.DestroyImmediate(m_RenderTexture);
m_RenderTexture = null;
}
if (Light0 == null)
{
UnityEngine.Object.DestroyImmediate(Light0.gameObject);

}
EditorSceneManager.ClosePreviewScene(m_Scene);
}
private void DrawMesh(Mesh mesh, Vector3 pos, Quaternion rot, Material mat, int subMeshIndex)
{
DrawMesh(mesh, pos, rot, mat, subMeshIndex, null, null, false);
}
private void DrawMesh(Mesh mesh, Vector3 pos, Quaternion rot, Material mat, int subMeshIndex, MaterialPropertyBlock customProperties, Transform probeAnchor, bool useLightProbe)
{
Graphics.DrawMesh(mesh, Matrix4x4.TRS(pos, rot, Vector3.one), mat, 1, m_Camera, subMeshIndex, customProperties, ShadowCastingMode.Off, false, probeAnchor, useLightProbe);
}
}
}

32
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/GraphEditorPresenter.cs


using UnityEditor.MaterialGraph.Drawing.Inspector;
using System;
using UnityEditor.MaterialGraph.Drawing.Inspector;
public class GraphEditorPresenter : ScriptableObject
public class GraphEditorPresenter : ScriptableObject, IDisposable
{
[SerializeField]
TitleBarPresenter m_TitleBarPresenter;

[SerializeField]
GraphInspectorPresenter m_GraphInspectorPresenter;
PreviewSystem m_PreviewSystem;
public TitleBarPresenter titleBarPresenter
{

public void Initialize(IGraph graph, IMaterialGraphEditWindow container, string assetName)
{
m_PreviewSystem = new PreviewSystem(graph);
m_GraphInspectorPresenter.Initialize(assetName, graph);
m_GraphInspectorPresenter.Initialize(assetName, graph, m_PreviewSystem);
m_GraphPresenter.Initialize(graph, container);
m_GraphPresenter.Initialize(graph, container, m_PreviewSystem);
}
public void UpdatePreviews()
{
m_PreviewSystem.Update();
}
public void Dispose()
{
if (m_GraphInspectorPresenter != null)
{
m_GraphInspectorPresenter.Dispose();
m_GraphInspectorPresenter = null;
}
if (m_PreviewSystem != null)
{
m_PreviewSystem.Dispose();
m_PreviewSystem = null;
}
}
}
}

96
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialGraphPresenter.cs


[Serializable]
public class MaterialGraphPresenter : GraphViewPresenter
{
Dictionary<Guid, MaterialNodePresenter> m_TimeDependentPresenters = new Dictionary<Guid, MaterialNodePresenter>();
public bool hasTimeDependentNodes
{
get { return m_TimeDependentPresenters.Any(); }
}
protected GraphTypeMapper typeMapper { get; set; }
GraphTypeMapper typeMapper { get; set; }
PreviewSystem m_PreviewSystem;
public IGraph graph { get; private set; }

void UpdateData()
{
var deletedElementPresenters = new List<GraphElementPresenter>();
var deletedElementPresenters = m_Elements
.OfType<MaterialNodePresenter>()
.Where(nd => !graph.ContainsNodeGuid(nd.node.guid))
.OfType<GraphElementPresenter>()
.ToList();
foreach (var presenter in m_Elements)
{
var nodePresenter = presenter as MaterialNodePresenter;
if (nodePresenter != null && !graph.ContainsNodeGuid(nodePresenter.node.guid))
{
nodePresenter.Dispose();
deletedElementPresenters.Add(nodePresenter);
}
}
// Find all edges currently being drawn which are no longer in the graph (i.e. deleted)
// Find all edges currently being drawn which are no longer in the graph (i.e. deleted)
foreach (var edgePresenter in deletedEdgePresenters)
{
// Make sure to disconnect the node, otherwise new connections won't be allowed for the used slots

var fromNodePresenter = m_Elements.OfType<MaterialNodePresenter>().FirstOrDefault(nd => nd.node.guid == fromNodeGuid);
var toNodeGuid = edgePresenter.edge.inputSlot.nodeGuid;
var toNodePresenter = m_Elements.OfType<MaterialNodePresenter>().FirstOrDefault(nd => nd.node.guid == toNodeGuid);
if (toNodePresenter != null)
var toNode = graph.GetNodeFromGuid(toNodeGuid);
if (toNode != null && toNode.onModified != null)
OnNodeChanged(toNodePresenter.node, ModificationScope.Graph);
toNode.onModified(toNode, ModificationScope.Graph);
deletedElementPresenters.Add(edgePresenter);
}

var nodePresenter = (MaterialNodePresenter)typeMapper.Create(node);
node.onModified += OnNodeChanged;
nodePresenter.Initialize(node);
nodePresenter.Initialize(node, m_PreviewSystem);
addedNodePresenters.Add(nodePresenter);
}

var targetAnchors = targetNodePresenter.inputAnchors.OfType<GraphAnchorPresenter>();
var targetAnchor = targetAnchors.FirstOrDefault(x => x.slot == targetSlot);
OnNodeChanged(targetNodePresenter.node, ModificationScope.Graph);
if (targetNodePresenter.node.onModified != null)
targetNodePresenter.node.onModified(targetNodePresenter.node, ModificationScope.Graph);
var edgePresenter = CreateInstance<GraphEdgePresenter>();
edgePresenter.Initialize(edge);

}
m_Elements.AddRange(edgePresenters.OfType<GraphElementPresenter>());
// Calculate which nodes require updates each frame (i.e. are time-dependent).
// Let the node set contain all the nodes that are directly time-dependent.
m_TimeDependentPresenters.Clear();
foreach (var presenter in m_Elements.OfType<MaterialNodePresenter>().Where(x => x.node.RequiresTime()))
m_TimeDependentPresenters.Add(presenter.node.guid, presenter);
// The wavefront contains time-dependent nodes from which we wish to propagate time-dependency into the
// nodes that it feeds into.
{
var wavefront = new Stack<MaterialNodePresenter>(m_TimeDependentPresenters.Values);
while (wavefront.Count > 0)
{
var presenter = wavefront.Pop();
// Loop through all nodes that the node feeds into.
foreach (var slot in presenter.node.GetOutputSlots<ISlot>())
{
foreach (var edge in graph.GetEdges(slot.slotReference))
{
// We look at each node we feed into.
var inputNodeGuid = edge.inputSlot.nodeGuid;
// If the input node is already in the set of time-dependent nodes, we don't need to process it.
if (m_TimeDependentPresenters.ContainsKey(inputNodeGuid))
continue;
// Find the matching presenter.
var inputPresenter = m_Elements.OfType<MaterialNodePresenter>().FirstOrDefault(p => p.node.guid == inputNodeGuid);
if (inputPresenter == null)
{
Debug.LogErrorFormat("A presenter could not be found for the node with guid `{0}`", inputNodeGuid);
continue;
}
// Add the node to the set of time-dependent nodes, and to the wavefront such that we can process the nodes that it feeds into.
m_TimeDependentPresenters.Add(inputPresenter.node.guid, inputPresenter);
wavefront.Push(inputPresenter);
}
}
}
}
m_PreviewSystem.UpdateTimeDependentPreviews();
public virtual void Initialize(IGraph graph, IMaterialGraphEditWindow container)
public virtual void Initialize(IGraph graph, IMaterialGraphEditWindow container, PreviewSystem previewSystem)
m_PreviewSystem = previewSystem;
this.graph = graph;
m_Container = container;

public override void RemoveElement(GraphElementPresenter element)
{
throw new ArgumentException("Not supported on Serializable Graph, data comes from data store");
}
public void UpdateTimeDependentNodes()
{
foreach (var nodePresenter in m_TimeDependentPresenters.Values)
{
nodePresenter.OnModified(ModificationScope.Node);
}
}
}
}

47
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialNodePresenter.cs


namespace UnityEditor.MaterialGraph.Drawing
{
[Serializable]
public class MaterialNodePresenter : NodePresenter
public class MaterialNodePresenter : NodePresenter, IDisposable
{
public INode node { get; private set; }

}
[SerializeField]
NodePreviewPresenter m_Preview;
int m_Version;
public NodePreviewPresenter preview
{
get { return m_Preview; }
}
PreviewHandle m_PreviewHandle;
[SerializeField]
int m_Version;
public Texture previewTexture { get; private set; }
public override bool expanded
{

}
}
public override UnityEngine.Object[] GetObjectsToWatch()
{
var towatch = new List<UnityEngine.Object>();
towatch.AddRange(base.GetObjectsToWatch());
towatch.Add(preview);
return towatch.ToArray();
}
public virtual void OnModified(ModificationScope scope)
{
m_Version++;

inputAnchors.Sort((x, y) => slots.IndexOf(((GraphAnchorPresenter)x).slot) - slots.IndexOf(((GraphAnchorPresenter)y).slot));
outputAnchors.Sort((x, y) => slots.IndexOf(((GraphAnchorPresenter)x).slot) - slots.IndexOf(((GraphAnchorPresenter)y).slot));
}
// TODO: Propagate callback rather than setting property
if (preview != null)
preview.modificationScope = scope;
}
public override void CommitChanges()

protected MaterialNodePresenter()
{}
public virtual void Initialize(INode inNode)
public virtual void Initialize(INode inNode, PreviewSystem previewSystem)
{
node = inNode;

position = new Rect(node.drawState.position.x, node.drawState.position.y, 0, 0);
m_Version = 0;
AddPreview(inNode);
m_PreviewHandle = previewSystem.GetPreviewHandle(inNode.guid);
m_PreviewHandle.onPreviewChanged += OnPreviewChanged;
private void AddPreview(INode inNode)
void OnPreviewChanged()
var materialNode = inNode as AbstractMaterialNode;
if (materialNode == null || !materialNode.hasPreview)
return;
previewTexture = m_PreviewHandle.texture;
m_Version++;
}
m_Preview = CreateInstance<NodePreviewPresenter>();
preview.Initialize(materialNode);
public void Dispose()
{
if (m_PreviewHandle != null)
{
m_PreviewHandle.Dispose();
m_PreviewHandle = null;
}
}
}
}

29
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/MaterialNodeView.cs


leftContainer.Add(m_PreviewContainer);
}
void UpdatePreviewTexture(NodePreviewPresenter preview)
void UpdatePreviewTexture(Texture previewTexture)
if (preview != null)
preview.UpdateTexture();
if (preview == null || preview.texture == null)
if (previewTexture == null)
// Debug.Log(GetPresenter<MaterialNodePresenter>().node.name);
m_PreviewContainer.Clear();
m_PreviewImage.image = Texture2D.whiteTexture;
}

m_PreviewContainer.Add(m_PreviewImage);
m_PreviewImage.image = preview.texture;
m_PreviewImage.image = previewTexture;
Dirty(ChangeType.Repaint);
Dirty(ChangeType.Repaint | ChangeType.Layout);
}
void UpdateControls(MaterialNodePresenter nodeData)

{
base.OnDataChanged();
var node = GetPresenter<MaterialNodePresenter>();
var nodePresenter = GetPresenter<MaterialNodePresenter>();
if (node == null)
if (nodePresenter == null)
{
m_ControlsContainer.Clear();
m_CurrentControls.Clear();

}
UpdateControls(node);
UpdatePreviewTexture(node.preview);
UpdateControls(nodePresenter);
if (node.expanded)
{
UpdatePreviewTexture(node.preview);
}
else
m_PreviewContainer.Clear();
// if (nodePresenter.expanded)
UpdatePreviewTexture(nodePresenter.previewTexture);
// else
// m_PreviewContainer.Clear();
}
}
}

33
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Resources/Styles/MaterialGraph.uss


}
GraphEditorView #content {
GraphEditorView > #content {
GraphEditorView #content #GraphView {
GraphEditorView > #content > #GraphView {
GraphEditorView #content #inspector {
GraphEditorView > #content > #inspector {
.MaterialNode #preview Image {
MaterialNodeView > .mainContainer > #left > #preview > Image {
.MaterialNode #preview.inactive,
.MaterialNode #preview.hidden {
width: 0;
height: 0;
}
grid-background-color:rgb(20, 21, 21);
grid-background-color: rgb(20, 21, 21);
spacing:75.0;
thick-lines:10;
spacing: 75.0;
thick-lines: 10;
flex-direction: column;
justify-content: space-between;
GraphInspectorView > #header {
GraphInspectorView > #top > #header {
GraphInspectorView > #header > #title {
GraphInspectorView > #top > #header > #title {
text-color: rgb(180, 180, 180);
font-style: bold;
padding-left: 16;

}
GraphInspectorView > #contentContainer > #selectionCount {
GraphInspectorView > #top > #content > #selectionCount {
}
GraphInspectorView > #bottom > #preview {
height: 400;
background-color: rgb(79, 79, 79);
}
.nodeEditor {

16
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Testing/IntegrationTests/ShaderGenerationTest.cs


Assert.IsNotNull(m_PreviewMaterial, "preview material could not be created");
const int res = 256;
using (var generator = new MaterialGraphPreviewGenerator(true))
using (var generator = new MaterialGraphPreviewGenerator())
var rendered =
generator.DoRenderPreview(m_PreviewMaterial, PreviewMode.Preview3D, new Rect(0, 0, res, res), 10) as
RenderTexture;
var renderTexture = new RenderTexture(res, res, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default) { hideFlags = HideFlags.HideAndDontSave };
generator.DoRenderPreview(renderTexture, m_PreviewMaterial, PreviewMode.Preview3D, true, 10);
Assert.IsNotNull(rendered, "Render failed");
Assert.IsNotNull(renderTexture, "Render failed");
RenderTexture.active = rendered;
m_Captured = new Texture2D(rendered.width, rendered.height, TextureFormat.ARGB32, false);
m_Captured.ReadPixels(new Rect(0, 0, rendered.width, rendered.height), 0, 0);
RenderTexture.active = renderTexture;
m_Captured = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false);
m_Captured.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
Object.DestroyImmediate(renderTexture, true);
// find the reference image
var dumpFileLocation = Path.Combine(shaderTemplatePath, string.Format("{0}.{1}", file.Name, "png"));

355
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/PreviewSystem.cs


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using UnityEngine;
using UnityEngine.Graphing;
using UnityEngine.MaterialGraph;
using Object = UnityEngine.Object;
namespace UnityEditor.MaterialGraph.Drawing
{
public class PreviewSystem : IDisposable
{
IGraph m_Graph;
Dictionary<Guid, PreviewData> m_Previews = new Dictionary<Guid, PreviewData>();
HashSet<Guid> m_DirtyPreviews = new HashSet<Guid>();
HashSet<Guid> m_DirtyShaders = new HashSet<Guid>();
HashSet<Guid> m_TimeDependentPreviews = new HashSet<Guid>();
Material m_PreviewMaterial;
MaterialPropertyBlock m_PreviewPropertyBlock;
MaterialGraphPreviewGenerator m_PreviewGenerator = new MaterialGraphPreviewGenerator();
Texture2D m_ErrorTexture;
public PreviewSystem(IGraph graph)
{
m_Graph = graph;
m_PreviewMaterial = new Material(Shader.Find("Unlit/Color")) { hideFlags = HideFlags.HideInHierarchy };
m_PreviewMaterial.hideFlags = HideFlags.HideInHierarchy;
m_PreviewPropertyBlock = new MaterialPropertyBlock();
m_ErrorTexture = new Texture2D(2, 2);
m_ErrorTexture.SetPixel(0, 0, Color.magenta);
m_ErrorTexture.SetPixel(0, 1, Color.black);
m_ErrorTexture.SetPixel(1, 0, Color.black);
m_ErrorTexture.SetPixel(1, 1, Color.magenta);
m_ErrorTexture.Apply();
}
public PreviewHandle GetPreviewHandle(Guid nodeGuid)
{
PreviewData previewData;
if (!m_Previews.TryGetValue(nodeGuid, out previewData))
{
var node = m_Graph.GetNodeFromGuid(nodeGuid);
if (node == null)
throw new ArgumentException("Node does not exist.", "nodeGuid");
previewData = new PreviewData();
previewData.renderTexture = new RenderTexture(256, 256, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default) { hideFlags = HideFlags.HideAndDontSave };
m_Previews.Add(nodeGuid, previewData);
m_DirtyShaders.Add(nodeGuid);
m_DirtyPreviews.Add(nodeGuid);
node.onModified += OnNodeModified;
}
previewData.refCount++;
return new PreviewHandle(nodeGuid, previewData, this);
}
void OnNodeModified(INode node, ModificationScope scope)
{
if (scope >= ModificationScope.Graph)
m_DirtyShaders.Add(node.guid);
else if (scope == ModificationScope.Node)
m_DirtyPreviews.Add(node.guid);
}
Stack<Guid> m_Wavefront = new Stack<Guid>();
void PropagateNodeSet(HashSet<Guid> nodeGuidSet, bool forward = true)
{
m_Wavefront.Clear();
foreach (var guid in nodeGuidSet)
m_Wavefront.Push(guid);
while (m_Wavefront.Count > 0)
{
var nodeGuid = m_Wavefront.Pop();
var node = m_Graph.GetNodeFromGuid(nodeGuid);
if (node == null)
continue;
// Loop through all nodes that the node feeds into.
foreach (var slot in forward ? node.GetOutputSlots<ISlot>() : node.GetInputSlots<ISlot>())
{
foreach (var edge in m_Graph.GetEdges(slot.slotReference))
{
// We look at each node we feed into.
var connectedSlot = forward ? edge.inputSlot : edge.outputSlot;
var connectedNodeGuid = connectedSlot.nodeGuid;
// If the input node is already in the set of time-dependent nodes, we don't need to process it.
if (nodeGuidSet.Contains(connectedNodeGuid))
continue;
// Add the node to the set of time-dependent nodes, and to the wavefront such that we can process the nodes that it feeds into.
nodeGuidSet.Add(connectedNodeGuid);
m_Wavefront.Push(connectedNodeGuid);
}
}
}
}
public void UpdateTimeDependentPreviews()
{
m_TimeDependentPreviews.Clear();
foreach (var node in m_Graph.GetNodes<INode>())
{
var timeNode = node as IMayRequireTime;
if (timeNode != null && timeNode.RequiresTime())
m_TimeDependentPreviews.Add(node.guid);
}
PropagateNodeSet(m_TimeDependentPreviews);
}
HashSet<Guid> m_PropertyNodeGuids = new HashSet<Guid>();
List<PreviewProperty> m_PreviewProperties = new List<PreviewProperty>();
public void Update()
{
PropagateNodeSet(m_DirtyShaders);
foreach (var nodeGuid in m_DirtyShaders)
{
UpdateShader(nodeGuid);
}
m_DirtyPreviews.UnionWith(m_DirtyShaders);
m_DirtyShaders.Clear();
PropagateNodeSet(m_DirtyPreviews);
m_DirtyPreviews.UnionWith(m_TimeDependentPreviews);
// Find nodes we need properties from
m_PropertyNodeGuids.Clear();
foreach (var nodeGuid in m_DirtyPreviews)
m_PropertyNodeGuids.Add(nodeGuid);
PropagateNodeSet(m_PropertyNodeGuids, false);
// Fill MaterialPropertyBlock
m_PreviewPropertyBlock.Clear();
foreach (var nodeGuid in m_DirtyPreviews)
{
var node = m_Graph.GetNodeFromGuid<AbstractMaterialNode>(nodeGuid);
node.CollectPreviewMaterialProperties(m_PreviewProperties);
foreach (var previewProperty in m_PreviewProperties)
{
if (previewProperty.m_PropType == PropertyType.Texture && previewProperty.m_Texture != null)
m_PreviewPropertyBlock.SetTexture(previewProperty.m_Name, previewProperty.m_Texture);
else if (previewProperty.m_PropType == PropertyType.Cubemap && previewProperty.m_Cubemap != null)
m_PreviewPropertyBlock.SetTexture(previewProperty.m_Name, previewProperty.m_Cubemap);
else if (previewProperty.m_PropType == PropertyType.Color)
m_PreviewPropertyBlock.SetColor(previewProperty.m_Name, previewProperty.m_Color);
else if (previewProperty.m_PropType == PropertyType.Vector2)
m_PreviewPropertyBlock.SetVector(previewProperty.m_Name, previewProperty.m_Vector4);
else if (previewProperty.m_PropType == PropertyType.Vector3)
m_PreviewPropertyBlock.SetVector(previewProperty.m_Name, previewProperty.m_Vector4);
else if (previewProperty.m_PropType == PropertyType.Vector4)
m_PreviewPropertyBlock.SetVector(previewProperty.m_Name, previewProperty.m_Vector4);
else if (previewProperty.m_PropType == PropertyType.Float)
m_PreviewPropertyBlock.SetFloat(previewProperty.m_Name, previewProperty.m_Float);
}
m_PreviewProperties.Clear();
}
var time = Time.realtimeSinceStartup;
foreach (var nodeGuid in m_DirtyPreviews)
{
var previewData = m_Previews[nodeGuid];
if (previewData.shader == null)
{
previewData.texture = null;
continue;
}
if (MaterialGraphAsset.ShaderHasError(previewData.shader))
{
previewData.texture = m_ErrorTexture;
continue;
}
var node = m_Graph.GetNodeFromGuid(nodeGuid);
m_PreviewMaterial.shader = previewData.shader;
m_PreviewGenerator.DoRenderPreview(previewData.renderTexture, m_PreviewMaterial, previewData.previewMode, node is IMasterNode, time, m_PreviewPropertyBlock);
previewData.texture = previewData.renderTexture;
}
foreach (var nodeGuid in m_DirtyPreviews)
{
var previewData = m_Previews[nodeGuid];
if (previewData.onPreviewChanged != null)
previewData.onPreviewChanged();
}
m_DirtyPreviews.Clear();
}
void UpdateShader(Guid nodeGuid)
{
var node = m_Graph.GetNodeFromGuid<AbstractMaterialNode>(nodeGuid);
PreviewData previewData;
if (!m_Previews.TryGetValue(nodeGuid, out previewData))
return;
if (node is IMasterNode)
{
var masterNode = (IMasterNode)node;
List<PropertyGenerator.TextureInfo> defaultTextures;
previewData.shaderString = masterNode.GetFullShader(GenerationMode.Preview, node.guid + "_preview", out defaultTextures);
previewData.previewMode = masterNode.has3DPreview() ? PreviewMode.Preview3D : PreviewMode.Preview2D;
}
else if (!node.hasPreview || NodeUtils.FindEffectiveShaderStage(node, true) == ShaderStage.Vertex)
{
previewData.shaderString = null;
}
else
{
PreviewMode previewMode;
previewData.shaderString = ShaderGenerator.GeneratePreviewShader(node, out previewMode);
previewData.previewMode = previewMode;
}
// Debug output
Debug.Log("RecreateShader: " + node.GetVariableNameForNode() + Environment.NewLine + previewData.shaderString);
File.WriteAllText(Application.dataPath + "/../GeneratedShader.shader", (previewData.shaderString ?? "null").Replace("UnityEngine.MaterialGraph", "Generated"));
if (string.IsNullOrEmpty(previewData.shaderString))
{
if (previewData.shader != null)
Object.DestroyImmediate(previewData.shader, true);
previewData.shader = null;
return;
}
if (previewData.shader != null && MaterialGraphAsset.ShaderHasError(previewData.shader))
{
Object.DestroyImmediate(previewData.shader, true);
previewData.shader = null;
}
if (previewData.shader == null)
{
previewData.shader = ShaderUtil.CreateShaderAsset(previewData.shaderString);
previewData.shader.hideFlags = HideFlags.HideAndDontSave;
}
else
{
ShaderUtil.UpdateShaderAsset(previewData.shader, previewData.shaderString);
}
}
public void DestroyPreviewHandle(Guid nodeGuid)
{
PreviewData previewData;
if (!m_Previews.TryGetValue(nodeGuid, out previewData))
return;
previewData.refCount--;
if (previewData.refCount == 0)
DestroyPreview(nodeGuid, previewData);
}
void DestroyPreview(Guid nodeGuid, PreviewData previewData)
{
if (m_Previews.Remove(nodeGuid))
{
if (previewData.shader != null)
Object.DestroyImmediate(previewData.shader, true);
if (previewData.renderTexture != null)
Object.DestroyImmediate(previewData.renderTexture, true);
var node = m_Graph.GetNodeFromGuid(nodeGuid);
if (node != null)
node.onModified -= OnNodeModified;
m_DirtyPreviews.Remove(nodeGuid);
m_DirtyShaders.Remove(nodeGuid);
m_TimeDependentPreviews.Remove(nodeGuid);
previewData.shader = null;
previewData.renderTexture = null;
previewData.texture = null;
previewData.onPreviewChanged = null;
}
}
void ReleaseUnmanagedResources()
{
if (m_PreviewMaterial != null)
Object.DestroyImmediate(m_PreviewMaterial, true);
m_PreviewMaterial = null;
if (m_PreviewGenerator != null)
m_PreviewGenerator.Dispose();
m_PreviewGenerator = null;
var previews = m_Previews.ToList();
foreach (var kvp in previews)
DestroyPreview(kvp.Key, kvp.Value);
}
public void Dispose()
{
ReleaseUnmanagedResources();
GC.SuppressFinalize(this);
}
~PreviewSystem()
{
ReleaseUnmanagedResources();
}
}
public delegate void OnPreviewChanged();
public class PreviewData
{
public Shader shader { get; set; }
public string shaderString { get; set; }
public PreviewMode previewMode { get; set; }
public RenderTexture renderTexture { get; set; }
public Texture texture { get; set; }
public int refCount { get; set; }
public OnPreviewChanged onPreviewChanged;
}
public class PreviewHandle : IDisposable
{
Guid m_NodeGuid;
PreviewData m_PreviewData;
PreviewSystem m_PreviewSystem;
public PreviewHandle(Guid nodeGuid, PreviewData previewData, PreviewSystem previewSystem)
{
m_NodeGuid = nodeGuid;
m_PreviewData = previewData;
m_PreviewSystem = previewSystem;
}
public OnPreviewChanged onPreviewChanged
{
get { return m_PreviewData.onPreviewChanged; }
set { m_PreviewData.onPreviewChanged = value; }
}
public Texture texture
{
get { return m_PreviewData.texture; }
}
void ReleaseUnmanagedResources()
{
m_PreviewSystem.DestroyPreviewHandle(m_NodeGuid);
}
public void Dispose()
{
ReleaseUnmanagedResources();
GC.SuppressFinalize(this);
}
~PreviewHandle()
{
ReleaseUnmanagedResources();
}
}
}

3
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/PreviewSystem.cs.meta


fileFormatVersion: 2
guid: aa2238545a2849ecb0a6285b5a632a69
timeCreated: 1505525146

12
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/NodePreviewPresenter.cs.meta


fileFormatVersion: 2
guid: 1b2eecd8c1fc12f41810a98414854158
timeCreated: 1476707366
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

256
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/NodePreviewPresenter.cs


using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor.Experimental.UIElements.GraphView;
using UnityEngine;
using UnityEngine.Graphing;
using UnityEngine.MaterialGraph;
using Object = UnityEngine.Object;
using UnityEditor.Experimental.UIElements.GraphView;
namespace UnityEditor.MaterialGraph.Drawing
{
[Serializable]
public class NodePreviewPresenter : ScriptableObject
{
protected NodePreviewPresenter()
{}
MaterialGraphPreviewGenerator m_PreviewGenerator;
[NonSerialized]
int m_LastShaderVersion = -1;
[NonSerialized]
Material m_PreviewMaterial;
[NonSerialized]
Shader m_PreviewShader;
AbstractMaterialNode m_Node;
[SerializeField]
ModificationScope m_ModificationScope;
// Null means no modification is currently in progress.
public ModificationScope modificationScope
{
get
{
return m_ModificationScope;
}
set
{
// External changes can only set the modification scope higher, to prevent missing out on a previously set shader regeneration.
if (m_ModificationScope >= value)
return;
m_ModificationScope = value;
}
}
[NonSerialized]
Texture m_Texture;
public Texture texture
{
get { return m_Texture; }
}
PreviewMode m_GeneratedShaderMode = PreviewMode.Preview2D;
public Material previewMaterial
{
get
{
if (m_PreviewMaterial == null)
{
m_PreviewMaterial = new Material(Shader.Find("Unlit/Color")) {hideFlags = HideFlags.HideInHierarchy};
m_PreviewMaterial.hideFlags = HideFlags.HideInHierarchy;
}
return m_PreviewMaterial;
}
}
MaterialGraphPreviewGenerator previewGenerator
{
get
{
if (m_PreviewGenerator == null)
{
m_PreviewGenerator = new MaterialGraphPreviewGenerator(m_Node is AbstractMasterNode);
}
return m_PreviewGenerator;
}
}
public void Initialize(AbstractMaterialNode node)
{
m_Node = node;
m_ModificationScope = ModificationScope.Graph;
}
public void UpdateTexture()
{
if (m_Node == null)
{
m_Texture = null;
return;
}
if (m_Node.hasPreview == false)
{
m_Texture = null;
return;
}
var scope = m_ModificationScope;
m_ModificationScope = ModificationScope.Nothing;
if (scope != ModificationScope.Nothing)
{
if (scope >= ModificationScope.Graph)
{
var stage = NodeUtils.FindEffectiveShaderStage(m_Node, true);
if (!(m_Node is AbstractSurfaceMasterNode) && stage == ShaderStage.Vertex)
{
// Debug.Log(m_Node.name + ":" + stage);
m_Texture = null;
return;
}
// TODO: Handle shader regeneration error
var status = UpdatePreviewShader();
}
m_Texture = RenderPreview(new Vector2(256, 256));
}
else if (texture == null)
{
m_Texture = RenderPreview(new Vector2(256, 256));
}
}
void OnDisable()
{
if (m_PreviewGenerator != null)
m_PreviewGenerator.Dispose();
}
protected virtual string GetPreviewShaderString()
{
// TODO: this is a workaround right now.
if (m_Node is IMasterNode)
{
var localNode = (IMasterNode)m_Node;
if (localNode == null)
return string.Empty;
List<PropertyGenerator.TextureInfo> defaultTextures;
var resultShader = ((IMasterNode)m_Node).GetFullShader(GenerationMode.Preview, m_Node.guid + "_preview", out defaultTextures);
if (((IMasterNode)m_Node).has3DPreview())
{
m_GeneratedShaderMode = PreviewMode.Preview3D;
}
return resultShader;
}
return ShaderGenerator.GeneratePreviewShader(m_Node, out m_GeneratedShaderMode);
}
bool UpdatePreviewShader()
{
if (m_Node == null || m_Node.hasError)
return false;
var resultShader = GetPreviewShaderString();
Debug.Log("RecreateShaderAndMaterial : " + m_Node.GetVariableNameForNode() + Environment.NewLine + resultShader);
string shaderOuputString = resultShader.Replace("UnityEngine.MaterialGraph", "Generated");
System.IO.File.WriteAllText(Application.dataPath + "/../GeneratedShader.shader", shaderOuputString);
if (string.IsNullOrEmpty(resultShader))
return false;
// workaround for some internal shader compiler weirdness
// if we are in error we sometimes to not properly clean
// out the error flags and will stay in error, even
// if we are now valid
if (m_PreviewShader && MaterialGraphAsset.ShaderHasError(m_PreviewShader))
{
Object.DestroyImmediate(m_PreviewShader, true);
m_PreviewShader = null;
}
if (m_PreviewShader == null)
{
m_PreviewShader = ShaderUtil.CreateShaderAsset(resultShader);
m_PreviewShader.hideFlags = HideFlags.HideAndDontSave;
}
else
{
ShaderUtil.UpdateShaderAsset(m_PreviewShader, resultShader);
}
return !MaterialGraphAsset.ShaderHasError(m_PreviewShader);
}
/// <summary>
/// RenderPreview gets called in OnPreviewGUI. Nodes can override
/// RenderPreview and do their own rendering to the render texture
/// </summary>
Texture RenderPreview(Vector2 targetSize)
{
previewMaterial.shader = m_PreviewShader;
UpdateMaterialProperties(m_Node, previewMaterial);
return previewGenerator.DoRenderPreview(previewMaterial, m_GeneratedShaderMode, new Rect(0, 0, targetSize.x, targetSize.y));
}
static void SetPreviewMaterialProperty(PreviewProperty previewProperty, Material mat)
{
switch (previewProperty.m_PropType)
{
case PropertyType.Texture:
mat.SetTexture(previewProperty.m_Name, previewProperty.m_Texture);
break;
case PropertyType.Cubemap:
mat.SetTexture(previewProperty.m_Name, previewProperty.m_Cubemap);
break;
case PropertyType.Color:
mat.SetColor(previewProperty.m_Name, previewProperty.m_Color);
break;
case PropertyType.Vector2:
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4);
break;
case PropertyType.Vector3:
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4);
break;
case PropertyType.Vector4:
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4);
break;
case PropertyType.Float:
mat.SetFloat(previewProperty.m_Name, previewProperty.m_Float);
break;
}
}
public static void UpdateMaterialProperties(AbstractMaterialNode target, Material material)
{
var childNodes = ListPool<INode>.Get();
NodeUtils.DepthFirstCollectNodesFromNode(childNodes, target);
var pList = ListPool<PreviewProperty>.Get();
for (var index = 0; index < childNodes.Count; index++)
{
var node = childNodes[index] as AbstractMaterialNode;
if (node == null)
continue;
node.CollectPreviewMaterialProperties(pList);
}
foreach (var prop in pList)
SetPreviewMaterialProperty(prop, material);
ListPool<INode>.Release(childNodes);
ListPool<PreviewProperty>.Release(pList);
}
}
}
正在加载...
取消
保存