initial commit

This commit is contained in:
Jo 2025-01-07 02:06:59 +01:00
parent 6715289efe
commit 788c3389af
37645 changed files with 2526849 additions and 80 deletions

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5fbe43a4058e69f4ca1ac77ea6e1bda6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,20 @@
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// (Deprecated) An add-on module for Cinemachine Virtual Camera that tweaks the orthographic size
/// of the virtual camera. It detects the presence of the Pixel Perfect Camera component and use the
/// settings from that Pixel Perfect Camera to correct the orthographic size so that pixel art
/// sprites would appear pixel perfect when the virtual camera becomes live.
/// </summary>
[AddComponentMenu("")] // Hide in menu
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
public class CinemachineUniversalPixelPerfect : MonoBehaviour
{
void OnEnable()
{
Debug.LogError("CinemachineUniversalPixelPerfect is now deprecated and doesn't function properly. Instead, use the one from Cinemachine v2.4.0 or newer.");
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9d020dac04a1b2b44a3a36eb8abe528f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -1
icon: {fileID: 2800000, guid: ec2f01df0bb1bfe459b5562a9e71c8d4, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 490481dd6f7a2a84b8c28566abbc677b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e0c762e8dad9af640925a542761eb35a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fea15e5ce57d36d489e00e9111e1c9ae
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,126 @@
fileFormatVersion: 2
guid: 5688ab254e4c0634f8d6c8e0792331ca
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: 4
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: 4
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: 4
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData: "<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<ExtraTextureSettings
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\r\n
<detailMap>false</detailMap>\r\n <hemiOctNormals>true</hemiOctNormals>\r\n
<geoRoughness>GenRoughness</geoRoughness>\r\n <geoRoughnessPow>1</geoRoughnessPow>\r\n
<dontReadSource>false</dontReadSource>\r\n</ExtraTextureSettings>"
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,447 @@
using System;
using UnityEngine.Serialization;
using UnityEngine.Scripting.APIUpdating;
using UnityEngine.U2D;
#if UNITY_EDITOR
using UnityEditor.Experimental.SceneManagement;
#endif
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Class <c>Light2D</c> is a 2D light which can be used with the 2D Renderer.
/// </summary>
///
[ExecuteAlways, DisallowMultipleComponent]
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
[AddComponentMenu("Rendering/2D/Light 2D")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@latest/index.html?subfolder=/manual/2DLightProperties.html")]
public sealed partial class Light2D : Light2DBase, ISerializationCallbackReceiver
{
/// <summary>
/// Deprecated Light types that are no supported. Please migrate to either Freeform or Point lights.
/// </summary>
public enum DeprecatedLightType
{
/// <summary>
/// N-gon shaped lights.
/// </summary>
Parametric = 0,
}
/// <summary>
/// An enumeration of the types of light
/// </summary>
public enum LightType
{
/// <summary>
/// N-gon shaped lights. Deprecated.
/// </summary>
Parametric = 0,
/// <summary>
/// The shape of the light is based on a user defined closed shape with multiple points.
/// </summary>
Freeform = 1,
/// <summary>
/// The shape of the light is based on a Sprite.
/// </summary>
Sprite = 2,
/// <summary>
/// The shape of light is circular and can also be configured into a pizza shape.
/// </summary>
Point = 3,
/// <summary>
/// Shapeless light that affects the entire screen.
/// </summary>
Global = 4
}
/// <summary>
/// The accuracy of how the normap map calculation.
/// </summary>
public enum NormalMapQuality
{
/// <summary>
/// Normal map not used.
/// </summary>
Disabled = 2,
/// <summary>
/// Faster calculation with less accuracy suited for small shapes on screen.
/// </summary>
Fast = 0,
/// <summary>
/// Accurate calculation useful for better output on bigger shapes on screen.
/// </summary>
Accurate = 1
}
/// <summary>
/// Determines how the final color is calculated when multiple lights overlap each other
/// </summary>
public enum OverlapOperation
{
/// <summary>
/// Colors are added together
/// </summary>
Additive,
/// <summary>
/// Colors are blended using standed blending (alpha, 1-alpha)
/// </summary>
AlphaBlend
}
private enum ComponentVersions
{
Version_Unserialized = 0,
Version_1 = 1
}
const ComponentVersions k_CurrentComponentVersion = ComponentVersions.Version_1;
[SerializeField] ComponentVersions m_ComponentVersion = ComponentVersions.Version_Unserialized;
#if USING_ANIMATION_MODULE
[UnityEngine.Animations.NotKeyable]
#endif
[SerializeField] LightType m_LightType = LightType.Point;
[SerializeField, FormerlySerializedAs("m_LightOperationIndex")]
int m_BlendStyleIndex = 0;
[SerializeField] float m_FalloffIntensity = 0.5f;
[ColorUsage(true)]
[SerializeField] Color m_Color = Color.white;
[SerializeField] float m_Intensity = 1;
[FormerlySerializedAs("m_LightVolumeOpacity")]
[SerializeField] float m_LightVolumeIntensity = 1.0f;
[SerializeField] bool m_LightVolumeIntensityEnabled = false;
[SerializeField] int[] m_ApplyToSortingLayers = new int[1]; // These are sorting layer IDs. If we need to update this at runtime make sure we add code to update global lights
[Reload("Textures/2D/Sparkle.png")]
[SerializeField] Sprite m_LightCookieSprite;
[FormerlySerializedAs("m_LightCookieSprite")]
[SerializeField] Sprite m_DeprecatedPointLightCookieSprite;
[SerializeField] int m_LightOrder = 0;
[SerializeField] OverlapOperation m_OverlapOperation = OverlapOperation.Additive;
[FormerlySerializedAs("m_PointLightDistance")]
[SerializeField] float m_NormalMapDistance = 3.0f;
#if USING_ANIMATION_MODULE
[UnityEngine.Animations.NotKeyable]
#endif
[FormerlySerializedAs("m_PointLightQuality")]
[SerializeField] NormalMapQuality m_NormalMapQuality = NormalMapQuality.Disabled;
[SerializeField] bool m_UseNormalMap = false; // This is now deprecated. Keep it here for backwards compatibility.
[SerializeField] bool m_ShadowIntensityEnabled = false;
[Range(0, 1)]
[SerializeField] float m_ShadowIntensity = 0.75f;
[SerializeField] bool m_ShadowVolumeIntensityEnabled = false;
[Range(0, 1)]
[SerializeField] float m_ShadowVolumeIntensity = 0.75f;
Mesh m_Mesh;
[SerializeField]
private LightUtility.LightMeshVertex[] m_Vertices = new LightUtility.LightMeshVertex[1];
[SerializeField]
private ushort[] m_Triangles = new ushort[1];
internal LightUtility.LightMeshVertex[] vertices { get { return m_Vertices; } set { m_Vertices = value; } }
internal ushort[] indices { get { return m_Triangles; } set { m_Triangles = value; } }
// Transients
int m_PreviousLightCookieSprite;
internal Vector3 m_CachedPosition;
internal int[] affectedSortingLayers => m_ApplyToSortingLayers;
private int lightCookieSpriteInstanceID => m_LightCookieSprite?.GetInstanceID() ?? 0;
[SerializeField]
Bounds m_LocalBounds;
internal BoundingSphere boundingSphere { get; private set; }
internal Mesh lightMesh
{
get
{
if (null == m_Mesh)
m_Mesh = new Mesh();
return m_Mesh;
}
}
internal bool hasCachedMesh => (vertices.Length > 1 && indices.Length > 1);
internal bool forceUpdate = false;
/// <summary>
/// The light's current type
/// </summary>
public LightType lightType
{
get => m_LightType;
set
{
if (m_LightType != value)
UpdateMesh();
m_LightType = value;
Light2DManager.ErrorIfDuplicateGlobalLight(this);
}
}
/// <summary>
/// The lights current operation index
/// </summary>
public int blendStyleIndex { get => m_BlendStyleIndex; set => m_BlendStyleIndex = value; }
/// <summary>
/// Specifies the darkness of the shadow
/// </summary>
public float shadowIntensity { get => m_ShadowIntensity; set => m_ShadowIntensity = Mathf.Clamp01(value); }
/// <summary>
/// Specifies that the shadows are enabled
/// </summary>
public bool shadowsEnabled { get => m_ShadowIntensityEnabled; set => m_ShadowIntensityEnabled = value; }
/// <summary>
/// Specifies the darkness of the shadow
/// </summary>
public float shadowVolumeIntensity { get => m_ShadowVolumeIntensity; set => m_ShadowVolumeIntensity = Mathf.Clamp01(value); }
/// <summary>
/// Specifies that the volumetric shadows are enabled
/// </summary>
public bool volumetricShadowsEnabled { get => m_ShadowVolumeIntensityEnabled; set => m_ShadowVolumeIntensityEnabled = value; }
/// <summary>
/// The lights current color
/// </summary>
public Color color { get => m_Color; set => m_Color = value; }
/// <summary>
/// The lights current intensity
/// </summary>
public float intensity { get => m_Intensity; set => m_Intensity = value; }
/// <summary>
/// The lights current intensity
/// </summary>
///
[Obsolete]
public float volumeOpacity => m_LightVolumeIntensity;
/// <summary>
/// Controls the visibility of the light's volume
/// </summary>
public float volumeIntensity => m_LightVolumeIntensity;
/// <summary>
/// Enables or disables the light's volume
/// </summary>
public bool volumeIntensityEnabled { get => m_LightVolumeIntensityEnabled; set => m_LightVolumeIntensityEnabled = value; }
/// <summary>
/// The Sprite that's used by the Sprite Light type to control the shape light
/// </summary>
public Sprite lightCookieSprite { get { return m_LightType != LightType.Point ? m_LightCookieSprite : m_DeprecatedPointLightCookieSprite; } }
/// <summary>
/// Controls the brightness and distance of the fall off (edge) of the light
/// </summary>
public float falloffIntensity => m_FalloffIntensity;
[Obsolete]
public bool alphaBlendOnOverlap { get { return m_OverlapOperation == OverlapOperation.AlphaBlend; } }
/// <summary>
/// Returns the overlap operation mode.
/// </summary>
public OverlapOperation overlapOperation => m_OverlapOperation;
/// <summary>
/// Gets or sets the light order. The lightOrder determines the order in which the lights are rendered onto the light textures.
/// </summary>
public int lightOrder { get => m_LightOrder; set => m_LightOrder = value; }
/// <summary>
/// The simulated z distance of the light from the surface used in normal map calculation.
/// </summary>
public float normalMapDistance => m_NormalMapDistance;
/// <summary>
/// Returns the calculation quality for the normal map rendering. Please refer to NormalMapQuality.
/// </summary>
public NormalMapQuality normalMapQuality => m_NormalMapQuality;
public bool renderVolumetricShadows => volumetricShadowsEnabled && shadowVolumeIntensity > 0;
internal void MarkForUpdate()
{
forceUpdate = true;
}
internal void CacheValues()
{
m_CachedPosition = transform.position;
}
internal int GetTopMostLitLayer()
{
var largestIndex = Int32.MinValue;
var largestLayer = 0;
var layers = Light2DManager.GetCachedSortingLayer();
for (var i = 0; i < m_ApplyToSortingLayers.Length; ++i)
{
for (var layer = layers.Length - 1; layer >= largestLayer; --layer)
{
if (layers[layer].id == m_ApplyToSortingLayers[i])
{
largestIndex = layers[layer].value;
largestLayer = layer;
}
}
}
return largestIndex;
}
internal Bounds UpdateSpriteMesh()
{
if (m_LightCookieSprite == null && (m_Vertices.Length != 1 || m_Triangles.Length != 1))
{
m_Vertices = new LightUtility.LightMeshVertex[1];
m_Triangles = new ushort[1];
}
return LightUtility.GenerateSpriteMesh(this, m_LightCookieSprite);
}
internal void UpdateMesh(bool forceUpdate = false)
{
var shapePathHash = LightUtility.GetShapePathHash(shapePath);
var fallOffSizeChanged = LightUtility.CheckForChange(m_ShapeLightFalloffSize, ref m_PreviousShapeLightFalloffSize);
var parametricRadiusChanged = LightUtility.CheckForChange(m_ShapeLightParametricRadius, ref m_PreviousShapeLightParametricRadius);
var parametricSidesChanged = LightUtility.CheckForChange(m_ShapeLightParametricSides, ref m_PreviousShapeLightParametricSides);
var parametricAngleOffsetChanged = LightUtility.CheckForChange(m_ShapeLightParametricAngleOffset, ref m_PreviousShapeLightParametricAngleOffset);
var spriteInstanceChanged = LightUtility.CheckForChange(lightCookieSpriteInstanceID, ref m_PreviousLightCookieSprite);
var shapePathHashChanged = LightUtility.CheckForChange(shapePathHash, ref m_PreviousShapePathHash);
var lightTypeChanged = LightUtility.CheckForChange(m_LightType, ref m_PreviousLightType);
var hashChanged = fallOffSizeChanged || parametricRadiusChanged || parametricSidesChanged ||
parametricAngleOffsetChanged || spriteInstanceChanged || shapePathHashChanged || lightTypeChanged;
// Mesh Rebuilding
if (hashChanged || forceUpdate)
{
switch (m_LightType)
{
case LightType.Freeform:
m_LocalBounds = LightUtility.GenerateShapeMesh(this, m_ShapePath, m_ShapeLightFalloffSize);
break;
case LightType.Parametric:
m_LocalBounds = LightUtility.GenerateParametricMesh(this, m_ShapeLightParametricRadius, m_ShapeLightFalloffSize, m_ShapeLightParametricAngleOffset, m_ShapeLightParametricSides);
break;
case LightType.Sprite:
m_LocalBounds = UpdateSpriteMesh();
break;
case LightType.Point:
m_LocalBounds = LightUtility.GenerateParametricMesh(this, 1.412135f, 0, 0, 4);
break;
}
}
}
internal void UpdateBoundingSphere()
{
if (isPointLight)
{
boundingSphere = new BoundingSphere(transform.position, m_PointLightOuterRadius);
return;
}
var maxBound = transform.TransformPoint(Vector3.Max(m_LocalBounds.max, m_LocalBounds.max + (Vector3)m_ShapeLightFalloffOffset));
var minBound = transform.TransformPoint(Vector3.Min(m_LocalBounds.min, m_LocalBounds.min + (Vector3)m_ShapeLightFalloffOffset));
var center = 0.5f * (maxBound + minBound);
var radius = Vector3.Magnitude(maxBound - center);
boundingSphere = new BoundingSphere(center, radius);
}
internal bool IsLitLayer(int layer)
{
if (m_ApplyToSortingLayers == null)
return false;
for (var i = 0; i < m_ApplyToSortingLayers.Length; i++)
if (m_ApplyToSortingLayers[i] == layer)
return true;
return false;
}
private void Awake()
{
if (m_LightCookieSprite != null)
{
bool updateMesh = !hasCachedMesh || (m_LightType == LightType.Sprite && m_LightCookieSprite.packed);
UpdateMesh(updateMesh);
if (hasCachedMesh)
{
lightMesh.SetVertexBufferParams(vertices.Length, LightUtility.LightMeshVertex.VertexLayout);
lightMesh.SetVertexBufferData(vertices, 0, 0, vertices.Length);
lightMesh.SetIndices(indices, MeshTopology.Triangles, 0, false);
}
}
}
void OnEnable()
{
m_PreviousLightCookieSprite = lightCookieSpriteInstanceID;
Light2DManager.RegisterLight(this);
}
private void OnDisable()
{
Light2DManager.DeregisterLight(this);
}
private void LateUpdate()
{
if (m_LightType == LightType.Global)
return;
UpdateMesh(forceUpdate);
UpdateBoundingSphere();
forceUpdate = false;
}
public void OnBeforeSerialize()
{
m_ComponentVersion = k_CurrentComponentVersion;
}
public void OnAfterDeserialize()
{
// Upgrade from no serialized version
if (m_ComponentVersion == ComponentVersions.Version_Unserialized)
{
m_ShadowVolumeIntensityEnabled = m_ShadowVolumeIntensity > 0;
m_ShadowIntensityEnabled = m_ShadowIntensity > 0;
m_LightVolumeIntensityEnabled = m_LightVolumeIntensity > 0;
m_NormalMapQuality = !m_UseNormalMap ? NormalMapQuality.Disabled : m_NormalMapQuality;
m_ComponentVersion = ComponentVersions.Version_1;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 073797afb82c5a1438f328866b10b3f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,36 @@
using System.Collections.Generic;
namespace UnityEngine.Rendering.Universal
{
public sealed partial class Light2D
{
#if UNITY_EDITOR
private const string s_IconsPath = "Packages/com.unity.render-pipelines.universal/Editor/2D/Resources/SceneViewIcons/";
private static readonly string[] s_LightIconFileNames = new[]
{
"ParametricLight.png",
"FreeformLight.png",
"SpriteLight.png",
"PointLight.png",
"GlobalLight.png"
};
private void OnDrawGizmos()
{
Gizmos.color = Color.blue;
Gizmos.DrawIcon(transform.position, s_IconsPath + s_LightIconFileNames[(int)m_LightType], true);
}
void Reset()
{
m_ShapePath = new Vector3[] { new Vector3(-0.5f, -0.5f), new Vector3(0.5f, -0.5f), new Vector3(0.5f, 0.5f), new Vector3(-0.5f, 0.5f) };
}
internal List<Vector2> GetFalloffShape()
{
return LightUtility.GetOutlinePath(m_ShapePath, m_ShapeLightFalloffSize);
}
#endif
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 14716551160f4757bf2332c27a53ec34
timeCreated: 1595907042

View file

@ -0,0 +1,127 @@
using System;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Controls how the light texture is used when rendering Sprites and other 2D renderers.
/// </summary>
[Serializable]
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
public struct Light2DBlendStyle
{
internal enum TextureChannel
{
None = 0,
R = 1,
G = 2,
B = 3,
A = 4,
OneMinusR = 5,
OneMinusG = 6,
OneMinusB = 7,
OneMinusA = 8
}
internal struct MaskChannelFilter
{
public Vector4 mask { get; private set; }
public Vector4 inverted { get; private set; }
public MaskChannelFilter(Vector4 m, Vector4 i)
{
mask = m;
inverted = i;
}
}
internal enum BlendMode
{
Additive = 0,
Multiply = 1,
Subtractive = 2
}
[Serializable]
internal struct BlendFactors
{
public float multiplicative;
public float additive;
}
/// <summary>
/// Returns the name of the blend style
/// </summary>
public string name;
[SerializeField]
internal TextureChannel maskTextureChannel;
[SerializeField]
internal BlendMode blendMode;
internal Vector2 blendFactors
{
get
{
var result = new Vector2();
switch (blendMode)
{
case BlendMode.Additive:
result.x = 0.0f;
result.y = 1.0f;
break;
case BlendMode.Multiply:
result.x = 1.0f;
result.y = 0.0f;
break;
case BlendMode.Subtractive:
result.x = 0.0f;
result.y = -1.0f;
break;
default:
result.x = 1.0f;
result.y = 0.0f;
break;
}
return result;
}
}
internal MaskChannelFilter maskTextureChannelFilter
{
get
{
switch (maskTextureChannel)
{
case TextureChannel.R:
return new MaskChannelFilter(new Vector4(1, 0, 0, 0), new Vector4(0, 0, 0, 0));
case TextureChannel.OneMinusR:
return new MaskChannelFilter(new Vector4(1, 0, 0, 0), new Vector4(1, 0, 0, 0));
case TextureChannel.G:
return new MaskChannelFilter(new Vector4(0, 1, 0, 0), new Vector4(0, 0, 0, 0));
case TextureChannel.OneMinusG:
return new MaskChannelFilter(new Vector4(0, 1, 0, 0), new Vector4(0, 1, 0, 0));
case TextureChannel.B:
return new MaskChannelFilter(new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 0));
case TextureChannel.OneMinusB:
return new MaskChannelFilter(new Vector4(0, 0, 1, 0), new Vector4(0, 0, 1, 0));
case TextureChannel.A:
return new MaskChannelFilter(new Vector4(0, 0, 0, 1), new Vector4(0, 0, 0, 0));
case TextureChannel.OneMinusA:
return new MaskChannelFilter(new Vector4(0, 0, 0, 1), new Vector4(0, 0, 0, 1));
case TextureChannel.None:
default:
return new MaskChannelFilter(Vector4.zero, Vector4.zero);
}
}
}
// Transient data
internal bool isDirty { get; set; }
internal bool hasRenderTarget { get; set; }
internal RenderTargetHandle renderTargetHandle;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f4caf3da21d83644ea1c04986c6cea14
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,110 @@
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine.Profiling;
namespace UnityEngine.Rendering.Universal
{
internal struct LightStats
{
public int totalLights;
public int totalNormalMapUsage;
public int totalVolumetricUsage;
public uint blendStylesUsed;
public uint blendStylesWithLights;
}
internal interface ILight2DCullResult
{
List<Light2D> visibleLights { get; }
LightStats GetLightStatsByLayer(int layer);
bool IsSceneLit();
}
internal class Light2DCullResult : ILight2DCullResult
{
private List<Light2D> m_VisibleLights = new List<Light2D>();
public List<Light2D> visibleLights => m_VisibleLights;
public bool IsSceneLit()
{
if (visibleLights.Count > 0)
return true;
foreach (var light in Light2DManager.lights)
{
if (light.lightType == Light2D.LightType.Global)
return true;
}
return false;
}
public LightStats GetLightStatsByLayer(int layer)
{
var returnStats = new LightStats();
foreach (var light in visibleLights)
{
if (!light.IsLitLayer(layer))
continue;
returnStats.totalLights++;
if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled)
returnStats.totalNormalMapUsage++;
if (light.volumeIntensity > 0)
returnStats.totalVolumetricUsage++;
returnStats.blendStylesUsed |= (uint)(1 << light.blendStyleIndex);
if (light.lightType != Light2D.LightType.Global)
returnStats.blendStylesWithLights |= (uint)(1 << light.blendStyleIndex);
}
return returnStats;
}
public void SetupCulling(ref ScriptableCullingParameters cullingParameters, Camera camera)
{
Profiler.BeginSample("Cull 2D Lights");
m_VisibleLights.Clear();
foreach (var light in Light2DManager.lights)
{
if ((camera.cullingMask & (1 << light.gameObject.layer)) == 0)
continue;
#if UNITY_EDITOR
if (!UnityEditor.SceneManagement.StageUtility.IsGameObjectRenderedByCamera(light.gameObject, camera))
continue;
#endif
if (light.lightType == Light2D.LightType.Global)
{
m_VisibleLights.Add(light);
continue;
}
Profiler.BeginSample("Test Planes");
var position = light.boundingSphere.position;
var culled = false;
for (var i = 0; i < cullingParameters.cullingPlaneCount; ++i)
{
var plane = cullingParameters.GetCullingPlane(i);
// most of the time is spent getting world position
var distance = math.dot(position, plane.normal) + plane.distance;
if (distance < -light.boundingSphere.radius)
{
culled = true;
break;
}
}
Profiler.EndSample();
if (culled)
continue;
m_VisibleLights.Add(light);
}
// must be sorted here because light order could change
m_VisibleLights.Sort((l1, l2) => l1.lightOrder - l2.lightOrder);
Profiler.EndSample();
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 704a37a0ce184459805c0b7719a25a60
timeCreated: 1596067202

View file

@ -0,0 +1,117 @@
using System.Collections.Generic;
namespace UnityEngine.Rendering.Universal
{
internal static class Light2DManager
{
private static SortingLayer[] s_SortingLayers;
public static List<Light2D> lights { get; } = new List<Light2D>();
// Called during OnEnable
public static void RegisterLight(Light2D light)
{
Debug.Assert(!lights.Contains(light));
lights.Add(light);
ErrorIfDuplicateGlobalLight(light);
}
// Called during OnEnable
public static void DeregisterLight(Light2D light)
{
Debug.Assert(lights.Contains(light));
lights.Remove(light);
}
public static void ErrorIfDuplicateGlobalLight(Light2D light)
{
if (light.lightType != Light2D.LightType.Global)
return;
foreach (var sortingLayer in light.affectedSortingLayers)
{
// should this really trigger at runtime?
if (ContainsDuplicateGlobalLight(sortingLayer, light.blendStyleIndex))
Debug.LogError("More than one global light on layer " + SortingLayer.IDToName(sortingLayer) + " for light blend style index " + light.blendStyleIndex);
}
}
public static bool GetGlobalColor(int sortingLayerIndex, int blendStyleIndex, out Color color)
{
var foundGlobalColor = false;
color = Color.black;
// This should be rewritten to search only global lights
foreach (var light in lights)
{
if (light.lightType != Light2D.LightType.Global ||
light.blendStyleIndex != blendStyleIndex ||
!light.IsLitLayer(sortingLayerIndex))
continue;
var inCurrentPrefabStage = true;
#if UNITY_EDITOR
// If we found the first global light in our prefab stage
inCurrentPrefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage()?.IsPartOfPrefabContents(light.gameObject) ?? true;
#endif
if (inCurrentPrefabStage)
{
color = light.color * light.intensity;
return true;
}
else
{
if (!foundGlobalColor)
{
color = light.color * light.intensity;
foundGlobalColor = true;
}
}
}
return foundGlobalColor;
}
private static bool ContainsDuplicateGlobalLight(int sortingLayerIndex, int blendStyleIndex)
{
var globalLightCount = 0;
// This should be rewritten to search only global lights
foreach (var light in lights)
{
if (light.lightType == Light2D.LightType.Global &&
light.blendStyleIndex == blendStyleIndex &&
light.IsLitLayer(sortingLayerIndex))
{
#if UNITY_EDITOR
// If we found the first global light in our prefab stage
if (UnityEditor.SceneManagement.PrefabStageUtility.GetPrefabStage(light.gameObject) == UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage())
#endif
{
if (globalLightCount > 0)
return true;
globalLightCount++;
}
}
}
return false;
}
public static SortingLayer[] GetCachedSortingLayer()
{
if (s_SortingLayers is null)
{
s_SortingLayers = SortingLayer.layers;
}
#if UNITY_EDITOR
// we should fix. Make a non allocating version of this
if (!Application.isPlaying)
s_SortingLayers = SortingLayer.layers;
#endif
return s_SortingLayers;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d8151411c155429aa167611d958fbb8c
timeCreated: 1595907591

View file

@ -0,0 +1,61 @@
using System;
namespace UnityEngine.Rendering.Universal
{
public sealed partial class Light2D
{
[SerializeField] float m_PointLightInnerAngle = 360.0f;
[SerializeField] float m_PointLightOuterAngle = 360.0f;
[SerializeField] float m_PointLightInnerRadius = 0.0f;
[SerializeField] float m_PointLightOuterRadius = 1.0f;
/// <summary>
/// The inner angle of the point light shape. The bigger the angle, the wider the gap.
/// The gap between the innner and outer angle will determine the size of the light's penumbra.
/// </summary>
public float pointLightInnerAngle
{
get => m_PointLightInnerAngle;
set => m_PointLightInnerAngle = value;
}
/// <summary>
/// The angle that determins the shape of the inner light area.
/// The gap between the innner and outer angle will determine the size of the light's penumbra.
/// </summary>
public float pointLightOuterAngle
{
get => m_PointLightOuterAngle;
set => m_PointLightOuterAngle = value;
}
/// <summary>
/// The radius of the inner light area that has full brightness.
/// The gap between the inner and outer radius will determine the size of the light's penumbra.
/// </summary>
public float pointLightInnerRadius
{
get => m_PointLightInnerRadius;
set => m_PointLightInnerRadius = value;
}
/// <summary>
/// The outer radius that determines the size of the light.
/// The gap between the inner and outer radius will determine the size of the light's penumbra.
/// </summary>
public float pointLightOuterRadius
{
get => m_PointLightOuterRadius;
set => m_PointLightOuterRadius = value;
}
[Obsolete("pointLightDistance has been changed to normalMapDistance", true)]
public float pointLightDistance => m_NormalMapDistance;
[Obsolete("pointLightQuality has been changed to normalMapQuality", true)]
public NormalMapQuality pointLightQuality => m_NormalMapQuality;
internal bool isPointLight => m_LightType == LightType.Point;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1202285d83908604784202e4a57aa93c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,57 @@
namespace UnityEngine.Rendering.Universal
{
public sealed partial class Light2D
{
[SerializeField] int m_ShapeLightParametricSides = 5;
[SerializeField] float m_ShapeLightParametricAngleOffset = 0.0f;
[SerializeField] float m_ShapeLightParametricRadius = 1.0f;
[SerializeField] float m_ShapeLightFalloffSize = 0.50f;
[SerializeField] Vector2 m_ShapeLightFalloffOffset = Vector2.zero;
[SerializeField] Vector3[] m_ShapePath = null;
float m_PreviousShapeLightFalloffSize = -1;
int m_PreviousShapeLightParametricSides = -1;
float m_PreviousShapeLightParametricAngleOffset = -1;
float m_PreviousShapeLightParametricRadius = -1;
int m_PreviousShapePathHash = -1;
LightType m_PreviousLightType = LightType.Parametric;
/// <summary>
/// The number of sides in the parametric shape.
/// </summary>
public int shapeLightParametricSides => m_ShapeLightParametricSides;
/// <summary>
/// The offset of the shape from the light's origin.
/// </summary>
public float shapeLightParametricAngleOffset => m_ShapeLightParametricAngleOffset;
/// <summary>
/// The size of the shape.
/// </summary>
public float shapeLightParametricRadius
{
get { return m_ShapeLightParametricRadius; }
internal set { m_ShapeLightParametricRadius = value; }
}
/// <summary>
/// The size of the fall-off area. Bigger value corresponds to bigger fall off size.
/// </summary>
public float shapeLightFalloffSize => m_ShapeLightFalloffSize;
/// <summary>
/// Returns the path that represents the shape light. Values are in object space.
/// </summary>
public Vector3[] shapePath
{
get { return m_ShapePath; }
internal set { m_ShapePath = value; }
}
internal void SetShapePath(Vector3[] path)
{
m_ShapePath = path;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 074e9a8a8d8919e469b8dd79c7dc69a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,522 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine.Rendering.Universal.LibTessDotNet;
using UnityEngine.U2D;
namespace UnityEngine.Rendering.Universal
{
internal static class LightUtility
{
public static bool CheckForChange(Light2D.LightType a, ref Light2D.LightType b)
{
var changed = a != b;
b = a;
return changed;
}
public static bool CheckForChange(int a, ref int b)
{
var changed = a != b;
b = a;
return changed;
}
public static bool CheckForChange(float a, ref float b)
{
var changed = a != b;
b = a;
return changed;
}
public static bool CheckForChange(bool a, ref bool b)
{
var changed = a != b;
b = a;
return changed;
}
private enum PivotType
{
PivotBase,
PivotCurve,
PivotIntersect,
PivotSkip,
PivotClip
};
[Serializable]
internal struct LightMeshVertex
{
public Vector3 position;
public Color color;
public Vector2 uv;
public static readonly VertexAttributeDescriptor[] VertexLayout = new[]
{
new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 3),
new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.Float32, 4),
new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2),
};
}
static void Tessellate(Tess tess, ElementType boundaryType, NativeArray<ushort> indices,
NativeArray<LightMeshVertex> vertices, Color c, ref int VCount, ref int ICount)
{
tess.Tessellate(WindingRule.NonZero, boundaryType, 3);
var prevCount = VCount;
var tessIndices = tess.Elements.Select(i => i);
var tessVertices = tess.Vertices.Select(v =>
new LightMeshVertex() { position = new float3(v.Position.X, v.Position.Y, 0), color = c });
foreach (var v in tessVertices)
vertices[VCount++] = v;
foreach (var i in tessIndices)
indices[ICount++] = (ushort)(i + prevCount);
}
static bool TestPivot(List<IntPoint> path, int activePoint, long lastPoint)
{
for (int i = activePoint; i < path.Count; ++i)
{
if (path[i].N > lastPoint)
return true;
}
return (path[activePoint].N == -1);
}
// Degenerate Pivots at the End Points.
static List<IntPoint> DegeneratePivots(List<IntPoint> path, List<IntPoint> inPath)
{
List<IntPoint> degenerate = new List<IntPoint>();
var minN = path[0].N;
var maxN = path[0].N;
for (int i = 1; i < path.Count; ++i)
{
if (path[i].N != -1)
{
minN = Math.Min(minN, path[i].N);
maxN = Math.Max(maxN, path[i].N);
}
}
for (long i = 0; i < minN; ++i)
{
IntPoint ins = path[(int)minN];
ins.N = i;
degenerate.Add(ins);
}
degenerate.AddRange(path.GetRange(0, path.Count));
for (long i = maxN + 1; i < inPath.Count; ++i)
{
IntPoint ins = inPath[(int)i];
ins.N = i;
degenerate.Add(ins);
}
return degenerate;
}
// Ensure that we get a valid path from 0.
static List<IntPoint> SortPivots(List<IntPoint> outPath, List<IntPoint> inPath)
{
List<IntPoint> sorted = new List<IntPoint>();
var min = outPath[0].N;
var max = outPath[0].N;
var minIndex = 0;
bool newMin = true;
for (int i = 1; i < outPath.Count; ++i)
{
if (max > outPath[i].N && newMin && outPath[i].N != -1)
{
min = max = outPath[i].N;
minIndex = i;
newMin = false;
}
else if (outPath[i].N >= max)
{
max = outPath[i].N;
newMin = true;
}
}
sorted.AddRange(outPath.GetRange(minIndex, (outPath.Count - minIndex)));
sorted.AddRange(outPath.GetRange(0, minIndex));
return sorted;
}
// Ensure that all points eliminated due to overlaps and intersections are accounted for Tessellation.
static List<IntPoint> FixPivots(List<IntPoint> outPath, List<IntPoint> inPath)
{
var path = SortPivots(outPath, inPath);
long pivotPoint = path[0].N;
// Connect Points for Overlaps.
for (int i = 1; i < path.Count; ++i)
{
var j = (i == path.Count - 1) ? 0 : (i + 1);
var prev = path[i - 1];
var curr = path[i];
var next = path[j];
if (prev.N > curr.N)
{
var incr = TestPivot(path, i, pivotPoint);
if (incr)
{
if (prev.N == next.N)
curr.N = prev.N;
else
curr.N = (pivotPoint + 1) < inPath.Count ? (pivotPoint + 1) : 0;
curr.D = 3;
path[i] = curr;
}
}
pivotPoint = path[i].N;
}
// Insert Skipped Points.
for (int i = 1; i < path.Count - 1;)
{
var prev = path[i - 1];
var curr = path[i];
var next = path[i + 1];
if (curr.N - prev.N > 1)
{
if (curr.N == next.N)
{
IntPoint ins = curr;
ins.N = (ins.N - 1);
path[i] = ins;
}
else
{
IntPoint ins = curr;
ins.N = (ins.N - 1);
path.Insert(i, ins);
}
}
else
{
i++;
}
}
path = DegeneratePivots(path, inPath);
return path;
}
// Rough shape only used in Inspector for quick preview.
internal static List<Vector2> GetOutlinePath(Vector3[] shapePath, float offsetDistance)
{
const float kClipperScale = 10000.0f;
List<IntPoint> path = new List<IntPoint>();
List<Vector2> output = new List<Vector2>();
for (var i = 0; i < shapePath.Length; ++i)
{
var newPoint = new Vector2(shapePath[i].x, shapePath[i].y) * kClipperScale;
path.Add(new IntPoint((System.Int64)(newPoint.x), (System.Int64)(newPoint.y)));
}
List<List<IntPoint>> solution = new List<List<IntPoint>>();
ClipperOffset clipOffset = new ClipperOffset(2048.0f);
clipOffset.AddPath(path, JoinType.jtRound, EndType.etClosedPolygon);
clipOffset.Execute(ref solution, kClipperScale * offsetDistance, path.Count);
if (solution.Count > 0)
{
for (int i = 0; i < solution[0].Count; ++i)
output.Add(new Vector2(solution[0][i].X / kClipperScale, solution[0][i].Y / kClipperScale));
}
return output;
}
static void TransferToMesh(NativeArray<LightMeshVertex> vertices, int vertexCount, NativeArray<ushort> indices,
int indexCount, Light2D light)
{
var mesh = light.lightMesh;
mesh.SetVertexBufferParams(vertexCount, LightMeshVertex.VertexLayout);
mesh.SetVertexBufferData(vertices, 0, 0, vertexCount);
mesh.SetIndices(indices, 0, indexCount, MeshTopology.Triangles, 0, true);
light.vertices = new LightMeshVertex[vertexCount];
NativeArray<LightMeshVertex>.Copy(vertices, light.vertices, vertexCount);
light.indices = new ushort[indexCount];
NativeArray<ushort>.Copy(indices, light.indices, indexCount);
}
public static Bounds GenerateShapeMesh(Light2D light, Vector3[] shapePath, float falloffDistance)
{
var ix = 0;
var vcount = 0;
var icount = 0;
const float kClipperScale = 10000.0f;
var mesh = light.lightMesh;
// todo Revisit this while we do Batching.
var meshInteriorColor = new Color(0.0f, 0, 0, 1.0f);
var meshExteriorColor = new Color(0.0f, 0, 0, 0.0f);
var vertices = new NativeArray<LightMeshVertex>(shapePath.Length * 256, Allocator.Temp);
var indices = new NativeArray<ushort>(shapePath.Length * 256, Allocator.Temp);
// Create shape geometry
var inputPointCount = shapePath.Length;
var inner = new ContourVertex[inputPointCount + 1];
for (var i = 0; i < inputPointCount; ++i)
inner[ix++] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y, Z = 0 } };
inner[ix++] = inner[0];
var tess = new Tess();
tess.AddContour(inner, ContourOrientation.CounterClockwise);
Tessellate(tess, ElementType.Polygons, indices, vertices, meshInteriorColor, ref vcount, ref icount);
// Create falloff geometry
List<IntPoint> path = new List<IntPoint>();
for (var i = 0; i < inputPointCount; ++i)
{
var newPoint = new Vector2(inner[i].Position.X, inner[i].Position.Y) * kClipperScale;
var addPoint = new IntPoint((System.Int64)(newPoint.x), (System.Int64)(newPoint.y));
addPoint.N = i; addPoint.D = -1;
path.Add(addPoint);
}
var lastPointIndex = inputPointCount - 1;
// Generate Bevels.
List<List<IntPoint>> solution = new List<List<IntPoint>>();
ClipperOffset clipOffset = new ClipperOffset(24.0f);
clipOffset.AddPath(path, JoinType.jtRound, EndType.etClosedPolygon);
clipOffset.Execute(ref solution, kClipperScale * falloffDistance, path.Count);
if (solution.Count > 0)
{
// Fix path for Pivots.
var outPath = solution[0];
var minPath = (long)inputPointCount;
for (int i = 0; i < outPath.Count; ++i)
minPath = (outPath[i].N != -1) ? Math.Min(minPath, outPath[i].N) : minPath;
var containsStart = minPath == 0;
outPath = FixPivots(outPath, path);
// Tessellate.
var bIndices = new NativeArray<ushort>(icount + (outPath.Count * 6) + 6, Allocator.Temp);
for (int i = 0; i < icount; ++i)
bIndices[i] = indices[i];
var bVertices = new NativeArray<LightMeshVertex>(vcount + outPath.Count + inputPointCount, Allocator.Temp);
for (int i = 0; i < vcount; ++i)
bVertices[i] = vertices[i];
var innerIndices = new ushort[inputPointCount];
// Inner Vertices. (These may or may not be part of the created path. Beware!!)
for (int i = 0; i < inputPointCount; ++i)
{
bVertices[vcount++] = new LightMeshVertex()
{
position = new float3(inner[i].Position.X, inner[i].Position.Y, 0),
color = meshInteriorColor
};
innerIndices[i] = (ushort)(vcount - 1);
}
var saveIndex = (ushort)vcount;
var pathStart = saveIndex;
var prevIndex = outPath[0].N == -1 ? 0 : outPath[0].N;
for (int i = 0; i < outPath.Count; ++i)
{
var curr = outPath[i];
var currPoint = new float2(curr.X / kClipperScale, curr.Y / kClipperScale);
var currIndex = curr.N == -1 ? 0 : curr.N;
bVertices[vcount++] = new LightMeshVertex()
{
position = new float3(currPoint.x, currPoint.y, 0),
color = meshExteriorColor
};
if (prevIndex != currIndex)
{
bIndices[icount++] = innerIndices[prevIndex];
bIndices[icount++] = innerIndices[currIndex];
bIndices[icount++] = (ushort)(vcount - 1);
}
bIndices[icount++] = innerIndices[prevIndex];
bIndices[icount++] = saveIndex;
bIndices[icount++] = saveIndex = (ushort)(vcount - 1);
prevIndex = currIndex;
}
// Close the Loop.
{
bIndices[icount++] = pathStart;
bIndices[icount++] = innerIndices[minPath];
bIndices[icount++] = containsStart ? innerIndices[lastPointIndex] : saveIndex;
bIndices[icount++] = containsStart ? pathStart : saveIndex;
bIndices[icount++] = containsStart ? saveIndex : innerIndices[minPath];
bIndices[icount++] = containsStart ? innerIndices[lastPointIndex] : innerIndices[minPath - 1];
}
TransferToMesh(bVertices, vcount, bIndices, icount, light);
}
else
{
TransferToMesh(vertices, vcount, indices, icount, light);
}
return mesh.GetSubMesh(0).bounds;
}
public static Bounds GenerateParametricMesh(Light2D light, float radius, float falloffDistance, float angle, int sides)
{
var angleOffset = Mathf.PI / 2.0f + Mathf.Deg2Rad * angle;
if (sides < 3)
{
radius = 0.70710678118654752440084436210485f * radius;
sides = 4;
}
if (sides == 4)
{
angleOffset = Mathf.PI / 4.0f + Mathf.Deg2Rad * angle;
}
var vertexCount = 1 + 2 * sides;
var indexCount = 3 * 3 * sides;
var vertices = new NativeArray<LightMeshVertex>(vertexCount, Allocator.Temp);
var triangles = new NativeArray<ushort>(indexCount, Allocator.Temp);
var centerIndex = (ushort)(2 * sides);
var mesh = light.lightMesh;
// Only Alpha value in Color channel is ever used. May remove it or keep it for batching params in the future.
var color = new Color(0, 0, 0, 1);
vertices[centerIndex] = new LightMeshVertex
{
position = float3.zero,
color = color
};
var radiansPerSide = 2 * Mathf.PI / sides;
var min = new float3(float.MaxValue, float.MaxValue, 0);
var max = new float3(float.MinValue, float.MinValue, 0);
for (var i = 0; i < sides; i++)
{
var endAngle = (i + 1) * radiansPerSide;
var extrudeDir = new float3(math.cos(endAngle + angleOffset), math.sin(endAngle + angleOffset), 0);
var endPoint = radius * extrudeDir;
var vertexIndex = (2 * i + 2) % (2 * sides);
vertices[vertexIndex] = new LightMeshVertex
{
position = endPoint,
color = new Color(extrudeDir.x, extrudeDir.y, 0, 0)
};
vertices[vertexIndex + 1] = new LightMeshVertex
{
position = endPoint,
color = color
};
// Triangle 1 (Tip)
var triangleIndex = 9 * i;
triangles[triangleIndex] = (ushort)(vertexIndex + 1);
triangles[triangleIndex + 1] = (ushort)(2 * i + 1);
triangles[triangleIndex + 2] = centerIndex;
// Triangle 2 (Upper Top Left)
triangles[triangleIndex + 3] = (ushort)(vertexIndex);
triangles[triangleIndex + 4] = (ushort)(2 * i);
triangles[triangleIndex + 5] = (ushort)(2 * i + 1);
// Triangle 2 (Bottom Top Left)
triangles[triangleIndex + 6] = (ushort)(vertexIndex + 1);
triangles[triangleIndex + 7] = (ushort)(vertexIndex);
triangles[triangleIndex + 8] = (ushort)(2 * i + 1);
min = math.min(min, endPoint + extrudeDir * falloffDistance);
max = math.max(max, endPoint + extrudeDir * falloffDistance);
}
mesh.SetVertexBufferParams(vertexCount, LightMeshVertex.VertexLayout);
mesh.SetVertexBufferData(vertices, 0, 0, vertexCount);
mesh.SetIndices(triangles, MeshTopology.Triangles, 0, false);
light.vertices = new LightMeshVertex[vertexCount];
NativeArray<LightMeshVertex>.Copy(vertices, light.vertices, vertexCount);
light.indices = new ushort[indexCount];
NativeArray<ushort>.Copy(triangles, light.indices, indexCount);
return new Bounds
{
min = min,
max = max
};
}
public static Bounds GenerateSpriteMesh(Light2D light, Sprite sprite)
{
var mesh = light.lightMesh;
if (sprite == null)
{
mesh.Clear();
return new Bounds(Vector3.zero, Vector3.zero);
}
// this needs to be called before getting UV at the line below.
// Venky fixed it, enroute to trunk
var uvs = sprite.uv;
var srcVertices = sprite.GetVertexAttribute<Vector3>(VertexAttribute.Position);
var srcUVs = sprite.GetVertexAttribute<Vector2>(VertexAttribute.TexCoord0);
var srcIndices = sprite.GetIndices();
var center = 0.5f * (sprite.bounds.min + sprite.bounds.max);
var vertices = new NativeArray<LightMeshVertex>(srcIndices.Length, Allocator.Temp);
var color = new Color(0, 0, 0, 1);
for (var i = 0; i < srcVertices.Length; i++)
{
vertices[i] = new LightMeshVertex
{
position = new Vector3(srcVertices[i].x, srcVertices[i].y, 0),
color = color,
uv = srcUVs[i]
};
}
mesh.SetVertexBufferParams(vertices.Length, LightMeshVertex.VertexLayout);
mesh.SetVertexBufferData(vertices, 0, 0, vertices.Length);
mesh.SetIndices(srcIndices, MeshTopology.Triangles, 0, true);
light.vertices = new LightMeshVertex[vertices.Length];
NativeArray<LightMeshVertex>.Copy(vertices, light.vertices, vertices.Length);
light.indices = new ushort[srcIndices.Length];
NativeArray<ushort>.Copy(srcIndices, light.indices, srcIndices.Length);
return mesh.GetSubMesh(0).bounds;
}
public static int GetShapePathHash(Vector3[] path)
{
unchecked
{
int hashCode = (int)2166136261;
if (path != null)
{
foreach (var point in path)
hashCode = hashCode * 16777619 ^ point.GetHashCode();
}
else
{
hashCode = 0;
}
return hashCode;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fd90885134624894ba845bbc692698a0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f74b40ff9aaa99a49a36a3c646ca5917
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,7 @@
namespace UnityEngine.Rendering.Universal
{
internal interface IRenderPass2D
{
Renderer2DData rendererData { get; }
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ed92912a74ef47789c37ffbe7c5672a8
timeCreated: 1595414585

View file

@ -0,0 +1,46 @@
namespace UnityEngine.Rendering.Universal
{
// Only to be used when Pixel Perfect Camera is present and it has Crop Frame X or Y enabled.
// This pass simply clears BuiltinRenderTextureType.CameraTarget to black, so that the letterbox or pillarbox is black instead of garbage.
// In the future this can be extended to draw a custom background image instead of just clearing.
internal class PixelPerfectBackgroundPass : ScriptableRenderPass
{
private static readonly ProfilingSampler m_ProfilingScope = new ProfilingSampler("Pixel Perfect Background Pass");
private bool m_SavedIsOrthographic;
private float m_SavedOrthographicSize;
public PixelPerfectBackgroundPass(RenderPassEvent evt)
{
renderPassEvent = evt;
}
public void Setup(bool savedIsOrthographic, float savedOrthographicSize)
{
m_SavedIsOrthographic = savedIsOrthographic;
m_SavedOrthographicSize = savedOrthographicSize;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingScope))
{
CoreUtils.SetRenderTarget(
cmd,
BuiltinRenderTextureType.CameraTarget,
RenderBufferLoadAction.DontCare,
RenderBufferStoreAction.Store,
ClearFlag.Color,
Color.black);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
renderingData.cameraData.camera.orthographic = m_SavedIsOrthographic;
renderingData.cameraData.camera.orthographicSize = m_SavedOrthographicSize;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d4ffb7da24670bf4687d34e0a1e19eaa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,446 @@
using System.Collections.Generic;
using UnityEngine.Profiling;
namespace UnityEngine.Rendering.Universal
{
internal class Render2DLightingPass : ScriptableRenderPass, IRenderPass2D
{
private static readonly int k_HDREmulationScaleID = Shader.PropertyToID("_HDREmulationScale");
private static readonly int k_InverseHDREmulationScaleID = Shader.PropertyToID("_InverseHDREmulationScale");
private static readonly int k_UseSceneLightingID = Shader.PropertyToID("_UseSceneLighting");
private static readonly int k_RendererColorID = Shader.PropertyToID("_RendererColor");
private static readonly int k_CameraSortingLayerTextureID = Shader.PropertyToID("_CameraSortingLayerTexture");
private static readonly int[] k_ShapeLightTextureIDs =
{
Shader.PropertyToID("_ShapeLightTexture0"),
Shader.PropertyToID("_ShapeLightTexture1"),
Shader.PropertyToID("_ShapeLightTexture2"),
Shader.PropertyToID("_ShapeLightTexture3")
};
private static readonly ShaderTagId k_CombinedRenderingPassName = new ShaderTagId("Universal2D");
private static readonly ShaderTagId k_NormalsRenderingPassName = new ShaderTagId("NormalsRendering");
private static readonly ShaderTagId k_LegacyPassName = new ShaderTagId("SRPDefaultUnlit");
private static readonly List<ShaderTagId> k_ShaderTags = new List<ShaderTagId>() { k_LegacyPassName, k_CombinedRenderingPassName };
private static readonly ProfilingSampler m_ProfilingDrawLights = new ProfilingSampler("Draw 2D Lights");
private static readonly ProfilingSampler m_ProfilingDrawLightTextures = new ProfilingSampler("Draw 2D Lights Textures");
private static readonly ProfilingSampler m_ProfilingDrawRenderers = new ProfilingSampler("Draw All Renderers");
private static readonly ProfilingSampler m_ProfilingDrawLayerBatch = new ProfilingSampler("Draw Layer Batch");
private static readonly ProfilingSampler m_ProfilingSamplerUnlit = new ProfilingSampler("Render Unlit");
Material m_BlitMaterial;
Material m_SamplingMaterial;
private readonly Renderer2DData m_Renderer2DData;
private bool m_NeedsDepth;
private short m_CameraSortingLayerBoundsIndex;
public Render2DLightingPass(Renderer2DData rendererData, Material blitMaterial, Material samplingMaterial)
{
m_Renderer2DData = rendererData;
m_BlitMaterial = blitMaterial;
m_SamplingMaterial = samplingMaterial;
m_CameraSortingLayerBoundsIndex = GetCameraSortingLayerBoundsIndex();
}
internal void Setup(bool useDepth)
{
m_NeedsDepth = useDepth;
}
private void GetTransparencySortingMode(Camera camera, ref SortingSettings sortingSettings)
{
var mode = m_Renderer2DData.transparencySortMode;
if (mode == TransparencySortMode.Default)
{
mode = camera.orthographic ? TransparencySortMode.Orthographic : TransparencySortMode.Perspective;
}
switch (mode)
{
case TransparencySortMode.Perspective:
sortingSettings.distanceMetric = DistanceMetric.Perspective;
break;
case TransparencySortMode.Orthographic:
sortingSettings.distanceMetric = DistanceMetric.Orthographic;
break;
default:
sortingSettings.distanceMetric = DistanceMetric.CustomAxis;
sortingSettings.customAxis = m_Renderer2DData.transparencySortAxis;
break;
}
}
private void CopyCameraSortingLayerRenderTexture(ScriptableRenderContext context, RenderingData renderingData, RenderBufferStoreAction mainTargetStoreAction)
{
var cmd = CommandBufferPool.Get();
cmd.Clear();
this.CreateCameraSortingLayerRenderTexture(renderingData, cmd, m_Renderer2DData.cameraSortingLayerDownsamplingMethod);
Material copyMaterial = m_Renderer2DData.cameraSortingLayerDownsamplingMethod == Downsampling._4xBox ? m_SamplingMaterial : m_BlitMaterial;
RenderingUtils.Blit(cmd, colorAttachment, m_Renderer2DData.cameraSortingLayerRenderTarget.id, copyMaterial, 0, false, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
cmd.SetRenderTarget(colorAttachment, RenderBufferLoadAction.Load, mainTargetStoreAction,
depthAttachment, RenderBufferLoadAction.Load, mainTargetStoreAction);
cmd.SetGlobalTexture(k_CameraSortingLayerTextureID, m_Renderer2DData.cameraSortingLayerRenderTarget.id);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
private short GetCameraSortingLayerBoundsIndex()
{
SortingLayer[] sortingLayers = Light2DManager.GetCachedSortingLayer();
for (short i = 0; i < sortingLayers.Length; i++)
{
if (sortingLayers[i].id == m_Renderer2DData.cameraSortingLayerTextureBound)
return (short)sortingLayers[i].value;
}
return short.MinValue;
}
private void DetermineWhenToResolve(int startIndex, int batchesDrawn, int batchCount, LayerBatch[] layerBatches,
out int resolveDuringBatch, out bool resolveIsAfterCopy)
{
bool anyLightWithVolumetricShadows = false;
var lights = m_Renderer2DData.lightCullResult.visibleLights;
for (int i = 0; i < lights.Count; i++)
{
anyLightWithVolumetricShadows = lights[i].renderVolumetricShadows;
if (anyLightWithVolumetricShadows)
break;
}
var lastVolumetricLightBatch = -1;
if (anyLightWithVolumetricShadows)
{
for (int i = startIndex + batchesDrawn - 1; i >= startIndex; i--)
{
if (layerBatches[i].lightStats.totalVolumetricUsage > 0)
{
lastVolumetricLightBatch = i;
break;
}
}
}
if (m_Renderer2DData.useCameraSortingLayerTexture)
{
var cameraSortingLayerBoundsIndex = GetCameraSortingLayerBoundsIndex();
var copyBatch = -1;
for (int i = startIndex; i < startIndex + batchesDrawn; i++)
{
var layerBatch = layerBatches[i];
if (cameraSortingLayerBoundsIndex >= layerBatch.layerRange.lowerBound && cameraSortingLayerBoundsIndex <= layerBatch.layerRange.upperBound)
{
copyBatch = i;
break;
}
}
resolveIsAfterCopy = copyBatch > lastVolumetricLightBatch;
resolveDuringBatch = resolveIsAfterCopy ? copyBatch : lastVolumetricLightBatch;
}
else
{
resolveDuringBatch = lastVolumetricLightBatch;
resolveIsAfterCopy = false;
}
}
private void Render(ScriptableRenderContext context, CommandBuffer cmd, ref RenderingData renderingData, ref FilteringSettings filterSettings, DrawingSettings drawSettings)
{
var activeDebugHandler = GetActiveDebugHandler(renderingData);
if (activeDebugHandler != null)
{
RenderStateBlock renderStateBlock = new RenderStateBlock();
activeDebugHandler.DrawWithDebugRenderState(context, cmd, ref renderingData, ref drawSettings, ref filterSettings, ref renderStateBlock,
(ScriptableRenderContext ctx, ref RenderingData data, ref DrawingSettings ds, ref FilteringSettings fs, ref RenderStateBlock rsb) =>
{
ctx.DrawRenderers(data.cullResults, ref ds, ref fs, ref rsb);
});
}
else
{
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings);
}
}
private int DrawLayerBatches(
LayerBatch[] layerBatches,
int batchCount,
int startIndex,
CommandBuffer cmd,
ScriptableRenderContext context,
ref RenderingData renderingData,
ref FilteringSettings filterSettings,
ref DrawingSettings normalsDrawSettings,
ref DrawingSettings drawSettings,
ref RenderTextureDescriptor desc)
{
var debugHandler = GetActiveDebugHandler(renderingData);
bool drawLights = debugHandler?.IsLightingActive ?? true;
var batchesDrawn = 0;
var rtCount = 0U;
// Draw lights
using (new ProfilingScope(cmd, m_ProfilingDrawLights))
{
for (var i = startIndex; i < batchCount; ++i)
{
ref var layerBatch = ref layerBatches[i];
var blendStyleMask = layerBatch.lightStats.blendStylesUsed;
var blendStyleCount = 0U;
while (blendStyleMask > 0)
{
blendStyleCount += blendStyleMask & 1;
blendStyleMask >>= 1;
}
rtCount += blendStyleCount;
if (rtCount > LayerUtility.maxTextureCount)
break;
batchesDrawn++;
if (layerBatch.lightStats.totalNormalMapUsage > 0)
{
filterSettings.sortingLayerRange = layerBatch.layerRange;
var depthTarget = m_NeedsDepth ? depthAttachment : BuiltinRenderTextureType.None;
this.RenderNormals(context, renderingData, normalsDrawSettings, filterSettings, depthTarget, cmd, layerBatch.lightStats);
}
using (new ProfilingScope(cmd, m_ProfilingDrawLightTextures))
{
this.RenderLights(renderingData, cmd, layerBatch.startLayerID, ref layerBatch, ref desc);
}
}
}
// Determine when to resolve in case we use MSAA
var msaaEnabled = renderingData.cameraData.cameraTargetDescriptor.msaaSamples > 1;
var isFinalBatchSet = startIndex + batchesDrawn >= batchCount;
var resolveDuringBatch = -1;
var resolveIsAfterCopy = false;
if (msaaEnabled && isFinalBatchSet)
DetermineWhenToResolve(startIndex, batchesDrawn, batchCount, layerBatches, out resolveDuringBatch, out resolveIsAfterCopy);
// Draw renderers
var blendStylesCount = m_Renderer2DData.lightBlendStyles.Length;
using (new ProfilingScope(cmd, m_ProfilingDrawRenderers))
{
RenderBufferStoreAction initialStoreAction;
if (msaaEnabled)
initialStoreAction = resolveDuringBatch < startIndex ? RenderBufferStoreAction.Resolve : RenderBufferStoreAction.StoreAndResolve;
else
initialStoreAction = RenderBufferStoreAction.Store;
cmd.SetRenderTarget(colorAttachment, RenderBufferLoadAction.Load, initialStoreAction, depthAttachment, RenderBufferLoadAction.Load, initialStoreAction);
for (var i = startIndex; i < startIndex + batchesDrawn; i++)
{
using (new ProfilingScope(cmd, m_ProfilingDrawLayerBatch))
{
// This is a local copy of the array element (it's a struct). Remember to add a ref here if you need to modify the real thing.
var layerBatch = layerBatches[i];
if (layerBatch.lightStats.totalLights > 0)
{
for (var blendStyleIndex = 0; blendStyleIndex < blendStylesCount; blendStyleIndex++)
{
var blendStyleMask = (uint)(1 << blendStyleIndex);
var blendStyleUsed = (layerBatch.lightStats.blendStylesUsed & blendStyleMask) > 0;
if (blendStyleUsed)
{
var identifier = layerBatch.GetRTId(cmd, desc, blendStyleIndex);
cmd.SetGlobalTexture(k_ShapeLightTextureIDs[blendStyleIndex], identifier);
}
RendererLighting.EnableBlendStyle(cmd, blendStyleIndex, blendStyleUsed);
}
}
else
{
for (var blendStyleIndex = 0; blendStyleIndex < k_ShapeLightTextureIDs.Length; blendStyleIndex++)
{
cmd.SetGlobalTexture(k_ShapeLightTextureIDs[blendStyleIndex], Texture2D.blackTexture);
RendererLighting.EnableBlendStyle(cmd, blendStyleIndex, blendStyleIndex == 0);
}
}
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
short cameraSortingLayerBoundsIndex = GetCameraSortingLayerBoundsIndex();
RenderBufferStoreAction copyStoreAction;
if (msaaEnabled)
copyStoreAction = resolveDuringBatch == i && resolveIsAfterCopy ? RenderBufferStoreAction.Resolve : RenderBufferStoreAction.StoreAndResolve;
else
copyStoreAction = RenderBufferStoreAction.Store;
// If our camera sorting layer texture bound is inside our batch we need to break up the DrawRenderers into two batches
if (cameraSortingLayerBoundsIndex >= layerBatch.layerRange.lowerBound && cameraSortingLayerBoundsIndex < layerBatch.layerRange.upperBound && m_Renderer2DData.useCameraSortingLayerTexture)
{
filterSettings.sortingLayerRange = new SortingLayerRange(layerBatch.layerRange.lowerBound, cameraSortingLayerBoundsIndex);
Render(context, cmd, ref renderingData, ref filterSettings, drawSettings);
CopyCameraSortingLayerRenderTexture(context, renderingData, copyStoreAction);
filterSettings.sortingLayerRange = new SortingLayerRange((short)(cameraSortingLayerBoundsIndex + 1), layerBatch.layerRange.upperBound);
Render(context, cmd, ref renderingData, ref filterSettings, drawSettings);
}
else
{
filterSettings.sortingLayerRange = new SortingLayerRange(layerBatch.layerRange.lowerBound, layerBatch.layerRange.upperBound);
Render(context, cmd, ref renderingData, ref filterSettings, drawSettings);
if (cameraSortingLayerBoundsIndex == layerBatch.layerRange.upperBound && m_Renderer2DData.useCameraSortingLayerTexture)
CopyCameraSortingLayerRenderTexture(context, renderingData, copyStoreAction);
}
// Draw light volumes
if (drawLights && (layerBatch.lightStats.totalVolumetricUsage > 0))
{
var sampleName = "Render 2D Light Volumes";
cmd.BeginSample(sampleName);
RenderBufferStoreAction storeAction;
if (msaaEnabled)
storeAction = resolveDuringBatch == i && !resolveIsAfterCopy ? RenderBufferStoreAction.Resolve : RenderBufferStoreAction.StoreAndResolve;
else
storeAction = RenderBufferStoreAction.Store;
this.RenderLightVolumes(renderingData, cmd, layerBatch.startLayerID, layerBatch.endLayerValue, colorAttachment, depthAttachment,
RenderBufferStoreAction.Store, storeAction, false, m_Renderer2DData.lightCullResult.visibleLights);
cmd.EndSample(sampleName);
}
}
}
}
for (var i = startIndex; i < startIndex + batchesDrawn; ++i)
{
ref var layerBatch = ref layerBatches[i];
layerBatch.ReleaseRT(cmd);
}
return batchesDrawn;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var isLitView = true;
#if UNITY_EDITOR
if (renderingData.cameraData.isSceneViewCamera)
isLitView = UnityEditor.SceneView.currentDrawingSceneView.sceneLighting;
if (renderingData.cameraData.camera.cameraType == CameraType.Preview)
isLitView = false;
#endif
var camera = renderingData.cameraData.camera;
var filterSettings = new FilteringSettings();
filterSettings.renderQueueRange = RenderQueueRange.all;
filterSettings.layerMask = -1;
filterSettings.renderingLayerMask = 0xFFFFFFFF;
filterSettings.sortingLayerRange = SortingLayerRange.all;
LayerUtility.InitializeBudget(m_Renderer2DData.lightRenderTextureMemoryBudget);
ShadowRendering.InitializeBudget(m_Renderer2DData.shadowRenderTextureMemoryBudget);
var isSceneLit = m_Renderer2DData.lightCullResult.IsSceneLit();
if (isSceneLit)
{
var combinedDrawSettings = CreateDrawingSettings(k_ShaderTags, ref renderingData, SortingCriteria.CommonTransparent);
var normalsDrawSettings = CreateDrawingSettings(k_NormalsRenderingPassName, ref renderingData, SortingCriteria.CommonTransparent);
var sortSettings = combinedDrawSettings.sortingSettings;
GetTransparencySortingMode(camera, ref sortSettings);
combinedDrawSettings.sortingSettings = sortSettings;
normalsDrawSettings.sortingSettings = sortSettings;
var cmd = CommandBufferPool.Get();
cmd.SetGlobalFloat(k_HDREmulationScaleID, m_Renderer2DData.hdrEmulationScale);
cmd.SetGlobalFloat(k_InverseHDREmulationScaleID, 1.0f / m_Renderer2DData.hdrEmulationScale);
cmd.SetGlobalFloat(k_UseSceneLightingID, isLitView ? 1.0f : 0.0f);
cmd.SetGlobalColor(k_RendererColorID, Color.white);
this.SetShapeLightShaderGlobals(cmd);
var desc = this.GetBlendStyleRenderTextureDesc(renderingData);
var layerBatches = LayerUtility.CalculateBatches(m_Renderer2DData.lightCullResult, out var batchCount);
var batchesDrawn = 0;
for (var i = 0; i < batchCount; i += batchesDrawn)
batchesDrawn = DrawLayerBatches(layerBatches, batchCount, i, cmd, context, ref renderingData, ref filterSettings, ref normalsDrawSettings, ref combinedDrawSettings, ref desc);
this.DisableAllKeywords(cmd);
this.ReleaseRenderTextures(cmd);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
else
{
var unlitDrawSettings = CreateDrawingSettings(k_ShaderTags, ref renderingData, SortingCriteria.CommonTransparent);
var msaaEnabled = renderingData.cameraData.cameraTargetDescriptor.msaaSamples > 1;
var storeAction = msaaEnabled ? RenderBufferStoreAction.Resolve : RenderBufferStoreAction.Store;
var sortSettings = unlitDrawSettings.sortingSettings;
GetTransparencySortingMode(camera, ref sortSettings);
unlitDrawSettings.sortingSettings = sortSettings;
var cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingSamplerUnlit))
{
cmd.SetRenderTarget(colorAttachment, RenderBufferLoadAction.Load, storeAction, depthAttachment, RenderBufferLoadAction.Load, storeAction);
cmd.SetGlobalFloat(k_UseSceneLightingID, isLitView ? 1.0f : 0.0f);
cmd.SetGlobalColor(k_RendererColorID, Color.white);
for (var blendStyleIndex = 0; blendStyleIndex < k_ShapeLightTextureIDs.Length; blendStyleIndex++)
{
if (blendStyleIndex == 0)
cmd.SetGlobalTexture(k_ShapeLightTextureIDs[blendStyleIndex], Texture2D.blackTexture);
RendererLighting.EnableBlendStyle(cmd, blendStyleIndex, blendStyleIndex == 0);
}
}
this.DisableAllKeywords(cmd);
context.ExecuteCommandBuffer(cmd);
Profiler.BeginSample("Render Sprites Unlit");
if (m_Renderer2DData.useCameraSortingLayerTexture)
{
filterSettings.sortingLayerRange = new SortingLayerRange(short.MinValue, m_CameraSortingLayerBoundsIndex);
Render(context, cmd, ref renderingData, ref filterSettings, unlitDrawSettings);
CopyCameraSortingLayerRenderTexture(context, renderingData, storeAction);
filterSettings.sortingLayerRange = new SortingLayerRange(m_CameraSortingLayerBoundsIndex, short.MaxValue);
Render(context, cmd, ref renderingData, ref filterSettings, unlitDrawSettings);
}
else
{
Render(context, cmd, ref renderingData, ref filterSettings, unlitDrawSettings);
}
Profiler.EndSample();
CommandBufferPool.Release(cmd);
}
filterSettings.sortingLayerRange = SortingLayerRange.all;
RenderingUtils.RenderObjectsWithError(context, ref renderingData.cullResults, camera, filterSettings, SortingCriteria.None);
}
Renderer2DData IRenderPass2D.rendererData
{
get { return m_Renderer2DData; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c4cbc2d2d710ce84696437385ac8866c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f895f2b1dbb2da84e82eedb22e2620f7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,154 @@
using Unity.Mathematics;
namespace UnityEngine.Rendering.Universal
{
internal struct LayerBatch
{
public int startLayerID;
public int endLayerValue;
public SortingLayerRange layerRange;
public LightStats lightStats;
private unsafe fixed int renderTargetIds[4];
private unsafe fixed bool renderTargetUsed[4];
public void InitRTIds(int index)
{
for (var i = 0; i < 4; i++)
{
unsafe
{
renderTargetUsed[i] = false;
renderTargetIds[i] = Shader.PropertyToID($"_LightTexture_{index}_{i}");
}
}
}
public RenderTargetIdentifier GetRTId(CommandBuffer cmd, RenderTextureDescriptor desc, int index)
{
unsafe
{
if (!renderTargetUsed[index])
{
cmd.GetTemporaryRT(renderTargetIds[index], desc, FilterMode.Bilinear);
renderTargetUsed[index] = true;
}
return new RenderTargetIdentifier(renderTargetIds[index]);
}
}
public void ReleaseRT(CommandBuffer cmd)
{
for (var i = 0; i < 4; i++)
{
unsafe
{
if (!renderTargetUsed[i])
continue;
cmd.ReleaseTemporaryRT(renderTargetIds[i]);
renderTargetUsed[i] = false;
}
}
}
}
internal static class LayerUtility
{
private static LayerBatch[] s_LayerBatches;
public static uint maxTextureCount { get; private set; }
public static void InitializeBudget(uint maxTextureCount)
{
LayerUtility.maxTextureCount = math.max(4, maxTextureCount);
}
private static bool CanBatchLightsInLayer(int layerIndex1, int layerIndex2, SortingLayer[] sortingLayers, ILight2DCullResult lightCullResult)
{
var layerId1 = sortingLayers[layerIndex1].id;
var layerId2 = sortingLayers[layerIndex2].id;
foreach (var light in lightCullResult.visibleLights)
{
// If the lit layers are different, or if they are lit but this is a shadow casting light then don't batch.
bool lightCastsShadows = (light.lightType != Light2D.LightType.Global && light.shadowsEnabled);
if ((light.IsLitLayer(layerId1) != light.IsLitLayer(layerId2)) || (light.IsLitLayer(layerId1) && lightCastsShadows))
return false;
}
return true;
}
private static int FindUpperBoundInBatch(int startLayerIndex, SortingLayer[] sortingLayers, ILight2DCullResult lightCullResult)
{
// start checking at the next layer
for (var i = startLayerIndex + 1; i < sortingLayers.Length; i++)
{
if (!CanBatchLightsInLayer(startLayerIndex, i, sortingLayers, lightCullResult))
return i - 1;
}
return sortingLayers.Length - 1;
}
private static void InitializeBatchInfos(SortingLayer[] cachedSortingLayers)
{
var count = cachedSortingLayers.Length;
var needInit = s_LayerBatches == null;
if (s_LayerBatches is null)
{
s_LayerBatches = new LayerBatch[count];
}
#if UNITY_EDITOR
// we should fix. Make a non allocating version of this
if (!Application.isPlaying && s_LayerBatches.Length != count)
{
s_LayerBatches = new LayerBatch[count];
needInit = true;
}
#endif
if (needInit)
{
for (var i = 0; i < s_LayerBatches.Length; i++)
{
ref var layerBatch = ref s_LayerBatches[i];
layerBatch.InitRTIds(i);
}
}
}
public static LayerBatch[] CalculateBatches(ILight2DCullResult lightCullResult, out int batchCount)
{
var cachedSortingLayers = Light2DManager.GetCachedSortingLayer();
InitializeBatchInfos(cachedSortingLayers);
batchCount = 0;
for (var i = 0; i < cachedSortingLayers.Length;)
{
var layerToRender = cachedSortingLayers[i].id;
var lightStats = lightCullResult.GetLightStatsByLayer(layerToRender);
ref var layerBatch = ref s_LayerBatches[batchCount++];
// Find the highest layer that share the same set of lights as this layer.
var upperLayerInBatch = FindUpperBoundInBatch(i, cachedSortingLayers, lightCullResult);
// Some renderers override their sorting layer value with short.MinValue or short.MaxValue.
// When drawing the first sorting layer, we should include the range from short.MinValue to layerValue.
// Similarly, when drawing the last sorting layer, include the range from layerValue to short.MaxValue.
var startLayerValue = (short)cachedSortingLayers[i].value;
var lowerBound = (i == 0) ? short.MinValue : startLayerValue;
var endLayerValue = (short)cachedSortingLayers[upperLayerInBatch].value;
var upperBound = (upperLayerInBatch == cachedSortingLayers.Length - 1) ? short.MaxValue : endLayerValue;
// Renderer within this range share the same set of lights so they should be rendered together.
var sortingLayerRange = new SortingLayerRange(lowerBound, upperBound);
layerBatch.startLayerID = layerToRender;
layerBatch.endLayerValue = endLayerValue;
layerBatch.layerRange = sortingLayerRange;
layerBatch.lightStats = lightStats;
i = upperLayerInBatch + 1;
}
return s_LayerBatches;
}
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 837cbe89c0a94e149f5b494ae9c69a51
timeCreated: 1599108159

View file

@ -0,0 +1,96 @@
using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering.Universal
{
internal static class Light2DLookupTexture
{
private static Texture2D s_PointLightLookupTexture;
public static Texture GetLightLookupTexture()
{
if (s_PointLightLookupTexture == null)
s_PointLightLookupTexture = CreatePointLightLookupTexture();
return s_PointLightLookupTexture;
}
private static Texture2D CreatePointLightLookupTexture()
{
const int WIDTH = 256;
const int HEIGHT = 256;
var textureFormat = GraphicsFormat.R8G8B8A8_UNorm;
if (RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.R16G16B16A16_SFloat, FormatUsage.SetPixels))
textureFormat = GraphicsFormat.R16G16B16A16_SFloat;
else if (RenderingUtils.SupportsGraphicsFormat(GraphicsFormat.R32G32B32A32_SFloat, FormatUsage.SetPixels))
textureFormat = GraphicsFormat.R32G32B32A32_SFloat;
var texture = new Texture2D(WIDTH, HEIGHT, textureFormat, TextureCreationFlags.None);
texture.filterMode = FilterMode.Bilinear;
texture.wrapMode = TextureWrapMode.Clamp;
var center = new Vector2(WIDTH / 2.0f, HEIGHT / 2.0f);
for (var y = 0; y < HEIGHT; y++)
{
for (var x = 0; x < WIDTH; x++)
{
var pos = new Vector2(x, y);
var distance = Vector2.Distance(pos, center);
var relPos = pos - center;
var direction = center - pos;
direction.Normalize();
// red = 1-0 distance
// green = 1-0 angle
// blue = direction.x
// alpha = direction.y
float red;
if (x == WIDTH - 1 || y == HEIGHT - 1)
red = 0;
else
red = Mathf.Clamp(1 - (2.0f * distance / WIDTH), 0.0f, 1.0f);
var cosAngle = Vector2.Dot(Vector2.down, relPos.normalized);
var angle = Mathf.Acos(cosAngle) / Mathf.PI; // 0-1
var green = Mathf.Clamp(1 - angle, 0.0f, 1.0f);
var blue = direction.x;
var alpha = direction.y;
var color = new Color(red, green, blue, alpha);
texture.SetPixel(x, y, color);
}
}
texture.Apply();
return texture;
}
// private static Texture2D s_FalloffLookupTexture;
//#if UNITY_EDITOR
// [MenuItem("Light2D Debugging/Write Light Texture")]
// static public void WriteLightTexture()
// {
// var path = EditorUtility.SaveFilePanel("Save texture as PNG", "", "LightLookupTexture.exr", "png");
// CreatePointLightLookupTexture();
// byte[] imgData = s_PointLightLookupTexture.EncodeToEXR(Texture2D.EXRFlags.CompressRLE);
// if (imgData != null)
// File.WriteAllBytes(path, imgData);
// }
// [MenuItem("Light2D Debugging/Write Falloff Texture")]
// static public void WriteCurveTexture()
// {
// var path = EditorUtility.SaveFilePanel("Save texture as PNG", "", "FalloffLookupTexture.png", "png");
// CreateFalloffLookupTexture();
// byte[] imgData = s_FalloffLookupTexture.EncodeToPNG();
// if (imgData != null)
// File.WriteAllBytes(path, imgData);
// }
//#endif
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fed3c64eff8b51649bfa3da654d69182
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,684 @@
using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
using Unity.Collections;
namespace UnityEngine.Rendering.Universal
{
internal static class RendererLighting
{
private static readonly ProfilingSampler m_ProfilingSampler = new ProfilingSampler("Draw Normals");
private static readonly ShaderTagId k_NormalsRenderingPassName = new ShaderTagId("NormalsRendering");
private static readonly Color k_NormalClearColor = new Color(0.5f, 0.5f, 0.5f, 1.0f);
private static readonly string k_SpriteLightKeyword = "SPRITE_LIGHT";
private static readonly string k_UsePointLightCookiesKeyword = "USE_POINT_LIGHT_COOKIES";
private static readonly string k_LightQualityFastKeyword = "LIGHT_QUALITY_FAST";
private static readonly string k_UseNormalMap = "USE_NORMAL_MAP";
private static readonly string k_UseAdditiveBlendingKeyword = "USE_ADDITIVE_BLENDING";
private static readonly string[] k_UseBlendStyleKeywords =
{
"USE_SHAPE_LIGHT_TYPE_0", "USE_SHAPE_LIGHT_TYPE_1", "USE_SHAPE_LIGHT_TYPE_2", "USE_SHAPE_LIGHT_TYPE_3"
};
private static readonly int[] k_BlendFactorsPropIDs =
{
Shader.PropertyToID("_ShapeLightBlendFactors0"),
Shader.PropertyToID("_ShapeLightBlendFactors1"),
Shader.PropertyToID("_ShapeLightBlendFactors2"),
Shader.PropertyToID("_ShapeLightBlendFactors3")
};
private static readonly int[] k_MaskFilterPropIDs =
{
Shader.PropertyToID("_ShapeLightMaskFilter0"),
Shader.PropertyToID("_ShapeLightMaskFilter1"),
Shader.PropertyToID("_ShapeLightMaskFilter2"),
Shader.PropertyToID("_ShapeLightMaskFilter3")
};
private static readonly int[] k_InvertedFilterPropIDs =
{
Shader.PropertyToID("_ShapeLightInvertedFilter0"),
Shader.PropertyToID("_ShapeLightInvertedFilter1"),
Shader.PropertyToID("_ShapeLightInvertedFilter2"),
Shader.PropertyToID("_ShapeLightInvertedFilter3")
};
private static GraphicsFormat s_RenderTextureFormatToUse = GraphicsFormat.R8G8B8A8_UNorm;
private static bool s_HasSetupRenderTextureFormatToUse;
private static readonly int k_SrcBlendID = Shader.PropertyToID("_SrcBlend");
private static readonly int k_DstBlendID = Shader.PropertyToID("_DstBlend");
private static readonly int k_FalloffIntensityID = Shader.PropertyToID("_FalloffIntensity");
private static readonly int k_FalloffDistanceID = Shader.PropertyToID("_FalloffDistance");
private static readonly int k_LightColorID = Shader.PropertyToID("_LightColor");
private static readonly int k_VolumeOpacityID = Shader.PropertyToID("_VolumeOpacity");
private static readonly int k_CookieTexID = Shader.PropertyToID("_CookieTex");
private static readonly int k_FalloffLookupID = Shader.PropertyToID("_FalloffLookup");
private static readonly int k_LightPositionID = Shader.PropertyToID("_LightPosition");
private static readonly int k_LightInvMatrixID = Shader.PropertyToID("_LightInvMatrix");
private static readonly int k_InnerRadiusMultID = Shader.PropertyToID("_InnerRadiusMult");
private static readonly int k_OuterAngleID = Shader.PropertyToID("_OuterAngle");
private static readonly int k_InnerAngleMultID = Shader.PropertyToID("_InnerAngleMult");
private static readonly int k_LightLookupID = Shader.PropertyToID("_LightLookup");
private static readonly int k_IsFullSpotlightID = Shader.PropertyToID("_IsFullSpotlight");
private static readonly int k_LightZDistanceID = Shader.PropertyToID("_LightZDistance");
private static readonly int k_PointLightCookieTexID = Shader.PropertyToID("_PointLightCookieTex");
private static GraphicsFormat GetRenderTextureFormat()
{
if (!s_HasSetupRenderTextureFormatToUse)
{
if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, FormatUsage.Linear | FormatUsage.Render))
s_RenderTextureFormatToUse = GraphicsFormat.B10G11R11_UFloatPack32;
else if (SystemInfo.IsFormatSupported(GraphicsFormat.R16G16B16A16_SFloat, FormatUsage.Linear | FormatUsage.Render))
s_RenderTextureFormatToUse = GraphicsFormat.R16G16B16A16_SFloat;
s_HasSetupRenderTextureFormatToUse = true;
}
return s_RenderTextureFormatToUse;
}
public static void CreateNormalMapRenderTexture(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, float renderScale)
{
if (renderScale != pass.rendererData.normalsRenderTargetScale)
{
if (pass.rendererData.isNormalsRenderTargetValid)
{
cmd.ReleaseTemporaryRT(pass.rendererData.normalsRenderTarget.id);
}
pass.rendererData.isNormalsRenderTargetValid = true;
pass.rendererData.normalsRenderTargetScale = renderScale;
var descriptor = new RenderTextureDescriptor(
(int)(renderingData.cameraData.cameraTargetDescriptor.width * renderScale),
(int)(renderingData.cameraData.cameraTargetDescriptor.height * renderScale));
descriptor.graphicsFormat = GetRenderTextureFormat();
descriptor.useMipMap = false;
descriptor.autoGenerateMips = false;
descriptor.depthBufferBits = pass.rendererData.useDepthStencilBuffer ? 32 : 0;
descriptor.msaaSamples = renderingData.cameraData.cameraTargetDescriptor.msaaSamples;
descriptor.dimension = TextureDimension.Tex2D;
cmd.GetTemporaryRT(pass.rendererData.normalsRenderTarget.id, descriptor, FilterMode.Bilinear);
}
}
public static RenderTextureDescriptor GetBlendStyleRenderTextureDesc(this IRenderPass2D pass, RenderingData renderingData)
{
var renderTextureScale = Mathf.Clamp(pass.rendererData.lightRenderTextureScale, 0.01f, 1.0f);
var width = (int)(renderingData.cameraData.cameraTargetDescriptor.width * renderTextureScale);
var height = (int)(renderingData.cameraData.cameraTargetDescriptor.height * renderTextureScale);
var descriptor = new RenderTextureDescriptor(width, height);
descriptor.graphicsFormat = GetRenderTextureFormat();
descriptor.useMipMap = false;
descriptor.autoGenerateMips = false;
descriptor.depthBufferBits = 0;
descriptor.msaaSamples = 1;
descriptor.dimension = TextureDimension.Tex2D;
return descriptor;
}
public static void CreateCameraSortingLayerRenderTexture(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, Downsampling downsamplingMethod)
{
var renderTextureScale = 1.0f;
if (downsamplingMethod == Downsampling._2xBilinear)
renderTextureScale = 0.5f;
else if (downsamplingMethod == Downsampling._4xBox || downsamplingMethod == Downsampling._4xBilinear)
renderTextureScale = 0.25f;
var width = (int)(renderingData.cameraData.cameraTargetDescriptor.width * renderTextureScale);
var height = (int)(renderingData.cameraData.cameraTargetDescriptor.height * renderTextureScale);
var descriptor = new RenderTextureDescriptor(width, height);
descriptor.graphicsFormat = renderingData.cameraData.cameraTargetDescriptor.graphicsFormat;
descriptor.useMipMap = false;
descriptor.autoGenerateMips = false;
descriptor.depthBufferBits = 0;
descriptor.msaaSamples = 1;
descriptor.dimension = TextureDimension.Tex2D;
cmd.GetTemporaryRT(pass.rendererData.cameraSortingLayerRenderTarget.id, descriptor, FilterMode.Bilinear);
}
public static void EnableBlendStyle(CommandBuffer cmd, int blendStyleIndex, bool enabled)
{
var keyword = k_UseBlendStyleKeywords[blendStyleIndex];
if (enabled)
cmd.EnableShaderKeyword(keyword);
else
cmd.DisableShaderKeyword(keyword);
}
public static void DisableAllKeywords(this IRenderPass2D pass, CommandBuffer cmd)
{
foreach (var keyword in k_UseBlendStyleKeywords)
{
cmd.DisableShaderKeyword(keyword);
}
}
public static void ReleaseRenderTextures(this IRenderPass2D pass, CommandBuffer cmd)
{
pass.rendererData.isNormalsRenderTargetValid = false;
pass.rendererData.normalsRenderTargetScale = 0.0f;
cmd.ReleaseTemporaryRT(pass.rendererData.normalsRenderTarget.id);
cmd.ReleaseTemporaryRT(pass.rendererData.shadowsRenderTarget.id);
cmd.ReleaseTemporaryRT(pass.rendererData.cameraSortingLayerRenderTarget.id);
}
public static void DrawPointLight(CommandBuffer cmd, Light2D light, Mesh lightMesh, Material material)
{
var scale = new Vector3(light.pointLightOuterRadius, light.pointLightOuterRadius, light.pointLightOuterRadius);
var matrix = Matrix4x4.TRS(light.transform.position, light.transform.rotation, scale);
cmd.DrawMesh(lightMesh, matrix, material);
}
private static bool CanCastShadows(Light2D light, int layerToRender)
{
return light.shadowsEnabled && light.shadowIntensity > 0 && light.IsLitLayer(layerToRender);
}
private static bool CanCastVolumetricShadows(Light2D light, int endLayerValue)
{
var topMostLayerValue = light.GetTopMostLitLayer();
return light.volumetricShadowsEnabled && light.shadowVolumeIntensity > 0 && topMostLayerValue == endLayerValue;
}
private static void RenderLightSet(IRenderPass2D pass, RenderingData renderingData, int blendStyleIndex, CommandBuffer cmd, int layerToRender, RenderTargetIdentifier renderTexture, List<Light2D> lights)
{
var maxShadowLightCount = ShadowRendering.maxTextureCount * 4;
var requiresRTInit = true;
// This case should never happen, but if it does it may cause an infinite loop later.
if (maxShadowLightCount < 1)
{
Debug.LogError("maxShadowTextureCount cannot be less than 1");
return;
}
NativeArray<bool> doesLightAtIndexHaveShadows = new NativeArray<bool>(lights.Count, Allocator.Temp);
// Break up light rendering into batches for the purpose of shadow casting
var lightIndex = 0;
while (lightIndex < lights.Count)
{
var remainingLights = (uint)lights.Count - lightIndex;
var batchedLights = 0;
// Add lights to our batch until the number of shadow textures reach the maxShadowTextureCount
int shadowLightCount = 0;
while (batchedLights < remainingLights && shadowLightCount < maxShadowLightCount)
{
int curLightIndex = lightIndex + batchedLights;
var light = lights[curLightIndex];
if (CanCastShadows(light, layerToRender))
{
doesLightAtIndexHaveShadows[curLightIndex] = false;
if (ShadowRendering.PrerenderShadows(pass, renderingData, cmd, layerToRender, light, shadowLightCount, light.shadowIntensity))
{
doesLightAtIndexHaveShadows[curLightIndex] = true;
shadowLightCount++;
}
}
batchedLights++;
}
// Set the current RT to the light RT
if (shadowLightCount > 0 || requiresRTInit)
{
cmd.SetRenderTarget(renderTexture, RenderBufferLoadAction.Load, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
requiresRTInit = false;
}
// Render all the lights.
shadowLightCount = 0;
for (var lightIndexOffset = 0; lightIndexOffset < batchedLights; lightIndexOffset++)
{
var light = lights[(int)(lightIndex + lightIndexOffset)];
if (light != null &&
light.lightType != Light2D.LightType.Global &&
light.blendStyleIndex == blendStyleIndex &&
light.IsLitLayer(layerToRender))
{
// Render light
var lightMaterial = pass.rendererData.GetLightMaterial(light, false);
if (lightMaterial == null)
continue;
var lightMesh = light.lightMesh;
if (lightMesh == null)
continue;
// Set the shadow texture to read from
if (doesLightAtIndexHaveShadows[lightIndex + lightIndexOffset])
ShadowRendering.SetGlobalShadowTexture(cmd, light, shadowLightCount++);
else
ShadowRendering.DisableGlobalShadowTexture(cmd);
if (light.lightType == Light2D.LightType.Sprite && light.lightCookieSprite != null && light.lightCookieSprite.texture != null)
cmd.SetGlobalTexture(k_CookieTexID, light.lightCookieSprite.texture);
SetGeneralLightShaderGlobals(pass, cmd, light);
if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled || light.lightType == Light2D.LightType.Point)
SetPointLightShaderGlobals(pass, cmd, light);
// Light code could be combined...
if (light.lightType == (Light2D.LightType)Light2D.DeprecatedLightType.Parametric || light.lightType == Light2D.LightType.Freeform || light.lightType == Light2D.LightType.Sprite)
{
cmd.DrawMesh(lightMesh, light.transform.localToWorldMatrix, lightMaterial);
}
else if (light.lightType == Light2D.LightType.Point)
{
DrawPointLight(cmd, light, lightMesh, lightMaterial);
}
}
}
// Release all of the temporary shadow textures
for (var releaseIndex = shadowLightCount - 1; releaseIndex >= 0; releaseIndex--)
ShadowRendering.ReleaseShadowRenderTexture(cmd, releaseIndex);
lightIndex += batchedLights;
}
doesLightAtIndexHaveShadows.Dispose();
}
public static void RenderLightVolumes(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, int layerToRender, int endLayerValue,
RenderTargetIdentifier renderTexture, RenderTargetIdentifier depthTexture, RenderBufferStoreAction intermediateStoreAction,
RenderBufferStoreAction finalStoreAction, bool requiresRTInit, List<Light2D> lights)
{
var maxShadowLightCount = ShadowRendering.maxTextureCount * 4; // Now encodes shadows into RGBA as well as seperate textures
NativeArray<bool> doesLightAtIndexHaveShadows = new NativeArray<bool>(lights.Count, Allocator.Temp);
// This case should never happen, but if it does it may cause an infinite loop later.
if (maxShadowLightCount < 1)
{
Debug.LogError("maxShadowLightCount cannot be less than 1");
return;
}
// Determine last light with volumetric shadows to be rendered if we want to use a different store action after using rendering its volumetric shadows
int useFinalStoreActionAfter = lights.Count;
if (intermediateStoreAction != finalStoreAction)
{
for (int i = lights.Count - 1; i >= 0; i--)
{
if (lights[i].renderVolumetricShadows)
{
useFinalStoreActionAfter = i;
break;
}
}
}
// Break up light rendering into batches for the purpose of shadow casting
var lightIndex = 0;
while (lightIndex < lights.Count)
{
var remainingLights = (uint)lights.Count - lightIndex;
var batchedLights = 0;
// Add lights to our batch until the number of shadow textures reach the maxShadowTextureCount
var shadowLightCount = 0;
while (batchedLights < remainingLights && shadowLightCount < maxShadowLightCount)
{
int curLightIndex = lightIndex + batchedLights;
var light = lights[curLightIndex];
if (CanCastVolumetricShadows(light, endLayerValue))
{
doesLightAtIndexHaveShadows[curLightIndex] = false;
if (ShadowRendering.PrerenderShadows(pass, renderingData, cmd, layerToRender, light, shadowLightCount, light.shadowVolumeIntensity))
{
doesLightAtIndexHaveShadows[curLightIndex] = true;
shadowLightCount++;
}
}
batchedLights++;
}
// Set the current RT to the light RT
if (shadowLightCount > 0 || requiresRTInit)
{
var storeAction = lightIndex + batchedLights >= useFinalStoreActionAfter ? finalStoreAction : intermediateStoreAction;
cmd.SetRenderTarget(renderTexture, RenderBufferLoadAction.Load, storeAction, depthTexture, RenderBufferLoadAction.Load, storeAction);
requiresRTInit = false;
}
// Render all the lights.
shadowLightCount = 0;
for (var lightIndexOffset = 0; lightIndexOffset < batchedLights; lightIndexOffset++)
{
var light = lights[(int)(lightIndex + lightIndexOffset)];
if (light.lightType == Light2D.LightType.Global)
continue;
if (light.volumeIntensity <= 0.0f || !light.volumeIntensityEnabled)
continue;
var topMostLayerValue = light.GetTopMostLitLayer();
if (endLayerValue == topMostLayerValue) // this implies the layer is correct
{
var lightVolumeMaterial = pass.rendererData.GetLightMaterial(light, true);
var lightMesh = light.lightMesh;
// Set the shadow texture to read from.
if (doesLightAtIndexHaveShadows[lightIndex + lightIndexOffset])
ShadowRendering.SetGlobalShadowTexture(cmd, light, shadowLightCount++);
else
ShadowRendering.DisableGlobalShadowTexture(cmd);
if (light.lightType == Light2D.LightType.Sprite && light.lightCookieSprite != null && light.lightCookieSprite.texture != null)
cmd.SetGlobalTexture(k_CookieTexID, light.lightCookieSprite.texture);
SetGeneralLightShaderGlobals(pass, cmd, light);
// Is this needed
if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled || light.lightType == Light2D.LightType.Point)
SetPointLightShaderGlobals(pass, cmd, light);
// Could be combined...
if (light.lightType == Light2D.LightType.Parametric || light.lightType == Light2D.LightType.Freeform || light.lightType == Light2D.LightType.Sprite)
{
cmd.DrawMesh(lightMesh, light.transform.localToWorldMatrix, lightVolumeMaterial);
}
else if (light.lightType == Light2D.LightType.Point)
{
DrawPointLight(cmd, light, lightMesh, lightVolumeMaterial);
}
}
}
// Release all of the temporary shadow textures
for (var releaseIndex = shadowLightCount - 1; releaseIndex >= 0; releaseIndex--)
ShadowRendering.ReleaseShadowRenderTexture(cmd, releaseIndex);
lightIndex += batchedLights;
}
doesLightAtIndexHaveShadows.Dispose();
}
public static void SetShapeLightShaderGlobals(this IRenderPass2D pass, CommandBuffer cmd)
{
for (var i = 0; i < pass.rendererData.lightBlendStyles.Length; i++)
{
var blendStyle = pass.rendererData.lightBlendStyles[i];
if (i >= k_BlendFactorsPropIDs.Length)
break;
cmd.SetGlobalVector(k_BlendFactorsPropIDs[i], blendStyle.blendFactors);
cmd.SetGlobalVector(k_MaskFilterPropIDs[i], blendStyle.maskTextureChannelFilter.mask);
cmd.SetGlobalVector(k_InvertedFilterPropIDs[i], blendStyle.maskTextureChannelFilter.inverted);
}
cmd.SetGlobalTexture(k_FalloffLookupID, pass.rendererData.fallOffLookup);
}
private static float GetNormalizedInnerRadius(Light2D light)
{
return light.pointLightInnerRadius / light.pointLightOuterRadius;
}
private static float GetNormalizedAngle(float angle)
{
return (angle / 360.0f);
}
private static void GetScaledLightInvMatrix(Light2D light, out Matrix4x4 retMatrix)
{
var outerRadius = light.pointLightOuterRadius;
var lightScale = Vector3.one;
var outerRadiusScale = new Vector3(lightScale.x * outerRadius, lightScale.y * outerRadius, lightScale.z * outerRadius);
var transform = light.transform;
var scaledLightMat = Matrix4x4.TRS(transform.position, transform.rotation, outerRadiusScale);
retMatrix = Matrix4x4.Inverse(scaledLightMat);
}
private static void SetGeneralLightShaderGlobals(IRenderPass2D pass, CommandBuffer cmd, Light2D light)
{
float intensity = light.intensity * light.color.a;
Color color = intensity * light.color;
color.a = 1.0f;
float volumeIntensity = light.volumeIntensity;
cmd.SetGlobalFloat(k_FalloffIntensityID, light.falloffIntensity);
cmd.SetGlobalFloat(k_FalloffDistanceID, light.shapeLightFalloffSize);
cmd.SetGlobalColor(k_LightColorID, color);
cmd.SetGlobalFloat(k_VolumeOpacityID, volumeIntensity);
}
private static void SetPointLightShaderGlobals(IRenderPass2D pass, CommandBuffer cmd, Light2D light)
{
// This is used for the lookup texture
GetScaledLightInvMatrix(light, out var lightInverseMatrix);
var innerRadius = GetNormalizedInnerRadius(light);
var innerAngle = GetNormalizedAngle(light.pointLightInnerAngle);
var outerAngle = GetNormalizedAngle(light.pointLightOuterAngle);
var innerRadiusMult = 1 / (1 - innerRadius);
cmd.SetGlobalVector(k_LightPositionID, light.transform.position);
cmd.SetGlobalMatrix(k_LightInvMatrixID, lightInverseMatrix);
cmd.SetGlobalFloat(k_InnerRadiusMultID, innerRadiusMult);
cmd.SetGlobalFloat(k_OuterAngleID, outerAngle);
cmd.SetGlobalFloat(k_InnerAngleMultID, 1 / (outerAngle - innerAngle));
cmd.SetGlobalTexture(k_LightLookupID, Light2DLookupTexture.GetLightLookupTexture());
cmd.SetGlobalTexture(k_FalloffLookupID, pass.rendererData.fallOffLookup);
cmd.SetGlobalFloat(k_FalloffIntensityID, light.falloffIntensity);
cmd.SetGlobalFloat(k_IsFullSpotlightID, innerAngle == 1 ? 1.0f : 0.0f);
cmd.SetGlobalFloat(k_LightZDistanceID, light.normalMapDistance);
if (light.lightCookieSprite != null && light.lightCookieSprite.texture != null)
cmd.SetGlobalTexture(k_PointLightCookieTexID, light.lightCookieSprite.texture);
}
public static void ClearDirtyLighting(this IRenderPass2D pass, CommandBuffer cmd, uint blendStylesUsed)
{
for (var i = 0; i < pass.rendererData.lightBlendStyles.Length; ++i)
{
if ((blendStylesUsed & (uint)(1 << i)) == 0)
continue;
if (!pass.rendererData.lightBlendStyles[i].isDirty)
continue;
cmd.SetRenderTarget(pass.rendererData.lightBlendStyles[i].renderTargetHandle.Identifier());
cmd.ClearRenderTarget(false, true, Color.black);
pass.rendererData.lightBlendStyles[i].isDirty = false;
}
}
public static void RenderNormals(this IRenderPass2D pass, ScriptableRenderContext context, RenderingData renderingData, DrawingSettings drawSettings, FilteringSettings filterSettings, RenderTargetIdentifier depthTarget, CommandBuffer cmd, LightStats lightStats)
{
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
// figure out the scale
var normalRTScale = 0.0f;
if (depthTarget != BuiltinRenderTextureType.None)
normalRTScale = 1.0f;
else
normalRTScale = Mathf.Clamp(pass.rendererData.lightRenderTextureScale, 0.01f, 1.0f);
pass.CreateNormalMapRenderTexture(renderingData, cmd, normalRTScale);
var msaaEnabled = renderingData.cameraData.cameraTargetDescriptor.msaaSamples > 1;
var storeAction = msaaEnabled ? RenderBufferStoreAction.Resolve : RenderBufferStoreAction.Store;
if (depthTarget != BuiltinRenderTextureType.None)
{
cmd.SetRenderTarget(
pass.rendererData.normalsRenderTarget.Identifier(),
RenderBufferLoadAction.DontCare,
storeAction,
depthTarget,
RenderBufferLoadAction.Load,
RenderBufferStoreAction.Store);
}
else
cmd.SetRenderTarget(pass.rendererData.normalsRenderTarget.Identifier(), RenderBufferLoadAction.DontCare, storeAction);
cmd.ClearRenderTarget(pass.rendererData.useDepthStencilBuffer, true, k_NormalClearColor);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
drawSettings.SetShaderPassName(0, k_NormalsRenderingPassName);
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings);
}
}
public static void RenderLights(this IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmd, int layerToRender, ref LayerBatch layerBatch, ref RenderTextureDescriptor rtDesc)
{
// Before rendering the lights cache some values that are expensive to get/calculate
var culledLights = pass.rendererData.lightCullResult.visibleLights;
for (var i = 0; i < culledLights.Count; i++)
{
culledLights[i].CacheValues();
}
ShadowCasterGroup2DManager.CacheValues();
var blendStyles = pass.rendererData.lightBlendStyles;
for (var i = 0; i < blendStyles.Length; ++i)
{
if ((layerBatch.lightStats.blendStylesUsed & (uint)(1 << i)) == 0)
continue;
var sampleName = blendStyles[i].name;
cmd.BeginSample(sampleName);
if (!Light2DManager.GetGlobalColor(layerToRender, i, out var clearColor))
clearColor = Color.black;
var anyLights = (layerBatch.lightStats.blendStylesWithLights & (uint)(1 << i)) != 0;
var desc = rtDesc;
if (!anyLights) // No lights -- create tiny texture
desc.width = desc.height = 4;
var identifier = layerBatch.GetRTId(cmd, desc, i);
cmd.SetRenderTarget(identifier,
RenderBufferLoadAction.DontCare,
RenderBufferStoreAction.Store,
RenderBufferLoadAction.DontCare,
RenderBufferStoreAction.DontCare);
cmd.ClearRenderTarget(false, true, clearColor);
if (anyLights)
{
RenderLightSet(
pass, renderingData,
i,
cmd,
layerToRender,
identifier,
pass.rendererData.lightCullResult.visibleLights
);
}
cmd.EndSample(sampleName);
}
}
private static void SetBlendModes(Material material, BlendMode src, BlendMode dst)
{
material.SetFloat(k_SrcBlendID, (float)src);
material.SetFloat(k_DstBlendID, (float)dst);
}
private static uint GetLightMaterialIndex(Light2D light, bool isVolume)
{
var isPoint = light.isPointLight;
var bitIndex = 0;
var volumeBit = isVolume ? 1u << bitIndex : 0u;
bitIndex++;
var shapeBit = !isPoint ? 1u << bitIndex : 0u;
bitIndex++;
var additiveBit = light.overlapOperation == Light2D.OverlapOperation.AlphaBlend ? 0u : 1u << bitIndex;
bitIndex++;
var spriteBit = light.lightType == Light2D.LightType.Sprite ? 1u << bitIndex : 0u;
bitIndex++;
var pointCookieBit = (isPoint && light.lightCookieSprite != null && light.lightCookieSprite.texture != null) ? 1u << bitIndex : 0u;
bitIndex++;
var pointFastQualityBit = (isPoint && light.normalMapQuality == Light2D.NormalMapQuality.Fast) ? 1u << bitIndex : 0u;
bitIndex++;
var useNormalMap = light.normalMapQuality != Light2D.NormalMapQuality.Disabled ? 1u << bitIndex : 0u;
return pointFastQualityBit | pointCookieBit | spriteBit | additiveBit | shapeBit | volumeBit | useNormalMap;
}
private static Material CreateLightMaterial(Renderer2DData rendererData, Light2D light, bool isVolume)
{
var isPoint = light.isPointLight;
Material material;
if (isVolume)
material = CoreUtils.CreateEngineMaterial(isPoint ? rendererData.pointLightVolumeShader : rendererData.shapeLightVolumeShader);
else
{
material = CoreUtils.CreateEngineMaterial(isPoint ? rendererData.pointLightShader : rendererData.shapeLightShader);
if (light.overlapOperation == Light2D.OverlapOperation.Additive)
{
SetBlendModes(material, BlendMode.One, BlendMode.One);
material.EnableKeyword(k_UseAdditiveBlendingKeyword);
}
else
SetBlendModes(material, BlendMode.SrcAlpha, BlendMode.OneMinusSrcAlpha);
}
if (light.lightType == Light2D.LightType.Sprite)
material.EnableKeyword(k_SpriteLightKeyword);
if (isPoint && light.lightCookieSprite != null && light.lightCookieSprite.texture != null)
material.EnableKeyword(k_UsePointLightCookiesKeyword);
if (isPoint && light.normalMapQuality == Light2D.NormalMapQuality.Fast)
material.EnableKeyword(k_LightQualityFastKeyword);
if (light.normalMapQuality != Light2D.NormalMapQuality.Disabled)
material.EnableKeyword(k_UseNormalMap);
return material;
}
private static Material GetLightMaterial(this Renderer2DData rendererData, Light2D light, bool isVolume)
{
var materialIndex = GetLightMaterialIndex(light, isVolume);
if (!rendererData.lightMaterials.TryGetValue(materialIndex, out var material))
{
material = CreateLightMaterial(rendererData, light, isVolume);
rendererData.lightMaterials[materialIndex] = material;
}
return material;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7978073cb0cd25f4f8e29b37e3f55d2a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,428 @@
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Experimental.Rendering.Universal
{
/// <summary>
/// The Pixel Perfect Camera component ensures your pixel art remains crisp and clear at different resolutions, and stable in motion.
/// </summary>
[ExecuteInEditMode]
[DisallowMultipleComponent]
[AddComponentMenu("Rendering/2D/Pixel Perfect Camera")]
[RequireComponent(typeof(Camera))]
[MovedFrom("UnityEngine.Experimental.Rendering")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@latest/index.html?subfolder=/manual/2d-pixelperfect.html%23properties")]
public class PixelPerfectCamera : MonoBehaviour, IPixelPerfectCamera, ISerializationCallbackReceiver
{
public enum CropFrame
{
None,
Pillarbox,
Letterbox,
Windowbox,
StretchFill
}
public enum GridSnapping
{
None,
PixelSnapping,
UpscaleRenderTexture
}
public enum ComponentVersions
{
Version_Unserialized = 0,
Version_1 = 1
}
#if UNITY_EDITOR
const ComponentVersions k_CurrentComponentVersion = ComponentVersions.Version_1;
[SerializeField] ComponentVersions m_ComponentVersion = ComponentVersions.Version_Unserialized;
#endif
public CropFrame cropFrame { get { return m_CropFrame; } set { m_CropFrame = value; } }
public GridSnapping gridSnapping { get { return m_GridSnapping; } set { m_GridSnapping = value; } }
public float orthographicSize { get { return m_Internal.orthoSize; } }
/// <summary>
/// Match this value to to the Pixels Per Unit values of all Sprites within the Scene.
/// </summary>
public int assetsPPU { get { return m_AssetsPPU; } set { m_AssetsPPU = value > 0 ? value : 1; } }
/// <summary>
/// The original horizontal resolution your Assets are designed for.
/// </summary>
public int refResolutionX { get { return m_RefResolutionX; } set { m_RefResolutionX = value > 0 ? value : 1; } }
/// <summary>
/// Original vertical resolution your Assets are designed for.
/// </summary>
public int refResolutionY { get { return m_RefResolutionY; } set { m_RefResolutionY = value > 0 ? value : 1; } }
/// <summary>
/// Set to true to have the Scene rendered to a temporary texture set as close as possible to the Reference Resolution,
/// while maintaining the full screen aspect ratio. This temporary texture is then upscaled to fit the full screen.
/// </summary>
[System.Obsolete("Use gridSnapping instead", false)]
public bool upscaleRT
{
get
{
return m_GridSnapping == GridSnapping.UpscaleRenderTexture;
}
set
{
m_GridSnapping = value ? GridSnapping.UpscaleRenderTexture : GridSnapping.None;
}
}
/// <summary>
/// Set to true to prevent subpixel movement and make Sprites appear to move in pixel-by-pixel increments.
/// Only applicable when upscaleRT is false.
/// </summary>
[System.Obsolete("Use gridSnapping instead", false)]
public bool pixelSnapping
{
get
{
return m_GridSnapping == GridSnapping.PixelSnapping;
}
set
{
m_GridSnapping = value ? GridSnapping.PixelSnapping : GridSnapping.None;
}
}
/// <summary>
/// Set to true to crop the viewport with black bars to match refResolutionX in the horizontal direction.
/// </summary>
[System.Obsolete("Use cropFrame instead", false)]
public bool cropFrameX
{
get
{
return m_CropFrame == CropFrame.StretchFill || m_CropFrame == CropFrame.Windowbox || m_CropFrame == CropFrame.Pillarbox;
}
set
{
if (value)
{
if (m_CropFrame == CropFrame.None)
m_CropFrame = CropFrame.Pillarbox;
else if (m_CropFrame == CropFrame.Letterbox)
m_CropFrame = CropFrame.Windowbox;
}
else
{
if (m_CropFrame == CropFrame.Pillarbox)
m_CropFrame = CropFrame.None;
else if (m_CropFrame == CropFrame.Windowbox || m_CropFrame == CropFrame.StretchFill)
m_CropFrame = CropFrame.Letterbox;
}
}
}
/// <summary>
/// Set to true to crop the viewport with black bars to match refResolutionY in the vertical direction.
/// </summary>
[System.Obsolete("Use cropFrame instead", false)]
public bool cropFrameY
{
get
{
return m_CropFrame == CropFrame.StretchFill || m_CropFrame == CropFrame.Windowbox || m_CropFrame == CropFrame.Letterbox;
}
set
{
if (value)
{
if (m_CropFrame == CropFrame.None)
m_CropFrame = CropFrame.Letterbox;
else if (m_CropFrame == CropFrame.Pillarbox)
m_CropFrame = CropFrame.Windowbox;
}
else
{
if (m_CropFrame == CropFrame.Letterbox)
m_CropFrame = CropFrame.None;
else if (m_CropFrame == CropFrame.Windowbox || m_CropFrame == CropFrame.StretchFill)
m_CropFrame = CropFrame.Pillarbox;
}
}
}
/// <summary>
/// Set to true to expand the viewport to fit the screen resolution while maintaining the viewport's aspect ratio.
/// Only applicable when both cropFrameX and cropFrameY are true.
/// </summary>
[System.Obsolete("Use cropFrame instead", false)]
public bool stretchFill
{
get
{
return m_CropFrame == CropFrame.StretchFill;
}
set
{
if (value)
m_CropFrame = CropFrame.StretchFill;
else
m_CropFrame = CropFrame.Windowbox;
}
}
/// <summary>
/// Ratio of the rendered Sprites compared to their original size (readonly).
/// </summary>
public int pixelRatio
{
get
{
if (m_CinemachineCompatibilityMode)
{
if (m_GridSnapping == GridSnapping.UpscaleRenderTexture)
return m_Internal.zoom * m_Internal.cinemachineVCamZoom;
else
return m_Internal.cinemachineVCamZoom;
}
else
{
return m_Internal.zoom;
}
}
}
/// <summary>
/// Round a arbitrary position to an integer pixel position. Works in world space.
/// </summary>
/// <param name="position"> The position you want to round.</param>
/// <returns>
/// The rounded pixel position.
/// Depending on the values of upscaleRT and pixelSnapping, it could be a screen pixel position or an art pixel position.
/// </returns>
public Vector3 RoundToPixel(Vector3 position)
{
float unitsPerPixel = m_Internal.unitsPerPixel;
if (unitsPerPixel == 0.0f)
return position;
Vector3 result;
result.x = Mathf.Round(position.x / unitsPerPixel) * unitsPerPixel;
result.y = Mathf.Round(position.y / unitsPerPixel) * unitsPerPixel;
result.z = Mathf.Round(position.z / unitsPerPixel) * unitsPerPixel;
return result;
}
/// <summary>
/// Find a pixel-perfect orthographic size as close to targetOrthoSize as possible. Used by Cinemachine to solve compatibility issues with Pixel Perfect Camera.
/// </summary>
/// <param name="targetOrthoSize">Orthographic size from the live Cinemachine Virtual Camera.</param>
/// <returns>The corrected orthographic size.</returns>
public float CorrectCinemachineOrthoSize(float targetOrthoSize)
{
m_CinemachineCompatibilityMode = true;
if (m_Internal == null)
return targetOrthoSize;
else
return m_Internal.CorrectCinemachineOrthoSize(targetOrthoSize);
}
[SerializeField] int m_AssetsPPU = 100;
[SerializeField] int m_RefResolutionX = 320;
[SerializeField] int m_RefResolutionY = 180;
[SerializeField] CropFrame m_CropFrame;
[SerializeField] GridSnapping m_GridSnapping;
// These are obsolete. They are here only for migration.
#if UNITY_EDITOR
[SerializeField] bool m_UpscaleRT;
[SerializeField] bool m_PixelSnapping;
[SerializeField] bool m_CropFrameX;
[SerializeField] bool m_CropFrameY;
[SerializeField] bool m_StretchFill;
#endif
Camera m_Camera;
PixelPerfectCameraInternal m_Internal;
bool m_CinemachineCompatibilityMode;
internal FilterMode finalBlitFilterMode
{
get
{
return m_Internal.useStretchFill ? FilterMode.Bilinear : FilterMode.Point;
}
}
internal Vector2Int offscreenRTSize
{
get
{
return new Vector2Int(m_Internal.offscreenRTWidth, m_Internal.offscreenRTHeight);
}
}
Vector2Int cameraRTSize
{
get
{
var targetTexture = m_Camera.targetTexture;
return targetTexture == null ? new Vector2Int(Screen.width, Screen.height) : new Vector2Int(targetTexture.width, targetTexture.height);
}
}
// Snap camera position to pixels using Camera.worldToCameraMatrix.
void PixelSnap()
{
Vector3 cameraPosition = m_Camera.transform.position;
Vector3 roundedCameraPosition = RoundToPixel(cameraPosition);
Vector3 offset = roundedCameraPosition - cameraPosition;
offset.z = -offset.z;
Matrix4x4 offsetMatrix = Matrix4x4.TRS(-offset, Quaternion.identity, new Vector3(1.0f, 1.0f, -1.0f));
m_Camera.worldToCameraMatrix = offsetMatrix * m_Camera.transform.worldToLocalMatrix;
}
void Awake()
{
m_Camera = GetComponent<Camera>();
m_Internal = new PixelPerfectCameraInternal(this);
// Case 1249076: Initialize internals immediately after the scene is loaded,
// as the Cinemachine extension may need them before OnBeginContextRendering is called.
UpdateCameraProperties();
}
void UpdateCameraProperties()
{
var rtSize = cameraRTSize;
m_Internal.CalculateCameraProperties(rtSize.x, rtSize.y);
if (m_Internal.useOffscreenRT)
m_Camera.pixelRect = m_Internal.CalculateFinalBlitPixelRect(rtSize.x, rtSize.y);
else
m_Camera.rect = new Rect(0.0f, 0.0f, 1.0f, 1.0f);
}
void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
{
if (camera == m_Camera)
{
UpdateCameraProperties();
PixelSnap();
if (!m_CinemachineCompatibilityMode)
{
m_Camera.orthographicSize = m_Internal.orthoSize;
}
UnityEngine.U2D.PixelPerfectRendering.pixelSnapSpacing = m_Internal.unitsPerPixel;
}
}
void OnEndCameraRendering(ScriptableRenderContext context, Camera camera)
{
if (camera == m_Camera)
UnityEngine.U2D.PixelPerfectRendering.pixelSnapSpacing = 0.0f;
}
void OnEnable()
{
m_CinemachineCompatibilityMode = false;
RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
RenderPipelineManager.endCameraRendering += OnEndCameraRendering;
}
internal void OnDisable()
{
RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
RenderPipelineManager.endCameraRendering -= OnEndCameraRendering;
m_Camera.rect = new Rect(0.0f, 0.0f, 1.0f, 1.0f);
m_Camera.ResetWorldToCameraMatrix();
}
#if DEVELOPMENT_BUILD || UNITY_EDITOR
// Show on-screen warning about invalid render resolutions.
void OnGUI()
{
Color oldColor = GUI.color;
GUI.color = Color.red;
Vector2Int renderResolution = Vector2Int.zero;
renderResolution.x = m_Internal.useOffscreenRT ? m_Internal.offscreenRTWidth : m_Camera.pixelWidth;
renderResolution.y = m_Internal.useOffscreenRT ? m_Internal.offscreenRTHeight : m_Camera.pixelHeight;
if (renderResolution.x % 2 != 0 || renderResolution.y % 2 != 0)
{
string warning = string.Format("Rendering at an odd-numbered resolution ({0} * {1}). Pixel Perfect Camera may not work properly in this situation.", renderResolution.x, renderResolution.y);
GUILayout.Box(warning);
}
var targetTexture = m_Camera.targetTexture;
Vector2Int rtSize = targetTexture == null ? new Vector2Int(Screen.width, Screen.height) : new Vector2Int(targetTexture.width, targetTexture.height);
if (rtSize.x < refResolutionX || rtSize.y < refResolutionY)
{
GUILayout.Box("Target resolution is smaller than the reference resolution. Image may appear stretched or cropped.");
}
GUI.color = oldColor;
}
#endif
public void OnBeforeSerialize()
{
#if UNITY_EDITOR
m_ComponentVersion = k_CurrentComponentVersion;
#endif
}
public void OnAfterDeserialize()
{
#if UNITY_EDITOR
// Upgrade from no serialized version
if (m_ComponentVersion == ComponentVersions.Version_Unserialized)
{
if (m_UpscaleRT)
m_GridSnapping = GridSnapping.UpscaleRenderTexture;
else if (m_PixelSnapping)
m_GridSnapping = GridSnapping.PixelSnapping;
if (m_CropFrameX && m_CropFrameY)
{
if (m_StretchFill)
m_CropFrame = CropFrame.StretchFill;
else
m_CropFrame = CropFrame.Windowbox;
}
else if (m_CropFrameX)
{
m_CropFrame = CropFrame.Pillarbox;
}
else if (m_CropFrameY)
{
m_CropFrame = CropFrame.Letterbox;
}
else
{
m_CropFrame = CropFrame.None;
}
m_ComponentVersion = ComponentVersions.Version_1;
}
#endif
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c88f5cead0c0b2a4eb05b5900433f8d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 7cba34d70552e144586a4d3ce4a33de5, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,236 @@
using System;
using UnityEngine.Experimental.Rendering.Universal;
namespace UnityEngine.Rendering.Universal
{
internal interface IPixelPerfectCamera
{
int assetsPPU { get; set; }
int refResolutionX { get; set; }
int refResolutionY { get; set; }
bool upscaleRT { get; set; }
bool pixelSnapping { get; set; }
bool cropFrameX { get; set; }
bool cropFrameY { get; set; }
bool stretchFill { get; set; }
}
[Serializable]
internal class PixelPerfectCameraInternal : ISerializationCallbackReceiver
{
// Case 1061634:
// In order for this class to survive hot reloading, we need to make the fields serializable.
// Unity can't serialize an interface object, but does properly serialize UnityEngine.Object.
// So we cast the reference to PixelPerfectCamera (which inherits UnityEngine.Object)
// before serialization happens, and restore the interface reference after deserialization.
[NonSerialized]
IPixelPerfectCamera m_Component;
PixelPerfectCamera m_SerializableComponent;
internal float originalOrthoSize;
internal bool hasPostProcessLayer;
internal bool cropFrameXAndY = false;
internal bool cropFrameXOrY = false;
internal bool useStretchFill = false;
internal int zoom = 1;
internal bool useOffscreenRT = false;
internal int offscreenRTWidth = 0;
internal int offscreenRTHeight = 0;
internal Rect pixelRect = Rect.zero;
internal float orthoSize = 1.0f;
internal float unitsPerPixel = 0.0f;
internal int cinemachineVCamZoom = 1;
internal PixelPerfectCameraInternal(IPixelPerfectCamera component)
{
m_Component = component;
}
public void OnBeforeSerialize()
{
m_SerializableComponent = m_Component as PixelPerfectCamera;
}
public void OnAfterDeserialize()
{
if (m_SerializableComponent != null)
m_Component = m_SerializableComponent;
}
internal void CalculateCameraProperties(int screenWidth, int screenHeight)
{
int assetsPPU = m_Component.assetsPPU;
int refResolutionX = m_Component.refResolutionX;
int refResolutionY = m_Component.refResolutionY;
bool upscaleRT = m_Component.upscaleRT;
bool pixelSnapping = m_Component.pixelSnapping;
bool cropFrameX = m_Component.cropFrameX;
bool cropFrameY = m_Component.cropFrameY;
bool stretchFill = m_Component.stretchFill;
cropFrameXAndY = cropFrameY && cropFrameX;
cropFrameXOrY = cropFrameY || cropFrameX;
useStretchFill = cropFrameXAndY && stretchFill;
// zoom level (PPU scale)
int verticalZoom = screenHeight / refResolutionY;
int horizontalZoom = screenWidth / refResolutionX;
zoom = Math.Max(1, Math.Min(verticalZoom, horizontalZoom));
// off-screen RT
useOffscreenRT = false;
offscreenRTWidth = 0;
offscreenRTHeight = 0;
if (cropFrameXOrY)
{
useOffscreenRT = true;
if (!upscaleRT)
{
if (cropFrameXAndY)
{
offscreenRTWidth = zoom * refResolutionX;
offscreenRTHeight = zoom * refResolutionY;
}
else if (cropFrameY)
{
offscreenRTWidth = screenWidth;
offscreenRTHeight = zoom * refResolutionY;
}
else // crop frame X
{
offscreenRTWidth = zoom * refResolutionX;
offscreenRTHeight = screenHeight;
}
}
else
{
if (cropFrameXAndY)
{
offscreenRTWidth = refResolutionX;
offscreenRTHeight = refResolutionY;
}
else if (cropFrameY)
{
offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
offscreenRTHeight = refResolutionY;
}
else // crop frame X
{
offscreenRTWidth = refResolutionX;
offscreenRTHeight = screenHeight / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
}
}
}
else if (upscaleRT && zoom > 1)
{
useOffscreenRT = true;
offscreenRTWidth = screenWidth / zoom / 2 * 2; // Make sure it's an even number by / 2 * 2.
offscreenRTHeight = screenHeight / zoom / 2 * 2;
}
// viewport
if (useOffscreenRT)
{
// When we ask the render pipeline to create the offscreen RT for us, the size of the RT is determined by VP size.
// That's why we set the VP size to be (m_OffscreenRTWidth, m_OffscreenRTHeight) here.
pixelRect = new Rect(0.0f, 0.0f, offscreenRTWidth, offscreenRTHeight);
}
else
pixelRect = Rect.zero;
// orthographic size
if (cropFrameY)
orthoSize = (refResolutionY * 0.5f) / assetsPPU;
else if (cropFrameX)
{
float aspect = (pixelRect == Rect.zero) ? (float)screenWidth / screenHeight : pixelRect.width / pixelRect.height;
orthoSize = ((refResolutionX / aspect) * 0.5f) / assetsPPU;
}
else if (upscaleRT && zoom > 1)
orthoSize = (offscreenRTHeight * 0.5f) / assetsPPU;
else
{
float pixelHeight = (pixelRect == Rect.zero) ? screenHeight : pixelRect.height;
orthoSize = (pixelHeight * 0.5f) / (zoom * assetsPPU);
}
// Camera pixel grid spacing
if (upscaleRT || (!upscaleRT && pixelSnapping))
unitsPerPixel = 1.0f / assetsPPU;
else
unitsPerPixel = 1.0f / (zoom * assetsPPU);
}
internal Rect CalculateFinalBlitPixelRect(int screenWidth, int screenHeight)
{
// This VP is used when the internal temp RT is blitted back to screen.
Rect pixelRect = new Rect();
if (useStretchFill)
{
// stretch (fit either width or height)
float screenAspect = (float)screenWidth / screenHeight;
float cameraAspect = (float)m_Component.refResolutionX / m_Component.refResolutionY;
if (screenAspect > cameraAspect)
{
pixelRect.height = screenHeight;
pixelRect.width = screenHeight * cameraAspect;
pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
pixelRect.y = 0;
}
else
{
pixelRect.width = screenWidth;
pixelRect.height = screenWidth / cameraAspect;
pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
pixelRect.x = 0;
}
}
else
{
// center
if (m_Component.upscaleRT)
{
pixelRect.height = zoom * offscreenRTHeight;
pixelRect.width = zoom * offscreenRTWidth;
}
else
{
pixelRect.height = offscreenRTHeight;
pixelRect.width = offscreenRTWidth;
}
pixelRect.x = (screenWidth - (int)pixelRect.width) / 2;
pixelRect.y = (screenHeight - (int)pixelRect.height) / 2;
}
return pixelRect;
}
// Find a pixel-perfect orthographic size as close to targetOrthoSize as possible.
internal float CorrectCinemachineOrthoSize(float targetOrthoSize)
{
float correctedOrthoSize;
if (m_Component.upscaleRT)
{
cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(orthoSize / targetOrthoSize));
correctedOrthoSize = orthoSize / cinemachineVCamZoom;
}
else
{
cinemachineVCamZoom = Math.Max(1, Mathf.RoundToInt(zoom * orthoSize / targetOrthoSize));
correctedOrthoSize = zoom * orthoSize / cinemachineVCamZoom;
}
// In this case the actual zoom level is cinemachineVCamZoom instead of zoom.
if (!m_Component.upscaleRT && !m_Component.pixelSnapping)
unitsPerPixel = 1.0f / (cinemachineVCamZoom * m_Component.assetsPPU);
return correctedOrthoSize;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: adcb49d2b04b1654b85e627fe5dde64f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,285 @@
using UnityEngine.Experimental.Rendering.Universal;
using UnityEngine.Rendering.Universal.Internal;
namespace UnityEngine.Rendering.Universal
{
internal class Renderer2D : ScriptableRenderer
{
Render2DLightingPass m_Render2DLightingPass;
PixelPerfectBackgroundPass m_PixelPerfectBackgroundPass;
FinalBlitPass m_FinalBlitPass;
Light2DCullResult m_LightCullResult;
private static readonly ProfilingSampler m_ProfilingSampler = new ProfilingSampler("Create Camera Textures");
bool m_UseDepthStencilBuffer = true;
bool m_CreateColorTexture;
bool m_CreateDepthTexture;
readonly RenderTargetHandle k_ColorTextureHandle;
readonly RenderTargetHandle k_DepthTextureHandle;
Material m_BlitMaterial;
Material m_SamplingMaterial;
Renderer2DData m_Renderer2DData;
internal bool createColorTexture => m_CreateColorTexture;
internal bool createDepthTexture => m_CreateDepthTexture;
PostProcessPasses m_PostProcessPasses;
internal ColorGradingLutPass colorGradingLutPass { get => m_PostProcessPasses.colorGradingLutPass; }
internal PostProcessPass postProcessPass { get => m_PostProcessPasses.postProcessPass; }
internal PostProcessPass finalPostProcessPass { get => m_PostProcessPasses.finalPostProcessPass; }
internal RenderTargetHandle afterPostProcessColorHandle { get => m_PostProcessPasses.afterPostProcessColor; }
internal RenderTargetHandle colorGradingLutHandle { get => m_PostProcessPasses.colorGradingLut; }
public Renderer2D(Renderer2DData data) : base(data)
{
m_BlitMaterial = CoreUtils.CreateEngineMaterial(data.blitShader);
m_SamplingMaterial = CoreUtils.CreateEngineMaterial(data.samplingShader);
m_Render2DLightingPass = new Render2DLightingPass(data, m_BlitMaterial, m_SamplingMaterial);
// we should determine why clearing the camera target is set so late in the events... sounds like it could be earlier
m_PixelPerfectBackgroundPass = new PixelPerfectBackgroundPass(RenderPassEvent.AfterRenderingTransparents);
m_FinalBlitPass = new FinalBlitPass(RenderPassEvent.AfterRendering + 1, m_BlitMaterial);
m_PostProcessPasses = new PostProcessPasses(data.postProcessData, m_BlitMaterial);
m_UseDepthStencilBuffer = data.useDepthStencilBuffer;
// We probably should declare these names in the base class,
// as they must be the same across all ScriptableRenderer types for camera stacking to work.
k_ColorTextureHandle.Init("_CameraColorTexture");
k_DepthTextureHandle.Init("_CameraDepthAttachment");
m_Renderer2DData = data;
supportedRenderingFeatures = new RenderingFeatures()
{
cameraStacking = true,
};
m_LightCullResult = new Light2DCullResult();
m_Renderer2DData.lightCullResult = m_LightCullResult;
}
protected override void Dispose(bool disposing)
{
m_PostProcessPasses.Dispose();
}
public Renderer2DData GetRenderer2DData()
{
return m_Renderer2DData;
}
void CreateRenderTextures(
ref CameraData cameraData,
bool forceCreateColorTexture,
FilterMode colorTextureFilterMode,
CommandBuffer cmd,
out RenderTargetHandle colorTargetHandle,
out RenderTargetHandle depthTargetHandle)
{
ref var cameraTargetDescriptor = ref cameraData.cameraTargetDescriptor;
if (cameraData.renderType == CameraRenderType.Base)
{
m_CreateColorTexture = forceCreateColorTexture
|| cameraData.postProcessEnabled
|| cameraData.isHdrEnabled
|| cameraData.isSceneViewCamera
|| !cameraData.isDefaultViewport
|| cameraData.requireSrgbConversion
|| !cameraData.resolveFinalTarget
|| m_Renderer2DData.useCameraSortingLayerTexture
|| !Mathf.Approximately(cameraData.renderScale, 1.0f);
m_CreateDepthTexture = !cameraData.resolveFinalTarget && m_UseDepthStencilBuffer;
colorTargetHandle = m_CreateColorTexture ? k_ColorTextureHandle : RenderTargetHandle.CameraTarget;
depthTargetHandle = m_CreateDepthTexture ? k_DepthTextureHandle : colorTargetHandle;
if (m_CreateColorTexture)
{
var colorDescriptor = cameraTargetDescriptor;
colorDescriptor.depthBufferBits = m_CreateDepthTexture || !m_UseDepthStencilBuffer ? 0 : 32;
cmd.GetTemporaryRT(k_ColorTextureHandle.id, colorDescriptor, colorTextureFilterMode);
}
if (m_CreateDepthTexture)
{
var depthDescriptor = cameraTargetDescriptor;
depthDescriptor.colorFormat = RenderTextureFormat.Depth;
depthDescriptor.depthBufferBits = 32;
depthDescriptor.bindMS = depthDescriptor.msaaSamples > 1 && !SystemInfo.supportsMultisampleAutoResolve && (SystemInfo.supportsMultisampledTextures != 0);
cmd.GetTemporaryRT(k_DepthTextureHandle.id, depthDescriptor, FilterMode.Point);
}
}
else // Overlay camera
{
// These render textures are created by the base camera, but it's the responsibility of the last overlay camera's ScriptableRenderer
// to release the textures in its FinishRendering().
m_CreateColorTexture = true;
m_CreateDepthTexture = true;
colorTargetHandle = k_ColorTextureHandle;
depthTargetHandle = k_DepthTextureHandle;
}
}
public override void Setup(ScriptableRenderContext context, ref RenderingData renderingData)
{
ref CameraData cameraData = ref renderingData.cameraData;
ref var cameraTargetDescriptor = ref cameraData.cameraTargetDescriptor;
bool stackHasPostProcess = renderingData.postProcessingEnabled;
bool lastCameraInStack = cameraData.resolveFinalTarget;
var colorTextureFilterMode = FilterMode.Bilinear;
PixelPerfectCamera ppc = null;
bool ppcUsesOffscreenRT = false;
bool ppcUpscaleRT = false;
bool savedIsOrthographic = renderingData.cameraData.camera.orthographic;
float savedOrthographicSize = renderingData.cameraData.camera.orthographicSize;
if (DebugHandler != null)
{
#if UNITY_EDITOR
UnityEditorInternal.SpriteMaskUtility.EnableDebugMode(DebugHandler.DebugDisplaySettings.MaterialSettings.DebugMaterialModeData == DebugMaterialMode.SpriteMask);
#endif
if (DebugHandler.AreAnySettingsActive)
{
stackHasPostProcess = stackHasPostProcess && DebugHandler.IsPostProcessingAllowed;
}
DebugHandler.Setup(context, ref cameraData);
}
#if UNITY_EDITOR
// The scene view camera cannot be uninitialized or skybox when using the 2D renderer.
if (cameraData.cameraType == CameraType.SceneView)
{
renderingData.cameraData.camera.clearFlags = CameraClearFlags.SolidColor;
}
#endif
// Pixel Perfect Camera doesn't support camera stacking.
if (cameraData.renderType == CameraRenderType.Base && lastCameraInStack)
{
cameraData.camera.TryGetComponent(out ppc);
if (ppc != null && ppc.enabled)
{
if (ppc.offscreenRTSize != Vector2Int.zero)
{
ppcUsesOffscreenRT = true;
// Pixel Perfect Camera may request a different RT size than camera VP size.
// In that case we need to modify cameraTargetDescriptor here so that all the passes would use the same size.
cameraTargetDescriptor.width = ppc.offscreenRTSize.x;
cameraTargetDescriptor.height = ppc.offscreenRTSize.y;
}
renderingData.cameraData.camera.orthographic = true;
renderingData.cameraData.camera.orthographicSize = ppc.orthographicSize;
colorTextureFilterMode = ppc.finalBlitFilterMode;
ppcUpscaleRT = ppc.gridSnapping == PixelPerfectCamera.GridSnapping.UpscaleRenderTexture;
}
}
RenderTargetHandle colorTargetHandle;
RenderTargetHandle depthTargetHandle;
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
CreateRenderTextures(ref cameraData, ppcUsesOffscreenRT, colorTextureFilterMode, cmd,
out colorTargetHandle, out depthTargetHandle);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
ConfigureCameraTarget(colorTargetHandle.Identifier(), depthTargetHandle.Identifier());
// Add passes from Renderer Features. - NOTE: This should be reexamined in the future. Please see feedback from this PR https://github.com/Unity-Technologies/Graphics/pull/3147/files
isCameraColorTargetValid = true; // This is to make it possible to call ScriptableRenderer.cameraColorTarget in the custom passes.
AddRenderPasses(ref renderingData);
isCameraColorTargetValid = false;
// We generate color LUT in the base camera only. This allows us to not break render pass execution for overlay cameras.
if (stackHasPostProcess && cameraData.renderType == CameraRenderType.Base && m_PostProcessPasses.isCreated)
{
colorGradingLutPass.Setup(colorGradingLutHandle);
EnqueuePass(colorGradingLutPass);
}
var needsDepth = m_CreateDepthTexture || (!m_CreateColorTexture && m_UseDepthStencilBuffer);
m_Render2DLightingPass.Setup(needsDepth);
m_Render2DLightingPass.ConfigureTarget(colorTargetHandle.Identifier(), depthTargetHandle.Identifier());
EnqueuePass(m_Render2DLightingPass);
// When using Upscale Render Texture on a Pixel Perfect Camera, we want all post-processing effects done with a low-res RT,
// and only upscale the low-res RT to fullscreen when blitting it to camera target. Also, final post processing pass is not run in this case,
// so FXAA is not supported (you don't want to apply FXAA when everything is intentionally pixelated).
bool requireFinalPostProcessPass =
lastCameraInStack && !ppcUpscaleRT && stackHasPostProcess && cameraData.antialiasing == AntialiasingMode.FastApproximateAntialiasing;
bool hasPassesAfterPostProcessing = activeRenderPassQueue.Find(x => x.renderPassEvent == RenderPassEvent.AfterRenderingPostProcessing) != null;
if (stackHasPostProcess && m_PostProcessPasses.isCreated)
{
RenderTargetHandle postProcessDestHandle =
lastCameraInStack && !ppcUpscaleRT && !requireFinalPostProcessPass ? RenderTargetHandle.CameraTarget : afterPostProcessColorHandle;
postProcessPass.Setup(
cameraTargetDescriptor,
colorTargetHandle,
postProcessDestHandle,
depthTargetHandle,
colorGradingLutHandle,
requireFinalPostProcessPass,
postProcessDestHandle == RenderTargetHandle.CameraTarget,
hasPassesAfterPostProcessing);
EnqueuePass(postProcessPass);
colorTargetHandle = postProcessDestHandle;
}
if (ppc != null && ppc.enabled && (ppc.cropFrame == PixelPerfectCamera.CropFrame.Pillarbox || ppc.cropFrame == PixelPerfectCamera.CropFrame.Letterbox || ppc.cropFrame == PixelPerfectCamera.CropFrame.Windowbox || ppc.cropFrame == PixelPerfectCamera.CropFrame.StretchFill))
{
m_PixelPerfectBackgroundPass.Setup(savedIsOrthographic, savedOrthographicSize);
EnqueuePass(m_PixelPerfectBackgroundPass);
}
if (requireFinalPostProcessPass && m_PostProcessPasses.isCreated)
{
finalPostProcessPass.SetupFinalPass(colorTargetHandle, hasPassesAfterPostProcessing);
EnqueuePass(finalPostProcessPass);
}
else if (lastCameraInStack && colorTargetHandle != RenderTargetHandle.CameraTarget)
{
m_FinalBlitPass.Setup(cameraTargetDescriptor, colorTargetHandle);
EnqueuePass(m_FinalBlitPass);
}
}
public override void SetupCullingParameters(ref ScriptableCullingParameters cullingParameters, ref CameraData cameraData)
{
cullingParameters.cullingOptions = CullingOptions.None;
cullingParameters.isOrthographic = cameraData.camera.orthographic;
cullingParameters.shadowDistance = 0.0f;
m_LightCullResult.SetupCulling(ref cullingParameters, cameraData.camera);
}
public override void FinishRendering(CommandBuffer cmd)
{
if (m_CreateColorTexture)
cmd.ReleaseTemporaryRT(k_ColorTextureHandle.id);
if (m_CreateDepthTexture)
cmd.ReleaseTemporaryRT(k_DepthTextureHandle.id);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2c8841d47fff7714cb6671d40620dea6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using UnityEngine.Scripting.APIUpdating;
using UnityEngine.Serialization;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.ProjectWindowCallback;
#endif
namespace UnityEngine.Rendering.Universal
{
[Serializable, ReloadGroup, ExcludeFromPreset]
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@latest/index.html?subfolder=/manual/2DRendererData_overview.html")]
public partial class Renderer2DData : ScriptableRendererData
{
internal enum Renderer2DDefaultMaterialType
{
Lit,
Unlit,
Custom
}
[SerializeField]
TransparencySortMode m_TransparencySortMode = TransparencySortMode.Default;
[SerializeField]
Vector3 m_TransparencySortAxis = Vector3.up;
[SerializeField]
float m_HDREmulationScale = 1;
[SerializeField, Range(0.01f, 1.0f)]
float m_LightRenderTextureScale = 0.5f;
[SerializeField, FormerlySerializedAs("m_LightOperations")]
Light2DBlendStyle[] m_LightBlendStyles = null;
[SerializeField]
bool m_UseDepthStencilBuffer = true;
[SerializeField]
bool m_UseCameraSortingLayersTexture = false;
[SerializeField]
int m_CameraSortingLayersTextureBound = 0;
[SerializeField]
Downsampling m_CameraSortingLayerDownsamplingMethod = Downsampling.None;
[SerializeField]
uint m_MaxLightRenderTextureCount = 16;
[SerializeField]
uint m_MaxShadowRenderTextureCount = 1;
[SerializeField, Reload("Shaders/2D/Light2D-Shape.shader")]
Shader m_ShapeLightShader = null;
[SerializeField, Reload("Shaders/2D/Light2D-Shape-Volumetric.shader")]
Shader m_ShapeLightVolumeShader = null;
[SerializeField, Reload("Shaders/2D/Light2D-Point.shader")]
Shader m_PointLightShader = null;
[SerializeField, Reload("Shaders/2D/Light2D-Point-Volumetric.shader")]
Shader m_PointLightVolumeShader = null;
[SerializeField, Reload("Shaders/Utils/Blit.shader")]
Shader m_BlitShader = null;
[SerializeField, Reload("Shaders/Utils/Sampling.shader")]
Shader m_SamplingShader = null;
[SerializeField, Reload("Shaders/2D/Shadow2D-Projected.shader")]
Shader m_ProjectedShadowShader = null;
[SerializeField, Reload("Shaders/2D/Shadow2D-Shadow-Sprite.shader")]
Shader m_SpriteShadowShader = null;
[SerializeField, Reload("Shaders/2D/Shadow2D-Unshadow-Sprite.shader")]
Shader m_SpriteUnshadowShader = null;
[SerializeField, Reload("Shaders/2D/Shadow2D-Unshadow-Geometry.shader")]
Shader m_GeometryUnshadowShader = null;
[SerializeField, Reload("Shaders/Utils/FallbackError.shader")]
Shader m_FallbackErrorShader;
[SerializeField]
PostProcessData m_PostProcessData = null;
[SerializeField, Reload("Runtime/2D/Data/Textures/FalloffLookupTexture.png")]
[HideInInspector]
private Texture2D m_FallOffLookup = null;
/// <summary>
/// HDR Emulation Scale allows platforms to use HDR lighting by compressing the number of expressible colors in exchange for extra intensity range.
/// Scale describes this extra intensity range. Increasing this value too high may cause undesirable banding to occur.
/// </summary>
public float hdrEmulationScale => m_HDREmulationScale;
internal float lightRenderTextureScale => m_LightRenderTextureScale;
/// <summary>
/// Returns a list Light2DBlendStyle
/// </summary>
public Light2DBlendStyle[] lightBlendStyles => m_LightBlendStyles;
internal bool useDepthStencilBuffer => m_UseDepthStencilBuffer;
internal Texture2D fallOffLookup => m_FallOffLookup;
internal Shader shapeLightShader => m_ShapeLightShader;
internal Shader shapeLightVolumeShader => m_ShapeLightVolumeShader;
internal Shader pointLightShader => m_PointLightShader;
internal Shader pointLightVolumeShader => m_PointLightVolumeShader;
internal Shader blitShader => m_BlitShader;
internal Shader samplingShader => m_SamplingShader;
internal PostProcessData postProcessData { get => m_PostProcessData; set { m_PostProcessData = value; } }
internal Shader spriteShadowShader => m_SpriteShadowShader;
internal Shader spriteUnshadowShader => m_SpriteUnshadowShader;
internal Shader geometryUnshadowShader => m_GeometryUnshadowShader;
internal Shader projectedShadowShader => m_ProjectedShadowShader;
internal TransparencySortMode transparencySortMode => m_TransparencySortMode;
internal Vector3 transparencySortAxis => m_TransparencySortAxis;
internal uint lightRenderTextureMemoryBudget => m_MaxLightRenderTextureCount;
internal uint shadowRenderTextureMemoryBudget => m_MaxShadowRenderTextureCount;
internal bool useCameraSortingLayerTexture => m_UseCameraSortingLayersTexture;
internal int cameraSortingLayerTextureBound => m_CameraSortingLayersTextureBound;
internal Downsampling cameraSortingLayerDownsamplingMethod => m_CameraSortingLayerDownsamplingMethod;
protected override ScriptableRenderer Create()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
ReloadAllNullProperties();
}
#endif
return new Renderer2D(this);
}
protected override void OnEnable()
{
base.OnEnable();
for (var i = 0; i < m_LightBlendStyles.Length; ++i)
{
m_LightBlendStyles[i].renderTargetHandle.Init($"_ShapeLightTexture{i}");
}
normalsRenderTarget.Init("_NormalMap");
shadowsRenderTarget.Init("_ShadowTex");
spriteSelfShadowMaterial = null;
spriteUnshadowMaterial = null;
projectedShadowMaterial = null;
stencilOnlyShadowMaterial = null;
}
// transient data
internal Dictionary<uint, Material> lightMaterials { get; } = new Dictionary<uint, Material>();
internal Material[] spriteSelfShadowMaterial { get; set; }
internal Material[] spriteUnshadowMaterial { get; set; }
internal Material[] geometryUnshadowMaterial { get; set; }
internal Material[] projectedShadowMaterial { get; set; }
internal Material[] stencilOnlyShadowMaterial { get; set; }
internal bool isNormalsRenderTargetValid { get; set; }
internal float normalsRenderTargetScale { get; set; }
internal RenderTargetHandle normalsRenderTarget;
internal RenderTargetHandle shadowsRenderTarget;
internal RenderTargetHandle cameraSortingLayerRenderTarget;
// this shouldn've been in RenderingData along with other cull results
internal ILight2DCullResult lightCullResult { get; set; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 11145981673336645838492a2d98e247
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,111 @@
using UnityEditor;
namespace UnityEngine.Rendering.Universal
{
public partial class Renderer2DData
{
#if UNITY_EDITOR
[SerializeField]
Renderer2DDefaultMaterialType m_DefaultMaterialType = Renderer2DDefaultMaterialType.Lit;
[SerializeField, Reload("Runtime/Materials/Sprite-Lit-Default.mat")]
Material m_DefaultCustomMaterial = null;
[SerializeField, Reload("Runtime/Materials/Sprite-Lit-Default.mat")]
Material m_DefaultLitMaterial = null;
[SerializeField, Reload("Runtime/Materials/Sprite-Unlit-Default.mat")]
Material m_DefaultUnlitMaterial = null;
[SerializeField, Reload("Runtime/Materials/SpriteMask-Default.mat")]
Material m_DefaultMaskMaterial = null;
internal override Shader GetDefaultShader()
{
return Shader.Find("Universal Render Pipeline/2D/Sprite-Lit-Default");
}
internal override Material GetDefaultMaterial(DefaultMaterialType materialType)
{
if (materialType == DefaultMaterialType.Sprite || materialType == DefaultMaterialType.Particle)
{
if (m_DefaultMaterialType == Renderer2DDefaultMaterialType.Lit)
return m_DefaultLitMaterial;
else if (m_DefaultMaterialType == Renderer2DDefaultMaterialType.Unlit)
return m_DefaultUnlitMaterial;
else
return m_DefaultCustomMaterial;
}
if (materialType == DefaultMaterialType.SpriteMask)
{
return m_DefaultMaskMaterial;
}
return null;
}
private void OnEnableInEditor()
{
// Provide a list of suggested texture property names to Sprite Editor via EditorPrefs.
const string suggestedNamesKey = "SecondarySpriteTexturePropertyNames";
const string maskTex = "_MaskTex";
const string normalMap = "_NormalMap";
string suggestedNamesPrefs = EditorPrefs.GetString(suggestedNamesKey);
if (string.IsNullOrEmpty(suggestedNamesPrefs))
EditorPrefs.SetString(suggestedNamesKey, maskTex + "," + normalMap);
else
{
if (!suggestedNamesPrefs.Contains(maskTex))
suggestedNamesPrefs += ("," + maskTex);
if (!suggestedNamesPrefs.Contains(normalMap))
suggestedNamesPrefs += ("," + normalMap);
EditorPrefs.SetString(suggestedNamesKey, suggestedNamesPrefs);
}
ReloadAllNullProperties();
}
private void ReloadAllNullProperties()
{
ResourceReloader.TryReloadAllNullIn(this, UniversalRenderPipelineAsset.packagePath);
}
private void Awake()
{
if (m_LightBlendStyles != null)
{
for (int i = 0; i < m_LightBlendStyles.Length; ++i)
{
ref var blendStyle = ref m_LightBlendStyles[i];
// Custom blend mode (99) now falls back to Multiply.
if ((int)blendStyle.blendMode == 99)
blendStyle.blendMode = Light2DBlendStyle.BlendMode.Multiply;
}
return;
}
m_LightBlendStyles = new Light2DBlendStyle[4];
m_LightBlendStyles[0].name = "Multiply";
m_LightBlendStyles[0].blendMode = Light2DBlendStyle.BlendMode.Multiply;
m_LightBlendStyles[1].name = "Additive";
m_LightBlendStyles[1].blendMode = Light2DBlendStyle.BlendMode.Additive;
m_LightBlendStyles[2].name = "Multiply with Mask";
m_LightBlendStyles[2].blendMode = Light2DBlendStyle.BlendMode.Multiply;
m_LightBlendStyles[2].maskTextureChannel = Light2DBlendStyle.TextureChannel.R;
m_LightBlendStyles[3].name = "Additive with Mask";
m_LightBlendStyles[3].blendMode = Light2DBlendStyle.BlendMode.Additive;
m_LightBlendStyles[3].maskTextureChannel = Light2DBlendStyle.TextureChannel.R;
}
#endif
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c64a6e813af443b4864441f640dd1c9f
timeCreated: 1596423828

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5f7294749d1800e4daee980df3e624da
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,21 @@
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Rendering.Universal
{
[AddComponentMenu("Rendering/2D/Composite Shadow Caster 2D")]
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
[ExecuteInEditMode]
public class CompositeShadowCaster2D : ShadowCasterGroup2D
{
protected void OnEnable()
{
ShadowCasterGroup2DManager.AddGroup(this);
}
protected void OnDisable()
{
ShadowCasterGroup2DManager.RemoveGroup(this);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38f48a8d66b2adc46887f23a3a88ac01
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,249 @@
using System;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Class <c>ShadowCaster2D</c> contains properties used for shadow casting
/// </summary>
[ExecuteInEditMode]
[DisallowMultipleComponent]
[AddComponentMenu("Rendering/2D/Shadow Caster 2D")]
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
public class ShadowCaster2D : ShadowCasterGroup2D, ISerializationCallbackReceiver
{
public enum ComponentVersions
{
Version_Unserialized = 0,
Version_1 = 1
}
const ComponentVersions k_CurrentComponentVersion = ComponentVersions.Version_1;
[SerializeField] ComponentVersions m_ComponentVersion = ComponentVersions.Version_Unserialized;
[SerializeField] bool m_HasRenderer = false;
[SerializeField] bool m_UseRendererSilhouette = true;
[SerializeField] bool m_CastsShadows = true;
[SerializeField] bool m_SelfShadows = false;
[SerializeField] int[] m_ApplyToSortingLayers = null;
[SerializeField] Vector3[] m_ShapePath = null;
[SerializeField] int m_ShapePathHash = 0;
[SerializeField] Mesh m_Mesh;
[SerializeField] int m_InstanceId;
internal ShadowCasterGroup2D m_ShadowCasterGroup = null;
internal ShadowCasterGroup2D m_PreviousShadowCasterGroup = null;
[SerializeField]
internal BoundingSphere m_ProjectedBoundingSphere;
public Mesh mesh => m_Mesh;
public Vector3[] shapePath => m_ShapePath;
internal int shapePathHash { get { return m_ShapePathHash; } set { m_ShapePathHash = value; } }
int m_PreviousShadowGroup = 0;
bool m_PreviousCastsShadows = true;
int m_PreviousPathHash = 0;
internal Vector3 m_CachedPosition;
internal Vector3 m_CachedLossyScale;
internal Quaternion m_CachedRotation;
internal Matrix4x4 m_CachedShadowMatrix;
internal Matrix4x4 m_CachedInverseShadowMatrix;
internal Matrix4x4 m_CachedLocalToWorldMatrix;
internal override void CacheValues()
{
m_CachedPosition = transform.position;
m_CachedLossyScale = transform.lossyScale;
m_CachedRotation = transform.rotation;
m_CachedShadowMatrix = Matrix4x4.TRS(m_CachedPosition, m_CachedRotation, Vector3.one);
m_CachedInverseShadowMatrix = m_CachedShadowMatrix.inverse;
m_CachedLocalToWorldMatrix = transform.localToWorldMatrix;
}
/// <summary>
/// If selfShadows is true, useRendererSilhoutte specifies that the renderer's sihouette should be considered part of the shadow. If selfShadows is false, useRendererSilhoutte specifies that the renderer's sihouette should be excluded from the shadow
/// </summary>
public bool useRendererSilhouette
{
set { m_UseRendererSilhouette = value; }
get { return m_UseRendererSilhouette && m_HasRenderer; }
}
/// <summary>
/// If true, the shadow casting shape is included as part of the shadow. If false, the shadow casting shape is excluded from the shadow.
/// </summary>
public bool selfShadows
{
set { m_SelfShadows = value; }
get { return m_SelfShadows; }
}
/// <summary>
/// Specifies if shadows will be cast.
/// </summary>
public bool castsShadows
{
set { m_CastsShadows = value; }
get { return m_CastsShadows; }
}
static int[] SetDefaultSortingLayers()
{
int layerCount = SortingLayer.layers.Length;
int[] allLayers = new int[layerCount];
for (int layerIndex = 0; layerIndex < layerCount; layerIndex++)
{
allLayers[layerIndex] = SortingLayer.layers[layerIndex].id;
}
return allLayers;
}
internal bool IsLit(Light2D light)
{
// Oddly adding and subtracting vectors is expensive here because of the new structures created...
Vector3 deltaPos;
deltaPos.x = m_ProjectedBoundingSphere.position.x + m_CachedPosition.x;
deltaPos.y = m_ProjectedBoundingSphere.position.y + m_CachedPosition.y;
deltaPos.z = m_ProjectedBoundingSphere.position.z + m_CachedPosition.z;
deltaPos.x = light.m_CachedPosition.x - deltaPos.x;
deltaPos.y = light.m_CachedPosition.y - deltaPos.y;
deltaPos.z = light.m_CachedPosition.z - deltaPos.z;
float distanceSq = Vector3.SqrMagnitude(deltaPos);
float radiiLength = light.boundingSphere.radius + m_ProjectedBoundingSphere.radius;
return distanceSq <= (radiiLength * radiiLength);
}
internal bool IsShadowedLayer(int layer)
{
return m_ApplyToSortingLayers != null ? Array.IndexOf(m_ApplyToSortingLayers, layer) >= 0 : false;
}
private void Awake()
{
if (m_ApplyToSortingLayers == null)
m_ApplyToSortingLayers = SetDefaultSortingLayers();
Bounds bounds = new Bounds(transform.position, Vector3.one);
Renderer renderer = GetComponent<Renderer>();
if (renderer != null)
{
bounds = renderer.bounds;
}
#if USING_PHYSICS2D_MODULE
else
{
Collider2D collider = GetComponent<Collider2D>();
if (collider != null)
bounds = collider.bounds;
}
#endif
Vector3 inverseScale = Vector3.zero;
Vector3 relOffset = transform.position;
if (transform.lossyScale.x != 0 && transform.lossyScale.y != 0)
{
inverseScale = new Vector3(1 / transform.lossyScale.x, 1 / transform.lossyScale.y);
relOffset = new Vector3(inverseScale.x * -transform.position.x, inverseScale.y * -transform.position.y);
}
if (m_ShapePath == null || m_ShapePath.Length == 0)
{
m_ShapePath = new Vector3[]
{
relOffset + new Vector3(inverseScale.x * bounds.min.x, inverseScale.y * bounds.min.y),
relOffset + new Vector3(inverseScale.x * bounds.min.x, inverseScale.y * bounds.max.y),
relOffset + new Vector3(inverseScale.x * bounds.max.x, inverseScale.y * bounds.max.y),
relOffset + new Vector3(inverseScale.x * bounds.max.x, inverseScale.y * bounds.min.y),
};
}
}
protected void OnEnable()
{
if (m_Mesh == null || m_InstanceId != GetInstanceID())
{
m_Mesh = new Mesh();
m_ProjectedBoundingSphere = ShadowUtility.GenerateShadowMesh(m_Mesh, m_ShapePath);
m_InstanceId = GetInstanceID();
}
m_ShadowCasterGroup = null;
}
protected void OnDisable()
{
ShadowCasterGroup2DManager.RemoveFromShadowCasterGroup(this, m_ShadowCasterGroup);
}
public void Update()
{
Renderer renderer;
m_HasRenderer = TryGetComponent<Renderer>(out renderer);
bool rebuildMesh = LightUtility.CheckForChange(m_ShapePathHash, ref m_PreviousPathHash);
if (rebuildMesh)
{
m_ProjectedBoundingSphere = ShadowUtility.GenerateShadowMesh(m_Mesh, m_ShapePath);
}
m_PreviousShadowCasterGroup = m_ShadowCasterGroup;
bool addedToNewGroup = ShadowCasterGroup2DManager.AddToShadowCasterGroup(this, ref m_ShadowCasterGroup);
if (addedToNewGroup && m_ShadowCasterGroup != null)
{
if (m_PreviousShadowCasterGroup == this)
ShadowCasterGroup2DManager.RemoveGroup(this);
ShadowCasterGroup2DManager.RemoveFromShadowCasterGroup(this, m_PreviousShadowCasterGroup);
if (m_ShadowCasterGroup == this)
ShadowCasterGroup2DManager.AddGroup(this);
}
if (LightUtility.CheckForChange(m_ShadowGroup, ref m_PreviousShadowGroup))
{
ShadowCasterGroup2DManager.RemoveGroup(this);
ShadowCasterGroup2DManager.AddGroup(this);
}
if (LightUtility.CheckForChange(m_CastsShadows, ref m_PreviousCastsShadows))
{
if (m_CastsShadows)
ShadowCasterGroup2DManager.AddGroup(this);
else
ShadowCasterGroup2DManager.RemoveGroup(this);
}
}
public void OnBeforeSerialize()
{
m_ComponentVersion = k_CurrentComponentVersion;
}
public void OnAfterDeserialize()
{
// Upgrade from no serialized version
if (m_ComponentVersion == ComponentVersions.Version_Unserialized)
{
ShadowUtility.ComputeBoundingSphere(m_ShapePath, out m_ProjectedBoundingSphere);
m_ComponentVersion = ComponentVersions.Version_1;
}
}
#if UNITY_EDITOR
void Reset()
{
Awake();
OnEnable();
}
#endif
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7db70e0ea77f5ac47a8f4565a9406397
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,37 @@
using System.Collections.Generic;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Rendering.Universal
{
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
public abstract class ShadowCasterGroup2D : MonoBehaviour
{
[SerializeField] internal int m_ShadowGroup = 0;
List<ShadowCaster2D> m_ShadowCasters;
internal virtual void CacheValues()
{
for (int i = 0; i < m_ShadowCasters.Count; i++)
m_ShadowCasters[i].CacheValues();
}
public List<ShadowCaster2D> GetShadowCasters() { return m_ShadowCasters; }
public int GetShadowGroup() { return m_ShadowGroup; }
public void RegisterShadowCaster2D(ShadowCaster2D shadowCaster2D)
{
if (m_ShadowCasters == null)
m_ShadowCasters = new List<ShadowCaster2D>();
m_ShadowCasters.Add(shadowCaster2D);
}
public void UnregisterShadowCaster2D(ShadowCaster2D shadowCaster2D)
{
if (m_ShadowCasters != null)
m_ShadowCasters.Remove(shadowCaster2D);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dfd932337eaf30646ab42d63eed8f822
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,121 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.Rendering.Universal
{
#if UNITY_EDITOR
[InitializeOnLoadAttribute]
#endif
internal class ShadowCasterGroup2DManager
{
static List<ShadowCasterGroup2D> s_ShadowCasterGroups = null;
public static List<ShadowCasterGroup2D> shadowCasterGroups { get { return s_ShadowCasterGroups; } }
#if UNITY_EDITOR
static ShadowCasterGroup2DManager()
{
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
private static void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (s_ShadowCasterGroups != null && (state == PlayModeStateChange.ExitingEditMode || state == PlayModeStateChange.ExitingPlayMode))
s_ShadowCasterGroups.Clear();
}
#endif
public static void CacheValues()
{
if (shadowCasterGroups != null)
{
for (int i = 0; i < shadowCasterGroups.Count; i++)
{
if (shadowCasterGroups[i] != null)
shadowCasterGroups[i].CacheValues();
}
}
}
public static void AddShadowCasterGroupToList(ShadowCasterGroup2D shadowCaster, List<ShadowCasterGroup2D> list)
{
int positionToInsert = 0;
for (positionToInsert = 0; positionToInsert < list.Count; positionToInsert++)
{
if (shadowCaster.GetShadowGroup() == list[positionToInsert].GetShadowGroup())
break;
}
list.Insert(positionToInsert, shadowCaster);
}
public static void RemoveShadowCasterGroupFromList(ShadowCasterGroup2D shadowCaster, List<ShadowCasterGroup2D> list)
{
list.Remove(shadowCaster);
}
static CompositeShadowCaster2D FindTopMostCompositeShadowCaster(ShadowCaster2D shadowCaster)
{
CompositeShadowCaster2D retGroup = null;
Transform transformToCheck = shadowCaster.transform.parent;
while (transformToCheck != null)
{
CompositeShadowCaster2D currentGroup;
if (transformToCheck.TryGetComponent<CompositeShadowCaster2D>(out currentGroup))
retGroup = currentGroup;
transformToCheck = transformToCheck.parent;
}
return retGroup;
}
public static bool AddToShadowCasterGroup(ShadowCaster2D shadowCaster, ref ShadowCasterGroup2D shadowCasterGroup)
{
ShadowCasterGroup2D newShadowCasterGroup = FindTopMostCompositeShadowCaster(shadowCaster) as ShadowCasterGroup2D;
if (newShadowCasterGroup == null)
newShadowCasterGroup = shadowCaster.GetComponent<ShadowCaster2D>();
if (newShadowCasterGroup != null && shadowCasterGroup != newShadowCasterGroup)
{
newShadowCasterGroup.RegisterShadowCaster2D(shadowCaster);
shadowCasterGroup = newShadowCasterGroup;
return true;
}
return false;
}
public static void RemoveFromShadowCasterGroup(ShadowCaster2D shadowCaster, ShadowCasterGroup2D shadowCasterGroup)
{
if (shadowCasterGroup != null)
shadowCasterGroup.UnregisterShadowCaster2D(shadowCaster);
}
public static void AddGroup(ShadowCasterGroup2D group)
{
if (group == null)
return;
if (s_ShadowCasterGroups == null)
s_ShadowCasterGroups = new List<ShadowCasterGroup2D>();
AddShadowCasterGroupToList(group, s_ShadowCasterGroups);
}
public static void RemoveGroup(ShadowCasterGroup2D group)
{
if (group != null && s_ShadowCasterGroups != null)
RemoveShadowCasterGroupFromList(group, s_ShadowCasterGroups);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9d3c965386a423a4b9b2f6b30ecad735
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,343 @@
using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering.Universal
{
// TODO: Culling of shadow casters, rotate color channels for shadow casting, check get material functions.
internal static class ShadowRendering
{
private static readonly int k_LightPosID = Shader.PropertyToID("_LightPos");
private static readonly int k_SelfShadowingID = Shader.PropertyToID("_SelfShadowing");
private static readonly int k_ShadowStencilGroupID = Shader.PropertyToID("_ShadowStencilGroup");
private static readonly int k_ShadowIntensityID = Shader.PropertyToID("_ShadowIntensity");
private static readonly int k_ShadowVolumeIntensityID = Shader.PropertyToID("_ShadowVolumeIntensity");
private static readonly int k_ShadowRadiusID = Shader.PropertyToID("_ShadowRadius");
private static readonly int k_ShadowColorMaskID = Shader.PropertyToID("_ShadowColorMask");
private static readonly int k_ShadowModelMatrixID = Shader.PropertyToID("_ShadowModelMatrix");
private static readonly int k_ShadowModelInvMatrixID = Shader.PropertyToID("_ShadowModelInvMatrix");
private static readonly int k_ShadowModelScaleID = Shader.PropertyToID("_ShadowModelScale");
private static readonly ProfilingSampler m_ProfilingSamplerShadows = new ProfilingSampler("Draw 2D Shadow Texture");
private static readonly ProfilingSampler m_ProfilingSamplerShadowsA = new ProfilingSampler("Draw 2D Shadows (A)");
private static readonly ProfilingSampler m_ProfilingSamplerShadowsR = new ProfilingSampler("Draw 2D Shadows (R)");
private static readonly ProfilingSampler m_ProfilingSamplerShadowsG = new ProfilingSampler("Draw 2D Shadows (G)");
private static readonly ProfilingSampler m_ProfilingSamplerShadowsB = new ProfilingSampler("Draw 2D Shadows (B)");
private static RenderTargetHandle[] m_RenderTargets = null;
private static RenderTargetIdentifier[] m_LightInputTextures = null;
private static readonly Color[] k_ColorLookup = new Color[4] { new Color(0, 0, 0, 1), new Color(0, 0, 1, 0), new Color(0, 1, 0, 0), new Color(1, 0, 0, 0) };
private static readonly ProfilingSampler[] m_ProfilingSamplerShadowColorsLookup = new ProfilingSampler[4] { m_ProfilingSamplerShadowsA, m_ProfilingSamplerShadowsB, m_ProfilingSamplerShadowsG, m_ProfilingSamplerShadowsR };
public static uint maxTextureCount { get; private set; }
public static void InitializeBudget(uint maxTextureCount)
{
if (m_RenderTargets == null || m_RenderTargets.Length != maxTextureCount)
{
m_RenderTargets = new RenderTargetHandle[maxTextureCount];
ShadowRendering.maxTextureCount = maxTextureCount;
for (int i = 0; i < maxTextureCount; i++)
{
unsafe
{
m_RenderTargets[i].id = Shader.PropertyToID($"ShadowTex_{i}");
}
}
}
if (m_LightInputTextures == null || m_LightInputTextures.Length != maxTextureCount)
{
m_LightInputTextures = new RenderTargetIdentifier[maxTextureCount];
}
}
private static Material[] CreateMaterials(Shader shader, int pass = 0)
{
const int k_ColorChannels = 4;
Material[] materials = new Material[k_ColorChannels];
for (int i = 0; i < k_ColorChannels; i++)
{
materials[i] = CoreUtils.CreateEngineMaterial(shader);
materials[i].SetInt(k_ShadowColorMaskID, 1 << i);
materials[i].SetPass(pass);
}
return materials;
}
private static Material GetProjectedShadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.projectedShadowMaterial = null;
if (rendererData.projectedShadowMaterial == null || rendererData.projectedShadowMaterial.Length == 0 || rendererData.projectedShadowShader != rendererData.projectedShadowMaterial[0].shader)
{
rendererData.projectedShadowMaterial = CreateMaterials(rendererData.projectedShadowShader);
}
return rendererData.projectedShadowMaterial[colorIndex];
}
private static Material GetStencilOnlyShadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.stencilOnlyShadowMaterial = null;
if (rendererData.stencilOnlyShadowMaterial == null || rendererData.stencilOnlyShadowMaterial.Length == 0 || rendererData.projectedShadowShader != rendererData.stencilOnlyShadowMaterial[0].shader)
{
rendererData.stencilOnlyShadowMaterial = CreateMaterials(rendererData.projectedShadowShader, 1);
}
return rendererData.stencilOnlyShadowMaterial[colorIndex];
}
private static Material GetSpriteSelfShadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.spriteSelfShadowMaterial = null;
if (rendererData.spriteSelfShadowMaterial == null || rendererData.spriteSelfShadowMaterial.Length == 0 || rendererData.spriteShadowShader != rendererData.spriteSelfShadowMaterial[0].shader)
{
rendererData.spriteSelfShadowMaterial = CreateMaterials(rendererData.spriteShadowShader);
}
return rendererData.spriteSelfShadowMaterial[colorIndex];
}
private static Material GetSpriteUnshadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.spriteUnshadowMaterial = null;
if (rendererData.spriteUnshadowMaterial == null || rendererData.spriteUnshadowMaterial.Length == 0 || rendererData.spriteUnshadowShader != rendererData.spriteUnshadowMaterial[0].shader)
{
rendererData.spriteUnshadowMaterial = CreateMaterials(rendererData.spriteUnshadowShader);
}
return rendererData.spriteUnshadowMaterial[colorIndex];
}
private static Material GetGeometryUnshadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.geometryUnshadowMaterial = null;
if (rendererData.geometryUnshadowMaterial == null || rendererData.geometryUnshadowMaterial.Length == 0 || rendererData.geometryUnshadowShader != rendererData.geometryUnshadowMaterial[0].shader)
{
rendererData.geometryUnshadowMaterial = CreateMaterials(rendererData.geometryUnshadowShader);
}
return rendererData.geometryUnshadowMaterial[colorIndex];
}
public static void CreateShadowRenderTexture(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int shadowIndex)
{
CreateShadowRenderTexture(pass, m_RenderTargets[shadowIndex], renderingData, cmdBuffer);
}
public static bool PrerenderShadows(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int layerToRender, Light2D light, int shadowIndex, float shadowIntensity)
{
var colorChannel = shadowIndex % 4;
var textureIndex = shadowIndex / 4;
if (colorChannel == 0)
ShadowRendering.CreateShadowRenderTexture(pass, renderingData, cmdBuffer, textureIndex);
bool hadShadowsToRender = RenderShadows(pass, renderingData, cmdBuffer, layerToRender, light, shadowIntensity, m_RenderTargets[textureIndex].Identifier(), colorChannel);
// Render the shadows for this light
if (RenderShadows(pass, renderingData, cmdBuffer, layerToRender, light, shadowIntensity, m_RenderTargets[textureIndex].Identifier(), colorChannel))
m_LightInputTextures[textureIndex] = m_RenderTargets[textureIndex].Identifier();
else
m_LightInputTextures[textureIndex] = Texture2D.blackTexture;
return hadShadowsToRender;
}
public static void SetGlobalShadowTexture(CommandBuffer cmdBuffer, Light2D light, int shadowIndex)
{
var colorChannel = shadowIndex % 4;
var textureIndex = shadowIndex / 4;
cmdBuffer.SetGlobalTexture("_ShadowTex", m_LightInputTextures[textureIndex]);
cmdBuffer.SetGlobalColor(k_ShadowColorMaskID, k_ColorLookup[colorChannel]);
cmdBuffer.SetGlobalFloat(k_ShadowIntensityID, 1 - light.shadowIntensity);
cmdBuffer.SetGlobalFloat(k_ShadowVolumeIntensityID, 1 - light.shadowVolumeIntensity);
}
public static void DisableGlobalShadowTexture(CommandBuffer cmdBuffer)
{
cmdBuffer.SetGlobalFloat(k_ShadowIntensityID, 1);
cmdBuffer.SetGlobalFloat(k_ShadowVolumeIntensityID, 1);
}
private static void CreateShadowRenderTexture(IRenderPass2D pass, RenderTargetHandle rtHandle, RenderingData renderingData, CommandBuffer cmdBuffer)
{
var renderTextureScale = Mathf.Clamp(pass.rendererData.lightRenderTextureScale, 0.01f, 1.0f);
var width = (int)(renderingData.cameraData.cameraTargetDescriptor.width * renderTextureScale);
var height = (int)(renderingData.cameraData.cameraTargetDescriptor.height * renderTextureScale);
var descriptor = new RenderTextureDescriptor(width, height);
descriptor.useMipMap = false;
descriptor.autoGenerateMips = false;
descriptor.depthBufferBits = 24;
descriptor.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm;
descriptor.msaaSamples = 1;
descriptor.dimension = TextureDimension.Tex2D;
cmdBuffer.GetTemporaryRT(rtHandle.id, descriptor, FilterMode.Bilinear);
}
public static void ReleaseShadowRenderTexture(CommandBuffer cmdBuffer, int shadowIndex)
{
var colorChannel = shadowIndex % 4;
var textureIndex = shadowIndex / 4;
if (colorChannel == 0)
cmdBuffer.ReleaseTemporaryRT(m_RenderTargets[textureIndex].id);
}
public static void SetShadowProjectionGlobals(CommandBuffer cmdBuffer, ShadowCaster2D shadowCaster)
{
cmdBuffer.SetGlobalVector(k_ShadowModelScaleID, shadowCaster.m_CachedLossyScale);
cmdBuffer.SetGlobalMatrix(k_ShadowModelMatrixID, shadowCaster.m_CachedShadowMatrix);
cmdBuffer.SetGlobalMatrix(k_ShadowModelInvMatrixID, shadowCaster.m_CachedInverseShadowMatrix);
}
public static bool RenderShadows(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int layerToRender, Light2D light, float shadowIntensity, RenderTargetIdentifier renderTexture, int colorBit)
{
using (new ProfilingScope(cmdBuffer, m_ProfilingSamplerShadows))
{
bool hasShadow = false;
var shadowCasterGroups = ShadowCasterGroup2DManager.shadowCasterGroups;
if (shadowCasterGroups != null && shadowCasterGroups.Count > 0)
{
// Before doing anything check to see if any of the shadow casters are visible to this light
for (var group = 0; group < shadowCasterGroups.Count; group++)
{
var shadowCasterGroup = shadowCasterGroups[group];
var shadowCasters = shadowCasterGroup.GetShadowCasters();
if (shadowCasters != null)
{
// Draw the projected shadows for the shadow caster group. Writing into the group stencil buffer bit
for (var i = 0; i < shadowCasters.Count; i++)
{
var shadowCaster = shadowCasters[i];
if (shadowCaster != null && shadowCaster.IsLit(light) && shadowCaster.IsShadowedLayer(layerToRender))
{
hasShadow = true;
break;
}
}
}
}
if (hasShadow)
{
cmdBuffer.SetRenderTarget(renderTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
using (new ProfilingScope(cmdBuffer, m_ProfilingSamplerShadowColorsLookup[colorBit]))
{
if (colorBit == 0)
cmdBuffer.ClearRenderTarget(true, true, Color.clear);
else
cmdBuffer.ClearRenderTarget(true, false, Color.clear);
var shadowRadius = light.boundingSphere.radius;
cmdBuffer.SetGlobalVector(k_LightPosID, light.transform.position);
cmdBuffer.SetGlobalFloat(k_ShadowRadiusID, shadowRadius);
cmdBuffer.SetGlobalColor(k_ShadowColorMaskID, k_ColorLookup[colorBit]);
var unshadowGeometryMaterial = pass.rendererData.GetGeometryUnshadowMaterial(colorBit);
var projectedShadowsMaterial = pass.rendererData.GetProjectedShadowMaterial(colorBit);
var selfShadowMaterial = pass.rendererData.GetSpriteSelfShadowMaterial(colorBit);
var unshadowMaterial = pass.rendererData.GetSpriteUnshadowMaterial(colorBit);
var setGlobalStencilMaterial = pass.rendererData.GetStencilOnlyShadowMaterial(colorBit);
for (var group = 0; group < shadowCasterGroups.Count; group++)
{
var shadowCasterGroup = shadowCasterGroups[group];
var shadowCasters = shadowCasterGroup.GetShadowCasters();
if (shadowCasters != null)
{
for (var i = 0; i < shadowCasters.Count; i++)
{
var shadowCaster = shadowCasters[i];
if (shadowCaster.IsLit(light))
{
if (shadowCaster != null && projectedShadowsMaterial != null && shadowCaster.IsShadowedLayer(layerToRender))
{
if (shadowCaster.castsShadows)
{
SetShadowProjectionGlobals(cmdBuffer, shadowCaster);
cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.m_CachedLocalToWorldMatrix, unshadowGeometryMaterial, 0, 0);
cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.m_CachedLocalToWorldMatrix, projectedShadowsMaterial, 0, 0);
cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.m_CachedLocalToWorldMatrix, unshadowGeometryMaterial, 0, 1);
}
}
}
}
// Draw the sprites, either as self shadowing or unshadowing
for (var i = 0; i < shadowCasters.Count; i++)
{
var shadowCaster = shadowCasters[i];
if (shadowCaster.IsLit(light))
{
if (shadowCaster != null && shadowCaster.IsShadowedLayer(layerToRender))
{
if (shadowCaster.useRendererSilhouette)
{
// Draw using the sprite renderer
var renderer = (Renderer)null;
shadowCaster.TryGetComponent<Renderer>(out renderer);
if (renderer != null)
{
var material = shadowCaster.selfShadows ? selfShadowMaterial : unshadowMaterial;
if (material != null)
cmdBuffer.DrawRenderer(renderer, material);
}
}
else
{
var meshMat = shadowCaster.m_CachedLocalToWorldMatrix;
var material = shadowCaster.selfShadows ? selfShadowMaterial : unshadowMaterial;
// Draw using the shadow mesh
if (material != null)
cmdBuffer.DrawMesh(shadowCaster.mesh, meshMat, material);
}
}
}
}
// Draw the projected shadows for the shadow caster group. Writing clearing the group stencil bit, and setting the global bit
for (var i = 0; i < shadowCasters.Count; i++)
{
var shadowCaster = shadowCasters[i];
if (shadowCaster.IsLit(light))
{
if (shadowCaster != null && projectedShadowsMaterial != null && shadowCaster.IsShadowedLayer(layerToRender))
{
if (shadowCaster.castsShadows)
{
SetShadowProjectionGlobals(cmdBuffer, shadowCaster);
cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.m_CachedLocalToWorldMatrix, projectedShadowsMaterial, 0, 1);
}
}
}
}
}
}
}
}
}
return hasShadow;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d41cfd0a88e7a024797e86c60a0ff961
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,214 @@
using System.Collections.Generic;
using System;
using System.Linq;
using UnityEngine.Rendering.Universal.LibTessDotNet;
namespace UnityEngine.Rendering.Universal
{
internal class ShadowUtility
{
internal struct Edge : IComparable<Edge>
{
public int vertexIndex0;
public int vertexIndex1;
public Vector4 tangent;
private bool compareReversed; // This is done so that edge AB can equal edge BA
public void AssignVertexIndices(int vi0, int vi1)
{
vertexIndex0 = vi0;
vertexIndex1 = vi1;
compareReversed = vi0 > vi1;
}
public int Compare(Edge a, Edge b)
{
int adjustedVertexIndex0A = a.compareReversed ? a.vertexIndex1 : a.vertexIndex0;
int adjustedVertexIndex1A = a.compareReversed ? a.vertexIndex0 : a.vertexIndex1;
int adjustedVertexIndex0B = b.compareReversed ? b.vertexIndex1 : b.vertexIndex0;
int adjustedVertexIndex1B = b.compareReversed ? b.vertexIndex0 : b.vertexIndex1;
// Sort first by VI0 then by VI1
int deltaVI0 = adjustedVertexIndex0A - adjustedVertexIndex0B;
int deltaVI1 = adjustedVertexIndex1A - adjustedVertexIndex1B;
if (deltaVI0 == 0)
return deltaVI1;
else
return deltaVI0;
}
public int CompareTo(Edge edgeToCompare)
{
return Compare(this, edgeToCompare);
}
}
static Edge CreateEdge(int triangleIndexA, int triangleIndexB, List<Vector3> vertices, List<int> triangles)
{
Edge retEdge = new Edge();
retEdge.AssignVertexIndices(triangles[triangleIndexA], triangles[triangleIndexB]);
Vector3 vertex0 = vertices[retEdge.vertexIndex0];
vertex0.z = 0;
Vector3 vertex1 = vertices[retEdge.vertexIndex1];
vertex1.z = 0;
Vector3 edgeDir = Vector3.Normalize(vertex1 - vertex0);
retEdge.tangent = Vector3.Cross(-Vector3.forward, edgeDir);
return retEdge;
}
static void PopulateEdgeArray(List<Vector3> vertices, List<int> triangles, List<Edge> edges)
{
for (int triangleIndex = 0; triangleIndex < triangles.Count; triangleIndex += 3)
{
edges.Add(CreateEdge(triangleIndex, triangleIndex + 1, vertices, triangles));
edges.Add(CreateEdge(triangleIndex + 1, triangleIndex + 2, vertices, triangles));
edges.Add(CreateEdge(triangleIndex + 2, triangleIndex, vertices, triangles));
}
}
static bool IsOutsideEdge(int edgeIndex, List<Edge> edgesToProcess)
{
int previousIndex = edgeIndex - 1;
int nextIndex = edgeIndex + 1;
int numberOfEdges = edgesToProcess.Count;
Edge currentEdge = edgesToProcess[edgeIndex];
return (previousIndex < 0 || (currentEdge.CompareTo(edgesToProcess[edgeIndex - 1]) != 0)) && (nextIndex >= numberOfEdges || (currentEdge.CompareTo(edgesToProcess[edgeIndex + 1]) != 0));
}
static void SortEdges(List<Edge> edgesToProcess)
{
edgesToProcess.Sort();
}
static void CreateShadowTriangles(List<Vector3> vertices, List<Color> colors, List<int> triangles, List<Vector4> tangents, List<Edge> edges)
{
for (int edgeIndex = 0; edgeIndex < edges.Count; edgeIndex++)
{
if (IsOutsideEdge(edgeIndex, edges))
{
Edge edge = edges[edgeIndex];
tangents[edge.vertexIndex1] = -edge.tangent;
int newVertexIndex = vertices.Count;
vertices.Add(vertices[edge.vertexIndex0]);
colors.Add(colors[edge.vertexIndex0]);
tangents.Add(-edge.tangent);
triangles.Add(edge.vertexIndex0);
triangles.Add(newVertexIndex);
triangles.Add(edge.vertexIndex1);
}
}
}
static object InterpCustomVertexData(Vec3 position, object[] data, float[] weights)
{
return data[0];
}
static void InitializeTangents(int tangentsToAdd, List<Vector4> tangents)
{
for (int i = 0; i < tangentsToAdd; i++)
tangents.Add(Vector4.zero);
}
static internal void ComputeBoundingSphere(Vector3[] shapePath, out BoundingSphere boundingSphere)
{
float minX = float.MaxValue;
float maxX = float.MinValue;
float minY = float.MaxValue;
float maxY = float.MinValue;
// Add outline vertices
int pathLength = shapePath.Length;
for (int i = 0; i < pathLength; i++)
{
Vector3 vertex = shapePath[i];
if (minX > vertex.x)
minX = vertex.x;
if (maxX < vertex.x)
maxX = vertex.x;
if (minY > vertex.y)
minY = vertex.y;
if (maxY < vertex.y)
maxY = vertex.y;
}
// Calculate bounding sphere (circle)
Vector3 origin = new Vector2(0.5f * (minX + maxX), 0.5f * (minY + maxY));
float deltaX = maxX - minX;
float deltaY = maxY - minY;
float radius = 0.5f * Mathf.Sqrt(deltaX * deltaX + deltaY * deltaY);
boundingSphere.position = origin;
boundingSphere.radius = radius;
}
public static BoundingSphere GenerateShadowMesh(Mesh mesh, Vector3[] shapePath)
{
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
List<Vector4> tangents = new List<Vector4>();
List<Color> extrusion = new List<Color>();
// Create interior geometry
int pointCount = shapePath.Length;
var inputs = new ContourVertex[2 * pointCount];
for (int i = 0; i < pointCount; i++)
{
Color extrusionData = new Color(shapePath[i].x, shapePath[i].y, shapePath[i].x, shapePath[i].y);
int nextPoint = (i + 1) % pointCount;
inputs[2 * i] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y, Z = 0 }, Data = extrusionData };
extrusionData = new Color(shapePath[i].x, shapePath[i].y, shapePath[nextPoint].x, shapePath[nextPoint].y);
Vector2 midPoint = 0.5f * (shapePath[i] + shapePath[nextPoint]);
inputs[2 * i + 1] = new ContourVertex() { Position = new Vec3() { X = midPoint.x, Y = midPoint.y, Z = 0 }, Data = extrusionData };
}
Tess tessI = new Tess();
tessI.AddContour(inputs, ContourOrientation.Original);
tessI.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3, InterpCustomVertexData);
var indicesI = tessI.Elements.Select(i => i).ToArray();
var verticesI = tessI.Vertices.Select(v => new Vector3(v.Position.X, v.Position.Y, 0)).ToArray();
var extrusionI = tessI.Vertices.Select(v => new Color(((Color)v.Data).r, ((Color)v.Data).g, ((Color)v.Data).b, ((Color)v.Data).a)).ToArray();
vertices.AddRange(verticesI);
triangles.AddRange(indicesI);
extrusion.AddRange(extrusionI);
InitializeTangents(vertices.Count, tangents);
List<Edge> edges = new List<Edge>();
PopulateEdgeArray(vertices, triangles, edges);
SortEdges(edges);
CreateShadowTriangles(vertices, extrusion, triangles, tangents, edges);
Color[] finalExtrusion = extrusion.ToArray();
Vector3[] finalVertices = vertices.ToArray();
int[] finalTriangles = triangles.ToArray();
Vector4[] finalTangents = tangents.ToArray();
mesh.Clear();
mesh.vertices = finalVertices;
mesh.triangles = finalTriangles;
mesh.tangents = finalTangents;
mesh.colors = finalExtrusion;
BoundingSphere retSphere;
ComputeBoundingSphere(shapePath, out retSphere);
return retSphere;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed5876db37f0e544c8ef9b9802eff934
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("UniversalGraphicsTests")]
[assembly: InternalsVisibleTo("Universal2DGraphicsTests")]
[assembly: InternalsVisibleTo("Unity.RenderPipelines.Universal.Editor")]
[assembly: InternalsVisibleTo("Unity.RenderPipelines.Universal.Editor.Tests")]
[assembly: InternalsVisibleTo("Unity.RenderPipelines.Universal.Runtime.Tests")]
[assembly: InternalsVisibleTo("Unity.GraphicTests.Performance.Universal.Runtime")]

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61ba514d93f94d14a8638d884815c8c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,17 @@
namespace UnityEngine.Rendering.Universal
{
public static class ComponentUtility
{
/// <summary> Check if the provided camera is compatible with Universal Render Pipeline </summary>
/// <param name="camera">The Camera to check</param>
/// <returns>True if it is compatible, false otherwise</returns>
public static bool IsUniversalCamera(Camera camera)
=> camera.GetComponent<UniversalAdditionalCameraData>() != null;
/// <summary> Check if the provided light is compatible with Universal Render Pipeline </summary>
/// <param name="light">The Light to check</param>
/// <returns>True if it is compatible, false otherwise</returns>
public static bool IsUniversalLight(Light light)
=> light.GetComponent<UniversalAdditionalLightData>() != null;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 06368c8598883e74380014e9a7db3e7c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d59f1663563e245fabce035da7cecd75
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,54 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3}
m_Name: ForwardRendererData
m_EditorClassIdentifier:
debugShaders:
debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3}
m_RendererFeatures: []
m_RendererFeatureMap:
m_UseNativeRenderPass: 0
postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2}
shaders:
blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3}
copyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3}
screenSpaceShadowPS: {fileID: 4800000, guid: 0f854b35a0cf61a429bd5dcfea30eddd, type: 3}
samplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3}
stencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3}
fallbackErrorPS: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3}
materialErrorPS: {fileID: 4800000, guid: 5fd9a8feb75a4b5894c241777f519d4e, type: 3}
coreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3}
coreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3}
cameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3}
objectMotionVector: {fileID: 4800000, guid: 7b3ede40266cd49a395def176e1bc486, type: 3}
m_AssetVersion: 1
m_OpaqueLayerMask:
serializedVersion: 2
m_Bits: 4294967295
m_TransparentLayerMask:
serializedVersion: 2
m_Bits: 4294967295
m_DefaultStencilState:
overrideStencilState: 0
stencilReference: 0
stencilCompareFunction: 8
passOperation: 2
failOperation: 0
zFailOperation: 0
m_ShadowTransparentReceive: 1
m_RenderingMode: 0
m_DepthPrimingMode: 0
m_AccurateGbufferNormals: 0
m_ClusteredRendering: 0
m_TileSize: 32
m_IntermediateTextureMode: 0

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 618d298269e66c542b306de85db1faea
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,76 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 572910c10080c0945a0ef731ccedc739, type: 3}
m_Name: PostProcessData
m_EditorClassIdentifier:
shaders:
stopNanPS: {fileID: 4800000, guid: 1121bb4e615ca3c48b214e79e841e823, type: 3}
subpixelMorphologicalAntialiasingPS: {fileID: 4800000, guid: 63eaba0ebfb82cc43bde059b4a8c65f6, type: 3}
gaussianDepthOfFieldPS: {fileID: 4800000, guid: 5e7134d6e63e0bc47a1dd2669cedb379, type: 3}
bokehDepthOfFieldPS: {fileID: 4800000, guid: 2aed67ad60045d54ba3a00c91e2d2631, type: 3}
cameraMotionBlurPS: {fileID: 4800000, guid: 1edcd131364091c46a17cbff0b1de97a, type: 3}
paniniProjectionPS: {fileID: 4800000, guid: a15b78cf8ca26ca4fb2090293153c62c, type: 3}
lutBuilderLdrPS: {fileID: 4800000, guid: 65df88701913c224d95fc554db28381a, type: 3}
lutBuilderHdrPS: {fileID: 4800000, guid: ec9fec698a3456d4fb18cf8bacb7a2bc, type: 3}
bloomPS: {fileID: 4800000, guid: 5f1864addb451f54bae8c86d230f736e, type: 3}
LensFlareDataDrivenPS: {fileID: 4800000, guid: 6cda457ac28612740adb23da5d39ea92, type: 3}
scalingSetupPS: {fileID: 4800000, guid: e8ee25143a34b8c4388709ea947055d1, type: 3}
easuPS: {fileID: 4800000, guid: 562b7ae4f629f144aa97780546fce7c6, type: 3}
uberPostPS: {fileID: 4800000, guid: e7857e9d0c934dc4f83f270f8447b006, type: 3}
finalPostPassPS: {fileID: 4800000, guid: c49e63ed1bbcb334780a3bd19dfed403, type: 3}
textures:
blueNoise16LTex:
- {fileID: 2800000, guid: 81200413a40918d4d8702e94db29911c, type: 3}
- {fileID: 2800000, guid: d50c5e07c9911a74982bddf7f3075e7b, type: 3}
- {fileID: 2800000, guid: 1134690bf9216164dbc75050e35b7900, type: 3}
- {fileID: 2800000, guid: 7ce2118f74614a94aa8a0cdf2e6062c3, type: 3}
- {fileID: 2800000, guid: 2ca97df9d1801e84a8a8f2c53cb744f0, type: 3}
- {fileID: 2800000, guid: e63eef8f54aa9dc4da9a5ac094b503b5, type: 3}
- {fileID: 2800000, guid: 39451254daebd6d40b52899c1f1c0c1b, type: 3}
- {fileID: 2800000, guid: c94ad916058dff743b0f1c969ddbe660, type: 3}
- {fileID: 2800000, guid: ed5ea7ce59ca8ec4f9f14bf470a30f35, type: 3}
- {fileID: 2800000, guid: 071e954febf155243a6c81e48f452644, type: 3}
- {fileID: 2800000, guid: 96aaab9cc247d0b4c98132159688c1af, type: 3}
- {fileID: 2800000, guid: fc3fa8f108657e14486697c9a84ccfc5, type: 3}
- {fileID: 2800000, guid: bfed3e498947fcb4890b7f40f54d85b9, type: 3}
- {fileID: 2800000, guid: d512512f4af60a442ab3458489412954, type: 3}
- {fileID: 2800000, guid: 47a45908f6db0cb44a0d5e961143afec, type: 3}
- {fileID: 2800000, guid: 4dcc0502f8586f941b5c4a66717205e8, type: 3}
- {fileID: 2800000, guid: 9d92991794bb5864c8085468b97aa067, type: 3}
- {fileID: 2800000, guid: 14381521ff11cb74abe3fe65401c23be, type: 3}
- {fileID: 2800000, guid: d36f0fe53425e08499a2333cf423634c, type: 3}
- {fileID: 2800000, guid: d4044ea2490d63b43aa1765f8efbf8a9, type: 3}
- {fileID: 2800000, guid: c9bd74624d8070f429e3f46d161f9204, type: 3}
- {fileID: 2800000, guid: d5c9b274310e5524ebe32a4e4da3df1f, type: 3}
- {fileID: 2800000, guid: f69770e54f2823f43badf77916acad83, type: 3}
- {fileID: 2800000, guid: 10b6c6d22e73dea46a8ab36b6eebd629, type: 3}
- {fileID: 2800000, guid: a2ec5cbf5a9b64345ad3fab0912ddf7b, type: 3}
- {fileID: 2800000, guid: 1c3c6d69a645b804fa232004b96b7ad3, type: 3}
- {fileID: 2800000, guid: d18a24d7b4ed50f4387993566d9d3ae2, type: 3}
- {fileID: 2800000, guid: c989e1ed85cf7154caa922fec53e6af6, type: 3}
- {fileID: 2800000, guid: ff47e5a0f105eb34883b973e51f4db62, type: 3}
- {fileID: 2800000, guid: fa042edbfc40fbd4bad0ab9d505b1223, type: 3}
- {fileID: 2800000, guid: 896d9004736809c4fb5973b7c12eb8b9, type: 3}
- {fileID: 2800000, guid: 179f794063d2a66478e6e726f84a65bc, type: 3}
filmGrainTex:
- {fileID: 2800000, guid: 654c582f7f8a5a14dbd7d119cbde215d, type: 3}
- {fileID: 2800000, guid: dd77ffd079630404e879388999033049, type: 3}
- {fileID: 2800000, guid: 1097e90e1306e26439701489f391a6c0, type: 3}
- {fileID: 2800000, guid: f0b67500f7fad3b4c9f2b13e8f41ba6e, type: 3}
- {fileID: 2800000, guid: 9930fb4528622b34687b00bbe6883de7, type: 3}
- {fileID: 2800000, guid: bd9e8c758250ef449a4b4bfaad7a2133, type: 3}
- {fileID: 2800000, guid: 510a2f57334933e4a8dbabe4c30204e4, type: 3}
- {fileID: 2800000, guid: b4db8180660810945bf8d55ab44352ad, type: 3}
- {fileID: 2800000, guid: fd2fd78b392986e42a12df2177d3b89c, type: 3}
- {fileID: 2800000, guid: 5cdee82a77d13994f83b8fdabed7c301, type: 3}
smaaAreaTex: {fileID: 2800000, guid: d1f1048909d55cd4fa1126ab998f617e, type: 3}
smaaSearchTex: {fileID: 2800000, guid: 51eee22c2a633ef4aada830eed57c3fd, type: 3}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 41439944d30ece34e96484bdb6645b55
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,118 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.ProjectWindowCallback;
#endif
using System;
namespace UnityEngine.Rendering.Universal
{
[Serializable]
public class PostProcessData : ScriptableObject
{
#if UNITY_EDITOR
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812")]
internal class CreatePostProcessDataAsset : EndNameEditAction
{
public override void Action(int instanceId, string pathName, string resourceFile)
{
var instance = CreateInstance<PostProcessData>();
AssetDatabase.CreateAsset(instance, pathName);
ResourceReloader.ReloadAllNullIn(instance, UniversalRenderPipelineAsset.packagePath);
Selection.activeObject = instance;
}
}
[MenuItem("Assets/Create/Rendering/URP Post-process Data", priority = CoreUtils.Sections.section5 + CoreUtils.Priorities.assetsCreateRenderingMenuPriority)]
static void CreatePostProcessData()
{
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, CreateInstance<CreatePostProcessDataAsset>(), "CustomPostProcessData.asset", null, null);
}
internal static PostProcessData GetDefaultPostProcessData()
{
var path = System.IO.Path.Combine(UniversalRenderPipelineAsset.packagePath, "Runtime/Data/PostProcessData.asset");
return AssetDatabase.LoadAssetAtPath<PostProcessData>(path);
}
#endif
[Serializable, ReloadGroup]
public sealed class ShaderResources
{
[Reload("Shaders/PostProcessing/StopNaN.shader")]
public Shader stopNanPS;
[Reload("Shaders/PostProcessing/SubpixelMorphologicalAntialiasing.shader")]
public Shader subpixelMorphologicalAntialiasingPS;
[Reload("Shaders/PostProcessing/GaussianDepthOfField.shader")]
public Shader gaussianDepthOfFieldPS;
[Reload("Shaders/PostProcessing/BokehDepthOfField.shader")]
public Shader bokehDepthOfFieldPS;
[Reload("Shaders/PostProcessing/CameraMotionBlur.shader")]
public Shader cameraMotionBlurPS;
[Reload("Shaders/PostProcessing/PaniniProjection.shader")]
public Shader paniniProjectionPS;
[Reload("Shaders/PostProcessing/LutBuilderLdr.shader")]
public Shader lutBuilderLdrPS;
[Reload("Shaders/PostProcessing/LutBuilderHdr.shader")]
public Shader lutBuilderHdrPS;
[Reload("Shaders/PostProcessing/Bloom.shader")]
public Shader bloomPS;
[Reload("Shaders/PostProcessing/LensFlareDataDriven.shader")]
public Shader LensFlareDataDrivenPS;
[Reload("Shaders/PostProcessing/ScalingSetup.shader")]
public Shader scalingSetupPS;
[Reload("Shaders/PostProcessing/EdgeAdaptiveSpatialUpsampling.shader")]
public Shader easuPS;
[Reload("Shaders/PostProcessing/UberPost.shader")]
public Shader uberPostPS;
[Reload("Shaders/PostProcessing/FinalPost.shader")]
public Shader finalPostPassPS;
}
[Serializable, ReloadGroup]
public sealed class TextureResources
{
// Pre-baked noise
[Reload("Textures/BlueNoise16/L/LDR_LLL1_{0}.png", 0, 32)]
public Texture2D[] blueNoise16LTex;
// Post-processing
[Reload(new[]
{
"Textures/FilmGrain/Thin01.png",
"Textures/FilmGrain/Thin02.png",
"Textures/FilmGrain/Medium01.png",
"Textures/FilmGrain/Medium02.png",
"Textures/FilmGrain/Medium03.png",
"Textures/FilmGrain/Medium04.png",
"Textures/FilmGrain/Medium05.png",
"Textures/FilmGrain/Medium06.png",
"Textures/FilmGrain/Large01.png",
"Textures/FilmGrain/Large02.png"
})]
public Texture2D[] filmGrainTex;
[Reload("Textures/SMAA/AreaTex.tga")]
public Texture2D smaaAreaTex;
[Reload("Textures/SMAA/SearchTex.tga")]
public Texture2D smaaSearchTex;
}
public ShaderResources shaders;
public TextureResources textures;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 572910c10080c0945a0ef731ccedc739
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,13 @@
namespace UnityEngine.Rendering.Universal
{
[System.Serializable]
public class StencilStateData
{
public bool overrideStencilState = false;
public int stencilReference = 0;
public CompareFunction stencilCompareFunction = CompareFunction.Always;
public StencilOp passOperation = StencilOp.Keep;
public StencilOp failOperation = StencilOp.Keep;
public StencilOp zFailOperation = StencilOp.Keep;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 682abd313990845aabd60612b4828970
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: bf2edee5c58d82540a51f03df9d42094
timeCreated: 1488808083
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,36 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 76e49a5b88430df478c504fe5a5c1a62, type: 3}
m_Name: UniversalRenderPipelineEditorResources
m_EditorClassIdentifier:
shaders:
autodeskInteractivePS: {fileID: 4800000, guid: 0e9d5a909a1f7e84882a534d0d11e49f,
type: 3}
autodeskInteractiveTransparentPS: {fileID: 4800000, guid: 5c81372d981403744adbdda4433c9c11,
type: 3}
autodeskInteractiveMaskedPS: {fileID: 4800000, guid: 80aa867ac363ac043847b06ad71604cd,
type: 3}
terrainDetailLitPS: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144,
type: 3}
terrainDetailGrassPS: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1,
type: 3}
terrainDetailGrassBillboardPS: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90,
type: 3}
defaultSpeedTree7PS: {fileID: 4800000, guid: 0f4122b9a743b744abe2fb6a0a88868b,
type: 3}
defaultSpeedTree8PS: {fileID: 4800000, guid: 99134b1f0c27d54469a840832a28fadf,
type: 3}
materials:
lit: {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
particleLit: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2}
terrainLit: {fileID: 2100000, guid: 594ea882c5a793440b60ff72d896021e, type: 2}
decal: {fileID: 2100000, guid: 31d0dcc6f2dd4e4408d18036a2c93862, type: 2}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a3d8d823eedde654bb4c11a1cfaf1abb
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,74 @@
using System;
namespace UnityEngine.Rendering.Universal
{
public class UniversalRenderPipelineEditorResources : ScriptableObject
{
[Serializable, ReloadGroup]
public sealed class ShaderResources
{
[Reload("Shaders/Autodesk Interactive/Autodesk Interactive.shadergraph")]
public Shader autodeskInteractivePS;
[Reload("Shaders/Autodesk Interactive/Autodesk Interactive Transparent.shadergraph")]
public Shader autodeskInteractiveTransparentPS;
[Reload("Shaders/Autodesk Interactive/Autodesk Interactive Masked.shadergraph")]
public Shader autodeskInteractiveMaskedPS;
[Reload("Shaders/Terrain/TerrainDetailLit.shader")]
public Shader terrainDetailLitPS;
[Reload("Shaders/Terrain/WavingGrass.shader")]
public Shader terrainDetailGrassPS;
[Reload("Shaders/Terrain/WavingGrassBillboard.shader")]
public Shader terrainDetailGrassBillboardPS;
[Reload("Shaders/Nature/SpeedTree7.shader")]
public Shader defaultSpeedTree7PS;
[Reload("Shaders/Nature/SpeedTree8.shader")]
public Shader defaultSpeedTree8PS;
}
[Serializable, ReloadGroup]
public sealed class MaterialResources
{
[Reload("Runtime/Materials/Lit.mat")]
public Material lit;
[Reload("Runtime/Materials/ParticlesLit.mat")]
public Material particleLit;
[Reload("Runtime/Materials/TerrainLit.mat")]
public Material terrainLit;
[Reload("Runtime/Materials/Decal.mat")]
public Material decal;
}
public ShaderResources shaders;
public MaterialResources materials;
}
#if UNITY_EDITOR
[UnityEditor.CustomEditor(typeof(UniversalRenderPipelineEditorResources), true)]
class UniversalRenderPipelineEditorResourcesEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
// Add a "Reload All" button in inspector when we are in developer's mode
if (UnityEditor.EditorPrefs.GetBool("DeveloperMode") && GUILayout.Button("Reload All"))
{
var resources = target as UniversalRenderPipelineEditorResources;
resources.materials = null;
resources.shaders = null;
ResourceReloader.ReloadAllNullIn(target, UniversalRenderPipelineAsset.packagePath);
}
}
}
#endif
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 76e49a5b88430df478c504fe5a5c1a62
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,52 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3}
m_Name: UniversalRendererData
m_EditorClassIdentifier:
debugShaders:
debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3}
m_RendererFeatures: []
m_RendererFeatureMap:
m_UseNativeRenderPass: 0
postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2}
shaders:
blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3}
copyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3}
screenSpaceShadowPS: {fileID: 0}
samplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3}
stencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3}
fallbackErrorPS: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3}
materialErrorPS: {fileID: 4800000, guid: 5fd9a8feb75a4b5894c241777f519d4e, type: 3}
coreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3}
coreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3}
cameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3}
objectMotionVector: {fileID: 4800000, guid: 7b3ede40266cd49a395def176e1bc486, type: 3}
m_OpaqueLayerMask:
serializedVersion: 2
m_Bits: 4294967295
m_TransparentLayerMask:
serializedVersion: 2
m_Bits: 4294967295
m_DefaultStencilState:
overrideStencilState: 0
stencilReference: 0
stencilCompareFunction: 8
passOperation: 2
failOperation: 0
zFailOperation: 0
m_ShadowTransparentReceive: 1
m_RenderingMode: 0
m_DepthPrimingMode: 0
m_AccurateGbufferNormals: 0
m_ClusteredRendering: 0
m_TileSize: 32

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ba6e69114eba6af4585b7b850051b2d9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,35 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Saved volumetric settings
/// </summary>
[System.Serializable, CreateAssetMenu(fileName = "Volumetric Rendering Settings", menuName = "Rendering/Volumetric Rendering Settings", order = 10)]
public class VolumetricData : ScriptableObject
{
[Header("Volumetric camera settings")]
[Tooltip("Near Clip plane")]
public float near = 1;
[Tooltip("Far Clip plane")]
public float far = 40;
[Tooltip("Resolution")]
public int FroxelWidthResolution = 128;
[Tooltip("Resolution")]
public int FroxelHeightResolution = 128;
[Tooltip("Resolution")]
public int FroxelDepthResolution = 64;
//[Tooltip("Controls the bias of the froxel dispution. A value of 1 is linear. ")]
//public float FroxelDispution;
[Header("Prebaked clipmap settings - Controls both cascades")]
[Tooltip("Textile resolution per unit")]
public int ClipMapResolution = 128;
[Tooltip("Size of inner clipmap in units. Outter clipmap is 5x the size")]
public float ClipmapScale = 80;
public float ClipmapScale2 = 160;
[Tooltip("Distance (m) from previous sampling point to trigger resampling clipmap")]
public float ClipmapResampleThreshold = 1;
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 12df6f25bd2bedf478f47d04069582bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,17 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 307a736764ebbce44b54d72f8467b6fd, type: 3}
m_Name: XRSystemData
m_EditorClassIdentifier:
shaders:
xrOcclusionMeshPS: {fileID: 4800000, guid: 4431b1f1f743fbf4eb310a967890cbea, type: 3}
xrMirrorViewPS: {fileID: 4800000, guid: d5a307c014552314b9f560906d708772, type: 3}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 60e1133243b97e347b653163a8c01b64
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,45 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.ProjectWindowCallback;
#endif
using System;
namespace UnityEngine.Rendering.Universal
{
[Serializable]
public class XRSystemData : ScriptableObject
{
#if UNITY_EDITOR
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812")]
internal class CreateXRSystemDataAsset : EndNameEditAction
{
public override void Action(int instanceId, string pathName, string resourceFile)
{
var instance = CreateInstance<XRSystemData>();
AssetDatabase.CreateAsset(instance, pathName);
ResourceReloader.ReloadAllNullIn(instance, UniversalRenderPipelineAsset.packagePath);
Selection.activeObject = instance;
}
}
[MenuItem("Assets/Create/Rendering/URP XR System Data", priority = CoreUtils.Sections.section5 + CoreUtils.Priorities.assetsCreateRenderingMenuPriority)]
static void CreateXRSystemData()
{
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, CreateInstance<CreateXRSystemDataAsset>(), "CustomXRSystemData.asset", null, null);
}
#endif
[Serializable, ReloadGroup]
public sealed class ShaderResources
{
[Reload("Shaders/XR/XROcclusionMesh.shader")]
public Shader xrOcclusionMeshPS;
[Reload("Shaders/XR/XRMirrorView.shader")]
public Shader xrMirrorViewPS;
}
public ShaderResources shaders;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 307a736764ebbce44b54d72f8467b6fd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 91be52194fd414eefb9f1bc39b89292e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEngine.Rendering.Universal
{
public class DebugDisplaySettings : IDebugDisplaySettingsQuery
{
private readonly HashSet<IDebugDisplaySettingsData> m_Settings = new HashSet<IDebugDisplaySettingsData>();
private static readonly Lazy<DebugDisplaySettings> s_Instance = new Lazy<DebugDisplaySettings>(() => new DebugDisplaySettings());
/// <summary>
/// The singleton instance that contains the current settings of URP Rendering Debugger.
/// </summary>
public static DebugDisplaySettings Instance => s_Instance.Value;
DebugDisplaySettingsCommon CommonSettings { get; set; }
/// <summary>
/// Material-related Rendering Debugger settings.
/// </summary>
internal DebugDisplaySettingsMaterial MaterialSettings { get; private set; }
/// <summary>
/// Rendering-related Rendering Debugger settings.
/// </summary>
internal DebugDisplaySettingsRendering RenderingSettings { get; private set; }
/// <summary>
/// Lighting-related Rendering Debugger settings.
/// </summary>
internal DebugDisplaySettingsLighting LightingSettings { get; private set; }
#region IDebugDisplaySettingsQuery
/// <summary>
/// Returns true if any of the debug settings are currently active.
/// </summary>
public bool AreAnySettingsActive => MaterialSettings.AreAnySettingsActive ||
LightingSettings.AreAnySettingsActive ||
RenderingSettings.AreAnySettingsActive;
public bool TryGetScreenClearColor(ref Color color)
{
return MaterialSettings.TryGetScreenClearColor(ref color) ||
RenderingSettings.TryGetScreenClearColor(ref color) ||
LightingSettings.TryGetScreenClearColor(ref color);
}
/// <summary>
/// Returns true if lighting is active for current state of debug settings.
/// </summary>
public bool IsLightingActive => MaterialSettings.IsLightingActive &&
RenderingSettings.IsLightingActive &&
LightingSettings.IsLightingActive;
/// <summary>
/// Returns true if the current state of debug settings allows post-processing.
/// </summary>
public bool IsPostProcessingAllowed
{
get
{
DebugPostProcessingMode debugPostProcessingMode = RenderingSettings.debugPostProcessingMode;
switch (debugPostProcessingMode)
{
case DebugPostProcessingMode.Disabled:
{
return false;
}
case DebugPostProcessingMode.Auto:
{
// Only enable post-processing if we aren't using certain debug-views...
return MaterialSettings.IsPostProcessingAllowed &&
RenderingSettings.IsPostProcessingAllowed &&
LightingSettings.IsPostProcessingAllowed;
}
case DebugPostProcessingMode.Enabled:
{
return true;
}
default:
{
throw new ArgumentOutOfRangeException(nameof(debugPostProcessingMode), $"Invalid post-processing state {debugPostProcessingMode}");
}
}
}
}
#endregion
private TData Add<TData>(TData newData) where TData : IDebugDisplaySettingsData
{
m_Settings.Add(newData);
return newData;
}
DebugDisplaySettings()
{
Reset();
}
internal void Reset()
{
m_Settings.Clear();
CommonSettings = Add(new DebugDisplaySettingsCommon());
MaterialSettings = Add(new DebugDisplaySettingsMaterial());
LightingSettings = Add(new DebugDisplaySettingsLighting());
RenderingSettings = Add(new DebugDisplaySettingsRendering());
}
internal void ForEach(Action<IDebugDisplaySettingsData> onExecute)
{
foreach (IDebugDisplaySettingsData setting in m_Settings)
{
onExecute(setting);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f6344f2dc8b9435db33604d430c83d3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,119 @@
using System.Collections.Generic;
using UnityEngine;
namespace UnityEngine.Rendering.Universal
{
class DebugDisplaySettingsCommon : IDebugDisplaySettingsData
{
internal static class WidgetFactory
{
internal static DebugUI.Widget CreateMissingDebugShadersWarning() => new DebugUI.MessageBox
{
displayName = "Warning: the debug shader variants are missing. Ensure that the \"Strip Debug Variants\" option is disabled in URP Global Settings.",
style = DebugUI.MessageBox.Style.Warning,
isHiddenCallback = () =>
{
#if UNITY_EDITOR
return true;
#else
if (UniversalRenderPipelineGlobalSettings.instance != null)
return !UniversalRenderPipelineGlobalSettings.instance.stripDebugVariants;
return true;
#endif
}
};
}
private class SettingsPanel : DebugDisplaySettingsPanel
{
public override string PanelName => "Frequently Used";
const string k_GoToSectionString = "Go to Section...";
public SettingsPanel()
{
AddWidget(DebugDisplaySettingsCommon.WidgetFactory.CreateMissingDebugShadersWarning());
var materialSettingsData = DebugDisplaySettings.Instance.MaterialSettings;
AddWidget(new DebugUI.Foldout
{
displayName = "Material Filters",
isHeader = true,
opened = true,
children =
{
DebugDisplaySettingsMaterial.WidgetFactory.CreateMaterialOverride(materialSettingsData)
},
contextMenuItems = new List<DebugUI.Foldout.ContextMenuItem>()
{
new DebugUI.Foldout.ContextMenuItem
{
displayName = k_GoToSectionString,
action = () => { DebugManager.instance.RequestEditorWindowPanelIndex(1); }
}
}
});
var lightingSettingsData = DebugDisplaySettings.Instance.LightingSettings;
AddWidget(new DebugUI.Foldout
{
displayName = "Lighting Debug Modes",
isHeader = true,
opened = true,
children =
{
DebugDisplaySettingsLighting.WidgetFactory.CreateLightingDebugMode(lightingSettingsData),
DebugDisplaySettingsLighting.WidgetFactory.CreateLightingFeatures(lightingSettingsData)
},
contextMenuItems = new List<DebugUI.Foldout.ContextMenuItem>()
{
new DebugUI.Foldout.ContextMenuItem
{
displayName = k_GoToSectionString,
action = () => { DebugManager.instance.RequestEditorWindowPanelIndex(2); }
}
}
});
var renderingSettingsData = DebugDisplaySettings.Instance.RenderingSettings;
AddWidget(new DebugUI.Foldout
{
displayName = "Rendering Debug",
isHeader = true,
opened = true,
children =
{
DebugDisplaySettingsRendering.WidgetFactory.CreateHDR(renderingSettingsData),
DebugDisplaySettingsRendering.WidgetFactory.CreateMSAA(renderingSettingsData),
DebugDisplaySettingsRendering.WidgetFactory.CreatePostProcessing(renderingSettingsData),
DebugDisplaySettingsRendering.WidgetFactory.CreateAdditionalWireframeShaderViews(renderingSettingsData),
DebugDisplaySettingsRendering.WidgetFactory.CreateWireframeNotSupportedWarning(renderingSettingsData),
DebugDisplaySettingsRendering.WidgetFactory.CreateOverdraw(renderingSettingsData)
},
contextMenuItems = new List<DebugUI.Foldout.ContextMenuItem>()
{
new DebugUI.Foldout.ContextMenuItem
{
displayName = k_GoToSectionString,
action = () => { DebugManager.instance.RequestEditorWindowPanelIndex(3); }
}
}
});
}
}
#region IDebugDisplaySettingsData
public bool AreAnySettingsActive => DebugDisplaySettings.Instance.AreAnySettingsActive;
public bool IsPostProcessingAllowed => DebugDisplaySettings.Instance.IsPostProcessingAllowed;
public bool IsLightingActive => DebugDisplaySettings.Instance.IsLightingActive;
public bool TryGetScreenClearColor(ref Color color) => DebugDisplaySettings.Instance.TryGetScreenClearColor(ref color);
public IDebugDisplaySettingsPanelDisposable CreatePanel()
{
return new SettingsPanel();
}
#endregion
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 89bc0329853842ae999d6f86829fc126
timeCreated: 1615364496

View file

@ -0,0 +1,79 @@
using UnityEngine;
using NameAndTooltip = UnityEngine.Rendering.DebugUI.Widget.NameAndTooltip;
namespace UnityEngine.Rendering.Universal
{
class DebugDisplaySettingsLighting : IDebugDisplaySettingsData
{
internal DebugLightingMode DebugLightingMode { get; private set; }
internal DebugLightingFeatureFlags DebugLightingFeatureFlagsMask { get; private set; }
static class Strings
{
public static readonly NameAndTooltip LightingDebugMode = new() { name = "Lighting Debug Mode", tooltip = "Use the drop-down to select which lighting and shadow debug information to overlay on the screen." };
public static readonly NameAndTooltip LightingFeatures = new() { name = "Lighting Features", tooltip = "Filter and debug selected lighting features in the system." };
}
internal static class WidgetFactory
{
internal static DebugUI.Widget CreateLightingDebugMode(DebugDisplaySettingsLighting data) => new DebugUI.EnumField
{
nameAndTooltip = Strings.LightingDebugMode,
autoEnum = typeof(DebugLightingMode),
getter = () => (int)data.DebugLightingMode,
setter = (value) => { },
getIndex = () => (int)data.DebugLightingMode,
setIndex = (value) => data.DebugLightingMode = (DebugLightingMode)value
};
internal static DebugUI.Widget CreateLightingFeatures(DebugDisplaySettingsLighting data) => new DebugUI.BitField
{
nameAndTooltip = Strings.LightingFeatures,
getter = () => data.DebugLightingFeatureFlagsMask,
setter = (value) => data.DebugLightingFeatureFlagsMask = (DebugLightingFeatureFlags)value,
enumType = typeof(DebugLightingFeatureFlags),
};
}
private class SettingsPanel : DebugDisplaySettingsPanel
{
public override string PanelName => "Lighting";
public SettingsPanel(DebugDisplaySettingsLighting data)
{
AddWidget(DebugDisplaySettingsCommon.WidgetFactory.CreateMissingDebugShadersWarning());
AddWidget(new DebugUI.Foldout
{
displayName = "Lighting Debug Modes",
isHeader = true,
opened = true,
children =
{
WidgetFactory.CreateLightingDebugMode(data),
WidgetFactory.CreateLightingFeatures(data)
}
});
}
}
#region IDebugDisplaySettingsData
public bool AreAnySettingsActive => (DebugLightingMode != DebugLightingMode.None) || (DebugLightingFeatureFlagsMask != DebugLightingFeatureFlags.None);
public bool IsPostProcessingAllowed => (DebugLightingMode != DebugLightingMode.Reflections && DebugLightingMode != DebugLightingMode.ReflectionsWithSmoothness);
public bool IsLightingActive => true;
public bool TryGetScreenClearColor(ref Color color)
{
return false;
}
public IDebugDisplaySettingsPanelDisposable CreatePanel()
{
return new SettingsPanel(this);
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e3df3f6511ee9d84fb93259d602ff2e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,368 @@
using UnityEngine;
using NameAndTooltip = UnityEngine.Rendering.DebugUI.Widget.NameAndTooltip;
namespace UnityEngine.Rendering.Universal
{
class DebugDisplaySettingsMaterial : IDebugDisplaySettingsData
{
#region Material validation
internal enum AlbedoDebugValidationPreset
{
DefaultLuminance,
BlackAcrylicPaint,
DarkSoil,
WornAsphalt,
DryClaySoil,
GreenGrass,
OldConcrete,
RedClayTile,
DrySand,
NewConcrete,
WhiteAcrylicPaint,
FreshSnow,
BlueSky,
Foliage,
}
struct AlbedoDebugValidationPresetData
{
public string name;
public Color color;
public float minLuminance;
public float maxLuminance;
}
AlbedoDebugValidationPresetData[] m_AlbedoDebugValidationPresetData =
{
new AlbedoDebugValidationPresetData()
{
name = "Default Luminance",
color = new Color(127f / 255f, 127f / 255f, 127f / 255f),
minLuminance = 0.01f,
maxLuminance = 0.90f
},
// colors taken from http://www.babelcolor.com/index_htm_files/ColorChecker_RGB_and_spectra.xls
new AlbedoDebugValidationPresetData()
{
name = "Black Acrylic Paint",
color = new Color(56f / 255f, 56f / 255f, 56f / 255f),
minLuminance = 0.03f,
maxLuminance = 0.07f
},
new AlbedoDebugValidationPresetData()
{
name = "Dark Soil",
color = new Color(85f / 255f, 61f / 255f, 49f / 255f),
minLuminance = 0.05f,
maxLuminance = 0.14f
},
new AlbedoDebugValidationPresetData()
{
name = "Worn Asphalt",
color = new Color(91f / 255f, 91f / 255f, 91f / 255f),
minLuminance = 0.10f,
maxLuminance = 0.15f
},
new AlbedoDebugValidationPresetData()
{
name = "Dry Clay Soil",
color = new Color(137f / 255f, 120f / 255f, 102f / 255f),
minLuminance = 0.15f,
maxLuminance = 0.35f
},
new AlbedoDebugValidationPresetData()
{
name = "Green Grass",
color = new Color(123f / 255f, 131f / 255f, 74f / 255f),
minLuminance = 0.16f,
maxLuminance = 0.26f
},
new AlbedoDebugValidationPresetData()
{
name = "Old Concrete",
color = new Color(135f / 255f, 136f / 255f, 131f / 255f),
minLuminance = 0.17f,
maxLuminance = 0.30f
},
new AlbedoDebugValidationPresetData()
{
name = "Red Clay Tile",
color = new Color(197f / 255f, 125f / 255f, 100f / 255f),
minLuminance = 0.23f,
maxLuminance = 0.33f
},
new AlbedoDebugValidationPresetData()
{
name = "Dry Sand",
color = new Color(177f / 255f, 167f / 255f, 132f / 255f),
minLuminance = 0.20f,
maxLuminance = 0.45f
},
new AlbedoDebugValidationPresetData()
{
name = "New Concrete",
color = new Color(185f / 255f, 182f / 255f, 175f / 255f),
minLuminance = 0.32f,
maxLuminance = 0.55f
},
new AlbedoDebugValidationPresetData()
{
name = "White Acrylic Paint",
color = new Color(227f / 255f, 227f / 255f, 227f / 255f),
minLuminance = 0.75f,
maxLuminance = 0.85f
},
new AlbedoDebugValidationPresetData()
{
name = "Fresh Snow",
color = new Color(243f / 255f, 243f / 255f, 243f / 255f),
minLuminance = 0.85f,
maxLuminance = 0.95f
},
new AlbedoDebugValidationPresetData()
{
name = "Blue Sky",
color = new Color(93f / 255f, 123f / 255f, 157f / 255f),
minLuminance = new Color(93f / 255f, 123f / 255f, 157f / 255f).linear.maxColorComponent - 0.05f,
maxLuminance = new Color(93f / 255f, 123f / 255f, 157f / 255f).linear.maxColorComponent + 0.05f
},
new AlbedoDebugValidationPresetData()
{
name = "Foliage",
color = new Color(91f / 255f, 108f / 255f, 65f / 255f),
minLuminance = new Color(91f / 255f, 108f / 255f, 65f / 255f).linear.maxColorComponent - 0.05f,
maxLuminance = new Color(91f / 255f, 108f / 255f, 65f / 255f).linear.maxColorComponent + 0.05f
},
};
AlbedoDebugValidationPreset m_AlbedoDebugValidationPreset;
internal AlbedoDebugValidationPreset albedoDebugValidationPreset
{
get => m_AlbedoDebugValidationPreset;
set
{
m_AlbedoDebugValidationPreset = value;
AlbedoDebugValidationPresetData presetData = m_AlbedoDebugValidationPresetData[(int)value];
AlbedoMinLuminance = presetData.minLuminance;
AlbedoMaxLuminance = presetData.maxLuminance;
AlbedoCompareColor = presetData.color;
}
}
internal float AlbedoMinLuminance = 0.01f;
internal float AlbedoMaxLuminance = 0.90f;
float m_AlbedoHueTolerance = 0.104f;
internal float AlbedoHueTolerance
{
get => m_AlbedoDebugValidationPreset == AlbedoDebugValidationPreset.DefaultLuminance ? 1.0f : m_AlbedoHueTolerance;
private set => m_AlbedoHueTolerance = value;
}
float m_AlbedoSaturationTolerance = 0.214f;
internal float AlbedoSaturationTolerance
{
get => m_AlbedoDebugValidationPreset == AlbedoDebugValidationPreset.DefaultLuminance ? 1.0f : m_AlbedoSaturationTolerance;
private set => m_AlbedoSaturationTolerance = value;
}
internal Color AlbedoCompareColor = new Color(127f / 255f, 127f / 255f, 127f / 255f, 255f / 255f);
internal float MetallicMinValue = 0.0f;
internal float MetallicMaxValue = 0.9f;
internal DebugMaterialValidationMode MaterialValidationMode;
#endregion
internal DebugMaterialMode DebugMaterialModeData { get; private set; }
internal DebugVertexAttributeMode DebugVertexAttributeIndexData { get; private set; }
static class Strings
{
public const string AlbedoSettingsContainerName = "Albedo Settings";
public const string MetallicSettingsContainerName = "Metallic Settings";
public static readonly NameAndTooltip MaterialOverride = new() { name = "Material Override", tooltip = "Use the drop-down to select a Material property to visualize on every GameObject on screen." };
public static readonly NameAndTooltip VertexAttribute = new() { name = "Vertex Attribute", tooltip = "Use the drop-down to select a 3D GameObject attribute, like Texture Coordinates or Vertex Color, to visualize on screen." };
public static readonly NameAndTooltip MaterialValidationMode = new() { name = "Material Validation Mode", tooltip = "Debug and validate material properties." };
public static readonly NameAndTooltip ValidationPreset = new() { name = "Validation Preset", tooltip = "Validate using a list of preset surfaces and inputs based on real-world surfaces." };
public static readonly NameAndTooltip AlbedoMinLuminance = new() { name = "Min Luminance", tooltip = "Any values set below this field are invalid and appear red on screen." };
public static readonly NameAndTooltip AlbedoMaxLuminance = new() { name = "Max Luminance", tooltip = "Any values set above this field are invalid and appear blue on screen." };
public static readonly NameAndTooltip AlbedoHueTolerance = new() { name = "Hue Tolerance", tooltip = "Validate a material based on a specific hue." };
public static readonly NameAndTooltip AlbedoSaturationTolerance = new() { name = "Saturation Tolerance", tooltip = "Validate a material based on a specific Saturation." };
public static readonly NameAndTooltip MetallicMinValue = new() { name = "Min Value", tooltip = "Any values set below this field are invalid and appear red on screen." };
public static readonly NameAndTooltip MetallicMaxValue = new() { name = "Max Value", tooltip = "Any values set above this field are invalid and appear blue on screen." };
}
internal static class WidgetFactory
{
internal static DebugUI.Widget CreateMaterialOverride(DebugDisplaySettingsMaterial data) => new DebugUI.EnumField
{
nameAndTooltip = Strings.MaterialOverride,
autoEnum = typeof(DebugMaterialMode),
getter = () => (int)data.DebugMaterialModeData,
setter = (value) => { },
getIndex = () => (int)data.DebugMaterialModeData,
setIndex = (value) => data.DebugMaterialModeData = (DebugMaterialMode)value
};
internal static DebugUI.Widget CreateVertexAttribute(DebugDisplaySettingsMaterial data) => new DebugUI.EnumField
{
nameAndTooltip = Strings.VertexAttribute,
autoEnum = typeof(DebugVertexAttributeMode),
getter = () => (int)data.DebugVertexAttributeIndexData,
setter = (value) => { },
getIndex = () => (int)data.DebugVertexAttributeIndexData,
setIndex = (value) => data.DebugVertexAttributeIndexData = (DebugVertexAttributeMode)value
};
internal static DebugUI.Widget CreateMaterialValidationMode(DebugDisplaySettingsMaterial data) => new DebugUI.EnumField
{
nameAndTooltip = Strings.MaterialValidationMode,
autoEnum = typeof(DebugMaterialValidationMode),
getter = () => (int)data.MaterialValidationMode,
setter = (value) => { },
getIndex = () => (int)data.MaterialValidationMode,
setIndex = (value) => data.MaterialValidationMode = (DebugMaterialValidationMode)value,
onValueChanged = (_, _) => DebugManager.instance.ReDrawOnScreenDebug()
};
internal static DebugUI.Widget CreateAlbedoPreset(DebugDisplaySettingsMaterial data) => new DebugUI.EnumField
{
nameAndTooltip = Strings.ValidationPreset,
autoEnum = typeof(AlbedoDebugValidationPreset),
getter = () => (int)data.albedoDebugValidationPreset,
setter = (value) => { },
getIndex = () => (int)data.albedoDebugValidationPreset,
setIndex = (value) => data.albedoDebugValidationPreset = (AlbedoDebugValidationPreset)value,
onValueChanged = (_, _) => DebugManager.instance.ReDrawOnScreenDebug()
};
internal static DebugUI.Widget CreateAlbedoMinLuminance(DebugDisplaySettingsMaterial data) => new DebugUI.FloatField
{
nameAndTooltip = Strings.AlbedoMinLuminance,
getter = () => data.AlbedoMinLuminance,
setter = (value) => data.AlbedoMinLuminance = value,
incStep = 0.01f
};
internal static DebugUI.Widget CreateAlbedoMaxLuminance(DebugDisplaySettingsMaterial data) => new DebugUI.FloatField
{
nameAndTooltip = Strings.AlbedoMaxLuminance,
getter = () => data.AlbedoMaxLuminance,
setter = (value) => data.AlbedoMaxLuminance = value,
incStep = 0.01f
};
internal static DebugUI.Widget CreateAlbedoHueTolerance(DebugDisplaySettingsMaterial data) => new DebugUI.FloatField
{
nameAndTooltip = Strings.AlbedoHueTolerance,
getter = () => data.AlbedoHueTolerance,
setter = (value) => data.AlbedoHueTolerance = value,
incStep = 0.01f,
isHiddenCallback = () => data.albedoDebugValidationPreset == AlbedoDebugValidationPreset.DefaultLuminance
};
internal static DebugUI.Widget CreateAlbedoSaturationTolerance(DebugDisplaySettingsMaterial data) => new DebugUI.FloatField
{
nameAndTooltip = Strings.AlbedoSaturationTolerance,
getter = () => data.AlbedoSaturationTolerance,
setter = (value) => data.AlbedoSaturationTolerance = value,
incStep = 0.01f,
isHiddenCallback = () => data.albedoDebugValidationPreset == AlbedoDebugValidationPreset.DefaultLuminance
};
internal static DebugUI.Widget CreateMetallicMinValue(DebugDisplaySettingsMaterial data) => new DebugUI.FloatField
{
nameAndTooltip = Strings.MetallicMinValue,
getter = () => data.MetallicMinValue,
setter = (value) => data.MetallicMinValue = value,
incStep = 0.01f
};
internal static DebugUI.Widget CreateMetallicMaxValue(DebugDisplaySettingsMaterial data) => new DebugUI.FloatField
{
nameAndTooltip = Strings.MetallicMaxValue,
getter = () => data.MetallicMaxValue,
setter = (value) => data.MetallicMaxValue = value,
incStep = 0.01f
};
}
private class SettingsPanel : DebugDisplaySettingsPanel
{
public override string PanelName => "Material";
public SettingsPanel(DebugDisplaySettingsMaterial data)
{
AddWidget(DebugDisplaySettingsCommon.WidgetFactory.CreateMissingDebugShadersWarning());
AddWidget(new DebugUI.Foldout
{
displayName = "Material Filters",
isHeader = true,
opened = true,
children =
{
WidgetFactory.CreateMaterialOverride(data),
WidgetFactory.CreateVertexAttribute(data)
}
});
AddWidget(new DebugUI.Foldout
{
displayName = "Material Validation",
isHeader = true,
opened = true,
children =
{
WidgetFactory.CreateMaterialValidationMode(data),
new DebugUI.Container()
{
displayName = Strings.AlbedoSettingsContainerName,
isHiddenCallback = () => data.MaterialValidationMode != DebugMaterialValidationMode.Albedo,
children =
{
WidgetFactory.CreateAlbedoPreset(data),
WidgetFactory.CreateAlbedoMinLuminance(data),
WidgetFactory.CreateAlbedoMaxLuminance(data),
WidgetFactory.CreateAlbedoHueTolerance(data),
WidgetFactory.CreateAlbedoSaturationTolerance(data)
}
},
new DebugUI.Container()
{
displayName = Strings.MetallicSettingsContainerName,
isHiddenCallback = () => data.MaterialValidationMode != DebugMaterialValidationMode.Metallic,
children =
{
WidgetFactory.CreateMetallicMinValue(data),
WidgetFactory.CreateMetallicMaxValue(data)
}
}
}
});
}
}
#region IDebugDisplaySettingsData
public bool AreAnySettingsActive =>
(DebugMaterialModeData != DebugMaterialMode.None) ||
(DebugVertexAttributeIndexData != DebugVertexAttributeMode.None) ||
(MaterialValidationMode != DebugMaterialValidationMode.None);
public bool IsPostProcessingAllowed => !AreAnySettingsActive;
public bool IsLightingActive => !AreAnySettingsActive;
public bool TryGetScreenClearColor(ref Color color)
{
return false;
}
public IDebugDisplaySettingsPanelDisposable CreatePanel()
{
return new SettingsPanel(this);
}
#endregion
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b64304a6322ab44a3acc9758c949e286
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace UnityEngine.Rendering.Universal
{
public abstract class DebugDisplaySettingsPanel : IDebugDisplaySettingsPanelDisposable
{
private readonly List<DebugUI.Widget> m_Widgets = new List<DebugUI.Widget>();
public abstract string PanelName { get; }
public DebugUI.Widget[] Widgets => m_Widgets.ToArray();
protected void AddWidget(DebugUI.Widget widget)
{
m_Widgets.Add(widget);
}
public void Dispose()
{
m_Widgets.Clear();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e5ee786a2f4e04b5bbc5c7b2e645272e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show more