This commit is contained in:
2024-09-20 20:30:10 +02:00
commit 4fabf1a6fd
29169 changed files with 1706941 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
using System;
using Unity.Collections;
using UnityEngine.Jobs;
namespace UnityEngine.Rendering
{
/// <summary>
/// Array utilities functions
/// </summary>
public static class ArrayExtensions
{
/// <summary>
/// Resizes a native array. If an empty native array is passed, it will create a new one.
/// </summary>
/// <typeparam name="T">The type of the array</typeparam>
/// <param name="array">Target array to resize</param>
/// <param name="capacity">New size of native array to resize</param>
public static void ResizeArray<T>(this ref NativeArray<T> array, int capacity) where T : struct
{
var newArray = new NativeArray<T>(capacity, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
if (array.IsCreated)
{
NativeArray<T>.Copy(array, newArray, array.Length);
array.Dispose();
}
array = newArray;
}
/// <summary>
/// Resizes a transform access array.
/// </summary>
/// <param name="array">Target array to resize</param>
/// <param name="capacity">New size of transform access array to resize</param>
public static void ResizeArray(this ref TransformAccessArray array, int capacity)
{
var newArray = new TransformAccessArray(capacity);
if (array.isCreated)
{
for (int i = 0; i < array.length; ++i)
newArray.Add(array[i]);
array.Dispose();
}
array = newArray;
}
/// <summary>
/// Resizes an array. If a null reference is passed, it will allocate the desired array.
/// </summary>
/// <typeparam name="T">The type of the array</typeparam>
/// <param name="array">Target array to resize</param>
/// <param name="capacity">New size of array to resize</param>
public static void ResizeArray<T>(ref T[] array, int capacity)
{
if (array == null)
{
array = new T[capacity];
return;
}
Array.Resize<T>(ref array, capacity);
}
}
}

View File

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

View File

@@ -0,0 +1,260 @@
using System;
using System.Runtime.InteropServices;
namespace UnityEngine.Rendering
{
/// <summary>
/// Contains spherical harmonic coefficients used for lighting representation in the format
/// expected by <c>DOTS_INSTANCING_ON</c> shaders.
///
/// The size of the struct is padded to a power of two so arrays of such structs can be efficiently
/// indexed in shaders.
/// </summary>
/// <seealso cref="SphericalHarmonicsL2"/>
[StructLayout(LayoutKind.Sequential)]
[Serializable]
public struct SHCoefficients : IEquatable<SHCoefficients>
{
/// <summary>
/// Contains the SH coefficients that correspond to the <c>unity_SHAr</c> shader property.
/// </summary>
public Vector4 SHAr;
/// <summary>
/// Contains the SH coefficients that correspond to the <c>unity_SHAg</c> shader property.
/// </summary>
public Vector4 SHAg;
/// <summary>
/// Contains the SH coefficients that correspond to the <c>unity_SHAb</c> shader property.
/// </summary>
public Vector4 SHAb;
/// <summary>
/// Contains the SH coefficients that correspond to the <c>unity_SHBr</c> shader property.
/// </summary>
public Vector4 SHBr;
/// <summary>
/// Contains the SH coefficients that correspond to the <c>unity_SHBg</c> shader property.
/// </summary>
public Vector4 SHBg;
/// <summary>
/// Contains the SH coefficients that correspond to the <c>unity_SHBb</c> shader property.
/// </summary>
public Vector4 SHBb;
/// <summary>
/// Contains the SH coefficients that correspond to the <c>unity_SHC</c> shader property.
/// </summary>
public Vector4 SHC;
/// <summary>
/// Contains the baked shadowing data that corresponds to the <c>unity_ProbesOcclusion</c> shader property.
/// </summary>
public Vector4 ProbesOcclusion;
/// <summary>
/// Construct an instance of <c>SHCoefficients</c> that represents the same spherical
/// harmonic coefficients as the parameter.
/// </summary>
/// <param name="sh">The spherical harmonic coefficients to initialize with.</param>
public SHCoefficients(SphericalHarmonicsL2 sh)
{
SHAr = GetSHA(sh, 0);
SHAg = GetSHA(sh, 1);
SHAb = GetSHA(sh, 2);
SHBr = GetSHB(sh, 0);
SHBg = GetSHB(sh, 1);
SHBb = GetSHB(sh, 2);
SHC = GetSHC(sh);
ProbesOcclusion = Vector4.one;
}
/// <summary>
/// Construct an instance of <c>SHCoefficients</c> that represents the same spherical
/// harmonic coefficients as the parameter.
/// </summary>
/// <param name="sh">The spherical harmonic coefficients to initialize with.</param>
/// <param name="probesOcclusion">The baked shadowing data to include with this set of spherical harmonic coefficients.</param>
public SHCoefficients(SphericalHarmonicsL2 sh, Vector4 probesOcclusion)
: this(sh)
{
ProbesOcclusion = probesOcclusion;
}
static Vector4 GetSHA(SphericalHarmonicsL2 sh, int i)
{
return new Vector4(sh[i, 3], sh[i, 1], sh[i, 2], sh[i, 0] - sh[i, 6]);
}
static Vector4 GetSHB(SphericalHarmonicsL2 sh, int i)
{
return new Vector4(sh[i, 4], sh[i, 5], sh[i, 6] * 3f, sh[i, 7]);
}
static Vector4 GetSHC(SphericalHarmonicsL2 sh)
{
return new Vector4(sh[0, 8], sh[1, 8], sh[2, 8], 1);
}
/// <summary>
/// Equals implementation.
/// </summary>
/// <param name="other">Other SHCoefficients instance to comapre this against.</param>
/// <returns>True if contents are equal, False otherwise.</returns>
public bool Equals(SHCoefficients other)
{
return SHAr.Equals(other.SHAr) && SHAg.Equals(other.SHAg) && SHAb.Equals(other.SHAb) && SHBr.Equals(other.SHBr) && SHBg.Equals(other.SHBg) && SHBb.Equals(other.SHBb) && SHC.Equals(other.SHC) && ProbesOcclusion.Equals(other.ProbesOcclusion);
}
/// <summary>
/// Equals implementation.
/// </summary>
/// <param name="obj">Other object to compare this object against</param>
/// <returns>True if contents are equal, False otherwise.</returns>
public override bool Equals(object obj)
{
return obj is SHCoefficients other && Equals(other);
}
/// <summary>
/// GetHashCode implementation.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return HashCode.Combine(SHAr, SHAg, SHAb, SHBr, SHBg, SHBb, SHC, ProbesOcclusion);
}
/// <summary>
/// Equality operator implementation.
/// </summary>
/// <param name="left">Left operand of comparison</param>
/// <param name="right">Right operand of comparison</param>
/// <returns>True if contents are equal, False otherwise.</returns>
public static bool operator ==(SHCoefficients left, SHCoefficients right)
{
return left.Equals(right);
}
/// <summary>
/// Not equals operator implementation.
/// </summary>
/// <param name="left">Left operand of comparison</param>
/// <param name="right">Right operand of comparison</param>
/// <returns>True if contents are not equal, False otherwise.</returns>
public static bool operator !=(SHCoefficients left, SHCoefficients right)
{
return !left.Equals(right);
}
}
/// <summary>
/// Contains default values for built-in properties that the user is expected to manually
/// provide for <c>DOTS_INSTANCING_ON</c> shaders. The struct layout matches the
/// <c>unity_DOTSInstanceGlobalValues</c> constant buffer the shader expects the default
/// values in.
/// </summary>
[Obsolete("BatchRendererGroupGlobals and associated cbuffer are now set automatically by Unity. Setting it manually is no longer necessary or supported.")]
[StructLayout(LayoutKind.Sequential)]
[Serializable]
public struct BatchRendererGroupGlobals : IEquatable<BatchRendererGroupGlobals>
{
/// <summary>
/// The string name of the constant buffer <c>DOTS_INSTANCING_ON</c> shaders use
/// to read default values for the built-in properties contained in this struct.
/// </summary>
public const string kGlobalsPropertyName = "unity_DOTSInstanceGlobalValues";
/// <summary>
/// The unique identifier for <see cref="kGlobalsPropertyName"/>, retrieved using
/// <see cref="Shader.PropertyToID"/>.
/// </summary>
/// <seealso cref="Shader.PropertyToID"/>
public static readonly int kGlobalsPropertyId = Shader.PropertyToID(kGlobalsPropertyName);
/// <summary>
/// The default value to use for the <c>unity_ProbesOcclusion</c> built-in shader property.
/// </summary>
public Vector4 ProbesOcclusion;
/// <summary>
/// The default value to use for the <c>unity_SpecCube0_HDR</c> built-in shader property.
/// </summary>
public Vector4 SpecCube0_HDR;
/// <summary>
/// The default value to use for the <c>unity_SpecCube1_HDR</c> built-in shader property.
/// </summary>
public Vector4 SpecCube1_HDR;
/// <summary>
/// The default values to use for the built-in spherical harmonics shader properties.
/// </summary>
/// <seealso cref="SHCoefficients"/>
public SHCoefficients SHCoefficients;
/// <summary>
/// Construct a struct with default values based on the currently active reflection probe
/// and ambient lighting settings.
/// </summary>
public static BatchRendererGroupGlobals Default
{
get
{
var globals = new BatchRendererGroupGlobals();
globals.ProbesOcclusion = Vector4.one;
globals.SpecCube0_HDR = ReflectionProbe.defaultTextureHDRDecodeValues;
globals.SpecCube1_HDR = globals.SpecCube0_HDR;
globals.SHCoefficients = new SHCoefficients(RenderSettings.ambientProbe);
return globals;
}
}
/// <summary>
/// Equals implementation.
/// </summary>
/// <param name="other">Other BatchRendererGroupGlobals instance to comapre this against.</param>
/// <returns>True if contents are equal, False otherwise.</returns>
public bool Equals(BatchRendererGroupGlobals other)
{
return ProbesOcclusion.Equals(other.ProbesOcclusion) && SpecCube0_HDR.Equals(other.SpecCube0_HDR) && SpecCube1_HDR.Equals(other.SpecCube1_HDR) && SHCoefficients.Equals(other.SHCoefficients);
}
/// <summary>
/// Equals implementation.
/// </summary>
/// <param name="obj">Other object to comapre this against.</param>
/// <returns>True if contents are equal, False otherwise.</returns>
public override bool Equals(object obj)
{
return obj is BatchRendererGroupGlobals other && Equals(other);
}
/// <summary>
/// GetHashCode implementation.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return HashCode.Combine(ProbesOcclusion, SpecCube0_HDR, SpecCube1_HDR, SHCoefficients);
}
/// <summary>
/// Equality operator implementation.
/// </summary>
/// <param name="left">Left operand of comparison</param>
/// <param name="right">Right operand of comparison</param>
/// <returns>True if contents are equal, False otherwise.</returns>
public static bool operator ==(BatchRendererGroupGlobals left, BatchRendererGroupGlobals right)
{
return left.Equals(right);
}
/// <summary>
/// Not equals operator implementation.
/// </summary>
/// <param name="left">Left operand of comparison</param>
/// <param name="right">Right operand of comparison</param>
/// <returns>True if contents are not equal, False otherwise.</returns>
public static bool operator !=(BatchRendererGroupGlobals left, BatchRendererGroupGlobals right)
{
return !left.Equals(right);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ab8ad79e3d094044af2eb94ea63279cf
timeCreated: 1648738004

View File

@@ -0,0 +1,948 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace UnityEngine.Rendering
{
/// <summary>
/// IBitArray interface.
/// </summary>
public interface IBitArray
{
/// <summary>Gets the capacity of this BitArray. This is the number of bits that are usable.</summary>
uint capacity { get; }
/// <summary>Return `true` if all the bits of this BitArray are set to 0. Returns `false` otherwise.</summary>
bool allFalse { get; }
/// <summary>Return `true` if all the bits of this BitArray are set to 1. Returns `false` otherwise.</summary>
bool allTrue { get; }
/// <summary>
/// An indexer that allows access to the bit at a given index. This provides both read and write access.
/// </summary>
/// <param name="index">Index of the bit.</param>
/// <returns>State of the bit at the provided index.</returns>
bool this[uint index] { get; set; }
/// <summary>Writes the bits in the array in a human-readable form. This is as a string of 0s and 1s packed by 8 bits. This is useful for debugging.</summary>
string humanizedData { get; }
/// <summary>
/// Perform an AND bitwise operation between this BitArray and the one you pass into the function and return the result. Both BitArrays must have the same capacity. This will not change current BitArray values.
/// </summary>
/// <param name="other">BitArray with which to the And operation.</param>
/// <returns>The resulting bit array.</returns>
IBitArray BitAnd(IBitArray other);
/// <summary>
/// Perform an OR bitwise operation between this BitArray and the one you pass into the function and return the result. Both BitArrays must have the same capacity. This will not change current BitArray values.
/// </summary>
/// <param name="other">BitArray with which to the Or operation.</param>
/// <returns>The resulting bit array.</returns>
IBitArray BitOr(IBitArray other);
/// <summary>
/// Return the BitArray with every bit inverted.
/// </summary>
/// <returns></returns>
IBitArray BitNot();
}
// /!\ Important for serialization:
// Serialization helper will rely on the name of the struct type.
// In order to work, it must be BitArrayN where N is the capacity without suffix.
/// <summary>
/// Bit array of size 8.
/// </summary>
[Serializable]
[System.Diagnostics.DebuggerDisplay("{this.GetType().Name} {humanizedData}")]
public struct BitArray8 : IBitArray
{
[SerializeField]
byte data;
/// <summary>Number of elements in the bit array.</summary>
public uint capacity => 8u;
/// <summary>True if all bits are 0.</summary>
public bool allFalse => data == 0u;
/// <summary>True if all bits are 1.</summary>
public bool allTrue => data == byte.MaxValue;
/// <summary>Returns the bit array in a human readable form.</summary>
public string humanizedData => String.Format("{0, " + capacity + "}", Convert.ToString(data, 2)).Replace(' ', '0');
/// <summary>
/// Returns the state of the bit at a specific index.
/// </summary>
/// <param name="index">Index of the bit.</param>
/// <returns>State of the bit at the provided index.</returns>
public bool this[uint index]
{
get => BitArrayUtilities.Get8(index, data);
set => BitArrayUtilities.Set8(index, ref data, value);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="initValue">Initialization value.</param>
public BitArray8(byte initValue) => data = initValue;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="bitIndexTrue">List of indices where bits should be set to true.</param>
public BitArray8(IEnumerable<uint> bitIndexTrue)
{
data = (byte)0u;
if (bitIndexTrue == null)
return;
for (int index = bitIndexTrue.Count() - 1; index >= 0; --index)
{
uint bitIndex = bitIndexTrue.ElementAt(index);
if (bitIndex >= capacity) continue;
data |= (byte)(1u << (int)bitIndex);
}
}
/// <summary>
/// Bit-wise Not operator
/// </summary>
/// <param name="a">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray8 operator ~(BitArray8 a) => new BitArray8((byte)~a.data);
/// <summary>
/// Bit-wise Or operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray8 operator |(BitArray8 a, BitArray8 b) => new BitArray8((byte)(a.data | b.data));
/// <summary>
/// Bit-wise And operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray8 operator &(BitArray8 a, BitArray8 b) => new BitArray8((byte)(a.data & b.data));
/// <summary>
/// Bit-wise And
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitAnd(IBitArray other) => this & (BitArray8)other;
/// <summary>
/// Bit-wise Or
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitOr(IBitArray other) => this | (BitArray8)other;
/// <summary>
/// Bit-wise Not
/// </summary>
/// <returns>The resulting bit array.</returns>
public IBitArray BitNot() => ~this;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if both bit arrays are equals.</returns>
public static bool operator ==(BitArray8 a, BitArray8 b) => a.data == b.data;
/// <summary>
/// Inequality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if the bit arrays are not equals.</returns>
public static bool operator !=(BitArray8 a, BitArray8 b) => a.data != b.data;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="obj">Bit array to compare to.</param>
/// <returns>True if the provided bit array is equal to this..</returns>
public override bool Equals(object obj) => obj is BitArray8 && ((BitArray8)obj).data == data;
/// <summary>
/// Get the hashcode of the bit array.
/// </summary>
/// <returns>Hashcode of the bit array.</returns>
public override int GetHashCode() => 1768953197 + data.GetHashCode();
}
/// <summary>
/// Bit array of size 16.
/// </summary>
[Serializable]
[System.Diagnostics.DebuggerDisplay("{this.GetType().Name} {humanizedData}")]
public struct BitArray16 : IBitArray
{
[SerializeField]
ushort data;
/// <summary>Number of elements in the bit array.</summary>
public uint capacity => 16u;
/// <summary>True if all bits are 0.</summary>
public bool allFalse => data == 0u;
/// <summary>True if all bits are 1.</summary>
public bool allTrue => data == ushort.MaxValue;
/// <summary>Returns the bit array in a human readable form.</summary>
public string humanizedData => System.Text.RegularExpressions.Regex.Replace(String.Format("{0, " + capacity + "}", Convert.ToString(data, 2)).Replace(' ', '0'), ".{8}", "$0.").TrimEnd('.');
/// <summary>
/// Returns the state of the bit at a specific index.
/// </summary>
/// <param name="index">Index of the bit.</param>
/// <returns>State of the bit at the provided index.</returns>
public bool this[uint index]
{
get => BitArrayUtilities.Get16(index, data);
set => BitArrayUtilities.Set16(index, ref data, value);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="initValue">Initialization value.</param>
public BitArray16(ushort initValue) => data = initValue;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="bitIndexTrue">List of indices where bits should be set to true.</param>
public BitArray16(IEnumerable<uint> bitIndexTrue)
{
data = (ushort)0u;
if (bitIndexTrue == null)
return;
for (int index = bitIndexTrue.Count() - 1; index >= 0; --index)
{
uint bitIndex = bitIndexTrue.ElementAt(index);
if (bitIndex >= capacity) continue;
data |= (ushort)(1u << (int)bitIndex);
}
}
/// <summary>
/// Bit-wise Not operator
/// </summary>
/// <param name="a">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray16 operator ~(BitArray16 a) => new BitArray16((ushort)~a.data);
/// <summary>
/// Bit-wise Or operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray16 operator |(BitArray16 a, BitArray16 b) => new BitArray16((ushort)(a.data | b.data));
/// <summary>
/// Bit-wise And operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray16 operator &(BitArray16 a, BitArray16 b) => new BitArray16((ushort)(a.data & b.data));
/// <summary>
/// Bit-wise And
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitAnd(IBitArray other) => this & (BitArray16)other;
/// <summary>
/// Bit-wise Or
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitOr(IBitArray other) => this | (BitArray16)other;
/// <summary>
/// Bit-wise Not
/// </summary>
/// <returns>The resulting bit array.</returns>
public IBitArray BitNot() => ~this;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if both bit arrays are equals.</returns>
public static bool operator ==(BitArray16 a, BitArray16 b) => a.data == b.data;
/// <summary>
/// Inequality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if the bit arrays are not equals.</returns>
public static bool operator !=(BitArray16 a, BitArray16 b) => a.data != b.data;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="obj">Bit array to compare to.</param>
/// <returns>True if the provided bit array is equal to this..</returns>
public override bool Equals(object obj) => obj is BitArray16 && ((BitArray16)obj).data == data;
/// <summary>
/// Get the hashcode of the bit array.
/// </summary>
/// <returns>Hashcode of the bit array.</returns>
public override int GetHashCode() => 1768953197 + data.GetHashCode();
}
/// <summary>
/// Bit array of size 32.
/// </summary>
[Serializable]
[System.Diagnostics.DebuggerDisplay("{this.GetType().Name} {humanizedData}")]
public struct BitArray32 : IBitArray
{
[SerializeField]
uint data;
/// <summary>Number of elements in the bit array.</summary>
public uint capacity => 32u;
/// <summary>True if all bits are 0.</summary>
public bool allFalse => data == 0u;
/// <summary>True if all bits are 1.</summary>
public bool allTrue => data == uint.MaxValue;
string humanizedVersion => Convert.ToString(data, 2);
/// <summary>Returns the bit array in a human readable form.</summary>
public string humanizedData => System.Text.RegularExpressions.Regex.Replace(String.Format("{0, " + capacity + "}", Convert.ToString(data, 2)).Replace(' ', '0'), ".{8}", "$0.").TrimEnd('.');
/// <summary>
/// Returns the state of the bit at a specific index.
/// </summary>
/// <param name="index">Index of the bit.</param>
/// <returns>State of the bit at the provided index.</returns>
public bool this[uint index]
{
get => BitArrayUtilities.Get32(index, data);
set => BitArrayUtilities.Set32(index, ref data, value);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="initValue">Initialization value.</param>
public BitArray32(uint initValue) => data = initValue;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="bitIndexTrue">List of indices where bits should be set to true.</param>
public BitArray32(IEnumerable<uint> bitIndexTrue)
{
data = 0u;
if (bitIndexTrue == null)
return;
for (int index = bitIndexTrue.Count() - 1; index >= 0; --index)
{
uint bitIndex = bitIndexTrue.ElementAt(index);
if (bitIndex >= capacity) continue;
data |= 1u << (int)bitIndex;
}
}
/// <summary>
/// Bit-wise And
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitAnd(IBitArray other) => this & (BitArray32)other;
/// <summary>
/// Bit-wise Or
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitOr(IBitArray other) => this | (BitArray32)other;
/// <summary>
/// Bit-wise Not
/// </summary>
/// <returns>The resulting bit array.</returns>
public IBitArray BitNot() => ~this;
/// <summary>
/// Bit-wise Not operator
/// </summary>
/// <param name="a">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray32 operator ~(BitArray32 a) => new BitArray32(~a.data);
/// <summary>
/// Bit-wise Or operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray32 operator |(BitArray32 a, BitArray32 b) => new BitArray32(a.data | b.data);
/// <summary>
/// Bit-wise And operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray32 operator &(BitArray32 a, BitArray32 b) => new BitArray32(a.data & b.data);
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if both bit arrays are equals.</returns>
public static bool operator ==(BitArray32 a, BitArray32 b) => a.data == b.data;
/// <summary>
/// Inequality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if the bit arrays are not equals.</returns>
public static bool operator !=(BitArray32 a, BitArray32 b) => a.data != b.data;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="obj">Bit array to compare to.</param>
/// <returns>True if the provided bit array is equal to this..</returns>
public override bool Equals(object obj) => obj is BitArray32 && ((BitArray32)obj).data == data;
/// <summary>
/// Get the hashcode of the bit array.
/// </summary>
/// <returns>Hashcode of the bit array.</returns>
public override int GetHashCode() => 1768953197 + data.GetHashCode();
}
/// <summary>
/// Bit array of size 64.
/// </summary>
[Serializable]
[System.Diagnostics.DebuggerDisplay("{this.GetType().Name} {humanizedData}")]
public struct BitArray64 : IBitArray
{
[SerializeField]
ulong data;
/// <summary>Number of elements in the bit array.</summary>
public uint capacity => 64u;
/// <summary>True if all bits are 0.</summary>
public bool allFalse => data == 0uL;
/// <summary>True if all bits are 1.</summary>
public bool allTrue => data == ulong.MaxValue;
/// <summary>Returns the bit array in a human readable form.</summary>
public string humanizedData => System.Text.RegularExpressions.Regex.Replace(String.Format("{0, " + capacity + "}", Convert.ToString((long)data, 2)).Replace(' ', '0'), ".{8}", "$0.").TrimEnd('.');
/// <summary>
/// Returns the state of the bit at a specific index.
/// </summary>
/// <param name="index">Index of the bit.</param>
/// <returns>State of the bit at the provided index.</returns>
public bool this[uint index]
{
get => BitArrayUtilities.Get64(index, data);
set => BitArrayUtilities.Set64(index, ref data, value);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="initValue">Initialization value.</param>
public BitArray64(ulong initValue) => data = initValue;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="bitIndexTrue">List of indices where bits should be set to true.</param>
public BitArray64(IEnumerable<uint> bitIndexTrue)
{
data = 0L;
if (bitIndexTrue == null)
return;
for (int index = bitIndexTrue.Count() - 1; index >= 0; --index)
{
uint bitIndex = bitIndexTrue.ElementAt(index);
if (bitIndex >= capacity) continue;
data |= 1uL << (int)bitIndex;
}
}
/// <summary>
/// Bit-wise Not operator
/// </summary>
/// <param name="a">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray64 operator ~(BitArray64 a) => new BitArray64(~a.data);
/// <summary>
/// Bit-wise Or operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray64 operator |(BitArray64 a, BitArray64 b) => new BitArray64(a.data | b.data);
/// <summary>
/// Bit-wise And operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray64 operator &(BitArray64 a, BitArray64 b) => new BitArray64(a.data & b.data);
/// <summary>
/// Bit-wise And
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitAnd(IBitArray other) => this & (BitArray64)other;
/// <summary>
/// Bit-wise Or
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitOr(IBitArray other) => this | (BitArray64)other;
/// <summary>
/// Bit-wise Not
/// </summary>
/// <returns>The resulting bit array.</returns>
public IBitArray BitNot() => ~this;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if both bit arrays are equals.</returns>
public static bool operator ==(BitArray64 a, BitArray64 b) => a.data == b.data;
/// <summary>
/// Inequality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if the bit arrays are not equals.</returns>
public static bool operator !=(BitArray64 a, BitArray64 b) => a.data != b.data;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="obj">Bit array to compare to.</param>
/// <returns>True if the provided bit array is equal to this..</returns>
public override bool Equals(object obj) => obj is BitArray64 && ((BitArray64)obj).data == data;
/// <summary>
/// Get the hashcode of the bit array.
/// </summary>
/// <returns>Hashcode of the bit array.</returns>
public override int GetHashCode() => 1768953197 + data.GetHashCode();
}
/// <summary>
/// Bit array of size 128.
/// </summary>
[Serializable]
[System.Diagnostics.DebuggerDisplay("{this.GetType().Name} {humanizedData}")]
public struct BitArray128 : IBitArray
{
[SerializeField]
ulong data1;
[SerializeField]
ulong data2;
/// <summary>Number of elements in the bit array.</summary>
public uint capacity => 128u;
/// <summary>True if all bits are 0.</summary>
public bool allFalse => data1 == 0uL && data2 == 0uL;
/// <summary>True if all bits are 1.</summary>
public bool allTrue => data1 == ulong.MaxValue && data2 == ulong.MaxValue;
/// <summary>Returns the bit array in a human readable form.</summary>
public string humanizedData =>
System.Text.RegularExpressions.Regex.Replace(String.Format("{0, " + 64u + "}", Convert.ToString((long)data2, 2)).Replace(' ', '0'), ".{8}", "$0.")
+ System.Text.RegularExpressions.Regex.Replace(String.Format("{0, " + 64u + "}", Convert.ToString((long)data1, 2)).Replace(' ', '0'), ".{8}", "$0.").TrimEnd('.');
/// <summary>
/// Returns the state of the bit at a specific index.
/// </summary>
/// <param name="index">Index of the bit.</param>
/// <returns>State of the bit at the provided index.</returns>
public bool this[uint index]
{
get => BitArrayUtilities.Get128(index, data1, data2);
set => BitArrayUtilities.Set128(index, ref data1, ref data2, value);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="initValue1">Initialization value 1.</param>
/// <param name="initValue2">Initialization value 2.</param>
public BitArray128(ulong initValue1, ulong initValue2)
{
data1 = initValue1;
data2 = initValue2;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="bitIndexTrue">List of indices where bits should be set to true.</param>
public BitArray128(IEnumerable<uint> bitIndexTrue)
{
data1 = data2 = 0uL;
if (bitIndexTrue == null)
return;
for (int index = bitIndexTrue.Count() - 1; index >= 0; --index)
{
uint bitIndex = bitIndexTrue.ElementAt(index);
if (bitIndex < 64u)
data1 |= 1uL << (int)bitIndex;
else if (bitIndex < capacity)
data2 |= 1uL << (int)(bitIndex - 64u);
}
}
/// <summary>
/// Bit-wise Not operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray128 operator ~(BitArray128 a) => new BitArray128(~a.data1, ~a.data2);
/// <summary>
/// Bit-wise Or operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray128 operator |(BitArray128 a, BitArray128 b) => new BitArray128(a.data1 | b.data1, a.data2 | b.data2);
/// <summary>
/// Bit-wise And operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray128 operator &(BitArray128 a, BitArray128 b) => new BitArray128(a.data1 & b.data1, a.data2 & b.data2);
/// <summary>
/// Bit-wise And
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitAnd(IBitArray other) => this & (BitArray128)other;
/// <summary>
/// Bit-wise Or
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitOr(IBitArray other) => this | (BitArray128)other;
/// <summary>
/// Bit-wise Not
/// </summary>
/// <returns>The resulting bit array.</returns>
public IBitArray BitNot() => ~this;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if both bit arrays are equals.</returns>
public static bool operator ==(BitArray128 a, BitArray128 b) => a.data1 == b.data1 && a.data2 == b.data2;
/// <summary>
/// Inequality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if the bit arrays are not equals.</returns>
public static bool operator !=(BitArray128 a, BitArray128 b) => a.data1 != b.data1 || a.data2 != b.data2;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="obj">Bit array to compare to.</param>
/// <returns>True if the provided bit array is equal to this..</returns>
public override bool Equals(object obj) => (obj is BitArray128) && data1.Equals(((BitArray128)obj).data1) && data2.Equals(((BitArray128)obj).data2);
/// <summary>
/// Get the hashcode of the bit array.
/// </summary>
/// <returns>Hashcode of the bit array.</returns>
public override int GetHashCode()
{
var hashCode = 1755735569;
hashCode = hashCode * -1521134295 + data1.GetHashCode();
hashCode = hashCode * -1521134295 + data2.GetHashCode();
return hashCode;
}
}
/// <summary>
/// Bit array of size 256.
/// </summary>
[Serializable]
[System.Diagnostics.DebuggerDisplay("{this.GetType().Name} {humanizedData}")]
public struct BitArray256 : IBitArray
{
[SerializeField]
ulong data1;
[SerializeField]
ulong data2;
[SerializeField]
ulong data3;
[SerializeField]
ulong data4;
/// <summary>Number of elements in the bit array.</summary>
public uint capacity => 256u;
/// <summary>True if all bits are 0.</summary>
public bool allFalse => data1 == 0uL && data2 == 0uL && data3 == 0uL && data4 == 0uL;
/// <summary>True if all bits are 1.</summary>
public bool allTrue => data1 == ulong.MaxValue && data2 == ulong.MaxValue && data3 == ulong.MaxValue && data4 == ulong.MaxValue;
/// <summary>Returns the bit array in a human readable form.</summary>
public string humanizedData =>
System.Text.RegularExpressions.Regex.Replace(String.Format("{0, " + 64u + "}", Convert.ToString((long)data4, 2)).Replace(' ', '0'), ".{8}", "$0.")
+ System.Text.RegularExpressions.Regex.Replace(String.Format("{0, " + 64u + "}", Convert.ToString((long)data3, 2)).Replace(' ', '0'), ".{8}", "$0.")
+ System.Text.RegularExpressions.Regex.Replace(String.Format("{0, " + 64u + "}", Convert.ToString((long)data2, 2)).Replace(' ', '0'), ".{8}", "$0.")
+ System.Text.RegularExpressions.Regex.Replace(String.Format("{0, " + 64u + "}", Convert.ToString((long)data1, 2)).Replace(' ', '0'), ".{8}", "$0.").TrimEnd('.');
/// <summary>
/// Returns the state of the bit at a specific index.
/// </summary>
/// <param name="index">Index of the bit.</param>
/// <returns>State of the bit at the provided index.</returns>
public bool this[uint index]
{
get => BitArrayUtilities.Get256(index, data1, data2, data3, data4);
set => BitArrayUtilities.Set256(index, ref data1, ref data2, ref data3, ref data4, value);
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="initValue1">Initialization value 1.</param>
/// <param name="initValue2">Initialization value 2.</param>
/// <param name="initValue3">Initialization value 3.</param>
/// <param name="initValue4">Initialization value 4.</param>
public BitArray256(ulong initValue1, ulong initValue2, ulong initValue3, ulong initValue4)
{
data1 = initValue1;
data2 = initValue2;
data3 = initValue3;
data4 = initValue4;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="bitIndexTrue">List of indices where bits should be set to true.</param>
public BitArray256(IEnumerable<uint> bitIndexTrue)
{
data1 = data2 = data3 = data4 = 0uL;
if (bitIndexTrue == null)
return;
for (int index = bitIndexTrue.Count() - 1; index >= 0; --index)
{
uint bitIndex = bitIndexTrue.ElementAt(index);
if (bitIndex < 64u)
data1 |= 1uL << (int)bitIndex;
else if (bitIndex < 128u)
data2 |= 1uL << (int)(bitIndex - 64u);
else if (bitIndex < 192u)
data3 |= 1uL << (int)(bitIndex - 128u);
else if (bitIndex < capacity)
data4 |= 1uL << (int)(bitIndex - 192u);
}
}
/// <summary>
/// Bit-wise Not operator
/// </summary>
/// <param name="a">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray256 operator ~(BitArray256 a) => new BitArray256(~a.data1, ~a.data2, ~a.data3, ~a.data4);
/// <summary>
/// Bit-wise Or operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray256 operator |(BitArray256 a, BitArray256 b) => new BitArray256(a.data1 | b.data1, a.data2 | b.data2, a.data3 | b.data3, a.data4 | b.data4);
/// <summary>
/// Bit-wise And operator
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>The resulting bit array.</returns>
public static BitArray256 operator &(BitArray256 a, BitArray256 b) => new BitArray256(a.data1 & b.data1, a.data2 & b.data2, a.data3 & b.data3, a.data4 & b.data4);
/// <summary>
/// Bit-wise And
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitAnd(IBitArray other) => this & (BitArray256)other;
/// <summary>
/// Bit-wise Or
/// </summary>
/// <param name="other">Bit array with which to do the operation.</param>
/// <returns>The resulting bit array.</returns>
public IBitArray BitOr(IBitArray other) => this | (BitArray256)other;
/// <summary>
/// Bit-wise Not
/// </summary>
/// <returns>The resulting bit array.</returns>
public IBitArray BitNot() => ~this;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if both bit arrays are equals.</returns>
public static bool operator ==(BitArray256 a, BitArray256 b) => a.data1 == b.data1 && a.data2 == b.data2 && a.data3 == b.data3 && a.data4 == b.data4;
/// <summary>
/// Inequality operator.
/// </summary>
/// <param name="a">First bit array.</param>
/// <param name="b">Second bit array.</param>
/// <returns>True if the bit arrays are not equals.</returns>
public static bool operator !=(BitArray256 a, BitArray256 b) => a.data1 != b.data1 || a.data2 != b.data2 || a.data3 != b.data3 || a.data4 != b.data4;
/// <summary>
/// Equality operator.
/// </summary>
/// <param name="obj">Bit array to compare to.</param>
/// <returns>True if the provided bit array is equal to this..</returns>
public override bool Equals(object obj) =>
(obj is BitArray256)
&& data1.Equals(((BitArray256)obj).data1)
&& data2.Equals(((BitArray256)obj).data2)
&& data3.Equals(((BitArray256)obj).data3)
&& data4.Equals(((BitArray256)obj).data4);
/// <summary>
/// Get the hashcode of the bit array.
/// </summary>
/// <returns>Hashcode of the bit array.</returns>
public override int GetHashCode()
{
var hashCode = 1870826326;
hashCode = hashCode * -1521134295 + data1.GetHashCode();
hashCode = hashCode * -1521134295 + data2.GetHashCode();
hashCode = hashCode * -1521134295 + data3.GetHashCode();
hashCode = hashCode * -1521134295 + data4.GetHashCode();
return hashCode;
}
}
/// <summary>
/// Bit array utility class.
/// </summary>
public static class BitArrayUtilities
{
//written here to not duplicate the serialized accessor and runtime accessor
/// <summary>
/// Get a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data">Bit array data.</param>
/// <returns>The value of the bit at the specific index.</returns>
public static bool Get8(uint index, byte data) => (data & (1u << (int)index)) != 0u;
/// <summary>
/// Get a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data">Bit array data.</param>
/// <returns>The value of the bit at the specific index.</returns>
public static bool Get16(uint index, ushort data) => (data & (1u << (int)index)) != 0u;
/// <summary>
/// Get a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data">Bit array data.</param>
/// <returns>The value of the bit at the specific index.</returns>
public static bool Get32(uint index, uint data) => (data & (1u << (int)index)) != 0u;
/// <summary>
/// Get a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data">Bit array data.</param>
/// <returns>The value of the bit at the specific index.</returns>
public static bool Get64(uint index, ulong data) => (data & (1uL << (int)index)) != 0uL;
/// <summary>
/// Get a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data1">Bit array data 1.</param>
/// <param name="data2">Bit array data 2.</param>
/// <returns>The value of the bit at the specific index.</returns>
public static bool Get128(uint index, ulong data1, ulong data2)
=> index < 64u
? (data1 & (1uL << (int)index)) != 0uL
: (data2 & (1uL << (int)(index - 64u))) != 0uL;
/// <summary>
/// Get a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data1">Bit array data 1.</param>
/// <param name="data2">Bit array data 2.</param>
/// <param name="data3">Bit array data 3.</param>
/// <param name="data4">Bit array data 4.</param>
/// <returns>The value of the bit at the specific index.</returns>
public static bool Get256(uint index, ulong data1, ulong data2, ulong data3, ulong data4)
=> index < 128u
? index < 64u
? (data1 & (1uL << (int)index)) != 0uL
: (data2 & (1uL << (int)(index - 64u))) != 0uL
: index < 192u
? (data3 & (1uL << (int)(index - 128u))) != 0uL
: (data4 & (1uL << (int)(index - 192u))) != 0uL;
/// <summary>
/// Set a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data">Bit array data.</param>
/// <param name="value">Value to set the bit to.</param>
public static void Set8(uint index, ref byte data, bool value) => data = (byte)(value ? (data | (1u << (int)index)) : (data & ~(1u << (int)index)));
/// <summary>
/// Set a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data">Bit array data.</param>
/// <param name="value">Value to set the bit to.</param>
public static void Set16(uint index, ref ushort data, bool value) => data = (ushort)(value ? (data | (1u << (int)index)) : (data & ~(1u << (int)index)));
/// <summary>
/// Set a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data">Bit array data.</param>
/// <param name="value">Value to set the bit to.</param>
public static void Set32(uint index, ref uint data, bool value) => data = (value ? (data | (1u << (int)index)) : (data & ~(1u << (int)index)));
/// <summary>
/// Set a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data">Bit array data.</param>
/// <param name="value">Value to set the bit to.</param>
public static void Set64(uint index, ref ulong data, bool value) => data = (value ? (data | (1uL << (int)index)) : (data & ~(1uL << (int)index)));
/// <summary>
/// Set a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data1">Bit array data 1.</param>
/// <param name="data2">Bit array data 2.</param>
/// <param name="value">Value to set the bit to.</param>
public static void Set128(uint index, ref ulong data1, ref ulong data2, bool value)
{
if (index < 64u)
data1 = (value ? (data1 | (1uL << (int)index)) : (data1 & ~(1uL << (int)index)));
else
data2 = (value ? (data2 | (1uL << (int)(index - 64u))) : (data2 & ~(1uL << (int)(index - 64u))));
}
/// <summary>
/// Set a bit at a specific index.
/// </summary>
/// <param name="index">Bit index.</param>
/// <param name="data1">Bit array data 1.</param>
/// <param name="data2">Bit array data 2.</param>
/// <param name="data3">Bit array data 3.</param>
/// <param name="data4">Bit array data 4.</param>
/// <param name="value">Value to set the bit to.</param>
public static void Set256(uint index, ref ulong data1, ref ulong data2, ref ulong data3, ref ulong data4, bool value)
{
if (index < 64u)
data1 = (value ? (data1 | (1uL << (int)index)) : (data1 & ~(1uL << (int)index)));
else if (index < 128u)
data2 = (value ? (data2 | (1uL << (int)(index - 64u))) : (data2 & ~(1uL << (int)(index - 64u))));
else if (index < 192u)
data3 = (value ? (data3 | (1uL << (int)(index - 64u))) : (data3 & ~(1uL << (int)(index - 128u))));
else
data4 = (value ? (data4 | (1uL << (int)(index - 64u))) : (data4 & ~(1uL << (int)(index - 192u))));
}
}
}

View File

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

View File

@@ -0,0 +1,229 @@
#ifndef UNITY_CORE_BLIT_INCLUDED
#define UNITY_CORE_BLIT_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GlobalSamplers.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
TEXTURE2D_X(_BlitTexture);
TEXTURECUBE(_BlitCubeTexture);
uniform float4 _BlitScaleBias;
uniform float4 _BlitScaleBiasRt;
uniform float _BlitMipLevel;
uniform float2 _BlitTextureSize;
uniform uint _BlitPaddingSize;
uniform int _BlitTexArraySlice;
uniform float4 _BlitDecodeInstructions;
#if SHADER_API_GLES
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
#else
struct Attributes
{
uint vertexID : SV_VertexID;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
#endif
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vert(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
#if SHADER_API_GLES
float4 pos = input.positionOS;
float2 uv = input.uv;
#else
float4 pos = GetFullScreenTriangleVertexPosition(input.vertexID);
float2 uv = GetFullScreenTriangleTexCoord(input.vertexID);
#endif
output.positionCS = pos;
output.texcoord = uv * _BlitScaleBias.xy + _BlitScaleBias.zw;
return output;
}
Varyings VertQuad(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
#if SHADER_API_GLES
float4 pos = input.positionOS;
float2 uv = input.uv;
#else
float4 pos = GetQuadVertexPosition(input.vertexID);
float2 uv = GetQuadTexCoord(input.vertexID);
#endif
output.positionCS = pos * float4(_BlitScaleBiasRt.x, _BlitScaleBiasRt.y, 1, 1) + float4(_BlitScaleBiasRt.z, _BlitScaleBiasRt.w, 0, 0);
output.positionCS.xy = output.positionCS.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f); //convert to -1..1
output.texcoord = uv * _BlitScaleBias.xy + _BlitScaleBias.zw;
return output;
}
Varyings VertQuadPadding(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
float2 scalePadding = ((_BlitTextureSize + float(_BlitPaddingSize)) / _BlitTextureSize);
float2 offsetPadding = (float(_BlitPaddingSize) / 2.0) / (_BlitTextureSize + _BlitPaddingSize);
#if SHADER_API_GLES
float4 pos = input.positionOS;
float2 uv = input.uv;
#else
float4 pos = GetQuadVertexPosition(input.vertexID);
float2 uv = GetQuadTexCoord(input.vertexID);
#endif
output.positionCS = pos * float4(_BlitScaleBiasRt.x, _BlitScaleBiasRt.y, 1, 1) + float4(_BlitScaleBiasRt.z, _BlitScaleBiasRt.w, 0, 0);
output.positionCS.xy = output.positionCS.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f); //convert to -1..1
output.texcoord = uv;
output.texcoord = (output.texcoord - offsetPadding) * scalePadding;
output.texcoord = output.texcoord * _BlitScaleBias.xy + _BlitScaleBias.zw;
return output;
}
float4 FragBlit(Varyings input, SamplerState s)
{
#if defined(USE_TEXTURE2D_X_AS_ARRAY) && defined(BLIT_SINGLE_SLICE)
return SAMPLE_TEXTURE2D_ARRAY_LOD(_BlitTexture, s, input.texcoord.xy, _BlitTexArraySlice, _BlitMipLevel);
#endif
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, s, input.texcoord.xy, _BlitMipLevel);
}
float4 FragNearest(Varyings input) : SV_Target
{
return FragBlit(input, sampler_PointClamp);
}
float4 FragBilinear(Varyings input) : SV_Target
{
return FragBlit(input, sampler_LinearClamp);
}
float4 FragBilinearRepeat(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearRepeat, uv, _BlitMipLevel);
}
float4 FragNearestRepeat(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_PointRepeat, uv, _BlitMipLevel);
}
float4 FragOctahedralBilinearRepeat(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = RepeatOctahedralUV(input.texcoord.x, input.texcoord.y);
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearRepeat, uv, _BlitMipLevel);
}
float4 FragOctahedralProject(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 UV = saturate(input.texcoord);
float3 dir = UnpackNormalOctQuadEncode(2.0f*UV - 1.0f);
return float4(SAMPLE_TEXTURECUBE_LOD(_BlitCubeTexture, sampler_LinearRepeat, dir, _BlitMipLevel).rgb, 1);
}
float4 FragOctahedralProjectNearestRepeat(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = RepeatOctahedralUV(input.texcoord.x, input.texcoord.y);
float3 dir = UnpackNormalOctQuadEncode(2.0f * uv - 1.0f);
#ifdef BLIT_DECODE_HDR
return float4(DecodeHDREnvironment(SAMPLE_TEXTURECUBE_LOD(_BlitCubeTexture, sampler_PointRepeat, dir, _BlitMipLevel), _BlitDecodeInstructions), 1);
#else
return float4(SAMPLE_TEXTURECUBE_LOD(_BlitCubeTexture, sampler_PointRepeat, dir, _BlitMipLevel).rgb, 1);
#endif
}
float4 FragOctahedralProjectBilinearRepeat(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = RepeatOctahedralUV(input.texcoord.x, input.texcoord.y);
float3 dir = UnpackNormalOctQuadEncode(2.0f * uv - 1.0f);
#ifdef BLIT_DECODE_HDR
return float4(DecodeHDREnvironment(SAMPLE_TEXTURECUBE_LOD(_BlitCubeTexture, sampler_LinearRepeat, dir, _BlitMipLevel), _BlitDecodeInstructions), 1);
#else
return float4(SAMPLE_TEXTURECUBE_LOD(_BlitCubeTexture, sampler_LinearRepeat, dir, _BlitMipLevel).rgb, 1);
#endif
}
// 8-bit single channel sampling/format conversions
float4 FragOctahedralProjectLuminance(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 UV = saturate(input.texcoord);
float3 dir = UnpackNormalOctQuadEncode(2.0f*UV - 1.0f);
// sRGB/Rec.709
return Luminance(SAMPLE_TEXTURECUBE_LOD(_BlitCubeTexture, sampler_LinearRepeat, dir, _BlitMipLevel)).xxxx;
}
float4 FragOctahedralProjectRedToRGBA(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 UV = saturate(input.texcoord);
float3 dir = UnpackNormalOctQuadEncode(2.0f*UV - 1.0f);
return SAMPLE_TEXTURECUBE_LOD(_BlitCubeTexture, sampler_LinearRepeat, dir, _BlitMipLevel).rrrr;
}
float4 FragOctahedralProjectAlphaToRGBA(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 UV = saturate(input.texcoord);
float3 dir = UnpackNormalOctQuadEncode(2.0f*UV - 1.0f);
return SAMPLE_TEXTURECUBE_LOD(_BlitCubeTexture, sampler_LinearRepeat, dir, _BlitMipLevel).aaaa;
}
float4 FragBilinearLuminance(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
// sRGB/Rec.709
return Luminance(SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearRepeat, uv, _BlitMipLevel)).xxxx;
}
float4 FragBilinearRedToRGBA(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearRepeat, uv, _BlitMipLevel).rrrr;
}
float4 FragBilinearAlphaToRGBA(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearRepeat, uv, _BlitMipLevel).aaaa;
}
#endif //UNITY_CORE_BLIT_INCLUDED

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d55706914cfa84431bb4f9277ebd1054
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
#ifndef UNITY_CORE_BLIT_COLOR_AND_DEPTH_INCLUDED
#define UNITY_CORE_BLIT_COLOR_AND_DEPTH_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"
TEXTURE2D (_BlitTexture);
TEXTURE2D (_InputDepthTexture);
SamplerState sampler_PointClamp;
SamplerState sampler_LinearClamp;
uniform float4 _BlitScaleBias;
uniform float _BlitMipLevel;
#if SHADER_API_GLES
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
#else
struct Attributes
{
uint vertexID : SV_VertexID;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
#endif
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vert(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
#if SHADER_API_GLES
float4 pos = input.positionOS;
float2 uv = input.uv;
#else
float4 pos = GetFullScreenTriangleVertexPosition(input.vertexID);
float2 uv = GetFullScreenTriangleTexCoord(input.vertexID);
#endif
output.positionCS = pos;
output.texcoord = uv * _BlitScaleBias.xy + _BlitScaleBias.zw;
return output;
}
float4 FragColorOnly(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
return SAMPLE_TEXTURE2D_LOD(_BlitTexture, sampler_LinearClamp, input.texcoord.xy, _BlitMipLevel);
}
struct PixelData
{
float4 color : SV_Target;
float depth : SV_Depth;
};
PixelData FragColorAndDepth(Varyings input)
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
PixelData pd;
pd.color = SAMPLE_TEXTURE2D_LOD(_BlitTexture, sampler_LinearClamp, input.texcoord.xy, _BlitMipLevel);
pd.depth = SAMPLE_TEXTURE2D_LOD(_InputDepthTexture, sampler_PointClamp, input.texcoord.xy, _BlitMipLevel).x;
return pd;
}
#endif // UNITY_CORE_BLIT_COLOR_AND_DEPTH_INCLUDED

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: cdea49463de0449b48cacd6a3925dcf7
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,660 @@
using System;
using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Assertions;
using System.Text.RegularExpressions;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.Rendering
{
/// <summary>
/// Various blit (texture copy) utilities for the Scriptable Render Pipelines.
/// </summary>
public static class Blitter
{
static Material s_Blit;
static Material s_BlitTexArray;
static Material s_BlitTexArraySingleSlice;
static Material s_BlitColorAndDepth;
static MaterialPropertyBlock s_PropertyBlock = new MaterialPropertyBlock();
static Mesh s_TriangleMesh;
static Mesh s_QuadMesh;
static LocalKeyword s_DecodeHdrKeyword;
static class BlitShaderIDs
{
public static readonly int _BlitTexture = Shader.PropertyToID("_BlitTexture");
public static readonly int _BlitCubeTexture = Shader.PropertyToID("_BlitCubeTexture");
public static readonly int _BlitScaleBias = Shader.PropertyToID("_BlitScaleBias");
public static readonly int _BlitScaleBiasRt = Shader.PropertyToID("_BlitScaleBiasRt");
public static readonly int _BlitMipLevel = Shader.PropertyToID("_BlitMipLevel");
public static readonly int _BlitTextureSize = Shader.PropertyToID("_BlitTextureSize");
public static readonly int _BlitPaddingSize = Shader.PropertyToID("_BlitPaddingSize");
public static readonly int _BlitDecodeInstructions = Shader.PropertyToID("_BlitDecodeInstructions");
public static readonly int _InputDepth = Shader.PropertyToID("_InputDepthTexture");
}
/// <summary>
/// Initialize Blitter resources. Must be called once before any use
/// </summary>
/// <param name="blitPS"></param> Blit shader
/// <param name="blitColorAndDepthPS"></param> Blit shader
public static void Initialize(Shader blitPS, Shader blitColorAndDepthPS)
{
if (s_Blit != null)
{
throw new Exception("Blitter is already initialized. Please only initialize the blitter once or you will leak engine resources. If you need to re-initialize the blitter with different shaders destroy & recreate it.");
}
// NOTE NOTE NOTE NOTE NOTE NOTE
// If you create something here you must also destroy it in Cleanup()
// or it will leak during enter/leave play mode cycles
// NOTE NOTE NOTE NOTE NOTE NOTE
s_Blit = CoreUtils.CreateEngineMaterial(blitPS);
s_BlitColorAndDepth = CoreUtils.CreateEngineMaterial(blitColorAndDepthPS);
s_DecodeHdrKeyword = new LocalKeyword(blitPS, "BLIT_DECODE_HDR");
// With texture array enabled, we still need the normal blit version for other systems like atlas
if (TextureXR.useTexArray)
{
s_Blit.EnableKeyword("DISABLE_TEXTURE2D_X_ARRAY");
s_BlitTexArray = CoreUtils.CreateEngineMaterial(blitPS);
s_BlitTexArraySingleSlice = CoreUtils.CreateEngineMaterial(blitPS);
s_BlitTexArraySingleSlice.EnableKeyword("BLIT_SINGLE_SLICE");
}
if (SystemInfo.graphicsShaderLevel < 30)
{
/*UNITY_NEAR_CLIP_VALUE*/
float nearClipZ = -1;
if (SystemInfo.usesReversedZBuffer)
nearClipZ = 1;
if (!s_TriangleMesh)
{
s_TriangleMesh = new Mesh();
s_TriangleMesh.vertices = GetFullScreenTriangleVertexPosition(nearClipZ);
s_TriangleMesh.uv = GetFullScreenTriangleTexCoord();
s_TriangleMesh.triangles = new int[3] { 0, 1, 2 };
}
if (!s_QuadMesh)
{
s_QuadMesh = new Mesh();
s_QuadMesh.vertices = GetQuadVertexPosition(nearClipZ);
s_QuadMesh.uv = GetQuadTexCoord();
s_QuadMesh.triangles = new int[6] { 0, 1, 2, 0, 2, 3 };
}
// Should match Common.hlsl
static Vector3[] GetFullScreenTriangleVertexPosition(float z /*= UNITY_NEAR_CLIP_VALUE*/)
{
var r = new Vector3[3];
for (int i = 0; i < 3; i++)
{
Vector2 uv = new Vector2((i << 1) & 2, i & 2);
r[i] = new Vector3(uv.x * 2.0f - 1.0f, uv.y * 2.0f - 1.0f, z);
}
return r;
}
// Should match Common.hlsl
static Vector2[] GetFullScreenTriangleTexCoord()
{
var r = new Vector2[3];
for (int i = 0; i < 3; i++)
{
if (SystemInfo.graphicsUVStartsAtTop)
r[i] = new Vector2((i << 1) & 2, 1.0f - (i & 2));
else
r[i] = new Vector2((i << 1) & 2, i & 2);
}
return r;
}
// Should match Common.hlsl
static Vector3[] GetQuadVertexPosition(float z /*= UNITY_NEAR_CLIP_VALUE*/)
{
var r = new Vector3[4];
for (uint i = 0; i < 4; i++)
{
uint topBit = i >> 1;
uint botBit = (i & 1);
float x = topBit;
float y = 1 - (topBit + botBit) & 1; // produces 1 for indices 0,3 and 0 for 1,2
r[i] = new Vector3(x, y, z);
}
return r;
}
// Should match Common.hlsl
static Vector2[] GetQuadTexCoord()
{
var r = new Vector2[4];
for (uint i = 0; i < 4; i++)
{
uint topBit = i >> 1;
uint botBit = (i & 1);
float u = topBit;
float v = (topBit + botBit) & 1; // produces 0 for indices 0,3 and 1 for 1,2
if (SystemInfo.graphicsUVStartsAtTop)
v = 1.0f - v;
r[i] = new Vector2(u, v);
}
return r;
}
}
}
/// <summary>
/// Release Blitter resources.
/// </summary>
public static void Cleanup()
{
CoreUtils.Destroy(s_Blit);
s_Blit = null;
CoreUtils.Destroy(s_BlitColorAndDepth);
s_BlitColorAndDepth = null;
CoreUtils.Destroy(s_BlitTexArray);
s_BlitTexArray = null;
CoreUtils.Destroy(s_BlitTexArraySingleSlice);
s_BlitTexArraySingleSlice = null;
CoreUtils.Destroy(s_TriangleMesh);
s_TriangleMesh = null;
CoreUtils.Destroy(s_QuadMesh);
s_QuadMesh = null;
}
/// <summary>
/// Returns the default blit material.
/// </summary>
/// <param name="dimension">Dimension of the texture to blit, either 2D or 2D Array.</param>
/// <param name="singleSlice">Blit only a single slice of the array if applicable.</param>
/// <returns></returns>
static public Material GetBlitMaterial(TextureDimension dimension, bool singleSlice = false)
{
bool useTexArray = dimension == TextureDimension.Tex2DArray;
return useTexArray ? (singleSlice ? s_BlitTexArraySingleSlice : s_BlitTexArray) : s_Blit;
}
static private void DrawTriangle(CommandBuffer cmd, Material material, int shaderPass)
{
if (SystemInfo.graphicsShaderLevel < 30)
cmd.DrawMesh(s_TriangleMesh, Matrix4x4.identity, material, 0, shaderPass, s_PropertyBlock);
else
cmd.DrawProcedural(Matrix4x4.identity, material, shaderPass, MeshTopology.Triangles, 3, 1, s_PropertyBlock);
}
static internal void DrawQuad(CommandBuffer cmd, Material material, int shaderPass)
{
if (SystemInfo.graphicsShaderLevel < 30)
cmd.DrawMesh(s_QuadMesh, Matrix4x4.identity, material, 0, shaderPass, s_PropertyBlock);
else
cmd.DrawProcedural(Matrix4x4.identity, material, shaderPass, MeshTopology.Quads, 4, 1, s_PropertyBlock);
}
/// <summary>
/// Blit a RTHandle texture.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source RTHandle.</param>
/// <param name="scaleBias">Scale and bias for sampling the input texture.</param>
/// <param name="mipLevel">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
public static void BlitTexture(CommandBuffer cmd, RTHandle source, Vector4 scaleBias, float mipLevel, bool bilinear)
{
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevel);
BlitTexture(cmd, source, scaleBias, GetBlitMaterial(TextureXR.dimension), bilinear ? 1 : 0);
}
/// <summary>
/// Blit a RTHandle texture 2D.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source RTHandle.</param>
/// <param name="scaleBias">Scale and bias for sampling the input texture.</param>
/// <param name="mipLevel">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
public static void BlitTexture2D(CommandBuffer cmd, RTHandle source, Vector4 scaleBias, float mipLevel, bool bilinear)
{
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevel);
BlitTexture(cmd, source, scaleBias, GetBlitMaterial(TextureDimension.Tex2D), bilinear ? 1 : 0);
}
/// <summary>
/// Blit a 2D texture and depth buffer.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="sourceColor">Source Texture for color.</param>
/// <param name="sourceDepth">Source RenderTexture for depth.</param>
/// <param name="scaleBias">Scale and bias for sampling the input texture.</param>
/// <param name="mipLevel">Mip level to blit.</param>
/// <param name="blitDepth">Enable depth blit.</param>
public static void BlitColorAndDepth(CommandBuffer cmd, Texture sourceColor, RenderTexture sourceDepth, Vector4 scaleBias, float mipLevel, bool blitDepth)
{
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevel);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBias);
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitTexture, sourceColor);
if (blitDepth)
s_PropertyBlock.SetTexture(BlitShaderIDs._InputDepth, sourceDepth, RenderTextureSubElement.Depth);
DrawTriangle(cmd, s_BlitColorAndDepth, blitDepth ? 1 : 0);
}
/// <summary>
/// Blit a RTHandle texture
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source RTHandle.</param>
/// <param name="scaleBias">Scale and bias for sampling the input texture.</param>
/// <param name="material">Material to invoke when blitting.</param>
/// <param name="pass">Pass idx within the material to invoke.</param>
public static void BlitTexture(CommandBuffer cmd, RTHandle source, Vector4 scaleBias, Material material, int pass)
{
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBias);
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitTexture, source);
DrawTriangle(cmd, material, pass);
}
/// <summary>
/// Blit a RTHandle texture
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source render target.</param>
/// <param name="scaleBias">Scale and bias for sampling the input texture.</param>
/// <param name="material">Material to invoke when blitting.</param>
/// <param name="pass">Pass idx within the material to invoke.</param>
public static void BlitTexture(CommandBuffer cmd, RenderTargetIdentifier source, Vector4 scaleBias, Material material, int pass)
{
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBias);
// Unfortunately there is no function bind a RenderTargetIdentifier with a property block so we have to bind it globally.
cmd.SetGlobalTexture(BlitShaderIDs._BlitTexture, source);
DrawTriangle(cmd, material, pass);
}
/// <summary>
/// Blit a Texture with a specified material. The reference name "_BlitTexture" will be used to bind the input texture.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source render target.</param>
/// <param name="destination">Destination render target.</param>
/// <param name="material">Material to invoke when blitting.</param>
/// <param name="pass">Pass idx within the material to invoke.</param>
public static void BlitTexture(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, Material material, int pass)
{
// Unfortunately there is no function bind a RenderTargetIdentifier with a property block so we have to bind it globally.
cmd.SetGlobalTexture(BlitShaderIDs._BlitTexture, source);
cmd.SetRenderTarget(destination);
DrawTriangle(cmd, material, pass);
}
/// <summary>
/// Blit a Texture with a specified material. The reference name "_BlitTexture" will be used to bind the input texture.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source render target.</param>
/// <param name="destination">Destination render target.</param>
/// <param name="loadAction">Load action.</param>
/// <param name="storeAction">Store action.</param>
/// <param name="material">Material to invoke when blitting.</param>
/// <param name="pass">Pass idx within the material to invoke.</param>
public static void BlitTexture(CommandBuffer cmd, RenderTargetIdentifier source, RenderTargetIdentifier destination, RenderBufferLoadAction loadAction, RenderBufferStoreAction storeAction, Material material, int pass)
{
// Unfortunately there is no function bind a RenderTargetIdentifier with a property block so we have to bind it globally.
cmd.SetGlobalTexture(BlitShaderIDs._BlitTexture, source);
cmd.SetRenderTarget(destination, loadAction, storeAction);
DrawTriangle(cmd, material, pass);
}
/// <summary>
/// Blit a Texture with a given Material. Unity uses the reference name `_BlitTexture` to bind the input texture. Set the destination parameter before using this method.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="scaleBias">Scale and bias values for sampling the input texture.</param>
/// <param name="material">Material to invoke when blitting.</param>
/// <param name="pass">Pass index within the Material to invoke.</param>
public static void BlitTexture(CommandBuffer cmd, Vector4 scaleBias, Material material, int pass)
{
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBias);
DrawTriangle(cmd, material, pass);
}
/// <summary>
/// Blit a RTHandle to another RTHandle.
/// This will properly account for partial usage (in term of resolution) of the texture for the current viewport.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source RTHandle.</param>
/// <param name="destination">Destination RTHandle.</param>
/// <param name="mipLevel">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
public static void BlitCameraTexture(CommandBuffer cmd, RTHandle source, RTHandle destination, float mipLevel = 0.0f, bool bilinear = false)
{
Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one;
// Will set the correct camera viewport as well.
CoreUtils.SetRenderTarget(cmd, destination);
BlitTexture(cmd, source, viewportScale, mipLevel, bilinear);
}
/// <summary>
/// Blit a RThandle Texture2D RTHandle to another RTHandle.
/// This will properly account for partial usage (in term of resolution) of the texture for the current viewport.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source RTHandle.</param>
/// <param name="destination">Destination RTHandle.</param>
/// <param name="mipLevel">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
public static void BlitCameraTexture2D(CommandBuffer cmd, RTHandle source, RTHandle destination, float mipLevel = 0.0f, bool bilinear = false)
{
Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one;
// Will set the correct camera viewport as well.
CoreUtils.SetRenderTarget(cmd, destination);
BlitTexture2D(cmd, source, viewportScale, mipLevel, bilinear);
}
/// <summary>
/// Blit a RTHandle to another RTHandle.
/// This will properly account for partial usage (in term of resolution) of the texture for the current viewport.
/// This overloads allows the user to override the default blit shader
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source RTHandle.</param>
/// <param name="destination">Destination RTHandle.</param>
/// <param name="material">The material to use when blitting</param>
/// <param name="pass">pass to use of the provided material</param>
public static void BlitCameraTexture(CommandBuffer cmd, RTHandle source, RTHandle destination, Material material, int pass)
{
Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one;
// Will set the correct camera viewport as well.
CoreUtils.SetRenderTarget(cmd, destination);
BlitTexture(cmd, source, viewportScale, material, pass);
}
/// <summary>
/// Blit a RTHandle to another RTHandle.
/// This will properly account for partial usage (in term of resolution) of the texture for the current viewport.
/// This overloads allows the user to override the default blit shader
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source RTHandle.</param>
/// <param name="destination">Destination RTHandle.</param>
/// <param name="loadAction">Load action.</param>
/// <param name="storeAction">Store action.</param>
/// <param name="material">The material to use when blitting</param>
/// <param name="pass">pass to use of the provided material</param>
public static void BlitCameraTexture(CommandBuffer cmd, RTHandle source, RTHandle destination, RenderBufferLoadAction loadAction, RenderBufferStoreAction storeAction, Material material, int pass)
{
Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one;
// Will set the correct camera viewport as well.
CoreUtils.SetRenderTarget(cmd, destination, loadAction, storeAction, ClearFlag.None, Color.clear);
BlitTexture(cmd, source, viewportScale, material, pass);
}
/// <summary>
/// Blit a RTHandle to another RTHandle.
/// This will properly account for partial usage (in term of resolution) of the texture for the current viewport.
/// This overload allows user to override the scale and bias used when sampling the input RTHandle.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source RTHandle.</param>
/// <param name="destination">Destination RTHandle.</param>
/// <param name="scaleBias">Scale and bias used to sample the input RTHandle.</param>
/// <param name="mipLevel">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
public static void BlitCameraTexture(CommandBuffer cmd, RTHandle source, RTHandle destination, Vector4 scaleBias, float mipLevel = 0.0f, bool bilinear = false)
{
// Will set the correct camera viewport as well.
CoreUtils.SetRenderTarget(cmd, destination);
BlitTexture(cmd, source, scaleBias, mipLevel, bilinear);
}
/// <summary>
/// Blit a RTHandle to another RTHandle.
/// This will properly account for partial usage (in term of resolution) of the texture for the current viewport.
/// This overload allows user to override the viewport of the destination RTHandle.
/// </summary>
/// <param name="cmd">Command Buffer used for rendering.</param>
/// <param name="source">Source RTHandle.</param>
/// <param name="destination">Destination RTHandle.</param>
/// <param name="destViewport">Viewport of the destination RTHandle.</param>
/// <param name="mipLevel">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
public static void BlitCameraTexture(CommandBuffer cmd, RTHandle source, RTHandle destination, Rect destViewport, float mipLevel = 0.0f, bool bilinear = false)
{
Vector2 viewportScale = source.useScaling ? new Vector2(source.rtHandleProperties.rtHandleScale.x, source.rtHandleProperties.rtHandleScale.y) : Vector2.one;
CoreUtils.SetRenderTarget(cmd, destination);
cmd.SetViewport(destViewport);
BlitTexture(cmd, source, viewportScale, mipLevel, bilinear);
}
/// <summary>
/// Blit a texture using a quad in the current render target.
/// </summary>
/// <param name="cmd">Command buffer used for rendering.</param>
/// <param name="source">Source texture.</param>
/// <param name="scaleBiasTex">Scale and bias for the input texture.</param>
/// <param name="scaleBiasRT">Scale and bias for the output texture.</param>
/// <param name="mipLevelTex">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
public static void BlitQuad(CommandBuffer cmd, Texture source, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear)
{
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitTexture, source);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBiasTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBiasRt, scaleBiasRT);
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevelTex);
DrawQuad(cmd, GetBlitMaterial(source.dimension), bilinear ? 3 : 2);
}
/// <summary>
/// Blit a texture using a quad in the current render target.
/// </summary>
/// <param name="cmd">Command buffer used for rendering.</param>
/// <param name="source">Source texture.</param>
/// <param name="textureSize">Source texture size.</param>
/// <param name="scaleBiasTex">Scale and bias for sampling the input texture.</param>
/// <param name="scaleBiasRT">Scale and bias for the output texture.</param>
/// <param name="mipLevelTex">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
/// <param name="paddingInPixels">Padding in pixels.</param>
public static void BlitQuadWithPadding(CommandBuffer cmd, Texture source, Vector2 textureSize, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear, int paddingInPixels)
{
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitTexture, source);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBiasTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBiasRt, scaleBiasRT);
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevelTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitTextureSize, textureSize);
s_PropertyBlock.SetInt(BlitShaderIDs._BlitPaddingSize, paddingInPixels);
if (source.wrapMode == TextureWrapMode.Repeat)
DrawQuad(cmd, GetBlitMaterial(source.dimension), bilinear ? 7 : 6);
else
DrawQuad(cmd, GetBlitMaterial(source.dimension), bilinear ? 5 : 4);
}
/// <summary>
/// Blit a texture using a quad in the current render target, by performing an alpha blend with the existing content on the render target.
/// </summary>
/// <param name="cmd">Command buffer used for rendering.</param>
/// <param name="source">Source texture.</param>
/// <param name="textureSize">Source texture size.</param>
/// <param name="scaleBiasTex">Scale and bias for sampling the input texture.</param>
/// <param name="scaleBiasRT">Scale and bias for the output texture.</param>
/// <param name="mipLevelTex">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
/// <param name="paddingInPixels">Padding in pixels.</param>
public static void BlitQuadWithPaddingMultiply(CommandBuffer cmd, Texture source, Vector2 textureSize, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear, int paddingInPixels)
{
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitTexture, source);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBiasTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBiasRt, scaleBiasRT);
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevelTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitTextureSize, textureSize);
s_PropertyBlock.SetInt(BlitShaderIDs._BlitPaddingSize, paddingInPixels);
if (source.wrapMode == TextureWrapMode.Repeat)
DrawQuad(cmd, GetBlitMaterial(source.dimension), bilinear ? 12 : 11);
else
DrawQuad(cmd, GetBlitMaterial(source.dimension), bilinear ? 10 : 9);
}
/// <summary>
/// Blit a texture (which is a Octahedral projection) using a quad in the current render target.
/// </summary>
/// <param name="cmd">Command buffer used for rendering.</param>
/// <param name="source">Source texture.</param>
/// <param name="textureSize">Source texture size.</param>
/// <param name="scaleBiasTex">Scale and bias for sampling the input texture.</param>
/// <param name="scaleBiasRT">Scale and bias for the output texture.</param>
/// <param name="mipLevelTex">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
/// <param name="paddingInPixels">Padding in pixels.</param>
public static void BlitOctahedralWithPadding(CommandBuffer cmd, Texture source, Vector2 textureSize, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear, int paddingInPixels)
{
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitTexture, source);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBiasTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBiasRt, scaleBiasRT);
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevelTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitTextureSize, textureSize);
s_PropertyBlock.SetInt(BlitShaderIDs._BlitPaddingSize, paddingInPixels);
DrawQuad(cmd, GetBlitMaterial(source.dimension), 8);
}
/// <summary>
/// Blit a texture (which is a Octahedral projection) using a quad in the current render target, by performing an alpha blend with the existing content on the render target.
/// </summary>
/// <param name="cmd">Command buffer used for rendering.</param>
/// <param name="source">Source texture.</param>
/// <param name="textureSize">Source texture size.</param>
/// <param name="scaleBiasTex">Scale and bias for sampling the input texture.</param>
/// <param name="scaleBiasRT">Scale and bias for the output texture.</param>
/// <param name="mipLevelTex">Mip level to blit.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
/// <param name="paddingInPixels">Padding in pixels.</param>
public static void BlitOctahedralWithPaddingMultiply(CommandBuffer cmd, Texture source, Vector2 textureSize, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear, int paddingInPixels)
{
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitTexture, source);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBiasTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBiasRt, scaleBiasRT);
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevelTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitTextureSize, textureSize);
s_PropertyBlock.SetInt(BlitShaderIDs._BlitPaddingSize, paddingInPixels);
DrawQuad(cmd, GetBlitMaterial(source.dimension), 13);
}
/// <summary>
/// Blit a cube texture into 2d texture as octahedral quad. (projection)
/// </summary>
/// <param name="cmd">Command buffer used for rendering.</param>
/// <param name="source">Source cube texture.</param>
/// <param name="mipLevelTex">Mip level to sample.</param>
/// /// <param name="scaleBiasRT">Scale and bias for the output texture.</param>
public static void BlitCubeToOctahedral2DQuad(CommandBuffer cmd, Texture source, Vector4 scaleBiasRT, int mipLevelTex)
{
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitCubeTexture, source);
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevelTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, new Vector4(1, 1, 0, 0));
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBiasRt, scaleBiasRT);
DrawQuad(cmd, GetBlitMaterial(source.dimension), 14);
}
/// <summary>
/// Blit a cube texture into 2d texture as octahedral quad with padding. (projection)
/// </summary>
/// <param name="cmd">Command buffer used for rendering.</param>
/// <param name="source">Source cube texture.</param>
/// <param name="textureSize">Source texture size.</param>
/// <param name="mipLevelTex">Mip level to sample.</param>
/// <param name="scaleBiasRT">Scale and bias for the output texture.</param>
/// <param name="bilinear">Enable bilinear filtering.</param>
/// <param name="paddingInPixels">Padding in pixels.</param>
/// <param name="decodeInstructions">Decode instruction.</param>
public static void BlitCubeToOctahedral2DQuadWithPadding(CommandBuffer cmd, Texture source, Vector2 textureSize, Vector4 scaleBiasRT, int mipLevelTex, bool bilinear, int paddingInPixels, Vector4? decodeInstructions = null)
{
var material = GetBlitMaterial(source.dimension);
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitCubeTexture, source);
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevelTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, new Vector4(1, 1, 0, 0));
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBiasRt, scaleBiasRT);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitTextureSize, textureSize);
s_PropertyBlock.SetInt(BlitShaderIDs._BlitPaddingSize, paddingInPixels);
cmd.SetKeyword(material, s_DecodeHdrKeyword, decodeInstructions.HasValue);
if (decodeInstructions.HasValue)
{
s_PropertyBlock.SetVector(BlitShaderIDs._BlitDecodeInstructions, decodeInstructions.Value);
}
DrawQuad(cmd, material, bilinear ? 22 : 21);
cmd.SetKeyword(material, s_DecodeHdrKeyword, false);
}
/// <summary>
/// Blit a cube texture into 2d texture as octahedral quad. (projection)
/// Conversion between single and multi channel formats.
/// RGB(A) to YYYY (luminance).
/// R to RRRR.
/// A to AAAA.
/// </summary>
/// <param name="cmd">Command buffer used for rendering.</param>
/// <param name="source">Source texture.</param>
/// <param name="scaleBiasRT">Scale and bias for the output texture.</param>
/// <param name="mipLevelTex">Mip level to blit.</param>
public static void BlitCubeToOctahedral2DQuadSingleChannel(CommandBuffer cmd, Texture source, Vector4 scaleBiasRT, int mipLevelTex)
{
int pass = 15;
uint sourceChnCount = GraphicsFormatUtility.GetComponentCount(source.graphicsFormat);
if (sourceChnCount == 1)
{
if (GraphicsFormatUtility.IsAlphaOnlyFormat(source.graphicsFormat))
pass = 16;
if (GraphicsFormatUtility.GetSwizzleR(source.graphicsFormat) == FormatSwizzle.FormatSwizzleR)
pass = 17;
}
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitCubeTexture, source);
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevelTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, new Vector4(1, 1, 0, 0));
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBiasRt, scaleBiasRT);
DrawQuad(cmd, GetBlitMaterial(source.dimension), pass);
}
/// <summary>
/// Bilinear Blit a texture using a quad in the current render target.
/// Conversion between single and multi channel formats.
/// RGB(A) to YYYY (luminance).
/// R to RRRR.
/// A to AAAA.
/// </summary>
/// <param name="cmd">Command buffer used for rendering.</param>
/// <param name="source">Source texture.</param>
/// <param name="scaleBiasTex">Scale and bias for the input texture.</param>
/// <param name="scaleBiasRT">Scale and bias for the output texture.</param>
/// <param name="mipLevelTex">Mip level to blit.</param>
public static void BlitQuadSingleChannel(CommandBuffer cmd, Texture source, Vector4 scaleBiasTex, Vector4 scaleBiasRT, int mipLevelTex)
{
int pass = 18;
uint sourceChnCount = GraphicsFormatUtility.GetComponentCount(source.graphicsFormat);
if (sourceChnCount == 1)
{
if (GraphicsFormatUtility.IsAlphaOnlyFormat(source.graphicsFormat))
pass = 19;
if (GraphicsFormatUtility.GetSwizzleR(source.graphicsFormat) == FormatSwizzle.FormatSwizzleR)
pass = 20;
}
s_PropertyBlock.SetTexture(BlitShaderIDs._BlitTexture, source);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBias, scaleBiasTex);
s_PropertyBlock.SetVector(BlitShaderIDs._BlitScaleBiasRt, scaleBiasRT);
s_PropertyBlock.SetFloat(BlitShaderIDs._BlitMipLevel, mipLevelTex);
DrawQuad(cmd, GetBlitMaterial(source.dimension), pass);
}
}
}

View File

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

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
namespace UnityEngine.Rendering
{
/// <summary>
/// Bridge class for camera captures.
/// </summary>
public static class CameraCaptureBridge
{
private static Dictionary<Camera, HashSet<Action<RenderTargetIdentifier, CommandBuffer>>> actionDict =
new Dictionary<Camera, HashSet<Action<RenderTargetIdentifier, CommandBuffer>>>();
private static bool _enabled;
/// <summary>
/// Enable camera capture.
/// </summary>
public static bool enabled
{
get
{
return _enabled;
}
set
{
_enabled = value;
}
}
/// <summary>
/// Provides the set actions to the renderer to be triggered at the end of the render loop for camera capture
/// </summary>
/// <param name="camera">The camera to get actions for</param>
/// <returns>Enumeration of actions</returns>
public static IEnumerator<Action<RenderTargetIdentifier, CommandBuffer>> GetCaptureActions(Camera camera)
{
if (!actionDict.TryGetValue(camera, out var actions) || actions.Count == 0)
return null;
return actions.GetEnumerator();
}
/// <summary>
/// Adds actions for camera capture
/// </summary>
/// <param name="camera">The camera to add actions for</param>
/// <param name="action">The action to add</param>
public static void AddCaptureAction(Camera camera, Action<RenderTargetIdentifier, CommandBuffer> action)
{
actionDict.TryGetValue(camera, out var actions);
if (actions == null)
{
actions = new HashSet<Action<RenderTargetIdentifier, CommandBuffer>>();
actionDict.Add(camera, actions);
}
actions.Add(action);
}
/// <summary>
/// Removes actions for camera capture
/// </summary>
/// <param name="camera">The camera to remove actions for</param>
/// <param name="action">The action to remove</param>
public static void RemoveCaptureAction(Camera camera, Action<RenderTargetIdentifier, CommandBuffer> action)
{
if (camera == null)
return;
if (actionDict.TryGetValue(camera, out var actions))
actions.Remove(action);
}
}
}

View File

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

View File

@@ -0,0 +1,303 @@
namespace UnityEngine.Rendering
{
// Has to be kept in sync with PhysicalCamera.hlsl
/// <summary>
/// A set of color manipulation utilities.
/// </summary>
public static class ColorUtils
{
/// <summary>
/// Calibration constant (K) used for our virtual reflected light meter. Modifying this will lead to a change on how average scene luminance
/// gets mapped to exposure.
/// </summary>
static public float s_LightMeterCalibrationConstant = 12.5f;
/// <summary>
/// Factor used for our lens system w.r.t. exposure calculation. Modifying this will lead to a change on how linear exposure
/// multipliers are computed from EV100 values (and viceversa). s_LensAttenuation models transmission attenuation and lens vignetting.
/// Note that according to the standard ISO 12232, a lens saturates at s_LensAttenuation = 0.78f (under ISO 100).
/// </summary>
static public float s_LensAttenuation = 0.65f;
/// <summary>
/// Scale applied to exposure caused by lens imperfection. It is computed from s_LensAttenuation as follow:
/// (78 / ( S * q )) where S = 100 and q = s_LensAttenuation
/// </summary>
static public float lensImperfectionExposureScale
{
get => (78.0f / (100.0f * s_LensAttenuation));
}
/// <summary>
/// An analytical model of chromaticity of the standard illuminant, by Judd et al.
/// http://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D
/// Slightly modifed to adjust it with the D65 white point (x=0.31271, y=0.32902).
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
public static float StandardIlluminantY(float x) => 2.87f * x - 3f * x * x - 0.27509507f;
/// <summary>
/// CIE xy chromaticity to CAT02 LMS.
/// http://en.wikipedia.org/wiki/LMS_color_space#CAT02
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static Vector3 CIExyToLMS(float x, float y)
{
float Y = 1f;
float X = Y * x / y;
float Z = Y * (1f - x - y) / y;
float L = 0.7328f * X + 0.4296f * Y - 0.1624f * Z;
float M = -0.7036f * X + 1.6975f * Y + 0.0061f * Z;
float S = 0.0030f * X + 0.0136f * Y + 0.9834f * Z;
return new Vector3(L, M, S);
}
/// <summary>
/// Converts white balancing parameter to LMS coefficients.
/// </summary>
/// <param name="temperature">A temperature offset, in range [-100;100].</param>
/// <param name="tint">A tint offset, in range [-100;100].</param>
/// <returns>LMS coefficients.</returns>
public static Vector3 ColorBalanceToLMSCoeffs(float temperature, float tint)
{
// Range ~[-1.5;1.5] works best
float t1 = temperature / 65f;
float t2 = tint / 65f;
// Get the CIE xy chromaticity of the reference white point.
// Note: 0.31271 = x value on the D65 white point
float x = 0.31271f - t1 * (t1 < 0f ? 0.1f : 0.05f);
float y = StandardIlluminantY(x) + t2 * 0.05f;
// Calculate the coefficients in the LMS space.
var w1 = new Vector3(0.949237f, 1.03542f, 1.08728f); // D65 white point
var w2 = CIExyToLMS(x, y);
return new Vector3(w1.x / w2.x, w1.y / w2.y, w1.z / w2.z);
}
/// <summary>
/// Pre-filters shadows, midtones and highlights trackball values for shader use.
/// </summary>
/// <param name="inShadows">A color used for shadows.</param>
/// <param name="inMidtones">A color used for midtones.</param>
/// <param name="inHighlights">A color used for highlights.</param>
/// <returns>The three input colors pre-filtered for shader use.</returns>
public static (Vector4, Vector4, Vector4) PrepareShadowsMidtonesHighlights(in Vector4 inShadows, in Vector4 inMidtones, in Vector4 inHighlights)
{
float weight;
var shadows = inShadows;
shadows.x = Mathf.GammaToLinearSpace(shadows.x);
shadows.y = Mathf.GammaToLinearSpace(shadows.y);
shadows.z = Mathf.GammaToLinearSpace(shadows.z);
weight = shadows.w * (Mathf.Sign(shadows.w) < 0f ? 1f : 4f);
shadows.x = Mathf.Max(shadows.x + weight, 0f);
shadows.y = Mathf.Max(shadows.y + weight, 0f);
shadows.z = Mathf.Max(shadows.z + weight, 0f);
shadows.w = 0f;
var midtones = inMidtones;
midtones.x = Mathf.GammaToLinearSpace(midtones.x);
midtones.y = Mathf.GammaToLinearSpace(midtones.y);
midtones.z = Mathf.GammaToLinearSpace(midtones.z);
weight = midtones.w * (Mathf.Sign(midtones.w) < 0f ? 1f : 4f);
midtones.x = Mathf.Max(midtones.x + weight, 0f);
midtones.y = Mathf.Max(midtones.y + weight, 0f);
midtones.z = Mathf.Max(midtones.z + weight, 0f);
midtones.w = 0f;
var highlights = inHighlights;
highlights.x = Mathf.GammaToLinearSpace(highlights.x);
highlights.y = Mathf.GammaToLinearSpace(highlights.y);
highlights.z = Mathf.GammaToLinearSpace(highlights.z);
weight = highlights.w * (Mathf.Sign(highlights.w) < 0f ? 1f : 4f);
highlights.x = Mathf.Max(highlights.x + weight, 0f);
highlights.y = Mathf.Max(highlights.y + weight, 0f);
highlights.z = Mathf.Max(highlights.z + weight, 0f);
highlights.w = 0f;
return (shadows, midtones, highlights);
}
/// <summary>
/// Pre-filters lift, gamma and gain trackball values for shader use.
/// </summary>
/// <param name="inLift">A color used for lift.</param>
/// <param name="inGamma">A color used for gamma.</param>
/// <param name="inGain">A color used for gain.</param>
/// <returns>The three input colors pre-filtered for shader use.</returns>
public static (Vector4, Vector4, Vector4) PrepareLiftGammaGain(in Vector4 inLift, in Vector4 inGamma, in Vector4 inGain)
{
var lift = inLift;
lift.x = Mathf.GammaToLinearSpace(lift.x) * 0.15f;
lift.y = Mathf.GammaToLinearSpace(lift.y) * 0.15f;
lift.z = Mathf.GammaToLinearSpace(lift.z) * 0.15f;
float lumLift = Luminance(lift);
lift.x = lift.x - lumLift + lift.w;
lift.y = lift.y - lumLift + lift.w;
lift.z = lift.z - lumLift + lift.w;
lift.w = 0f;
var gamma = inGamma;
gamma.x = Mathf.GammaToLinearSpace(gamma.x) * 0.8f;
gamma.y = Mathf.GammaToLinearSpace(gamma.y) * 0.8f;
gamma.z = Mathf.GammaToLinearSpace(gamma.z) * 0.8f;
float lumGamma = Luminance(gamma);
gamma.w += 1f;
gamma.x = 1f / Mathf.Max(gamma.x - lumGamma + gamma.w, 1e-03f);
gamma.y = 1f / Mathf.Max(gamma.y - lumGamma + gamma.w, 1e-03f);
gamma.z = 1f / Mathf.Max(gamma.z - lumGamma + gamma.w, 1e-03f);
gamma.w = 0f;
var gain = inGain;
gain.x = Mathf.GammaToLinearSpace(gain.x) * 0.8f;
gain.y = Mathf.GammaToLinearSpace(gain.y) * 0.8f;
gain.z = Mathf.GammaToLinearSpace(gain.z) * 0.8f;
float lumGain = Luminance(gain);
gain.w += 1f;
gain.x = gain.x - lumGain + gain.w;
gain.y = gain.y - lumGain + gain.w;
gain.z = gain.z - lumGain + gain.w;
gain.w = 0f;
return (lift, gamma, gain);
}
/// <summary>
/// Pre-filters colors used for the split toning effect.
/// </summary>
/// <param name="inShadows">A color used for shadows.</param>
/// <param name="inHighlights">A color used for highlights.</param>
/// <param name="balance">The balance between the shadow and highlight colors, in range [-100;100].</param>
/// <returns>The two input colors pre-filtered for shader use.</returns>
public static (Vector4, Vector4) PrepareSplitToning(in Vector4 inShadows, in Vector4 inHighlights, float balance)
{
// As counter-intuitive as it is, to make split-toning work the same way it does in
// Adobe products we have to do all the maths in sRGB... So do not convert these to
// linear before sending them to the shader, this isn't a bug!
var shadows = inShadows;
var highlights = inHighlights;
// Balance is stored in `shadows.w`
shadows.w = balance / 100f;
highlights.w = 0f;
return (shadows, highlights);
}
/// <summary>
/// Returns the luminance of the specified color. The input is considered to be in linear
/// space with sRGB primaries and a D65 white point.
/// </summary>
/// <param name="color">The color to compute the luminance for.</param>
/// <returns>A luminance value.</returns>
public static float Luminance(in Color color) => color.r * 0.2126729f + color.g * 0.7151522f + color.b * 0.072175f;
/// <summary>
/// Computes an exposure value (EV100) from physical camera settings.
/// </summary>
/// <param name="aperture">The camera aperture.</param>
/// <param name="shutterSpeed">The camera exposure time.</param>
/// <param name="ISO">The camera sensor sensitivity.</param>
/// <returns>An exposure value, in EV100.</returns>
public static float ComputeEV100(float aperture, float shutterSpeed, float ISO)
{
// References:
// "Moving Frostbite to PBR" (Sébastien Lagarde & Charles de Rousiers)
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
// "Implementing a Physically Based Camera" (Padraic Hennessy)
// https://placeholderart.wordpress.com/2014/11/16/implementing-a-physically-based-camera-understanding-exposure/
// EV number is defined as:
// 2^ EV_s = N^2 / t and EV_s = EV_100 + log2 (S /100)
// This gives
// EV_s = log2 (N^2 / t)
// EV_100 + log2 (S /100) = log2 (N^2 / t)
// EV_100 = log2 (N^2 / t) - log2 (S /100)
// EV_100 = log2 (N^2 / t . 100 / S)
return Mathf.Log((aperture * aperture) / shutterSpeed * 100f / ISO, 2f);
}
/// <summary>
/// Converts an exposure value (EV100) to a linear multiplier.
/// </summary>
/// <param name="EV100">The exposure value to convert, in EV100.</param>
/// <returns>A linear multiplier.</returns>
public static float ConvertEV100ToExposure(float EV100)
{
// Compute the maximum luminance possible with H_sbs sensitivity
// maxLum = 78 / ( S * q ) * N^2 / t
// = 78 / ( S * q ) * 2^ EV_100
// = 78 / (100 * s_LensAttenuation) * 2^ EV_100
// = lensImperfectionExposureScale * 2^ EV
// Reference: http://en.wikipedia.org/wiki/Film_speed
float maxLuminance = lensImperfectionExposureScale * Mathf.Pow(2.0f, EV100);
return 1.0f / maxLuminance;
}
/// <summary>
/// Converts a linear multiplier to an exposure value (EV100).
/// </summary>
/// <param name="exposure">A linear multiplier.</param>
/// <returns>An exposure value, in EV100.</returns>
public static float ConvertExposureToEV100(float exposure)
{
// Compute the maximum luminance possible with H_sbs sensitivity
// EV_100 = log2( S * q / (78 * exposure) )
// = log2( 100 * s_LensAttenuation / (78 * exposure) )
// = log2( 1.0f / (lensImperfectionExposureScale * exposure) )
// Reference: http://en.wikipedia.org/wiki/Film_speed
return Mathf.Log(1.0f / (lensImperfectionExposureScale * exposure), 2.0f);
}
/// <summary>
/// Computes an exposure value (EV100) from an average luminance value.
/// </summary>
/// <param name="avgLuminance">An average luminance value.</param>
/// <returns>An exposure value, in EV100.</returns>
public static float ComputeEV100FromAvgLuminance(float avgLuminance)
{
// The middle grey used will be determined by the s_LightMeterCalibrationConstant.
// The suggested (ISO 2720) range is 10.64 to 13.4. Common values used by
// manufacturers range from 11.37 to 14. Ref: https://en.wikipedia.org/wiki/Light_meter
// The default is 12.5% as it is the closest to 12.7% in order to have
// a middle gray at 18% with a sqrt(2) room for specular highlights
// Note that this gives equivalent results as using an incident light meter
// with a calibration constant of C=314.
float K = s_LightMeterCalibrationConstant;
return Mathf.Log(avgLuminance * 100f / K, 2f);
}
/// <summary>
/// Computes the required ISO to reach <paramref name="targetEV100"/>.
/// </summary>
/// <param name="aperture">The camera aperture.</param>
/// <param name="shutterSpeed">The camera exposure time.</param>
/// <param name="targetEV100">The target exposure value (EV100) to reach.</param>
/// <returns>The required sensor sensitivity (ISO).</returns>
public static float ComputeISO(float aperture, float shutterSpeed, float targetEV100) => ((aperture * aperture) * 100f) / (shutterSpeed * Mathf.Pow(2f, targetEV100));
/// <summary>
/// Converts a color value to its 32-bit hexadecimal representation.
/// </summary>
/// <param name="c">The color to convert.</param>
/// <returns>A 32-bit hexadecimal representation of the color.</returns>
public static uint ToHex(Color c) => ((uint)(c.a * 255) << 24) | ((uint)(c.r * 255) << 16) | ((uint)(c.g * 255) << 8) | (uint)(c.b * 255);
/// <summary>
/// Converts a 32-bit hexadecimal value to a color value.
/// </summary>
/// <param name="hex">A 32-bit hexadecimal value.</param>
/// <returns>A color value.</returns>
public static Color ToRGBA(uint hex) => new Color(((hex >> 16) & 0xff) / 255f, ((hex >> 8) & 0xff) / 255f, (hex & 0xff) / 255f, ((hex >> 24) & 0xff) / 255f);
}
}

View File

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

View File

@@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering
{
using UnityObject = UnityEngine.Object;
/// <summary>
/// Set of utility functions for the Core Scriptable Render Pipeline Library related to Matrix operations
/// </summary>
public static class CoreMatrixUtils
{
/// <summary>
/// This function provides the equivalent of multiplying matrix parameter inOutMatrix with a translation matrix defined by the parameter translation.
/// The order of the equivalent multiplication is inOutMatrix * translation.
/// </summary>
/// <param name="inOutMatrix">Matrix to multiply with translation.</param>
/// <param name="translation">Translation component to multiply to the matrix.</param>
public static void MatrixTimesTranslation(ref Matrix4x4 inOutMatrix, Vector3 translation)
{
inOutMatrix.m03 += (inOutMatrix.m00 * translation.x + inOutMatrix.m01 * translation.y + inOutMatrix.m02 * translation.z);
inOutMatrix.m13 += (inOutMatrix.m10 * translation.x + inOutMatrix.m11 * translation.y + inOutMatrix.m12 * translation.z);
inOutMatrix.m23 += (inOutMatrix.m20 * translation.x + inOutMatrix.m21 * translation.y + inOutMatrix.m22 * translation.z);
}
/// <summary>
/// This function provides the equivalent of multiplying a translation matrix defined by the parameter translation with the matrix specified by the parameter inOutMatrix.
/// The order of the equivalent multiplication is translation * inOutMatrix.
/// </summary>
/// <param name="inOutMatrix">Matrix to multiply with translation.</param>
/// <param name="translation">Translation component to multiply to the matrix.</param>
public static void TranslationTimesMatrix(ref Matrix4x4 inOutMatrix, Vector3 translation)
{
inOutMatrix.m00 += translation.x * inOutMatrix.m30;
inOutMatrix.m01 += translation.x * inOutMatrix.m31;
inOutMatrix.m02 += translation.x * inOutMatrix.m32;
inOutMatrix.m03 += translation.x * inOutMatrix.m33;
inOutMatrix.m10 += translation.y * inOutMatrix.m30;
inOutMatrix.m11 += translation.y * inOutMatrix.m31;
inOutMatrix.m12 += translation.y * inOutMatrix.m32;
inOutMatrix.m13 += translation.y * inOutMatrix.m33;
inOutMatrix.m20 += translation.z * inOutMatrix.m30;
inOutMatrix.m21 += translation.z * inOutMatrix.m31;
inOutMatrix.m22 += translation.z * inOutMatrix.m32;
inOutMatrix.m23 += translation.z * inOutMatrix.m33;
}
/// <summary>
/// Multiplies a matrix with a perspective matrix. This function is faster than performing the full matrix multiplication.
/// The operation order is perspective * rhs.
/// </summary>
/// <param name="perspective">The perspective matrix to multiply with rhs.</param>
/// <param name="rhs">A matrix to be multiply to perspective.</param>
/// <returns>Returns the matrix that is the result of the multiplication.</returns>
public static Matrix4x4 MultiplyPerspectiveMatrix(Matrix4x4 perspective, Matrix4x4 rhs)
{
Matrix4x4 outMat;
outMat.m00 = perspective.m00 * rhs.m00;
outMat.m01 = perspective.m00 * rhs.m01;
outMat.m02 = perspective.m00 * rhs.m02;
outMat.m03 = perspective.m00 * rhs.m03;
outMat.m10 = perspective.m11 * rhs.m10;
outMat.m11 = perspective.m11 * rhs.m11;
outMat.m12 = perspective.m11 * rhs.m12;
outMat.m13 = perspective.m11 * rhs.m13;
outMat.m20 = perspective.m22 * rhs.m20 + perspective.m23 * rhs.m30;
outMat.m21 = perspective.m22 * rhs.m21 + perspective.m23 * rhs.m31;
outMat.m22 = perspective.m22 * rhs.m22 + perspective.m23 * rhs.m32;
outMat.m23 = perspective.m22 * rhs.m23 + perspective.m23 * rhs.m33;
outMat.m30 = -rhs.m20;
outMat.m31 = -rhs.m21;
outMat.m32 = -rhs.m22;
outMat.m33 = -rhs.m23;
return outMat;
}
// An orthographic projection is centered if (right+left) == 0 and (top+bottom) == 0
private static Matrix4x4 MultiplyOrthoMatrixCentered(Matrix4x4 ortho, Matrix4x4 rhs)
{
Matrix4x4 outMat;
outMat.m00 = ortho.m00 * rhs.m00;
outMat.m01 = ortho.m00 * rhs.m01;
outMat.m02 = ortho.m00 * rhs.m02;
outMat.m03 = ortho.m00 * rhs.m03;
outMat.m10 = ortho.m11 * rhs.m10;
outMat.m11 = ortho.m11 * rhs.m11;
outMat.m12 = ortho.m11 * rhs.m12;
outMat.m13 = ortho.m11 * rhs.m13;
outMat.m20 = ortho.m22 * rhs.m20 + ortho.m23 * rhs.m30;
outMat.m21 = ortho.m22 * rhs.m21 + ortho.m23 * rhs.m31;
outMat.m22 = ortho.m22 * rhs.m22 + ortho.m23 * rhs.m32;
outMat.m23 = ortho.m22 * rhs.m23 + ortho.m23 * rhs.m33;
outMat.m30 = rhs.m20;
outMat.m31 = rhs.m21;
outMat.m32 = rhs.m22;
outMat.m33 = rhs.m23;
return outMat;
}
// General case has m03 and m13 != 0
private static Matrix4x4 MultiplyGenericOrthoMatrix(Matrix4x4 ortho, Matrix4x4 rhs)
{
Matrix4x4 outMat;
outMat.m00 = ortho.m00 * rhs.m00 + ortho.m03 * rhs.m30;
outMat.m01 = ortho.m00 * rhs.m01 + ortho.m03 * rhs.m31;
outMat.m02 = ortho.m00 * rhs.m02 + ortho.m03 * rhs.m32;
outMat.m03 = ortho.m00 * rhs.m03 + ortho.m03 * rhs.m33;
outMat.m10 = ortho.m11 * rhs.m10 + ortho.m13 * rhs.m30;
outMat.m11 = ortho.m11 * rhs.m11 + ortho.m13 * rhs.m31;
outMat.m12 = ortho.m11 * rhs.m12 + ortho.m13 * rhs.m32;
outMat.m13 = ortho.m11 * rhs.m13 + ortho.m13 * rhs.m33;
outMat.m20 = ortho.m22 * rhs.m20 + ortho.m23 * rhs.m30;
outMat.m21 = ortho.m22 * rhs.m21 + ortho.m23 * rhs.m31;
outMat.m22 = ortho.m22 * rhs.m22 + ortho.m23 * rhs.m32;
outMat.m23 = ortho.m22 * rhs.m23 + ortho.m23 * rhs.m33;
outMat.m30 = rhs.m20;
outMat.m31 = rhs.m21;
outMat.m32 = rhs.m22;
outMat.m33 = rhs.m23;
return outMat;
}
/// <summary>
/// Multiplies a matrix with an orthographic matrix. This function is faster than performing the full matrix multiplication.
/// The operation order is ortho * rhs.
/// </summary>
/// <param name="ortho">The ortho matrix to multiply with rhs.</param>
/// <param name="rhs">A matrix to be multiply to perspective.</param>
/// <param name="centered">If true, it means that right and left are equivalently distant from center and similarly top/bottom are equivalently distant from center.</param>
/// <returns>Returns the matrix that is the result of the multiplication.</returns>
public static Matrix4x4 MultiplyOrthoMatrix(Matrix4x4 ortho, Matrix4x4 rhs, bool centered)
{
return centered ? MultiplyGenericOrthoMatrix(ortho, rhs) : MultiplyOrthoMatrixCentered(ortho, rhs);
}
/// <summary>
/// Multiplies a matrix with a projection matrix. This function is faster than performing the full matrix multiplication.
/// The operation order is projMatrix * rhs.
/// </summary>
/// <param name="projMatrix">The projection matrix to multiply with rhs.</param>
/// <param name="rhs">A matrix to be multiply to perspective.</param>
/// <param name="orthoCentered">If true, the projection matrix is a centered ( right+left == top+bottom == 0) orthographic projection, otherwise it is a perspective matrix..</param>
/// <returns>Returns the matrix that is the result of the multiplication.</returns>
public static Matrix4x4 MultiplyProjectionMatrix(Matrix4x4 projMatrix, Matrix4x4 rhs, bool orthoCentered)
{
return orthoCentered
? MultiplyOrthoMatrixCentered(projMatrix, rhs)
: MultiplyPerspectiveMatrix(projMatrix, rhs);
}
}
}

View File

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

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
namespace UnityEngine.Rendering
{
// This file can't be in the editor assembly as we need to access it in runtime-editor-specific
// places like OnGizmo etc and we don't want to add the editor assembly as a dependency of the
// runtime one
// The UI layout/styling in this panel is broken and can't match the one from built-ins
// preference panels as everything needed is internal/private (at the time of writing this
// comment)
#if UNITY_EDITOR
using UnityEditor;
public static class CoreRenderPipelinePreferences
{
// We do not want that GC frees the preferences that have been added, used to store their references
static readonly ConcurrentStack<object> s_ColorPref = new ConcurrentStack<object>();
#region Volumes Gizmo Color
[Obsolete("Use VolumePreferences", false)]
public static Color volumeGizmoColor { get; } = new Color(0.2f, 0.8f, 0.1f, 0.125f);
#endregion
#region Preview Camera Background Color
static readonly Color kPreviewCameraBackgroundColorDefault = new Color(82f / 255.0f, 82f / 255.0f, 82.0f / 255.0f, 0.0f);
public static Color previewBackgroundColor => kPreviewCameraBackgroundColorDefault;
#endregion
/// <summary>
/// Adds a <see cref="PrefColor"/> into the **Preferences > Colors** panel./>
/// </summary>
/// <param name="name">The name the color has in the **Colors** panel. This is in the format of 'group/name'.</param>
/// <param name="defaultColor">The initial color to use for the new entry in the **Colors** panel. This is also the value Unity uses when it resets the colors to their defaults.</param>
public static Func<Color> RegisterPreferenceColor(string name, Color defaultColor)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentException("You must give a valid name for the color property", nameof(name));
// PrefColor is the type to use to have a Color that is customizable inside the Preference/Colors panel.
// Sadly it is internal so we must create it and grab color from it by reflection.
Type prefColorType = typeof(Editor).Assembly.GetType("UnityEditor.PrefColor");
PropertyInfo colorInfo = prefColorType.GetProperty("Color");
var colorPref = Activator.CreateInstance(prefColorType, name, defaultColor.r, defaultColor.g, defaultColor.b, defaultColor.a);
s_ColorPref.Push(colorPref);
MemberExpression colorProperty = Expression.Property(Expression.Constant(colorPref, prefColorType), colorInfo);
// Make sure that the new preference color is being loaded into the Preference/Colors panel
MethodInfo loadMethod = prefColorType.GetMethod("Load");
loadMethod.Invoke(colorPref, null);
// Return the method to obtain the color
return Expression.Lambda<Func<Color>>(colorProperty).Compile();
}
}
#endif
}

View File

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

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: c86deb7236b4fe146b8b75ab0ac89586
timeCreated: 1507041147
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using System;
namespace UnityEngine.Rendering
{
/// <summary>
/// Delegate utility class.
/// </summary>
public static class DelegateUtility
{
/// <summary>
/// Cast a delegate.
/// </summary>
/// <param name="source">Source delegate.</param>
/// <param name="type">Type of the delegate.</param>
/// <returns>Cast delegate.</returns>
public static Delegate Cast(Delegate source, Type type)
{
if (source == null)
return null;
Delegate[] delegates = source.GetInvocationList();
if (delegates.Length == 1)
return Delegate.CreateDelegate(type,
delegates[0].Target, delegates[0].Method);
Delegate[] delegatesDest = new Delegate[delegates.Length];
for (int nDelegate = 0; nDelegate < delegates.Length; nDelegate++)
delegatesDest[nDelegate] = Delegate.CreateDelegate(type,
delegates[nDelegate].Target, delegates[nDelegate].Method);
return Delegate.Combine(delegatesDest);
}
}
}

View File

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

View File

@@ -0,0 +1,162 @@
using System;
using Unity.Collections;
namespace UnityEngine.Rendering
{
/// <summary>
/// Utility functions relating to FidelityFX Super Resolution (FSR)
///
/// These functions are expected to be used in conjuction with the helper functions provided by FSRCommon.hlsl.
/// </summary>
public static class FSRUtils
{
/// Shader constant ids used to communicate with the FSR shader implementation
static class ShaderConstants
{
// EASU
public static readonly int _FsrEasuConstants0 = Shader.PropertyToID("_FsrEasuConstants0");
public static readonly int _FsrEasuConstants1 = Shader.PropertyToID("_FsrEasuConstants1");
public static readonly int _FsrEasuConstants2 = Shader.PropertyToID("_FsrEasuConstants2");
public static readonly int _FsrEasuConstants3 = Shader.PropertyToID("_FsrEasuConstants3");
// RCAS
public static readonly int _FsrRcasConstants = Shader.PropertyToID("_FsrRcasConstants");
}
/// <summary>
/// Sets the constant values required by the FSR EASU shader on the provided command buffer
///
/// Logic ported from "FsrEasuCon()" in Runtime/PostProcessing/Shaders/ffx/ffx_fsr1.hlsl
/// </summary>
/// <param name="cmd">Command buffer to modify</param>
/// <param name="inputViewportSizeInPixels">This the rendered image resolution being upscaled</param>
/// <param name="inputImageSizeInPixels">This is the resolution of the resource containing the input image (useful for dynamic resolution)</param>
/// <param name="outputImageSizeInPixels">This is the display resolution which the input image gets upscaled to</param>
public static void SetEasuConstants(CommandBuffer cmd, Vector2 inputViewportSizeInPixels, Vector2 inputImageSizeInPixels, Vector2 outputImageSizeInPixels)
{
Vector4 constants0;
Vector4 constants1;
Vector4 constants2;
Vector4 constants3;
// Output integer position to a pixel position in viewport.
constants0.x = (inputViewportSizeInPixels.x / outputImageSizeInPixels.x);
constants0.y = (inputViewportSizeInPixels.y / outputImageSizeInPixels.y);
constants0.z = (0.5f * inputViewportSizeInPixels.x / outputImageSizeInPixels.x - 0.5f);
constants0.w = (0.5f * inputViewportSizeInPixels.y / outputImageSizeInPixels.y - 0.5f);
// Viewport pixel position to normalized image space.
// This is used to get upper-left of 'F' tap.
constants1.x = (1.0f / inputImageSizeInPixels.x);
constants1.y = (1.0f / inputImageSizeInPixels.y);
// Centers of gather4, first offset from upper-left of 'F'.
// +---+---+
// | | |
// +--(0)--+
// | b | c |
// +---F---+---+---+
// | e | f | g | h |
// +--(1)--+--(2)--+
// | i | j | k | l |
// +---+---+---+---+
// | n | o |
// +--(3)--+
// | | |
// +---+---+
constants1.z = (1.0f / inputImageSizeInPixels.x);
constants1.w = (-1.0f / inputImageSizeInPixels.y);
// These are from (0) instead of 'F'.
constants2.x = (-1.0f / inputImageSizeInPixels.x);
constants2.y = (2.0f / inputImageSizeInPixels.y);
constants2.z = (1.0f / inputImageSizeInPixels.x);
constants2.w = (2.0f / inputImageSizeInPixels.y);
constants3.x = (0.0f / inputImageSizeInPixels.x);
constants3.y = (4.0f / inputImageSizeInPixels.y);
// Fill the last constant with zeros to avoid using uninitialized memory
constants3.z = 0.0f;
constants3.w = 0.0f;
cmd.SetGlobalVector(ShaderConstants._FsrEasuConstants0, constants0);
cmd.SetGlobalVector(ShaderConstants._FsrEasuConstants1, constants1);
cmd.SetGlobalVector(ShaderConstants._FsrEasuConstants2, constants2);
cmd.SetGlobalVector(ShaderConstants._FsrEasuConstants3, constants3);
}
/// <summary>
/// The maximum sharpness value in stops before the effect of RCAS is no longer visible.
/// This value is used to map between linear and stops.
/// </summary>
internal const float kMaxSharpnessStops = 2.5f;
/// <summary>
/// AMD's FidelityFX Super Resolution integration guide recommends a value of 0.2 for the RCAS sharpness parameter when specified in stops
/// </summary>
public const float kDefaultSharpnessStops = 0.2f;
/// <summary>
/// The default RCAS sharpness parameter as a linear value
/// </summary>
public const float kDefaultSharpnessLinear = (1.0f - (kDefaultSharpnessStops / kMaxSharpnessStops));
/// <summary>
/// Sets the constant values required by the FSR RCAS shader on the provided command buffer
///
/// Logic ported from "FsrRcasCon()" in Runtime/PostProcessing/Shaders/ffx/ffx_fsr1.hlsl
/// For a more user-friendly version of this function, see SetRcasConstantsLinear().
/// </summary>
/// <param name="cmd">Command buffer to modify</param>
/// <param name="sharpnessStops">The scale is {0.0 := maximum, to N>0, where N is the number of stops(halving) of the reduction of sharpness</param>
public static void SetRcasConstants(CommandBuffer cmd, float sharpnessStops = kDefaultSharpnessStops)
{
// Transform from stops to linear value.
float sharpnessLinear = Mathf.Pow(2.0f, -sharpnessStops);
Vector4 constants;
uint sharpnessAsHalf = Mathf.FloatToHalf(sharpnessLinear);
int packedSharpness = (int)(sharpnessAsHalf | (sharpnessAsHalf << 16));
float packedSharpnessAsFloat = BitConverter.Int32BitsToSingle(packedSharpness);
constants.x = sharpnessLinear;
constants.y = packedSharpnessAsFloat;
// Fill the last constant with zeros to avoid using uninitialized memory
constants.z = 0.0f;
constants.w = 0.0f;
cmd.SetGlobalVector(ShaderConstants._FsrRcasConstants, constants);
}
/// <summary>
/// Sets the constant values required by the FSR RCAS shader on the provided command buffer
///
/// Equivalent to SetRcasConstants(), but handles the sharpness parameter as a linear value instead of one specified in stops.
/// This is intended to simplify code that allows users to configure the sharpening behavior from a GUI.
/// </summary>
/// <param name="cmd">Command buffer to modify</param>
/// <param name="sharpnessLinear">The level of intensity of the sharpening filter where 0.0 is the least sharp and 1.0 is the most sharp</param>
public static void SetRcasConstantsLinear(CommandBuffer cmd, float sharpnessLinear = kDefaultSharpnessLinear)
{
// Ensure that the input value is between 0.0 and 1.0 prevent incorrect results
Assertions.Assert.IsTrue((sharpnessLinear >= 0.0f) && (sharpnessLinear <= 1.0f));
float sharpnessStops = (1.0f - sharpnessLinear) * kMaxSharpnessStops;
SetRcasConstants(cmd, sharpnessStops);
}
/// <summary>
/// Returns true if FidelityFX Super Resolution (FSR) is supported on the current system
/// FSR requires the textureGather shader instruction which wasn't supported by OpenGL ES until version 3.1
/// </summary>
/// <returns>True if supported</returns>
public static bool IsSupported()
{
return SystemInfo.graphicsShaderLevel >= 45;
}
}
}

View File

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

View File

@@ -0,0 +1,169 @@
using System;
namespace UnityEngine.Rendering
{
/// <summary>
/// Utility class for outputting to an HDR display.
/// </summary>
public static class HDROutputUtils
{
/// <summary> HDR color operations that the shader applies. </summary>
[Flags]
public enum Operation
{
/// <summary> Do not perform operations specific to HDR output. </summary>
None = 0,
/// <summary> Convert colors to the color space of the HDR display. </summary>
ColorConversion = 1 << 0,
/// <summary> Encode colors with the transfer function corresponding to the HDR display. </summary>
ColorEncoding = 1 << 1
}
/// <summary>Shader keywords for communicating with the HDR Output shader implementation.</summary>
public static class ShaderKeywords
{
/// <summary>Keyword string for converting to the correct output color space. </summary>
public const string HDR_COLORSPACE_CONVERSION = "HDR_COLORSPACE_CONVERSION";
/// <summary>Keyword string for applying the color encoding. </summary>
public const string HDR_ENCODING = "HDR_ENCODING";
/// <summary>Keyword string for converting to the correct output color space and applying the color encoding. </summary>
public const string HDR_COLORSPACE_CONVERSION_AND_ENCODING = "HDR_COLORSPACE_CONVERSION_AND_ENCODING";
/// <summary>Keyword string to enable when a shader must be aware the input color space is in nits HDR range. </summary>
public const string HDR_INPUT = "HDR_INPUT";
/// <summary>Keyword for converting to the correct output color space. </summary>
internal static readonly ShaderKeyword HDRColorSpaceConversion = new ShaderKeyword(HDR_COLORSPACE_CONVERSION);
/// <summary>Keyword for applying the color encoding. </summary>
internal static readonly ShaderKeyword HDREncoding = new ShaderKeyword(HDR_ENCODING);
/// <summary>Keyword for converting to the correct output color space and applying the color encoding. </summary>
internal static readonly ShaderKeyword HDRColorSpaceConversionAndEncoding = new ShaderKeyword(HDR_COLORSPACE_CONVERSION_AND_ENCODING);
/// <summary>Keyword to enable when a shader must be aware the input color space is in nits HDR range. </summary>
internal static readonly ShaderKeyword HDRInput = new ShaderKeyword(HDR_INPUT);
}
static class ShaderPropertyId
{
public static readonly int hdrColorSpace = Shader.PropertyToID("_HDRColorspace");
public static readonly int hdrEncoding = Shader.PropertyToID("_HDREncoding");
}
private static bool GetColorSpaceForGamut(ColorGamut gamut, out int colorspace)
{
WhitePoint whitePoint = ColorGamutUtility.GetWhitePoint(gamut);
if (whitePoint != WhitePoint.D65)
{
Debug.LogWarningFormat("{0} white point is currently unsupported for outputting to HDR.", gamut.ToString());
colorspace = -1;
return false;
}
ColorPrimaries primaries = ColorGamutUtility.GetColorPrimaries(gamut);
switch (primaries)
{
case ColorPrimaries.Rec709:
colorspace = (int)HDRColorspace.Rec709;
return true;
case ColorPrimaries.Rec2020:
colorspace = (int)HDRColorspace.Rec2020;
return true;
default:
Debug.LogWarningFormat("{0} color space is currently unsupported for outputting to HDR.", gamut.ToString());
colorspace = -1;
return false;
}
}
private static bool GetColorEncodingForGamut(ColorGamut gamut, out int encoding)
{
TransferFunction transferFunction = ColorGamutUtility.GetTransferFunction(gamut);
switch (transferFunction)
{
case TransferFunction.Linear:
encoding = (int)HDREncoding.Linear;
return true;
case TransferFunction.PQ:
encoding = (int)HDREncoding.PQ;
return true;
default:
Debug.LogWarningFormat("{0} color encoding is currently unsupported for outputting to HDR.", gamut.ToString());
encoding = -1;
return false;
}
}
/// <summary>
/// Configures the Material keywords to use HDR output parameters.
/// </summary>
/// <param name="material">The Material used with HDR output.</param>
/// <param name="gamut">Color gamut (a combination of color space and encoding) queried from the device.</param>
/// <param name="operations">HDR color operations the shader applies.</param>
public static void ConfigureHDROutput(Material material, ColorGamut gamut, Operation operations)
{
int colorSpace;
int encoding;
if (!GetColorSpaceForGamut(gamut, out colorSpace) || !GetColorEncodingForGamut(gamut, out encoding))
return; // only exit here if there is an error or unsupported mode
material.SetInteger(ShaderPropertyId.hdrColorSpace, colorSpace);
material.SetInteger(ShaderPropertyId.hdrEncoding, encoding);
CoreUtils.SetKeyword(material, ShaderKeywords.HDRColorSpaceConversionAndEncoding.name, operations.HasFlag(Operation.ColorConversion) && operations.HasFlag(Operation.ColorEncoding));
CoreUtils.SetKeyword(material, ShaderKeywords.HDREncoding.name, operations.HasFlag(Operation.ColorEncoding) && !operations.HasFlag(Operation.ColorConversion));
CoreUtils.SetKeyword(material, ShaderKeywords.HDRColorSpaceConversion.name, operations.HasFlag(Operation.ColorConversion) && !operations.HasFlag(Operation.ColorEncoding));
// Optimizing shader variants: define HDR_INPUT only if HDR_COLORSPACE_CONVERSION and HDR_ENCODING were not previously defined
CoreUtils.SetKeyword(material, ShaderKeywords.HDRInput.name, operations == Operation.None);
}
/// <summary>
/// Configures the compute shader keywords to use HDR output parameters.
/// </summary>
/// <param name="computeShader">The compute shader used with HDR output.</param>
/// <param name="gamut">Color gamut (a combination of color space and encoding) queried from the device.</param>
/// <param name="operations">HDR color operations the shader applies.</param>
public static void ConfigureHDROutput(ComputeShader computeShader, ColorGamut gamut, Operation operations)
{
int colorSpace;
int encoding;
if (!GetColorSpaceForGamut(gamut, out colorSpace) || !GetColorEncodingForGamut(gamut, out encoding))
return; // only exit here if there is an error or unsupported mode
computeShader.SetInt(ShaderPropertyId.hdrColorSpace, colorSpace);
computeShader.SetInt(ShaderPropertyId.hdrEncoding, encoding);
CoreUtils.SetKeyword(computeShader, ShaderKeywords.HDRColorSpaceConversionAndEncoding.name, operations.HasFlag(Operation.ColorConversion) && operations.HasFlag(Operation.ColorEncoding));
CoreUtils.SetKeyword(computeShader, ShaderKeywords.HDREncoding.name, operations.HasFlag(Operation.ColorEncoding) && !operations.HasFlag(Operation.ColorConversion));
CoreUtils.SetKeyword(computeShader, ShaderKeywords.HDRColorSpaceConversion.name, operations.HasFlag(Operation.ColorConversion) && !operations.HasFlag(Operation.ColorEncoding));
// Optimizing shader variants: define HDR_INPUT only if HDR_COLORSPACE_CONVERSION and HDR_ENCODING were not previously defined
CoreUtils.SetKeyword(computeShader, ShaderKeywords.HDRInput.name, operations == Operation.None);
}
/// <summary>
/// Returns true if the given set of keywords is valid for HDR output.
/// </summary>
/// <param name="shaderKeywordSet">Shader keywords combination that represents a shader variant.</param>
/// <param name="isHDREnabled">Whether HDR output shader variants are required.</param>
/// <returns>True if the shader variant is valid and should not be stripped.</returns>
public static bool IsShaderVariantValid(ShaderKeywordSet shaderKeywordSet, bool isHDREnabled)
{
bool hasHDRKeywords = shaderKeywordSet.IsEnabled(ShaderKeywords.HDREncoding) || shaderKeywordSet.IsEnabled(ShaderKeywords.HDRColorSpaceConversion) || shaderKeywordSet.IsEnabled(ShaderKeywords.HDRColorSpaceConversionAndEncoding) || shaderKeywordSet.IsEnabled(ShaderKeywords.HDRInput);
// If we don't plan to enable HDR, remove all HDR Output variants
if (!isHDREnabled && hasHDRKeywords)
return false;
return true;
}
}
}

View File

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

View File

@@ -0,0 +1,386 @@
using static UnityEngine.Mathf;
namespace UnityEngine.Rendering
{
/// <summary>
/// An implementation of Hable's artist-friendly tonemapping curve.
/// http://filmicworlds.com/blog/filmic-tonemapping-with-piecewise-power-curves/
/// </summary>
public class HableCurve
{
/// <summary>
/// Individual curve segment.
/// </summary>
public class Segment
{
/// <summary>
/// The offset of the segment on the X axis.
/// </summary>
public float offsetX;
/// <summary>
/// The offset of the segment on the Y axis.
/// </summary>
public float offsetY;
/// <summary>
/// The scale of the segment on the X axis.
/// </summary>
public float scaleX;
/// <summary>
/// The scale of the segment on the Y axis.
/// </summary>
public float scaleY;
/// <summary>
/// <c>ln(A)</c> constant in the power curve <c>y = e^(ln(A) + B*ln(x))</c>.
/// </summary>
public float lnA;
/// <summary>
/// <c>B</c> constant in the power curve <c>y = e^(ln(A) + B*ln(x))</c>.
/// </summary>
public float B;
/// <summary>
/// Evaluate a point on the curve.
/// </summary>
/// <param name="x">The point to evaluate.</param>
/// <returns>The value of the curve, at the point specified.</returns>
public float Eval(float x)
{
float x0 = (x - offsetX) * scaleX;
float y0 = 0f;
// log(0) is undefined but our function should evaluate to 0. There are better ways
// to handle this, but it's doing it the slow way here for clarity.
if (x0 > 0)
y0 = Exp(lnA + B * Log(x0));
return y0 * scaleY + offsetY;
}
}
struct DirectParams
{
internal float x0;
internal float y0;
internal float x1;
internal float y1;
internal float W;
internal float overshootX;
internal float overshootY;
internal float gamma;
}
/// <summary>
/// The white point.
/// </summary>
public float whitePoint { get; private set; }
/// <summary>
/// The inverse of the white point.
/// </summary>
/// <seealso cref="whitePoint"/>
public float inverseWhitePoint { get; private set; }
/// <summary>
/// The start of the linear section (middle segment of the curve).
/// </summary>
public float x0 { get; private set; }
/// <summary>
/// The end of the linear section (middle segment of the curve).
/// </summary>
public float x1 { get; private set; }
/// <summary>
/// The three segments of the curve.
/// </summary>
public readonly Segment[] segments = new Segment[3];
/// <summary>
/// Creates a new curve.
/// </summary>
public HableCurve()
{
for (int i = 0; i < 3; i++)
segments[i] = new Segment();
uniforms = new Uniforms(this);
}
/// <summary>
/// Evaluates a point on the curve.
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
public float Eval(float x)
{
float normX = x * inverseWhitePoint;
int index = (normX < x0) ? 0 : ((normX < x1) ? 1 : 2);
var segment = segments[index];
float ret = segment.Eval(normX);
return ret;
}
/// <summary>
/// Initializes the curve.
/// </summary>
/// <param name="toeStrength">The strength of the transition between the curve's toe and the curve's mid-section. A value of 0 results in no transition and a value of 1 results in a very hard transition.</param>
/// <param name="toeLength">The length of the curve's toe. Higher values result in longer toes and therefore contain more of the dynamic range.</param>
/// <param name="shoulderStrength">The strength of the transition between the curve's midsection and the curve's shoulder. A value of 0 results in no transition and a value of 1 results in a very hard transition.</param>
/// <param name="shoulderLength">The amount of f-stops to add to the dynamic range of the curve. This is how much of the highlights that the curve takes into account.</param>
/// <param name="shoulderAngle">How much overshoot to add to the curve's shoulder.</param>
/// <param name="gamma">A gamma correction to the entire curve.</param>
public void Init(float toeStrength, float toeLength, float shoulderStrength, float shoulderLength, float shoulderAngle, float gamma)
{
var dstParams = new DirectParams();
// This is not actually the display gamma. It's just a UI space to avoid having to
// enter small numbers for the input.
const float kPerceptualGamma = 2.2f;
// Constraints
{
toeLength = Pow(Clamp01(toeLength), kPerceptualGamma);
toeStrength = Clamp01(toeStrength);
shoulderAngle = Clamp01(shoulderAngle);
shoulderStrength = Clamp(shoulderStrength, 1e-5f, 1f - 1e-5f);
shoulderLength = Max(0f, shoulderLength);
gamma = Max(1e-5f, gamma);
}
// Apply base params
{
// Toe goes from 0 to 0.5
float x0 = toeLength * 0.5f;
float y0 = (1f - toeStrength) * x0; // Lerp from 0 to x0
float remainingY = 1f - y0;
float initialW = x0 + remainingY;
float y1_offset = (1f - shoulderStrength) * remainingY;
float x1 = x0 + y1_offset;
float y1 = y0 + y1_offset;
// Filmic shoulder strength is in F stops
float extraW = Pow(2f, shoulderLength) - 1f;
float W = initialW + extraW;
dstParams.x0 = x0;
dstParams.y0 = y0;
dstParams.x1 = x1;
dstParams.y1 = y1;
dstParams.W = W;
// Bake the linear to gamma space conversion
dstParams.gamma = gamma;
}
dstParams.overshootX = (dstParams.W * 2f) * shoulderAngle * shoulderLength;
dstParams.overshootY = 0.5f * shoulderAngle * shoulderLength;
InitSegments(dstParams);
}
void InitSegments(DirectParams srcParams)
{
var paramsCopy = srcParams;
whitePoint = srcParams.W;
inverseWhitePoint = 1f / srcParams.W;
// normalize params to 1.0 range
paramsCopy.W = 1f;
paramsCopy.x0 /= srcParams.W;
paramsCopy.x1 /= srcParams.W;
paramsCopy.overshootX = srcParams.overshootX / srcParams.W;
float toeM = 0f;
float shoulderM = 0f;
{
float m, b;
AsSlopeIntercept(out m, out b, paramsCopy.x0, paramsCopy.x1, paramsCopy.y0, paramsCopy.y1);
float g = srcParams.gamma;
// Base function of linear section plus gamma is
// y = (mx+b)^g
//
// which we can rewrite as
// y = exp(g*ln(m) + g*ln(x+b/m))
//
// and our evaluation function is (skipping the if parts):
/*
float x0 = (x - offsetX) * scaleX;
y0 = exp(m_lnA + m_B*log(x0));
return y0*scaleY + m_offsetY;
*/
var midSegment = segments[1];
midSegment.offsetX = -(b / m);
midSegment.offsetY = 0f;
midSegment.scaleX = 1f;
midSegment.scaleY = 1f;
midSegment.lnA = g * Log(m);
midSegment.B = g;
toeM = EvalDerivativeLinearGamma(m, b, g, paramsCopy.x0);
shoulderM = EvalDerivativeLinearGamma(m, b, g, paramsCopy.x1);
// apply gamma to endpoints
paramsCopy.y0 = Max(1e-5f, Pow(paramsCopy.y0, paramsCopy.gamma));
paramsCopy.y1 = Max(1e-5f, Pow(paramsCopy.y1, paramsCopy.gamma));
paramsCopy.overshootY = Pow(1f + paramsCopy.overshootY, paramsCopy.gamma) - 1f;
}
this.x0 = paramsCopy.x0;
this.x1 = paramsCopy.x1;
// Toe section
{
var toeSegment = segments[0];
toeSegment.offsetX = 0;
toeSegment.offsetY = 0f;
toeSegment.scaleX = 1f;
toeSegment.scaleY = 1f;
float lnA, B;
SolveAB(out lnA, out B, paramsCopy.x0, paramsCopy.y0, toeM);
toeSegment.lnA = lnA;
toeSegment.B = B;
}
// Shoulder section
{
// Use the simple version that is usually too flat
var shoulderSegment = segments[2];
float x0 = (1f + paramsCopy.overshootX) - paramsCopy.x1;
float y0 = (1f + paramsCopy.overshootY) - paramsCopy.y1;
float lnA, B;
SolveAB(out lnA, out B, x0, y0, shoulderM);
shoulderSegment.offsetX = (1f + paramsCopy.overshootX);
shoulderSegment.offsetY = (1f + paramsCopy.overshootY);
shoulderSegment.scaleX = -1f;
shoulderSegment.scaleY = -1f;
shoulderSegment.lnA = lnA;
shoulderSegment.B = B;
}
// Normalize so that we hit 1.0 at our white point. We wouldn't have do this if we
// skipped the overshoot part.
{
// Evaluate shoulder at the end of the curve
float scale = segments[2].Eval(1f);
float invScale = 1f / scale;
segments[0].offsetY *= invScale;
segments[0].scaleY *= invScale;
segments[1].offsetY *= invScale;
segments[1].scaleY *= invScale;
segments[2].offsetY *= invScale;
segments[2].scaleY *= invScale;
}
}
// Find a function of the form:
// f(x) = e^(lnA + Bln(x))
// where
// f(0) = 0; not really a constraint
// f(x0) = y0
// f'(x0) = m
void SolveAB(out float lnA, out float B, float x0, float y0, float m)
{
B = (m * x0) / y0;
lnA = Log(y0) - B * Log(x0);
}
// Convert to y=mx+b
void AsSlopeIntercept(out float m, out float b, float x0, float x1, float y0, float y1)
{
float dy = (y1 - y0);
float dx = (x1 - x0);
if (dx == 0)
m = 1f;
else
m = dy / dx;
b = y0 - x0 * m;
}
// f(x) = (mx+b)^g
// f'(x) = gm(mx+b)^(g-1)
float EvalDerivativeLinearGamma(float m, float b, float g, float x)
{
return g * m * Pow(m * x + b, g - 1f);
}
/// <summary>
/// An utility class to ease the binding of curve parameters to shaders.
/// </summary>
public class Uniforms
{
HableCurve parent;
internal Uniforms(HableCurve parent)
{
this.parent = parent;
}
/// <summary>
/// Main curve settings, stored as <c>(inverseWhitePoint, x0, x1, 0)</c>.
/// </summary>
public Vector4 curve => new Vector4(parent.inverseWhitePoint, parent.x0, parent.x1, 0f);
/// <summary>
/// Toe segment settings, stored as <c>(offsetX, offsetY, scaleX, scaleY)</c>.
/// </summary>
public Vector4 toeSegmentA => new Vector4(parent.segments[0].offsetX, parent.segments[0].offsetY, parent.segments[0].scaleX, parent.segments[0].scaleY);
/// <summary>
/// Toe segment settings, stored as <c>(ln1, B, 0, 0)</c>.
/// </summary>
public Vector4 toeSegmentB => new Vector4(parent.segments[0].lnA, parent.segments[0].B, 0f, 0f);
/// <summary>
/// Mid segment settings, stored as <c>(offsetX, offsetY, scaleX, scaleY)</c>.
/// </summary>
public Vector4 midSegmentA => new Vector4(parent.segments[1].offsetX, parent.segments[1].offsetY, parent.segments[1].scaleX, parent.segments[1].scaleY);
/// <summary>
/// Mid segment settings, stored as <c>(ln1, B, 0, 0)</c>.
/// </summary>
public Vector4 midSegmentB => new Vector4(parent.segments[1].lnA, parent.segments[1].B, 0f, 0f);
/// <summary>
/// Shoulder segment settings, stored as <c>(offsetX, offsetY, scaleX, scaleY)</c>.
/// </summary>
public Vector4 shoSegmentA => new Vector4(parent.segments[2].offsetX, parent.segments[2].offsetY, parent.segments[2].scaleX, parent.segments[2].scaleY);
/// <summary>
/// Shoulder segment settings, stored as <c>(ln1, B, 0, 0)</c>.
/// </summary>
public Vector4 shoSegmentB => new Vector4(parent.segments[2].lnA, parent.segments[2].B, 0f, 0f);
}
/// <summary>
/// An instance of the <see cref="Uniforms"/> utility class for this curve.
/// </summary>
public readonly Uniforms uniforms;
}
}

View File

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

View File

@@ -0,0 +1,31 @@
namespace UnityEngine.Rendering
{
/// <summary>
/// An utility class to compute samples on the Halton sequence.
/// https://en.wikipedia.org/wiki/Halton_sequence
/// </summary>
public static class HaltonSequence
{
/// <summary>
/// Gets a deterministic sample in the Halton sequence.
/// </summary>
/// <param name="index">The index in the sequence.</param>
/// <param name="radix">The radix of the sequence.</param>
/// <returns>A sample from the Halton sequence.</returns>
public static float Get(int index, int radix)
{
float result = 0f;
float fraction = 1f / radix;
while (index > 0)
{
result += (index % radix) * fraction;
index /= radix;
fraction /= radix;
}
return result;
}
}
}

View File

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

View File

@@ -0,0 +1,167 @@
using System;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Rendering
{
/// <summary>
/// Material quality flags.
/// </summary>
[Flags]
[MovedFrom("Utilities")]
public enum MaterialQuality
{
/// <summary>Low Material Quality.</summary>
Low = 1 << 0,
/// <summary>Medium Material Quality.</summary>
Medium = 1 << 1,
/// <summary>High Material Quality.</summary>
High = 1 << 2
}
/// <summary>
/// Material Quality utility class.
/// </summary>
[MovedFrom("Utilities")]
public static class MaterialQualityUtilities
{
/// <summary>
/// Keywords strings for Material Quality levels.
/// </summary>
public static string[] KeywordNames =
{
"MATERIAL_QUALITY_LOW",
"MATERIAL_QUALITY_MEDIUM",
"MATERIAL_QUALITY_HIGH",
};
/// <summary>
/// String representation of the MaterialQuality enum.
/// </summary>
public static string[] EnumNames = Enum.GetNames(typeof(MaterialQuality));
/// <summary>
/// Keywords for Material Quality levels.
/// </summary>
public static ShaderKeyword[] Keywords =
{
new ShaderKeyword(KeywordNames[0]),
new ShaderKeyword(KeywordNames[1]),
new ShaderKeyword(KeywordNames[2]),
};
/// <summary>
/// Returns the highest available quality level in a MaterialQuality bitfield.
/// </summary>
/// <param name="levels">Input MaterialQuality bitfield.</param>
/// <returns>The highest available quality level.</returns>
public static MaterialQuality GetHighestQuality(this MaterialQuality levels)
{
for (var i = Keywords.Length - 1; i >= 0; --i)
{
var level = (MaterialQuality)(1 << i);
if ((levels & level) != 0)
return level;
}
return 0;
}
/// <summary>
/// Returns the closest available quality level in a MaterialQuality bitfield.
/// </summary>
/// <param name="availableLevels">Available MaterialQuality bitfield.</param>
/// <param name="requestedLevel">Input MaterialQuality level.</param>
/// <returns>The closest available quality level.</returns>
public static MaterialQuality GetClosestQuality(this MaterialQuality availableLevels, MaterialQuality requestedLevel)
{
// Special fallback when there are no available quality levels. Needs to match in the shader stripping code
if (availableLevels == 0)
return MaterialQuality.Low;
// First we want to find the closest available quality level below the requested one.
int requestedLevelIndex = ToFirstIndex(requestedLevel);
MaterialQuality chosenQuality = (MaterialQuality)0;
for (int i = requestedLevelIndex; i >= 0; --i)
{
var level = FromIndex(i);
if ((level & availableLevels) != 0)
{
chosenQuality = level;
break;
}
}
if (chosenQuality != 0)
return chosenQuality;
// If none is found then we fallback to the closest above.
for (var i = requestedLevelIndex + 1; i < Keywords.Length; ++i)
{
var level = FromIndex(i);
var diff = Math.Abs(requestedLevel - level);
if ((level & availableLevels) != 0)
{
chosenQuality = level;
break;
}
}
Debug.Assert(chosenQuality != 0);
return chosenQuality;
}
/// <summary>
/// Set the global keyword for the provided MaterialQuality.
/// </summary>
/// <param name="level">MaterialQuality level to set the keyword for.</param>
public static void SetGlobalShaderKeywords(this MaterialQuality level)
{
for (var i = 0; i < KeywordNames.Length; ++i)
{
if ((level & (MaterialQuality)(1 << i)) != 0)
Shader.EnableKeyword(KeywordNames[i]);
else
Shader.DisableKeyword(KeywordNames[i]);
}
}
/// <summary>
/// Set the global keyword for the provided MaterialQuality.
/// </summary>
/// <param name="level">MaterialQuality level to set the keyword for.</param>
/// <param name="cmd">Command Buffer used to setup the keyword.</param>
public static void SetGlobalShaderKeywords(this MaterialQuality level, CommandBuffer cmd)
{
for (var i = 0; i < KeywordNames.Length; ++i)
{
if ((level & (MaterialQuality)(1 << i)) != 0)
cmd.EnableShaderKeyword(KeywordNames[i]);
else
cmd.DisableShaderKeyword(KeywordNames[i]);
}
}
/// <summary>
/// Returns the index (in the MaterialQuality enum) of the first available level.
/// </summary>
/// <param name="level">MaterialQuality bitfield.</param>
/// <returns>The index of the first available level.</returns>
public static int ToFirstIndex(this MaterialQuality level)
{
for (var i = 0; i < KeywordNames.Length; ++i)
{
if ((level & (MaterialQuality)(1 << i)) != 0)
return i;
}
return -1;
}
/// <summary>
/// Returns the enum equivalent of the index in the MaterialQuality enum list.
/// </summary>
/// <param name="index">Index of the material quality.</param>
/// <returns>The equivalent enum.</returns>
public static MaterialQuality FromIndex(int index) => (MaterialQuality)(1 << index);
}
}

View File

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

View File

@@ -0,0 +1,105 @@
using UnityEngine;
using System.Collections.Generic;
using System.Reflection;
using System;
namespace UnityEngine.Rendering
{
/// <summary>
/// Helper to build and render a mesh for Gizmos, it is a lot more faster than drawing a ton of gizmos separately
/// </summary>
class MeshGizmo : IDisposable
{
public static readonly int vertexCountPerCube = 24;
public Mesh mesh;
List<Vector3> vertices;
List<int> indices;
List<Color> colors;
Material wireMaterial;
Material dottedWireMaterial;
Material solidMaterial;
public MeshGizmo(int capacity = 0)
{
vertices = new List<Vector3>(capacity);
indices = new List<int>(capacity);
colors = new List<Color>(capacity);
mesh = new Mesh { indexFormat = IndexFormat.UInt32, hideFlags = HideFlags.HideAndDontSave };
#if UNITY_EDITOR
wireMaterial = (Material)UnityEditor.EditorGUIUtility.LoadRequired("SceneView/HandleLines.mat");
dottedWireMaterial = (Material)UnityEditor.EditorGUIUtility.LoadRequired("SceneView/HandleDottedLines.mat");
solidMaterial = UnityEditor.HandleUtility.handleMaterial;
#endif
}
public void Clear()
{
vertices.Clear();
indices.Clear();
colors.Clear();
}
public void AddWireCube(Vector3 center, Vector3 size, Color color)
{
var halfSize = size / 2.0f;
Vector3 p0 = new Vector3(halfSize.x, halfSize.y, halfSize.z);
Vector3 p1 = new Vector3(-halfSize.x, halfSize.y, halfSize.z);
Vector3 p2 = new Vector3(-halfSize.x, -halfSize.y, halfSize.z);
Vector3 p3 = new Vector3(halfSize.x, -halfSize.y, halfSize.z);
Vector3 p4 = new Vector3(halfSize.x, halfSize.y, -halfSize.z);
Vector3 p5 = new Vector3(-halfSize.x, halfSize.y, -halfSize.z);
Vector3 p6 = new Vector3(-halfSize.x, -halfSize.y, -halfSize.z);
Vector3 p7 = new Vector3(halfSize.x, -halfSize.y, -halfSize.z);
AddEdge(center + p0, center + p1);
AddEdge(center + p1, center + p2);
AddEdge(center + p2, center + p3);
AddEdge(center + p3, center + p0);
AddEdge(center + p4, center + p5);
AddEdge(center + p5, center + p6);
AddEdge(center + p6, center + p7);
AddEdge(center + p7, center + p4);
AddEdge(center + p0, center + p4);
AddEdge(center + p1, center + p5);
AddEdge(center + p2, center + p6);
AddEdge(center + p3, center + p7);
void AddEdge(Vector3 p1, Vector3 p2)
{
vertices.Add(p1);
vertices.Add(p2);
indices.Add(indices.Count);
indices.Add(indices.Count);
colors.Add(color);
colors.Add(color);
}
}
void DrawMesh(Matrix4x4 trs, Material mat, MeshTopology topology, CompareFunction depthTest, string gizmoName)
{
mesh.Clear();
mesh.SetVertices(vertices);
mesh.SetColors(colors);
mesh.SetIndices(indices, topology, 0);
mat.SetFloat("_HandleZTest", (int)depthTest);
var cmd = CommandBufferPool.Get(gizmoName ?? "Mesh Gizmo Rendering");
cmd.DrawMesh(mesh, trs, mat, 0, 0);
Graphics.ExecuteCommandBuffer(cmd);
}
public void RenderWireframe(Matrix4x4 trs, CompareFunction depthTest = CompareFunction.LessEqual, string gizmoName = null)
=> DrawMesh(trs, wireMaterial, MeshTopology.Lines, depthTest, gizmoName);
public void Dispose()
{
CoreUtils.Destroy(mesh);
}
}
}

View File

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

View File

@@ -0,0 +1,367 @@
using System;
using System.IO;
using UnityEngine.Assertions;
#if UNITY_EDITOR
using UnityEditor;
using System.Reflection;
#endif
namespace UnityEngine.Rendering
{
#if UNITY_EDITOR
/// <summary>
/// The resources that need to be reloaded in Editor can live in Runtime.
/// The reload call should only be done in Editor context though but it
/// could be called from runtime entities.
/// </summary>
public static class ResourceReloader
{
/// <summary>
/// Looks for resources in the given <paramref name="container"/> object and reload the ones
/// that are missing or broken.
/// This version will still return null value without throwing error if the issue is due to
/// AssetDatabase being not ready. But in this case the assetDatabaseNotReady result will be true.
/// </summary>
/// <param name="container">The object containing reload-able resources</param>
/// <param name="basePath">The base path for the package</param>
/// <returns>
/// - 1 hasChange: True if something have been reloaded.
/// - 2 assetDatabaseNotReady: True if the issue preventing loading is due to state of AssetDatabase
/// </returns>
public static (bool hasChange, bool assetDatabaseNotReady) TryReloadAllNullIn(System.Object container, string basePath)
{
try
{
return (ReloadAllNullIn(container, basePath), false);
}
catch (Exception e)
{
if (!(e.Data.Contains("InvalidImport") && e.Data["InvalidImport"] is int && (int)e.Data["InvalidImport"] == 1))
throw e;
return (false, true);
}
}
/// <summary>
/// Looks for resources in the given <paramref name="container"/> object and reload the ones
/// that are missing or broken.
/// </summary>
/// <param name="container">The object containing reload-able resources</param>
/// <param name="basePath">The base path for the package</param>
/// <returns>True if something have been reloaded.</returns>
public static bool ReloadAllNullIn(System.Object container, string basePath)
{
if (IsNull(container))
return false;
var changed = false;
foreach (var fieldInfo in container.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
{
//Recurse on sub-containers
if (IsReloadGroup(fieldInfo))
{
changed |= FixGroupIfNeeded(container, fieldInfo);
changed |= ReloadAllNullIn(fieldInfo.GetValue(container), basePath);
}
//Find null field and reload them
var attribute = GetReloadAttribute(fieldInfo);
if (attribute != null)
{
if (attribute.paths.Length == 1)
{
changed |= SetAndLoadIfNull(container, fieldInfo, GetFullPath(basePath, attribute),
attribute.package);
}
else if (attribute.paths.Length > 1)
{
changed |= FixArrayIfNeeded(container, fieldInfo, attribute.paths.Length);
var array = (Array)fieldInfo.GetValue(container);
if (IsReloadGroup(array))
{
//Recurse on each sub-containers
for (int index = 0; index < attribute.paths.Length; ++index)
{
changed |= FixGroupIfNeeded(array, index);
changed |= ReloadAllNullIn(array.GetValue(index), basePath);
}
}
else
{
//Find each null element and reload them
for (int index = 0; index < attribute.paths.Length; ++index)
changed |= SetAndLoadIfNull(array, index, GetFullPath(basePath, attribute, index),
attribute.package);
}
}
}
}
if (changed && container is UnityEngine.Object c)
EditorUtility.SetDirty(c);
return changed;
}
static void CheckReloadGroupSupportedType(Type type)
{
if (type.IsSubclassOf(typeof(ScriptableObject)))
throw new Exception(@$"ReloadGroup attribute must not be used on {nameof(ScriptableObject)}.
If {nameof(ResourceReloader)} create an instance of it, it will be not saved as a file, resulting in corrupted ID when building.");
}
static bool FixGroupIfNeeded(System.Object container, FieldInfo info)
{
var type = info.FieldType;
CheckReloadGroupSupportedType(type);
if (IsNull(container, info))
{
var value = Activator.CreateInstance(type);
info.SetValue(
container,
value
);
return true;
}
return false;
}
static bool FixGroupIfNeeded(Array array, int index)
{
Assert.IsNotNull(array);
var type = array.GetType().GetElementType();
CheckReloadGroupSupportedType(type);
if (IsNull(array.GetValue(index)))
{
var value = type.IsSubclassOf(typeof(ScriptableObject))
? ScriptableObject.CreateInstance(type)
: Activator.CreateInstance(type);
array.SetValue(value, index);
return true;
}
return false;
}
static bool FixArrayIfNeeded(System.Object container, FieldInfo info, int length)
{
if (IsNull(container, info) || ((Array)info.GetValue(container)).Length < length)
{
info.SetValue(container, Activator.CreateInstance(info.FieldType, length));
return true;
}
return false;
}
static ReloadAttribute GetReloadAttribute(FieldInfo fieldInfo)
{
var attributes = (ReloadAttribute[])fieldInfo
.GetCustomAttributes(typeof(ReloadAttribute), false);
if (attributes.Length == 0)
return null;
return attributes[0];
}
static bool IsReloadGroup(FieldInfo info)
=> info.FieldType
.GetCustomAttributes(typeof(ReloadGroupAttribute), false).Length > 0;
static bool IsReloadGroup(Array field)
=> field.GetType().GetElementType()
.GetCustomAttributes(typeof(ReloadGroupAttribute), false).Length > 0;
static bool IsNull(System.Object container, FieldInfo info)
=> IsNull(info.GetValue(container));
static bool IsNull(System.Object field)
=> field == null || field.Equals(null);
static UnityEngine.Object Load(string path, Type type, ReloadAttribute.Package location)
{
// Check if asset exist.
// Direct loading can be prevented by AssetDatabase being reloading.
var guid = AssetDatabase.AssetPathToGUID(path);
if (location == ReloadAttribute.Package.Root && String.IsNullOrEmpty(guid))
throw new Exception($"Cannot load. Incorrect path: {path}");
// Else the path is good. Attempt loading resource if AssetDatabase available.
UnityEngine.Object result;
switch (location)
{
case ReloadAttribute.Package.Builtin:
if (type == typeof(Shader))
result = Shader.Find(path);
else
result = Resources.GetBuiltinResource(type, path); //handle wrong path error
break;
case ReloadAttribute.Package.BuiltinExtra:
if (type == typeof(Shader))
result = Shader.Find(path);
else
result = AssetDatabase.GetBuiltinExtraResource(type, path); //handle wrong path error
break;
case ReloadAttribute.Package.Root:
result = AssetDatabase.LoadAssetAtPath(path, type);
break;
default:
throw new NotImplementedException($"Unknown {location}");
}
if (IsNull(result))
{
var e = new Exception($"Cannot load. Path {path} is correct but AssetDatabase cannot load now.");
e.Data["InvalidImport"] = 1;
throw e;
}
return result;
}
static bool SetAndLoadIfNull(System.Object container, FieldInfo info,
string path, ReloadAttribute.Package location)
{
if (IsNull(container, info))
{
info.SetValue(container, Load(path, info.FieldType, location));
return true;
}
return false;
}
static bool SetAndLoadIfNull(Array array, int index, string path, ReloadAttribute.Package location)
{
var element = array.GetValue(index);
if (IsNull(element))
{
array.SetValue(Load(path, array.GetType().GetElementType(), location), index);
return true;
}
return false;
}
static string GetFullPath(string basePath, ReloadAttribute attribute, int index = 0)
{
string path;
switch (attribute.package)
{
case ReloadAttribute.Package.Builtin:
path = attribute.paths[index];
break;
case ReloadAttribute.Package.Root:
path = basePath + "/" + attribute.paths[index];
break;
default:
throw new ArgumentException("Unknown Package Path!");
}
return path;
}
}
#endif
/// <summary>
/// Attribute specifying information to reload with <see cref="ResourceReloader"/>. This is only
/// used in the editor and doesn't have any effect at runtime.
/// </summary>
/// <seealso cref="ResourceReloader"/>
/// <seealso cref="ReloadGroupAttribute"/>
[AttributeUsage(AttributeTargets.Field)]
public sealed class ReloadAttribute : Attribute
{
/// <summary>
/// Lookup method for a resource.
/// </summary>
public enum Package
{
/// <summary>
/// Used for builtin resources when the resource isn't part of the package (i.e. builtin
/// shaders).
/// </summary>
Builtin,
/// <summary>
/// Used for resources inside the package.
/// </summary>
Root,
/// <summary>
/// Used for builtin extra resources when the resource isn't part of the package (i.e. builtin
/// extra Sprite).
/// </summary>
BuiltinExtra,
};
#if UNITY_EDITOR
/// <summary>
/// The lookup method.
/// </summary>
public readonly Package package;
/// <summary>
/// Search paths.
/// </summary>
public readonly string[] paths;
#endif
/// <summary>
/// Creates a new <see cref="ReloadAttribute"/> for an array by specifying each resource
/// path individually.
/// </summary>
/// <param name="paths">Search paths</param>
/// <param name="package">The lookup method</param>
public ReloadAttribute(string[] paths, Package package = Package.Root)
{
#if UNITY_EDITOR
this.paths = paths;
this.package = package;
#endif
}
/// <summary>
/// Creates a new <see cref="ReloadAttribute"/> for a single resource.
/// </summary>
/// <param name="path">Search path</param>
/// <param name="package">The lookup method</param>
public ReloadAttribute(string path, Package package = Package.Root)
: this(new[] { path }, package)
{ }
/// <summary>
/// Creates a new <see cref="ReloadAttribute"/> for an array using automatic path name
/// numbering.
/// </summary>
/// <param name="pathFormat">The format used for the path</param>
/// <param name="rangeMin">The array start index (inclusive)</param>
/// <param name="rangeMax">The array end index (exclusive)</param>
/// <param name="package">The lookup method</param>
public ReloadAttribute(string pathFormat, int rangeMin, int rangeMax,
Package package = Package.Root)
{
#if UNITY_EDITOR
this.package = package;
paths = new string[rangeMax - rangeMin];
for (int index = rangeMin, i = 0; index < rangeMax; ++index, ++i)
paths[i] = string.Format(pathFormat, index);
#endif
}
}
/// <summary>
/// Attribute specifying that it contains element that should be reloaded.
/// If the instance of the class is null, the system will try to recreate
/// it with the default constructor.
/// Be sure classes using it have default constructor!
/// </summary>
/// <seealso cref="ReloadAttribute"/>
[AttributeUsage(AttributeTargets.Class)]
public sealed class ReloadGroupAttribute : Attribute
{ }
}

View File

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

View File

@@ -0,0 +1,137 @@
#if UNITY_EDITOR
using System;
using System.Linq.Expressions;
using System.Reflection;
using UnityEditor;
using UnityEngine.SceneManagement;
#endif //UNITY_EDITOR
namespace UnityEngine.Rendering
{
/// <summary>
/// Setup a specific render pipeline on scene loading.
/// This need to be used with caution as it will change project configuration.
/// </summary>
#if UNITY_EDITOR
[ExecuteAlways]
#endif //UNITY_EDITOR
public class SceneRenderPipeline : MonoBehaviour
{
#if UNITY_EDITOR
[SerializeField] bool firstTimeCreated = true;
/// <summary>
/// Scriptable Render Pipeline Asset to setup on scene load.
/// </summary>
public RenderPipelineAsset renderPipelineAsset;
void Awake()
{
if (firstTimeCreated)
{
renderPipelineAsset = GraphicsSettings.renderPipelineAsset;
firstTimeCreated = false;
}
#if ENABLE_CLOUD_SERVICES_ANALYTICS
//Send analytics each time to find usage in content dl on the asset store too
SceneRenderPipelineAnalytic.Send(this);
#endif
}
void OnEnable()
{
GraphicsSettings.renderPipelineAsset = renderPipelineAsset;
}
#if ENABLE_CLOUD_SERVICES_ANALYTICS
static class SceneRenderPipelineAnalytic
{
const int k_MaxEventsPerHour = 100;
const int k_MaxNumberOfElements = 1000;
const string k_VendorKey = "unity.srp";
[System.Diagnostics.DebuggerDisplay("{scene_guid}")]
internal struct Data
{
internal const string k_EventName = "sceneRenderPipelineAssignment";
// Naming convention for analytics data
public string scene_guid;
};
internal static void Send(SceneRenderPipeline sender)
{
if (!EditorAnalytics.enabled || !EditorAnalyticsExtensions.RegisterEventWithLimit(Data.k_EventName, k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey))
return;
var data = new Data() { scene_guid = SceneExtensions.GetGUID(sender.gameObject.scene) };
EditorAnalyticsExtensions.SendEventWithLimit(Data.k_EventName, data);
}
//bellow is missing API specific for 2022.2
internal static class SceneExtensions
{
static PropertyInfo s_SceneGUID = typeof(Scene).GetProperty("guid", BindingFlags.NonPublic | BindingFlags.Instance);
public static string GetGUID(Scene scene)
{
Debug.Assert(s_SceneGUID != null, "Reflection for scene GUID failed");
return (string)s_SceneGUID.GetValue(scene);
}
}
internal static class EditorAnalyticsExtensions
{
//All of this is just to bypass UnityEngine.Analytics module not being
//loaded in some test project in 2022. It is loaded in 2023.1+ though.
//EditorAnalytics.RegisterEventWithLimit method is thus ill-defined on those project as
//it returns the missing type. Lets just produce a casted to int similar method.
static Func<string, int, int, string, int> s_RegisterEventWithLimit;
static Func<string, object, int> s_SendEventWithLimit;
public static bool RegisterEventWithLimit(string eventName, int maxEventPerHour, int maxItems, string vendorKey)
=> s_RegisterEventWithLimit?.Invoke(eventName, maxEventPerHour, maxItems, vendorKey) == 0 /*UnityEngine.Analytics.AnalyticsResult.Ok*/;
public static bool SendEventWithLimit(string eventName, object parameters)
=> s_SendEventWithLimit?.Invoke(eventName, parameters) == 0 /*UnityEngine.Analytics.AnalyticsResult.Ok*/;
static EditorAnalyticsExtensions()
{
Type unityEditorType = typeof(UnityEditor.EditorAnalytics);
MethodInfo registerEventWithLimitMethodInfo = unityEditorType.GetMethod(
"RegisterEventWithLimit",
BindingFlags.Static | BindingFlags.Public,
null,
new Type[] { typeof(string), typeof(int), typeof(int), typeof(string) },
null);
MethodInfo sendEventWithLimitMethodInfo = unityEditorType.GetMethod(
"SendEventWithLimit",
BindingFlags.Static | BindingFlags.Public,
null,
new Type[] { typeof(string), typeof(object) },
null);
var eventNameParameter = Expression.Parameter(typeof(string), "eventName");
var maxEventPerHourParameter = Expression.Parameter(typeof(int), "maxEventPerHour");
var maxItemsParameter = Expression.Parameter(typeof(int), "maxItems");
var vendorKeyParameter = Expression.Parameter(typeof(string), "vendorKey");
var parametersParameter = Expression.Parameter(typeof(object), "parameters");
var registerEventWithLimitLambda = Expression.Lambda<Func<string, int, int, string, int>>(
Expression.Convert(
Expression.Call(registerEventWithLimitMethodInfo, eventNameParameter, maxEventPerHourParameter, maxItemsParameter, vendorKeyParameter),
typeof(int)),
eventNameParameter, maxEventPerHourParameter, maxItemsParameter, vendorKeyParameter);
var sendEventWithLimitLambda = Expression.Lambda<Func<string, object, int>>(
Expression.Convert(
Expression.Call(sendEventWithLimitMethodInfo, eventNameParameter, parametersParameter),
typeof(int)),
eventNameParameter, parametersParameter);
s_RegisterEventWithLimit = registerEventWithLimitLambda.Compile();
s_SendEventWithLimit = sendEventWithLimitLambda.Compile();
}
}
}
#endif //ENABLE_CLOUD_SERVICES_ANALYTICS
#endif //UNITY_EDITOR
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 06c0317e0632e6c47bb855ee99f95544
timeCreated: 1504094117
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,267 @@
using System;
using System.Runtime.CompilerServices;
using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering
{
// Due to limitations in the builtin AnimationCurve we need this custom wrapper.
// Improvements:
// - Dirty state handling so we know when a curve has changed or not
// - Looping support (infinite curve)
// - Zero-value curve
// - Cheaper length property
/// <summary>
/// A wrapper around <c>AnimationCurve</c> to automatically bake it into a texture.
/// </summary>
[Serializable]
public class TextureCurve : IDisposable
{
const int k_Precision = 128; // Edit LutBuilder3D if you change this value
const float k_Step = 1f / k_Precision;
/// <summary>
/// The number of keys in the curve.
/// </summary>
[field: SerializeField]
public int length { get; private set; } // Calling AnimationCurve.length is very slow, let's cache it
[SerializeField]
bool m_Loop;
[SerializeField]
float m_ZeroValue;
[SerializeField]
float m_Range;
/// <summary>
/// Internal curve used to generate the Texture
/// </summary>
[SerializeField]
AnimationCurve m_Curve;
AnimationCurve m_LoopingCurve;
Texture2D m_Texture;
bool m_IsCurveDirty;
bool m_IsTextureDirty;
/// <summary>
/// Retrieves the key at index.
/// </summary>
/// <param name="index">The index to look for.</param>
/// <returns>A key.</returns>
public Keyframe this[int index] => m_Curve[index];
/// <summary>
/// Creates a new <see cref="TextureCurve"/> from an existing <c>AnimationCurve</c>.
/// </summary>
/// <param name="baseCurve">The source <c>AnimationCurve</c>.</param>
/// <param name="zeroValue">The default value to use when the curve doesn't have any key.</param>
/// <param name="loop">Should the curve automatically loop in the given <paramref name="bounds"/>?</param>
/// <param name="bounds">The boundaries of the curve.</param>
public TextureCurve(AnimationCurve baseCurve, float zeroValue, bool loop, in Vector2 bounds)
: this(baseCurve.keys, zeroValue, loop, bounds) { }
/// <summary>
/// Creates a new <see cref="TextureCurve"/> from an arbitrary number of keyframes.
/// </summary>
/// <param name="keys">An array of Keyframes used to define the curve.</param>
/// <param name="zeroValue">The default value to use when the curve doesn't have any key.</param>
/// <param name="loop">Should the curve automatically loop in the given <paramref name="bounds"/>?</param>
/// <param name="bounds">The boundaries of the curve.</param>
public TextureCurve(Keyframe[] keys, float zeroValue, bool loop, in Vector2 bounds)
{
m_Curve = new AnimationCurve(keys);
m_ZeroValue = zeroValue;
m_Loop = loop;
m_Range = bounds.magnitude;
length = keys.Length;
SetDirty();
}
/// <summary>
/// Finalizer.
/// </summary>
~TextureCurve() { }
/// <summary>
/// Cleans up the internal texture resource.
/// </summary>
[Obsolete("Please use Release() instead.")]
public void Dispose() { }
/// <summary>
/// Releases the internal texture resource.
/// </summary>
public void Release()
{
CoreUtils.Destroy(m_Texture);
m_Texture = null;
}
/// <summary>
/// Marks the curve as dirty to trigger a redraw of the texture the next time <see cref="GetTexture"/>
/// is called.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetDirty()
{
m_IsCurveDirty = true;
m_IsTextureDirty = true;
}
static GraphicsFormat GetTextureFormat()
{
if (SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, FormatUsage.Sample | FormatUsage.SetPixels))
return GraphicsFormat.R16_SFloat;
if (SystemInfo.IsFormatSupported(GraphicsFormat.R8_UNorm, FormatUsage.Sample | FormatUsage.SetPixels))
return GraphicsFormat.R8_UNorm;
return GraphicsFormat.R8G8B8A8_UNorm;
}
/// <summary>
/// Gets the texture representation of this curve.
/// </summary>
/// <returns>A 128x1 texture.</returns>
public Texture2D GetTexture()
{
if (m_Texture == null)
{
m_Texture = new Texture2D(k_Precision, 1, GetTextureFormat(), TextureCreationFlags.None);
m_Texture.name = "CurveTexture";
m_Texture.hideFlags = HideFlags.HideAndDontSave;
m_Texture.filterMode = FilterMode.Bilinear;
m_Texture.wrapMode = TextureWrapMode.Clamp;
m_Texture.anisoLevel = 0;
m_IsTextureDirty = true;
}
if (m_IsTextureDirty)
{
var pixels = new Color[k_Precision];
for (int i = 0; i < pixels.Length; i++)
pixels[i].r = Evaluate(i * k_Step);
m_Texture.SetPixels(pixels);
m_Texture.Apply(false, false);
m_IsTextureDirty = false;
}
return m_Texture;
}
/// <summary>
/// Evaluate a time value on the curve.
/// </summary>
/// <param name="time">The time within the curve you want to evaluate.</param>
/// <returns>The value of the curve, at the point in time specified.</returns>
public float Evaluate(float time)
{
if (m_IsCurveDirty)
length = m_Curve.length;
if (length == 0)
return m_ZeroValue;
if (!m_Loop || length == 1)
return m_Curve.Evaluate(time);
if (m_IsCurveDirty)
{
if (m_LoopingCurve == null)
m_LoopingCurve = new AnimationCurve();
var prev = m_Curve[length - 1];
prev.time -= m_Range;
var next = m_Curve[0];
next.time += m_Range;
m_LoopingCurve.keys = m_Curve.keys; // GC pressure
m_LoopingCurve.AddKey(prev);
m_LoopingCurve.AddKey(next);
m_IsCurveDirty = false;
}
return m_LoopingCurve.Evaluate(time);
}
/// <summary>
/// Adds a new key to the curve.
/// </summary>
/// <param name="time">The time at which to add the key.</param>
/// <param name="value">The value for the key.</param>
/// <returns>The index of the added key, or -1 if the key could not be added.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int AddKey(float time, float value)
{
int r = m_Curve.AddKey(time, value);
if (r > -1)
SetDirty();
return r;
}
/// <summary>
/// Removes the keyframe at <paramref name="index"/> and inserts <paramref name="key"/>.
/// </summary>
/// <param name="index"></param>
/// <param name="key"></param>
/// <returns>The index of the keyframe after moving it.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int MoveKey(int index, in Keyframe key)
{
int r = m_Curve.MoveKey(index, key);
SetDirty();
return r;
}
/// <summary>
/// Removes a key.
/// </summary>
/// <param name="index">The index of the key to remove.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveKey(int index)
{
m_Curve.RemoveKey(index);
SetDirty();
}
/// <summary>
/// Smoothes the in and out tangents of the keyframe at <paramref name="index"/>. A <paramref name="weight"/> of 0 evens out tangents.
/// </summary>
/// <param name="index">The index of the keyframe to be smoothed.</param>
/// <param name="weight">The smoothing weight to apply to the keyframe's tangents.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SmoothTangents(int index, float weight)
{
m_Curve.SmoothTangents(index, weight);
SetDirty();
}
}
/// <summary>
/// A <see cref="VolumeParameter"/> that holds a <see cref="TextureCurve"/> value.
/// </summary>
[Serializable]
public class TextureCurveParameter : VolumeParameter<TextureCurve>
{
/// <summary>
/// Creates a new <see cref="TextureCurveParameter"/> instance.
/// </summary>
/// <param name="value">The initial value to store in the parameter.</param>
/// <param name="overrideState">The initial override state for the parameter.</param>
public TextureCurveParameter(TextureCurve value, bool overrideState = false)
: base(value, overrideState) { }
/// <summary>
/// Release implementation.
/// </summary>
public override void Release() => m_Value.Release();
// TODO: TextureCurve interpolation
}
}

View File

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

View File

@@ -0,0 +1,148 @@
namespace UnityEngine.Rendering
{
/// <summary>Utility for tiles layout</summary>
public static class TileLayoutUtils
{
/// <summary>Try decompose the givent rect into tiles given the parameter</summary>
/// <param name="src">The rect to split</param>
/// <param name="tileSize">The size of the tiles</param>
/// <param name="main">Computed main area</param>
/// <param name="topRow">Computed top row area</param>
/// <param name="rightCol">Computed right column area</param>
/// <param name="topRight">Computed top right corner area</param>
/// <returns>If true, the tiles decomposition is a success</returns>
public static bool TryLayoutByTiles(
RectInt src,
uint tileSize,
out RectInt main,
out RectInt topRow,
out RectInt rightCol,
out RectInt topRight)
{
if (src.width < tileSize || src.height < tileSize)
{
main = new RectInt(0, 0, 0, 0);
topRow = new RectInt(0, 0, 0, 0);
rightCol = new RectInt(0, 0, 0, 0);
topRight = new RectInt(0, 0, 0, 0);
return false;
}
int mainRows = src.height / (int)tileSize;
int mainCols = src.width / (int)tileSize;
int mainWidth = mainCols * (int)tileSize;
int mainHeight = mainRows * (int)tileSize;
main = new RectInt
{
x = src.x,
y = src.y,
width = mainWidth,
height = mainHeight,
};
topRow = new RectInt
{
x = src.x,
y = src.y + mainHeight,
width = mainWidth,
height = src.height - mainHeight
};
rightCol = new RectInt
{
x = src.x + mainWidth,
y = src.y,
width = src.width - mainWidth,
height = mainHeight
};
topRight = new RectInt
{
x = src.x + mainWidth,
y = src.y + mainHeight,
width = src.width - mainWidth,
height = src.height - mainHeight
};
return true;
}
/// <summary>Try decompose the givent rect into rows given the parameter</summary>
/// <param name="src">The rect to split</param>
/// <param name="tileSize">The size of the tiles</param>
/// <param name="main">Computed main area</param>
/// <param name="other">Computed other area</param>
/// <returns>If true, the tiles decomposition is a success</returns>
public static bool TryLayoutByRow(
RectInt src,
uint tileSize,
out RectInt main,
out RectInt other)
{
if (src.height < tileSize)
{
main = new RectInt(0, 0, 0, 0);
other = new RectInt(0, 0, 0, 0);
return false;
}
int mainRows = src.height / (int)tileSize;
int mainHeight = mainRows * (int)tileSize;
main = new RectInt
{
x = src.x,
y = src.y,
width = src.width,
height = mainHeight,
};
other = new RectInt
{
x = src.x,
y = src.y + mainHeight,
width = src.width,
height = src.height - mainHeight
};
return true;
}
/// <summary>Try decompose the givent rect into columns given the parameter</summary>
/// <param name="src">The rect to split</param>
/// <param name="tileSize">The size of the tiles</param>
/// <param name="main">Computed main area</param>
/// <param name="other">Computed other area</param>
/// <returns>If true, the tiles decomposition is a success</returns>
public static bool TryLayoutByCol(
RectInt src,
uint tileSize,
out RectInt main,
out RectInt other)
{
if (src.width < tileSize)
{
main = new RectInt(0, 0, 0, 0);
other = new RectInt(0, 0, 0, 0);
return false;
}
int mainCols = src.width / (int)tileSize;
int mainWidth = mainCols * (int)tileSize;
main = new RectInt
{
x = src.x,
y = src.y,
width = mainWidth,
height = src.height,
};
other = new RectInt
{
x = src.x + mainWidth,
y = src.y,
width = src.width - mainWidth,
height = src.height
};
return true;
}
}
}

View File

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

View File

@@ -0,0 +1,22 @@
namespace UnityEngine.Rendering
{
/// <summary>
/// XR Utility class.
/// </summary>
public static class XRUtils
{
/// <summary>
/// Draw the XR occlusion mesh.
/// </summary>
/// <param name="cmd">Command Buffer used to draw the occlusion mesh.</param>
/// <param name="camera">Camera for which the occlusion mesh is rendered.</param>
/// <param name="stereoEnabled">True if stereo rendering is enabled.</param>
public static void DrawOcclusionMesh(CommandBuffer cmd, Camera camera, bool stereoEnabled = true) // Optional stereoEnabled is for SRP-specific stereo logic
{
if ((!XRGraphics.enabled) || (!camera.stereoEnabled) || (!stereoEnabled))
return;
UnityEngine.RectInt normalizedCamViewport = new UnityEngine.RectInt(0, 0, camera.pixelWidth, camera.pixelHeight);
cmd.DrawOcclusionMesh(normalizedCamViewport);
}
}
}

View File

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