315 lines
12 KiB
C#
315 lines
12 KiB
C#
using System.Linq;
|
|
using System.IO;
|
|
using NUnit.Framework;
|
|
using UnityEngine;
|
|
using UnityEditor.Graphing;
|
|
|
|
namespace UnityEditor.ShaderGraph.UnitTests
|
|
{
|
|
[TestFixture]
|
|
class TargetTests
|
|
{
|
|
[OneTimeSetUp]
|
|
public void RunBeforeAnyTests()
|
|
{
|
|
Debug.unityLogger.logHandler = new ConsoleLogHandler();
|
|
}
|
|
|
|
[Test]
|
|
public void CanCreateBlankGraph()
|
|
{
|
|
GraphData graph = new GraphData();
|
|
graph.AddContexts();
|
|
|
|
Assert.IsNotNull(graph.activeTargets);
|
|
Assert.AreEqual(0, graph.activeTargets.Count());
|
|
}
|
|
|
|
public static bool s_ForceVFXFakeTargetVisible = false;
|
|
#if !VFX_GRAPH_10_0_0_OR_NEWER
|
|
//A barebone VFXTarget for testing coverage.
|
|
sealed class VFXTarget : UnityEditor.ShaderGraph.Target
|
|
{
|
|
public VFXTarget()
|
|
{
|
|
displayName = "Fake VFX Target"; //Should not be displayed outside the test runner.
|
|
isHidden = !s_ForceVFXFakeTargetVisible;
|
|
}
|
|
|
|
public override void GetActiveBlocks(ref UnityEditor.ShaderGraph.TargetActiveBlockContext context)
|
|
{
|
|
context.AddBlock(ShaderGraph.BlockFields.SurfaceDescription.BaseColor);
|
|
context.AddBlock(ShaderGraph.BlockFields.SurfaceDescription.Alpha);
|
|
}
|
|
|
|
public override void GetFields(ref TargetFieldContext context)
|
|
{
|
|
}
|
|
|
|
public override void Setup(ref TargetSetupContext context)
|
|
{
|
|
}
|
|
|
|
public override bool IsActive() => false;
|
|
public override bool WorksWithSRP(UnityEngine.Rendering.RenderPipelineAsset scriptableRenderPipeline)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, System.Action onChange, System.Action<System.String> registerUndo)
|
|
{
|
|
}
|
|
}
|
|
#endif
|
|
|
|
[Test]
|
|
public void CanInitializeOutputTargets()
|
|
{
|
|
s_ForceVFXFakeTargetVisible = true;
|
|
GraphData graph = new GraphData();
|
|
graph.AddContexts();
|
|
graph.InitializeOutputs(new[] { new VFXTarget() }, null);
|
|
|
|
Assert.IsNotNull(graph.activeTargets);
|
|
Assert.AreEqual(1, graph.activeTargets.Count());
|
|
Assert.AreEqual(typeof(VFXTarget), graph.activeTargets.ElementAt(0).GetType());
|
|
s_ForceVFXFakeTargetVisible = false;
|
|
}
|
|
|
|
[Test]
|
|
public void CanAddTarget()
|
|
{
|
|
s_ForceVFXFakeTargetVisible = true;
|
|
GraphData graph = new GraphData();
|
|
graph.AddContexts();
|
|
|
|
var vfxTarget = graph.allPotentialTargets.FirstOrDefault(x => x is VFXTarget);
|
|
graph.SetTargetActive(vfxTarget);
|
|
|
|
Assert.IsNotNull(graph.activeTargets);
|
|
Assert.AreEqual(1, graph.activeTargets.Count());
|
|
Assert.AreEqual(vfxTarget, graph.activeTargets.ElementAt(0));
|
|
s_ForceVFXFakeTargetVisible = false;
|
|
}
|
|
|
|
[Test]
|
|
public void ActiveTargetsArePotentialTargets()
|
|
{
|
|
s_ForceVFXFakeTargetVisible = true;
|
|
GraphData graph = new GraphData();
|
|
graph.AddContexts();
|
|
|
|
var vfxTarget = new VFXTarget();
|
|
graph.SetTargetActive(vfxTarget);
|
|
Assert.IsTrue(graph.allPotentialTargets.Contains(vfxTarget));
|
|
|
|
s_ForceVFXFakeTargetVisible = false;
|
|
}
|
|
|
|
[Test]
|
|
public void GetTargetIndexWorks()
|
|
{
|
|
s_ForceVFXFakeTargetVisible = true;
|
|
|
|
GraphData graph = new GraphData();
|
|
graph.AddContexts();
|
|
|
|
int targetIndex = graph.GetTargetIndexByKnownType(typeof(VFXTarget));
|
|
Assert.IsTrue(targetIndex >= 0);
|
|
|
|
var vfxTarget = new VFXTarget();
|
|
graph.SetTargetActive(vfxTarget);
|
|
|
|
var targetIndex2 = graph.GetTargetIndex(vfxTarget);
|
|
Assert.AreEqual(targetIndex, targetIndex2);
|
|
|
|
var nonActiveVFXTarget = new VFXTarget();
|
|
Assert.AreEqual(-1, graph.GetTargetIndex(nonActiveVFXTarget));
|
|
|
|
s_ForceVFXFakeTargetVisible = false;
|
|
}
|
|
|
|
[Test]
|
|
public void CanRemoveTarget()
|
|
{
|
|
s_ForceVFXFakeTargetVisible = true;
|
|
GraphData graph = new GraphData();
|
|
graph.AddContexts();
|
|
|
|
var vfxTarget = new VFXTarget();
|
|
graph.InitializeOutputs(new[] { vfxTarget }, null);
|
|
|
|
graph.SetTargetInactive(vfxTarget);
|
|
|
|
Assert.IsNotNull(graph.activeTargets);
|
|
Assert.AreEqual(0, graph.activeTargets.Count());
|
|
s_ForceVFXFakeTargetVisible = false;
|
|
}
|
|
|
|
[Test]
|
|
public void CanSetBlockActive()
|
|
{
|
|
s_ForceVFXFakeTargetVisible = true;
|
|
GraphData graph = new GraphData();
|
|
graph.AddContexts();
|
|
graph.InitializeOutputs(new[] { new VFXTarget() }, new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.BaseColor, BlockFields.SurfaceDescription.NormalTS });
|
|
|
|
// Block active state should match VFX Target's default GetActiveBlocks
|
|
var blocks = graph.GetNodes<BlockNode>().ToList();
|
|
Assert.AreEqual(2, blocks.Count);
|
|
Assert.AreEqual(BlockFields.SurfaceDescription.BaseColor, blocks[0].descriptor);
|
|
Assert.AreEqual(true, blocks[0].isActive);
|
|
Assert.AreEqual(BlockFields.SurfaceDescription.NormalTS, blocks[1].descriptor);
|
|
Assert.AreEqual(false, blocks[1].isActive);
|
|
s_ForceVFXFakeTargetVisible = false;
|
|
}
|
|
|
|
[Test]
|
|
public void CanUpdateBlockActiveState()
|
|
{
|
|
s_ForceVFXFakeTargetVisible = true;
|
|
GraphData graph = new GraphData();
|
|
graph.AddContexts();
|
|
graph.InitializeOutputs(new[] { new VFXTarget() }, new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.BaseColor, BlockFields.SurfaceDescription.NormalTS });
|
|
|
|
// Remove VFX target
|
|
var vfxTarget = graph.allPotentialTargets.FirstOrDefault(x => x is VFXTarget);
|
|
graph.SetTargetInactive(vfxTarget);
|
|
|
|
var activeBlocks = graph.GetActiveBlocksForAllActiveTargets();
|
|
graph.UpdateActiveBlocks(activeBlocks);
|
|
|
|
// All blocks should be inactive as there are no active targets
|
|
var blocks = graph.GetNodes<BlockNode>().ToList();
|
|
Assert.AreEqual(2, blocks.Count);
|
|
Assert.AreEqual(BlockFields.SurfaceDescription.BaseColor, blocks[0].descriptor);
|
|
Assert.AreEqual(false, blocks[0].isActive);
|
|
Assert.AreEqual(BlockFields.SurfaceDescription.NormalTS, blocks[1].descriptor);
|
|
Assert.AreEqual(false, blocks[1].isActive);
|
|
s_ForceVFXFakeTargetVisible = false;
|
|
}
|
|
|
|
sealed class MultiShaderTarget : UnityEditor.ShaderGraph.Target
|
|
{
|
|
public MultiShaderTarget()
|
|
{
|
|
displayName = "MultiShader Test Target";
|
|
isHidden = false;
|
|
}
|
|
|
|
public override void GetActiveBlocks(ref UnityEditor.ShaderGraph.TargetActiveBlockContext context)
|
|
{
|
|
context.AddBlock(ShaderGraph.BlockFields.SurfaceDescription.BaseColor);
|
|
context.AddBlock(ShaderGraph.BlockFields.SurfaceDescription.Alpha);
|
|
}
|
|
|
|
public override void GetFields(ref TargetFieldContext context)
|
|
{
|
|
}
|
|
|
|
public static PassDescriptor BuildPass()
|
|
{
|
|
PassDescriptor pass = new PassDescriptor()
|
|
{
|
|
// Definition
|
|
displayName = "DepthOnly",
|
|
referenceName = "SHADERPASS_DEPTHONLY",
|
|
lightMode = "DepthOnly",
|
|
useInPreview = true,
|
|
|
|
// Template
|
|
passTemplatePath = "Packages/com.unity.shadergraph/Editor/Generation/Targets/BuiltIn/Editor/ShaderGraph/Templates/ShaderPass.template",
|
|
sharedTemplateDirectories = GenerationUtils.GetDefaultSharedTemplateDirectories(),
|
|
|
|
// Port Mask
|
|
validVertexBlocks = new BlockFieldDescriptor[] { BlockFields.VertexDescription.Position, BlockFields.VertexDescription.Normal, BlockFields.VertexDescription.Tangent },
|
|
validPixelBlocks = new BlockFieldDescriptor[] { BlockFields.SurfaceDescription.Alpha, BlockFields.SurfaceDescription.AlphaClipThreshold },
|
|
|
|
// Fields
|
|
structs = new StructCollection { { Structs.Attributes }, { Structs.SurfaceDescriptionInputs }, { Structs.VertexDescriptionInputs } },
|
|
fieldDependencies = FieldDependencies.Default,
|
|
|
|
// Conditional State
|
|
renderStates = null,
|
|
pragmas = new PragmaCollection { { Pragma.Target(ShaderModel.Target30) }, { Pragma.MultiCompileInstancing }, { Pragma.Vertex("vert") }, { Pragma.Fragment("frag") } },
|
|
defines = null,
|
|
keywords = null,
|
|
includes = null,
|
|
customInterpolators = null,
|
|
};
|
|
return pass;
|
|
}
|
|
|
|
public static SubShaderDescriptor BuildSubShader(string additionaShaderID)
|
|
{
|
|
SubShaderDescriptor result = new SubShaderDescriptor()
|
|
{
|
|
pipelineTag = "TestPipeline",
|
|
renderType = "Opaque",
|
|
renderQueue = "Geometry",
|
|
generatesPreview = true,
|
|
passes = new PassCollection(),
|
|
additionalShaderID = additionaShaderID
|
|
};
|
|
result.passes.Add(BuildPass());
|
|
return result;
|
|
}
|
|
|
|
public override void Setup(ref TargetSetupContext context)
|
|
{
|
|
var ss = BuildSubShader(null); // primary shader
|
|
var ss2 = BuildSubShader("{Name}-second");
|
|
context.AddSubShader(ss);
|
|
context.AddSubShader(ss2);
|
|
}
|
|
|
|
public override bool IsActive() => true;
|
|
public override bool WorksWithSRP(UnityEngine.Rendering.RenderPipelineAsset scriptableRenderPipeline)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, System.Action onChange, System.Action<System.String> registerUndo)
|
|
{
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void CanBuildMultipleShaders()
|
|
{
|
|
GraphData graph = new GraphData();
|
|
graph.AddContexts();
|
|
|
|
var multiTarget = new MultiShaderTarget();
|
|
graph.SetTargetActive(multiTarget);
|
|
Assert.IsTrue(graph.allPotentialTargets.Contains(multiTarget));
|
|
|
|
graph.OnEnable();
|
|
graph.ValidateGraph();
|
|
|
|
var generator = new Generator(graph, graph.outputNode, GenerationMode.ForReals, "MyTestShader");
|
|
var generatedShaders = generator.allGeneratedShaders.ToList();
|
|
|
|
Assert.AreEqual(2, generatedShaders.Count);
|
|
Assert.IsTrue(generatedShaders[0].shaderName == "MyTestShader");
|
|
Assert.IsTrue(generatedShaders[1].shaderName == "MyTestShader-second");
|
|
Assert.IsTrue(generatedShaders[0].codeString.Contains("Shader \"MyTestShader\""));
|
|
Assert.IsTrue(generatedShaders[1].codeString.Contains("Shader \"MyTestShader-second\""));
|
|
|
|
// save graph to file on disk and import it...
|
|
var path = AssetDatabase.GenerateUniqueAssetPath("Assets/multiShaderTest.ShaderGraph");
|
|
FileUtilities.WriteShaderGraphToDisk(path, graph);
|
|
|
|
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate | ImportAssetOptions.DontDownloadFromCacheServer);
|
|
|
|
// check that we actually have two shader assets in the import result
|
|
// (they won't work, but they should exist)
|
|
var assets = AssetDatabase.LoadAllAssetsAtPath(path);
|
|
int shaderCount = assets.OfType<Shader>().Count();
|
|
Assert.AreEqual(2, shaderCount);
|
|
|
|
AssetDatabase.DeleteAsset(path);
|
|
}
|
|
}
|
|
}
|