You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
11 KiB
190 lines
11 KiB
using System;
|
|
using System.Linq;
|
|
using UnityEngine.Rendering.HighDefinition;
|
|
using UnityEditor.ShaderGraph;
|
|
using UnityEditor.ShaderGraph.Legacy;
|
|
|
|
using static UnityEngine.Rendering.HighDefinition.HDMaterial;
|
|
using static UnityEditor.Rendering.HighDefinition.HDFields;
|
|
|
|
namespace UnityEditor.Rendering.HighDefinition.ShaderGraph
|
|
{
|
|
sealed partial class HairSubTarget : LightingSubTarget, ILegacyTarget, IRequiresData<HairData>
|
|
{
|
|
public HairSubTarget() => displayName = "Hair";
|
|
|
|
static readonly GUID kSubTargetSourceCodeGuid = new GUID("7e681cc79dd8e6c46ba1e8412d519e26"); // HairSubTarget.cs
|
|
|
|
static string[] passTemplateMaterialDirectories = new string[]
|
|
{
|
|
$"{HDUtils.GetHDRenderPipelinePath()}Editor/Material/Hair/ShaderGraph/"
|
|
};
|
|
|
|
protected override string[] templateMaterialDirectories => passTemplateMaterialDirectories;
|
|
protected override GUID subTargetAssetGuid => kSubTargetSourceCodeGuid;
|
|
protected override ShaderID shaderID => ShaderID.SG_Hair;
|
|
protected override string subShaderInclude => CoreIncludes.kHair;
|
|
protected override string raytracingInclude => CoreIncludes.kHairRaytracing;
|
|
protected override FieldDescriptor subShaderField => new FieldDescriptor(kSubShader, "Hair SubShader", "");
|
|
protected override bool requireSplitLighting => false;
|
|
protected override bool supportPathtracing => !TargetsVFX();
|
|
protected override string pathtracingInclude => CoreIncludes.kHairPathtracing;
|
|
|
|
HairData m_HairData;
|
|
|
|
HairData IRequiresData<HairData>.data
|
|
{
|
|
get => m_HairData;
|
|
set => m_HairData = value;
|
|
}
|
|
|
|
public HairData hairData
|
|
{
|
|
get => m_HairData;
|
|
set => m_HairData = value;
|
|
}
|
|
|
|
public static FieldDescriptor KajiyaKay = new FieldDescriptor(kMaterial, "KajiyaKay", "_MATERIAL_FEATURE_HAIR_KAJIYA_KAY 1");
|
|
public static FieldDescriptor Marschner = new FieldDescriptor(kMaterial, "Marschner", "_MATERIAL_FEATURE_HAIR_MARSCHNER 1");
|
|
public static FieldDescriptor MarschnerCinematic = new FieldDescriptor(kMaterial, "MarschnerCinematic", "_MATERIAL_FEATURE_HAIR_MARSCHNER_CINEMATIC 1");
|
|
public static FieldDescriptor RimTransmissionIntensity = new FieldDescriptor(string.Empty, "RimTransmissionIntensity", "_RIM_TRANSMISSION_INTENSITY 1");
|
|
public static FieldDescriptor HairStrandDirection = new FieldDescriptor(string.Empty, "HairStrandDirection", "_HAIR_STRAND_DIRECTION 1");
|
|
public static FieldDescriptor UseLightFacingNormal = new FieldDescriptor(string.Empty, "UseLightFacingNormal", "_USE_LIGHT_FACING_NORMAL 1");
|
|
public static FieldDescriptor Transmittance = new FieldDescriptor(string.Empty, "Transmittance", "_TRANSMITTANCE 1");
|
|
public static FieldDescriptor AbsorptionFromColor = new FieldDescriptor(string.Empty, "AbsorptionFromColor", "_ABSORPTION_FROM_COLOR 1");
|
|
public static FieldDescriptor AbsorptionFromMelanin = new FieldDescriptor(string.Empty, "AbsorptionFromMelanin", "_ABSORPTION_FROM_MELANIN 1");
|
|
public static FieldDescriptor UseSplineVisibilityForScattering = new FieldDescriptor(string.Empty, "UseSplineVisibilityForScattering", "_USE_SPLINE_VISIBILITY_FOR_MULTIPLE_SCATTERING 1");
|
|
|
|
// Cinematic sample counts
|
|
public static FieldDescriptor EnvironmentLightSamplesLow = new FieldDescriptor(string.Empty, "EnvironmentLightSamplesLow", "#define ENVIRONMENT_LIGHT_SAMPLE_COUNT 4");
|
|
public static FieldDescriptor EnvironmentLightSamplesMedium = new FieldDescriptor(string.Empty, "EnvironmentLightSamplesMedium", "#define ENVIRONMENT_LIGHT_SAMPLE_COUNT 8");
|
|
public static FieldDescriptor EnvironmentLightSamplesHigh = new FieldDescriptor(string.Empty, "EnvironmentLightSamplesHigh", "#define ENVIRONMENT_LIGHT_SAMPLE_COUNT 12");
|
|
public static FieldDescriptor EnvironmentLightSamplesUltra = new FieldDescriptor(string.Empty, "EnvironmentLightSamplesUltra", "#define ENVIRONMENT_LIGHT_SAMPLE_COUNT 24");
|
|
|
|
public static FieldDescriptor AreaLightSamplesLow = new FieldDescriptor(string.Empty, "AreaLightSamplesLow", "#define _AREA_LIGHT_SAMPLE_COUNT 4");
|
|
public static FieldDescriptor AreaLightSamplesMedium = new FieldDescriptor(string.Empty, "AreaLightSamplesMedium", "#define _AREA_LIGHT_SAMPLE_COUNT 8");
|
|
public static FieldDescriptor AreaLightSamplesHigh = new FieldDescriptor(string.Empty, "AreaLightSamplesHigh", "#define _AREA_LIGHT_SAMPLE_COUNT 12");
|
|
public static FieldDescriptor AreaLightSamplesUltra = new FieldDescriptor(string.Empty, "AreaLightSamplesUltra", "#define _AREA_LIGHT_SAMPLE_COUNT 24");
|
|
|
|
public override void GetFields(ref TargetFieldContext context)
|
|
{
|
|
base.GetFields(ref context);
|
|
|
|
var descs = context.blocks.Select(x => x.descriptor);
|
|
|
|
// Hair specific properties:
|
|
context.AddField(KajiyaKay, hairData.materialType == HairData.MaterialType.Approximate);
|
|
context.AddField(Marschner, hairData.materialType == HairData.MaterialType.Physical);
|
|
context.AddField(MarschnerCinematic, hairData.materialType == HairData.MaterialType.PhysicalCinematic);
|
|
context.AddField(HairStrandDirection, descs.Contains(HDBlockFields.SurfaceDescription.HairStrandDirection) && context.pass.validPixelBlocks.Contains(HDBlockFields.SurfaceDescription.HairStrandDirection));
|
|
context.AddField(RimTransmissionIntensity, descs.Contains(HDBlockFields.SurfaceDescription.RimTransmissionIntensity) && context.pass.validPixelBlocks.Contains(HDBlockFields.SurfaceDescription.RimTransmissionIntensity));
|
|
context.AddField(UseLightFacingNormal, hairData.geometryType == HairData.GeometryType.Strands || hairData.materialType != HairData.MaterialType.Approximate);
|
|
context.AddField(Transmittance, descs.Contains(HDBlockFields.SurfaceDescription.Transmittance) && context.pass.validPixelBlocks.Contains(HDBlockFields.SurfaceDescription.Transmittance));
|
|
context.AddField(AbsorptionFromColor, hairData.colorParameterization == HairData.ColorParameterization.BaseColor);
|
|
context.AddField(AbsorptionFromMelanin, hairData.colorParameterization == HairData.ColorParameterization.Melanin);
|
|
context.AddField(UseSplineVisibilityForScattering, hairData.materialType == HairData.MaterialType.PhysicalCinematic && hairData.directionalFractionMode == HairData.DirectionalFractionMode.ShadowMap);
|
|
|
|
switch (hairData.environmentSamples)
|
|
{
|
|
case HairData.CinematicSampleCount.Low:
|
|
context.AddField(EnvironmentLightSamplesLow);
|
|
break;
|
|
case HairData.CinematicSampleCount.Medium:
|
|
context.AddField(EnvironmentLightSamplesMedium);
|
|
break;
|
|
case HairData.CinematicSampleCount.High:
|
|
context.AddField(EnvironmentLightSamplesHigh);
|
|
break;
|
|
case HairData.CinematicSampleCount.Ultra:
|
|
context.AddField(EnvironmentLightSamplesUltra);
|
|
break;
|
|
}
|
|
|
|
switch (hairData.areaLightSamples)
|
|
{
|
|
case HairData.CinematicSampleCount.Low:
|
|
context.AddField(AreaLightSamplesLow);
|
|
break;
|
|
case HairData.CinematicSampleCount.Medium:
|
|
context.AddField(AreaLightSamplesMedium);
|
|
break;
|
|
case HairData.CinematicSampleCount.High:
|
|
context.AddField(AreaLightSamplesHigh);
|
|
break;
|
|
case HairData.CinematicSampleCount.Ultra:
|
|
context.AddField(AreaLightSamplesUltra);
|
|
break;
|
|
}
|
|
|
|
// Misc
|
|
context.AddField(SpecularAA, lightingData.specularAA &&
|
|
context.pass.validPixelBlocks.Contains(HDBlockFields.SurfaceDescription.SpecularAAThreshold) &&
|
|
context.pass.validPixelBlocks.Contains(HDBlockFields.SurfaceDescription.SpecularAAScreenSpaceVariance));
|
|
}
|
|
|
|
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
|
|
{
|
|
base.GetActiveBlocks(ref context);
|
|
|
|
// Hair specific blocks
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.HairStrandDirection);
|
|
|
|
// Parametrization for Kajiya-Kay and Marschner models.
|
|
if (hairData.materialType == HairData.MaterialType.Approximate)
|
|
{
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.Transmittance);
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.RimTransmissionIntensity);
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.SpecularTint);
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.SpecularShift);
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.SecondarySpecularTint);
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.SecondarySmoothness);
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.SecondarySpecularShift);
|
|
}
|
|
else
|
|
{
|
|
// Color parameterization for cortex (default is base color)
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.AbsorptionCoefficient, hairData.colorParameterization == HairData.ColorParameterization.Absorption);
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.Eumelanin, hairData.colorParameterization == HairData.ColorParameterization.Melanin);
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.Pheomelanin, hairData.colorParameterization == HairData.ColorParameterization.Melanin);
|
|
|
|
// Need to explicitly remove the base color here as it is by default always included.
|
|
if (hairData.colorParameterization != HairData.ColorParameterization.BaseColor)
|
|
context.activeBlocks.Remove(BlockFields.SurfaceDescription.BaseColor);
|
|
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.RadialSmoothness);
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.CuticleAngle);
|
|
|
|
// TODO: Refraction Index
|
|
// Right now, the Marschner model implicitly assumes a human hair IOR of 1.55.
|
|
|
|
context.AddBlock(HDBlockFields.SurfaceDescription.StrandCountProbe, hairData.materialType == HairData.MaterialType.PhysicalCinematic);
|
|
}
|
|
}
|
|
|
|
protected override void CollectPassKeywords(ref PassDescriptor pass)
|
|
{
|
|
base.CollectPassKeywords(ref pass);
|
|
|
|
if (pass.lightMode == (HDShaderPassNames.s_LineRenderingOffscreenShading))
|
|
{
|
|
pass.keywords.Add(CoreKeywordDescriptors.Native16Bit);
|
|
}
|
|
}
|
|
|
|
protected override void AddInspectorPropertyBlocks(SubTargetPropertiesGUI blockList)
|
|
{
|
|
blockList.AddPropertyBlock(new HairSurfaceOptionPropertyBlock(SurfaceOptionPropertyBlock.Features.Lit, hairData));
|
|
|
|
if (hairData.materialType == HairData.MaterialType.PhysicalCinematic)
|
|
{
|
|
#if !HAS_UNITY_HAIR_PACKAGE
|
|
// Skip the advanced block, there will be a help box in the main one to tell the user that the hair package
|
|
// should be installed to use cinematic hair shading.
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
blockList.AddPropertyBlock(new HairAdvancedOptionsPropertyBlock(hairData));
|
|
}
|
|
}
|
|
}
|