您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
241 行
8.2 KiB
241 行
8.2 KiB
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()
|
|
{}
|
|
|
|
private MaterialGraphPreviewGenerator m_PreviewGenerator;
|
|
|
|
[NonSerialized]
|
|
private int m_LastShaderVersion = -1;
|
|
|
|
[NonSerialized]
|
|
private Material m_PreviewMaterial;
|
|
|
|
[NonSerialized]
|
|
private Shader m_PreviewShader;
|
|
|
|
private AbstractMaterialNode m_Node;
|
|
|
|
[SerializeField]
|
|
private 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]
|
|
private Texture m_texture;
|
|
|
|
private 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;
|
|
}
|
|
}
|
|
|
|
private MaterialGraphPreviewGenerator previewGenerator
|
|
{
|
|
get
|
|
{
|
|
if (m_PreviewGenerator == null)
|
|
{
|
|
m_PreviewGenerator = new MaterialGraphPreviewGenerator();
|
|
}
|
|
return m_PreviewGenerator;
|
|
}
|
|
}
|
|
|
|
public void Initialize(AbstractMaterialNode node)
|
|
{
|
|
m_Node = node;
|
|
m_modificationScope = ModificationScope.Graph;
|
|
}
|
|
|
|
public Texture Render(Vector2 dimension)
|
|
{
|
|
if (m_Node == null)
|
|
return null;
|
|
|
|
if (m_Node.hasPreview == false)
|
|
return null;
|
|
|
|
var scope = m_modificationScope;
|
|
m_modificationScope = ModificationScope.Nothing;
|
|
|
|
if (scope != ModificationScope.Nothing)
|
|
{
|
|
bool status = false;
|
|
if (scope >= ModificationScope.Graph)
|
|
{
|
|
// TODO: Handle shader regeneration error
|
|
status = UpdatePreviewShader();
|
|
}
|
|
m_texture = RenderPreview(dimension);
|
|
}
|
|
else if (m_texture == null)
|
|
{
|
|
m_texture = RenderPreview(dimension);
|
|
}
|
|
|
|
return m_texture;
|
|
}
|
|
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);
|
|
}
|
|
|
|
private 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>
|
|
private 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));
|
|
}
|
|
|
|
private 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);
|
|
}
|
|
}
|
|
}
|