Initial Commit
This commit is contained in:
commit
ee5c2f922d
2255 changed files with 547750 additions and 0 deletions
449
Assets/Plugins/Light2D/Scripts/CustomSprite.cs
Normal file
449
Assets/Plugins/Light2D/Scripts/CustomSprite.cs
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Light2D;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom sprite wich uses MeshFilter and MeshRenderer to render.
|
||||
/// Main improvement from Unity SpriteRenderer is that you can access and modify mesh.
|
||||
/// Also multiple CustomSprites could be merged to single mesh with MeshCombiner,
|
||||
/// which gives much better performance for small meshes than StaticBatchingUtility.Combine.
|
||||
/// </summary>
|
||||
[ExecuteInEditMode]
|
||||
public class CustomSprite : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Vertex color of mesh.
|
||||
/// </summary>
|
||||
public Color Color = Color.white;
|
||||
|
||||
/// <summary>
|
||||
/// Sprite from which mesh will be generated.
|
||||
/// </summary>
|
||||
public Sprite Sprite;
|
||||
|
||||
/// <summary>
|
||||
/// Sorting order of MeshRenderer.
|
||||
/// </summary>
|
||||
public int SortingOrder;
|
||||
|
||||
/// <summary>
|
||||
/// Material to be used.
|
||||
/// </summary>
|
||||
public Material Material;
|
||||
|
||||
// mesh data
|
||||
protected Color[] _colors;
|
||||
protected Vector2[] _uv0;
|
||||
protected Vector2[] _uv1;
|
||||
protected Vector3[] _vertices;
|
||||
protected int[] _triangles;
|
||||
protected Vector4[] _tangents;
|
||||
|
||||
protected bool _isMeshDirty = false;
|
||||
protected MeshRenderer _meshRenderer;
|
||||
protected MeshFilter _meshFilter;
|
||||
protected Mesh _mesh;
|
||||
private Color _oldColor;
|
||||
private Sprite _oldSprite;
|
||||
private Material _oldMaterial;
|
||||
private MaterialKey _oldMaterialKey;
|
||||
public static Dictionary<MaterialKey, MaterialValue> MaterialMap = new Dictionary<MaterialKey, MaterialValue>();
|
||||
private const string GeneratedMaterialName = "Generated Material (DONT change it)";
|
||||
private const string GeneratedMeshName = "Generated Mesh (DONT change it)";
|
||||
|
||||
public bool RendererEnabled { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is that sprite is staticaly batched?
|
||||
/// </summary>
|
||||
public bool IsPartOfStaticBatch
|
||||
{
|
||||
get { return _meshRenderer.isPartOfStaticBatch; }
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
_colors = new Color[4];
|
||||
_uv1 = new Vector2[4];
|
||||
_uv0 = new Vector2[4];
|
||||
_vertices = new Vector3[4];
|
||||
_triangles = new[] {2, 1, 0, 1, 2, 3};
|
||||
_meshRenderer = GetComponent<MeshRenderer>();
|
||||
_meshFilter = GetComponent<MeshFilter>();
|
||||
|
||||
if (_meshRenderer == null)
|
||||
{
|
||||
_meshRenderer = gameObject.AddComponent<MeshRenderer>();
|
||||
_meshRenderer.receiveShadows = false;
|
||||
_meshRenderer.shadowCastingMode = ShadowCastingMode.Off;
|
||||
}
|
||||
|
||||
if (_meshFilter == null)
|
||||
{
|
||||
_meshFilter = gameObject.AddComponent<MeshFilter>();
|
||||
}
|
||||
|
||||
|
||||
if (Material == null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Material = AssetDatabase.GetBuiltinExtraResource<Material>("Sprites-Default.mat");
|
||||
#else
|
||||
Material = Resources.GetBuiltinResource<Material>("Sprites-Default.mat");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
TryReleaseMesh();
|
||||
_meshFilter.sharedMesh = _mesh = new Mesh();
|
||||
_mesh.MarkDynamic();
|
||||
_mesh.name = GeneratedMeshName;
|
||||
|
||||
_tangents = new Vector4[4];
|
||||
for (int i = 0; i < _tangents.Length; i++)
|
||||
_tangents[i] = new Vector4(1, 0, 0);
|
||||
|
||||
UpdateMeshData(true);
|
||||
|
||||
RendererEnabled = _meshRenderer.enabled;
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
UpdateMeshData(true);
|
||||
}
|
||||
|
||||
private void OnWillRenderObject()
|
||||
{
|
||||
UpdateMeshData();
|
||||
if (Application.isPlaying && LightingSystem.Instance.EnableNormalMapping)
|
||||
{
|
||||
RendererEnabled = _meshRenderer.enabled;
|
||||
_meshRenderer.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRenderObject()
|
||||
{
|
||||
if (Application.isPlaying && LightingSystem.Instance.EnableNormalMapping)
|
||||
{
|
||||
_meshRenderer.enabled = RendererEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Getting material from cache or instantiating new one.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Material GetOrCreateMaterial()
|
||||
{
|
||||
TryReleaseMaterial();
|
||||
|
||||
if (Material == null || Sprite == null)
|
||||
return null;
|
||||
|
||||
MaterialValue matValue;
|
||||
var key = new MaterialKey(Material, Sprite.texture);
|
||||
|
||||
if (!MaterialMap.TryGetValue(key, out matValue))
|
||||
{
|
||||
var mat = (Material)Instantiate(Material);
|
||||
mat.name = GeneratedMaterialName;
|
||||
mat.mainTexture = Sprite.texture;
|
||||
MaterialMap[key] = matValue = new MaterialValue(mat, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
matValue.UsageCount++;
|
||||
}
|
||||
|
||||
_oldMaterialKey = key;
|
||||
|
||||
return matValue.Material;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Getting material from cache or instantiating new one.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Material GetOrCreateMaterial(Material baseMaterial, Texture2D texture, out MaterialKey materialKey)
|
||||
{
|
||||
if (baseMaterial == null || texture == null)
|
||||
{
|
||||
materialKey = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
MaterialValue matValue;
|
||||
var key = materialKey = new MaterialKey(baseMaterial, texture);
|
||||
|
||||
if (!MaterialMap.TryGetValue(key, out matValue))
|
||||
{
|
||||
var mat = (Material)Instantiate(baseMaterial);
|
||||
mat.name = GeneratedMaterialName;
|
||||
mat.mainTexture = texture;
|
||||
MaterialMap[key] = matValue = new MaterialValue(mat, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
matValue.UsageCount++;
|
||||
}
|
||||
|
||||
return matValue.Material;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deleting material from cache with reference counting.
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public static void ReleaseMaterial(MaterialKey key)
|
||||
{
|
||||
MaterialValue matValue;
|
||||
|
||||
if (!MaterialMap.TryGetValue(key, out matValue))
|
||||
return;
|
||||
|
||||
matValue.UsageCount--;
|
||||
|
||||
if (matValue.UsageCount <= 0)
|
||||
{
|
||||
Util.Destroy(matValue.Material);
|
||||
MaterialMap.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
void TryReleaseMesh()
|
||||
{
|
||||
if (_meshFilter != null && _meshFilter.sharedMesh != null &&
|
||||
_meshFilter.sharedMesh.name == GeneratedMeshName && _mesh == _meshFilter.sharedMesh)
|
||||
{
|
||||
Util.Destroy(_meshFilter.sharedMesh);
|
||||
_meshFilter.sharedMesh = null;
|
||||
}
|
||||
}
|
||||
|
||||
void TryReleaseMaterial()
|
||||
{
|
||||
if (_oldMaterialKey != default(MaterialKey))
|
||||
{
|
||||
ReleaseMaterial(_oldMaterialKey);
|
||||
_oldMaterialKey = default(MaterialKey);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
TryReleaseMesh();
|
||||
TryReleaseMaterial();
|
||||
}
|
||||
|
||||
protected virtual void UpdateColor()
|
||||
{
|
||||
for (int i = 0; i < _colors.Length; i++)
|
||||
_colors[i] = Color;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recreating mesh data for Sprite based on it's bounds.
|
||||
/// </summary>
|
||||
protected virtual void UpdateSprite()
|
||||
{
|
||||
if (Sprite == null)
|
||||
return;
|
||||
|
||||
var rect = Sprite.textureRect;
|
||||
var bounds = Sprite.bounds;
|
||||
var tex = Sprite.texture;
|
||||
var textureSize = new Point2(tex.width, tex.height);
|
||||
|
||||
// HACK: mipmap could cause texture padding sometimes so padded size of texture needs to be computed.
|
||||
var realSize =
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE
|
||||
tex.mipmapCount <= 1
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
? textureSize
|
||||
: new Point2(Mathf.NextPowerOfTwo(textureSize.x), Mathf.NextPowerOfTwo(textureSize.y));
|
||||
|
||||
var unitSize2 = rect.size/Sprite.pixelsPerUnit/2f;
|
||||
var offest = (Vector2) bounds.center;
|
||||
|
||||
_vertices[0] = new Vector3(-unitSize2.x + offest.x, -unitSize2.y + offest.y, 0);
|
||||
_vertices[1] = new Vector3(unitSize2.x + offest.x, -unitSize2.y + offest.y, 0);
|
||||
_vertices[2] = new Vector3(-unitSize2.x + offest.x, unitSize2.y + offest.y, 0);
|
||||
_vertices[3] = new Vector3(unitSize2.x + offest.x, unitSize2.y + offest.y, 0);
|
||||
|
||||
_uv0[0] = new Vector2(rect.xMin/realSize.x, rect.yMin/realSize.y); // 0, 0
|
||||
_uv0[1] = new Vector2(rect.xMax/realSize.x, rect.yMin/realSize.y); // 1, 0
|
||||
_uv0[2] = new Vector2(rect.xMin/realSize.x, rect.yMax/realSize.y); // 0, 1
|
||||
_uv0[3] = new Vector2(rect.xMax/realSize.x, rect.yMax/realSize.y); // 1, 1
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
_colors[i] = Color;
|
||||
}
|
||||
|
||||
_meshRenderer.sharedMaterial = GetOrCreateMaterial();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clearing and rebuilding mesh.
|
||||
/// </summary>
|
||||
protected virtual void UpdateMesh()
|
||||
{
|
||||
_mesh.Clear();
|
||||
_mesh.vertices = _vertices;
|
||||
_mesh.triangles = _triangles;
|
||||
_mesh.uv = _uv0;
|
||||
_mesh.uv2 = _uv1;
|
||||
_mesh.colors = _colors;
|
||||
_mesh.tangents = _tangents;
|
||||
_mesh.RecalculateBounds();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checking public fields and mesh data, then rebuilding internal state if changes found.
|
||||
/// </summary>
|
||||
/// <param name="forceUpdate">Force update even if no changes found.</param>
|
||||
protected virtual void UpdateMeshData(bool forceUpdate = false)
|
||||
{
|
||||
if (_meshRenderer == null || _meshFilter == null || IsPartOfStaticBatch)
|
||||
return;
|
||||
|
||||
_meshRenderer.sortingOrder = SortingOrder;
|
||||
|
||||
if (Color != _oldColor || forceUpdate)
|
||||
{
|
||||
UpdateColor();
|
||||
_isMeshDirty = true;
|
||||
_oldColor = Color;
|
||||
}
|
||||
if (Sprite != _oldSprite || Material != _oldMaterial || forceUpdate)
|
||||
{
|
||||
UpdateSprite();
|
||||
_isMeshDirty = true;
|
||||
_oldSprite = Sprite;
|
||||
_oldMaterial = Material;
|
||||
}
|
||||
if (_isMeshDirty)
|
||||
{
|
||||
UpdateMesh();
|
||||
_isMeshDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used as a value to material map to support reference counting.
|
||||
/// </summary>
|
||||
public class MaterialValue
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiated material from MaterialKey.Material with texture from MaterialKey.Texture.
|
||||
/// </summary>
|
||||
public Material Material;
|
||||
|
||||
/// <summary>
|
||||
/// Count of CustomSprites using that material.
|
||||
/// </summary>
|
||||
public int UsageCount;
|
||||
|
||||
public MaterialValue(Material material, int usageCount)
|
||||
{
|
||||
Material = material;
|
||||
UsageCount = usageCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used as a key to material map.
|
||||
/// </summary>
|
||||
public class MaterialKey : IEquatable<MaterialKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// Sprite's texture.
|
||||
/// </summary>
|
||||
public Texture2D Texture;
|
||||
|
||||
/// <summary>
|
||||
/// Non instantiated material.
|
||||
/// </summary>
|
||||
public Material Material;
|
||||
|
||||
public MaterialKey(Material material, Texture2D texture)
|
||||
{
|
||||
Material = material;
|
||||
Texture = texture;
|
||||
}
|
||||
|
||||
private sealed class TextureMaterialEqualityComparer : IEqualityComparer<MaterialKey>
|
||||
{
|
||||
public bool Equals(MaterialKey x, MaterialKey y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return Equals(x.Texture, y.Texture) && Equals(x.Material, y.Material);
|
||||
}
|
||||
|
||||
public int GetHashCode(MaterialKey obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ((obj.Texture != null ? obj.Texture.GetHashCode() : 0)*397) ^ (obj.Material != null ? obj.Material.GetHashCode() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly IEqualityComparer<MaterialKey> TextureMaterialComparerInstance = new TextureMaterialEqualityComparer();
|
||||
|
||||
public static IEqualityComparer<MaterialKey> TextureMaterialComparer
|
||||
{
|
||||
get { return TextureMaterialComparerInstance; }
|
||||
}
|
||||
|
||||
public bool Equals(MaterialKey other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Equals(Texture, other.Texture) && Equals(Material, other.Material);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((MaterialKey) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ((Texture != null ? Texture.GetHashCode() : 0)*397) ^ (Material != null ? Material.GetHashCode() : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator ==(MaterialKey left, MaterialKey right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(MaterialKey left, MaterialKey right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Assets/Plugins/Light2D/Scripts/CustomSprite.cs.meta
Normal file
8
Assets/Plugins/Light2D/Scripts/CustomSprite.cs.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 29d8c03e86a89194f8ee931d9cf69ba1
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
75
Assets/Plugins/Light2D/Scripts/LightObstacleGenerator.cs
Normal file
75
Assets/Plugins/Light2D/Scripts/LightObstacleGenerator.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// That class is generating obstacles for object it attached to.
|
||||
/// Obect must have MeshRenderer, SpriteRenderer or CustomSprite script from which texture for obstacle will be grabbed.
|
||||
/// For rendering obstacle of SpriteRenderer and CustomSprite LightObstacleSprite with material "Material" (material with dual color shader by default) will be used.
|
||||
/// For objects with MeshRenderer "Material" property is ignored. MeshRenderer.sharedMaterial is used instead.
|
||||
/// </summary>
|
||||
[ExecuteInEditMode]
|
||||
public class LightObstacleGenerator : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Vertex color.
|
||||
/// </summary>
|
||||
public Color MultiplicativeColor = new Color(0, 0, 0, 1);
|
||||
|
||||
/// <summary>
|
||||
/// AdditiveColor that will be used for obstacle when SpriteRenderer or CustomSprite scripts is attached.
|
||||
/// Only DualColor shader supports additive color.
|
||||
/// </summary>
|
||||
public Color AdditiveColor;
|
||||
|
||||
/// <summary>
|
||||
/// Material that will be used for obstacle when SpriteRenderer or CustomSprite scripts is attached.
|
||||
/// </summary>
|
||||
public Material Material;
|
||||
|
||||
public float LightObstacleScale = 1;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (Material == null)
|
||||
{
|
||||
Material = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>("Assets/Light2D/Materials/DualColor.mat");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Application.isPlaying)
|
||||
return;
|
||||
|
||||
var obstacleObj = new GameObject(gameObject.name + " Light Obstacle");
|
||||
|
||||
obstacleObj.transform.parent = gameObject.transform;
|
||||
obstacleObj.transform.localPosition = Vector3.zero;
|
||||
obstacleObj.transform.localRotation = Quaternion.identity;
|
||||
obstacleObj.transform.localScale = Vector3.one*LightObstacleScale;
|
||||
if (LightingSystem.Instance != null)
|
||||
obstacleObj.layer = LightingSystem.Instance.LightObstaclesLayer;
|
||||
|
||||
if (GetComponent<SpriteRenderer>() != null || GetComponent<CustomSprite>() != null)
|
||||
{
|
||||
var obstacleSprite = obstacleObj.AddComponent<LightObstacleSprite>();
|
||||
obstacleSprite.Color = MultiplicativeColor;
|
||||
obstacleSprite.AdditiveColor = AdditiveColor;
|
||||
obstacleSprite.Material = Material;
|
||||
}
|
||||
else
|
||||
{
|
||||
var obstacleMesh = obstacleObj.AddComponent<LightObstacleMesh>();
|
||||
obstacleMesh.MultiplicativeColor = MultiplicativeColor;
|
||||
obstacleMesh.AdditiveColor = AdditiveColor;
|
||||
obstacleMesh.Material = Material;
|
||||
}
|
||||
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a0184ff86886f974d95dfead14754f36
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
114
Assets/Plugins/Light2D/Scripts/LightObstacleMesh.cs
Normal file
114
Assets/Plugins/Light2D/Scripts/LightObstacleMesh.cs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Automatically updating mesh, material and main texture of light obstacle.
|
||||
/// Class is copying all data used for rendering from parent.
|
||||
/// </summary>
|
||||
public class LightObstacleMesh : MonoBehaviour
|
||||
{
|
||||
public Color32 MultiplicativeColor;
|
||||
public Color AdditiveColor;
|
||||
public Material Material;
|
||||
private MeshRenderer _parentMeshRenderer;
|
||||
private MeshFilter _parentMeshFilter;
|
||||
private MeshRenderer _meshRenderer;
|
||||
private MeshFilter _meshFilter;
|
||||
private Mesh _oldParentMesh;
|
||||
private Color32 _oldMulColor;
|
||||
private Color _oldAddColor;
|
||||
private Material _oldMaterial;
|
||||
private CustomSprite.MaterialKey _materialKey;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_parentMeshRenderer = transform.parent.GetComponent<MeshRenderer>();
|
||||
_parentMeshFilter = transform.parent.GetComponent<MeshFilter>();
|
||||
_meshRenderer = GetComponent<MeshRenderer>();
|
||||
if (_meshRenderer == null) _meshRenderer = gameObject.AddComponent<MeshRenderer>();
|
||||
_meshFilter = GetComponent<MeshFilter>();
|
||||
if (_meshFilter == null) _meshFilter = gameObject.AddComponent<MeshFilter>();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Refresh()
|
||||
{
|
||||
if (_parentMeshFilter == null || _parentMeshFilter == null || _meshRenderer == null || _meshFilter == null ||
|
||||
_parentMeshFilter.sharedMesh == null || _parentMeshRenderer.sharedMaterial == null)
|
||||
{
|
||||
if (_meshRenderer != null)
|
||||
_meshRenderer.enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool dirty = false;
|
||||
if (_parentMeshFilter.mesh != _oldParentMesh)
|
||||
{
|
||||
if (_meshFilter.mesh != null)
|
||||
Destroy(_meshFilter.mesh);
|
||||
_meshFilter.mesh = (Mesh) Instantiate(_parentMeshFilter.sharedMesh);
|
||||
_meshFilter.mesh.MarkDynamic();
|
||||
|
||||
if (_meshFilter.mesh.tangents == null)
|
||||
{
|
||||
var tangents = new Vector4[_meshFilter.mesh.vertexCount];
|
||||
for (int i = 0; i < tangents.Length; i++)
|
||||
tangents[i] = new Vector4(1, 0);
|
||||
_meshFilter.mesh.tangents = tangents;
|
||||
}
|
||||
|
||||
_oldParentMesh = _parentMeshFilter.sharedMesh;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (_oldMaterial != _parentMeshRenderer.sharedMaterial ||
|
||||
(_oldMaterial != null && _parentMeshRenderer.sharedMaterial != null &&
|
||||
_oldMaterial.mainTexture != _parentMeshRenderer.sharedMaterial.mainTexture))
|
||||
{
|
||||
if (_meshRenderer.sharedMaterial != null && _materialKey != null)
|
||||
{
|
||||
CustomSprite.ReleaseMaterial(_materialKey);
|
||||
}
|
||||
var baseMat = Material == null ? _parentMeshRenderer.sharedMaterial : Material;
|
||||
var tex = _parentMeshRenderer.sharedMaterial.mainTexture as Texture2D;
|
||||
_meshRenderer.sharedMaterial = CustomSprite.GetOrCreateMaterial(baseMat, tex, out _materialKey);
|
||||
_oldMaterial = _parentMeshRenderer.sharedMaterial;
|
||||
}
|
||||
|
||||
if (!MultiplicativeColor.Equals(_oldMulColor) || AdditiveColor != _oldAddColor || dirty)
|
||||
{
|
||||
var colors = _meshFilter.mesh.colors32;
|
||||
if (colors == null || colors.Length != _meshFilter.mesh.vertexCount)
|
||||
colors = new Color32[_meshFilter.mesh.vertexCount];
|
||||
|
||||
for (int i = 0; i < colors.Length; i++)
|
||||
colors[i] = MultiplicativeColor;
|
||||
_meshFilter.mesh.colors32 = colors;
|
||||
|
||||
var uv1 = new Vector2(
|
||||
Util.DecodeFloatRGBA((Vector4) AdditiveColor),
|
||||
Util.DecodeFloatRGBA(new Vector4(AdditiveColor.a, 0, 0)));
|
||||
var uv1Arr = _meshFilter.mesh.uv2;
|
||||
if (uv1Arr == null || uv1Arr.Length != colors.Length)
|
||||
uv1Arr = new Vector2[colors.Length];
|
||||
for (int i = 0; i < uv1Arr.Length; i++)
|
||||
{
|
||||
uv1Arr[i] = uv1;
|
||||
}
|
||||
_meshFilter.mesh.uv2 = uv1Arr;
|
||||
|
||||
_oldMulColor = MultiplicativeColor;
|
||||
_oldAddColor = AdditiveColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Assets/Plugins/Light2D/Scripts/LightObstacleMesh.cs.meta
Normal file
8
Assets/Plugins/Light2D/Scripts/LightObstacleMesh.cs.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 53b0c4c5d380d084db011bc570d0fe96
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
100
Assets/Plugins/Light2D/Scripts/LightObstacleSprite.cs
Normal file
100
Assets/Plugins/Light2D/Scripts/LightObstacleSprite.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Sprite with dual color support. Grabs sprite from GameSpriteRenderer field.
|
||||
/// </summary>
|
||||
[ExecuteInEditMode]
|
||||
public class LightObstacleSprite : CustomSprite
|
||||
{
|
||||
/// <summary>
|
||||
/// Renderer from which sprite will be used.
|
||||
/// </summary>
|
||||
public Renderer GameSpriteRenderer;
|
||||
|
||||
/// <summary>
|
||||
/// Color is packed in mesh UV1.
|
||||
/// </summary>
|
||||
public Color AdditiveColor;
|
||||
private Color _oldSecondaryColor;
|
||||
private Renderer _oldGameSpriteRenderer;
|
||||
private SpriteRenderer _oldUnitySprite;
|
||||
private CustomSprite _oldCustomSprite;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (Material == null)
|
||||
{
|
||||
Material = AssetDatabase.LoadAssetAtPath<Material>("Assets/Light2D/Materials/DualColor.mat");
|
||||
}
|
||||
#endif
|
||||
|
||||
base.OnEnable();
|
||||
|
||||
if (GameSpriteRenderer == null && transform.parent != null)
|
||||
GameSpriteRenderer = transform.parent.gameObject.GetComponent<Renderer>();
|
||||
|
||||
gameObject.layer = LightingSystem.Instance.LightObstaclesLayer;
|
||||
|
||||
UpdateMeshData(true);
|
||||
}
|
||||
|
||||
private void UpdateSecondaryColor()
|
||||
{
|
||||
var uv1 = new Vector2(
|
||||
Util.DecodeFloatRGBA((Vector4)AdditiveColor),
|
||||
Util.DecodeFloatRGBA(new Vector4(AdditiveColor.a, 0, 0)));
|
||||
for (int i = 0; i < _uv1.Length; i++)
|
||||
{
|
||||
_uv1[i] = uv1;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateMeshData(bool forceUpdate = false)
|
||||
{
|
||||
if (_meshRenderer == null || _meshFilter == null || IsPartOfStaticBatch)
|
||||
return;
|
||||
|
||||
if (GameSpriteRenderer != null && (GameSpriteRenderer != _oldGameSpriteRenderer || forceUpdate ||
|
||||
(_oldUnitySprite != null && _oldUnitySprite.sprite != null && _oldUnitySprite.sprite != Sprite) ||
|
||||
(_oldCustomSprite != null && _oldCustomSprite.Sprite != null && _oldCustomSprite.Sprite != Sprite)))
|
||||
{
|
||||
_oldGameSpriteRenderer = GameSpriteRenderer;
|
||||
|
||||
_oldCustomSprite = GameSpriteRenderer.GetComponent<CustomSprite>();
|
||||
if (_oldCustomSprite != null)
|
||||
{
|
||||
Sprite = _oldCustomSprite.Sprite;
|
||||
}
|
||||
else
|
||||
{
|
||||
_oldUnitySprite = GameSpriteRenderer.GetComponent<SpriteRenderer>();
|
||||
if (_oldUnitySprite != null)
|
||||
Sprite = _oldUnitySprite.sprite;
|
||||
}
|
||||
|
||||
Material.EnableKeyword("NORMAL_TEXCOORD");
|
||||
}
|
||||
|
||||
if (_oldSecondaryColor != AdditiveColor || forceUpdate)
|
||||
{
|
||||
UpdateSecondaryColor();
|
||||
_isMeshDirty = true;
|
||||
_oldSecondaryColor = AdditiveColor;
|
||||
}
|
||||
|
||||
base.UpdateMeshData(forceUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c849e7d3a5bc0ff408d0cfcf61f81906
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
182
Assets/Plugins/Light2D/Scripts/LightSprite.cs
Normal file
182
Assets/Plugins/Light2D/Scripts/LightSprite.cs
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to draw lights. Puts LightOrigin world position to UV1.
|
||||
/// Supports Point and Line light types.
|
||||
/// </summary>
|
||||
[ExecuteInEditMode]
|
||||
public class LightSprite : CustomSprite
|
||||
{
|
||||
public static List<LightSprite> AllLightSprites = new List<LightSprite>();
|
||||
public Vector3 LightOrigin = new Vector3(0, 0, 1);
|
||||
public LightShape Shape = LightShape.Point;
|
||||
private Matrix4x4 _modelMatrix;
|
||||
private Vector3 _oldLightOrigin;
|
||||
private LightShape _oldLightShape;
|
||||
|
||||
public MeshRenderer Renderer
|
||||
{
|
||||
get { return _meshRenderer; }
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
AllLightSprites.Add(this);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
AllLightSprites.Remove(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update UV1 which is used for raytracking in shader. UV1 is set to world position of LightOrigin.
|
||||
/// </summary>
|
||||
private void UpdatePosition()
|
||||
{
|
||||
if (Sprite == null || !Application.isPlaying)
|
||||
return;
|
||||
|
||||
var mat = _modelMatrix;
|
||||
Vector2 size = Sprite.bounds.size;
|
||||
|
||||
if (Shape == LightShape.Point)
|
||||
{
|
||||
// LightOrigin needs to be send in world position instead of local because
|
||||
// Unity non uniform scaling is breaking model matrix in shader.
|
||||
var pos = mat.MultiplyPoint(((Vector2)LightOrigin).Mul(size));
|
||||
for (int i = 0; i < _uv1.Length; i++)
|
||||
_uv1[i] = pos;
|
||||
}
|
||||
else if (Shape == LightShape.Line)
|
||||
{
|
||||
var lpos = mat.MultiplyPoint(new Vector2(-0.5f, LightOrigin.y).Mul(size));
|
||||
var rpos = mat.MultiplyPoint(new Vector2(0.5f, LightOrigin.y).Mul(size));
|
||||
_uv1[0] = lpos;
|
||||
_uv1[1] = rpos;
|
||||
_uv1[2] = lpos;
|
||||
_uv1[3] = rpos;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateMeshData(bool forceUpdate = false)
|
||||
{
|
||||
if (IsPartOfStaticBatch)
|
||||
return;
|
||||
|
||||
var objMat = transform.localToWorldMatrix;
|
||||
if (!objMat.FastEquals(_modelMatrix) ||
|
||||
_oldLightOrigin != LightOrigin || _oldLightShape != Shape || forceUpdate)
|
||||
{
|
||||
_modelMatrix = objMat;
|
||||
_oldLightOrigin = LightOrigin;
|
||||
_oldLightShape = Shape;
|
||||
UpdatePosition();
|
||||
_isMeshDirty = true;
|
||||
}
|
||||
|
||||
base.UpdateMeshData(forceUpdate);
|
||||
}
|
||||
|
||||
public enum LightShape
|
||||
{
|
||||
Point,
|
||||
Line,
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
if (Sprite == null)
|
||||
return;
|
||||
|
||||
var size = Sprite.bounds.size;
|
||||
if (Shape == LightShape.Point)
|
||||
{
|
||||
var center = transform.TransformPoint(LightOrigin);
|
||||
Gizmos.DrawLine(
|
||||
center + transform.TransformDirection(new Vector2(-0.1f, 0)),
|
||||
center + transform.TransformDirection(new Vector2(0.1f, 0)));
|
||||
Gizmos.DrawLine(
|
||||
center + transform.TransformDirection(new Vector2(0, -0.1f)),
|
||||
center + transform.TransformDirection(new Vector2(0, 0.1f)));
|
||||
}
|
||||
else if (Shape == LightShape.Line && Sprite != null)
|
||||
{
|
||||
var lpos = transform.TransformPoint(new Vector3(-0.5f, LightOrigin.y).Mul(size));
|
||||
var rpos = transform.TransformPoint(new Vector3(0.5f, LightOrigin.y).Mul(size));
|
||||
Gizmos.DrawLine(lpos, rpos);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawLightingNow(Vector2 lightCamLocalPos)
|
||||
{
|
||||
var material = _meshRenderer.sharedMaterial;
|
||||
|
||||
if (!material.SetPass(0))
|
||||
return;
|
||||
|
||||
var v1 = _modelMatrix.MultiplyPoint(_vertices[0]) - (Vector3)lightCamLocalPos;
|
||||
var v2 = _modelMatrix.MultiplyPoint(_vertices[2]) - (Vector3)lightCamLocalPos;
|
||||
var v3 = _modelMatrix.MultiplyPoint(_vertices[3]) - (Vector3)lightCamLocalPos;
|
||||
var v4 = _modelMatrix.MultiplyPoint(_vertices[1]) - (Vector3)lightCamLocalPos;
|
||||
|
||||
GL.Begin(GL.QUADS);
|
||||
|
||||
GL.Color(Color);
|
||||
|
||||
GL.MultiTexCoord(0, _uv0[0]);
|
||||
GL.MultiTexCoord(1, _uv1[0] - lightCamLocalPos);
|
||||
GL.Vertex(v1);
|
||||
|
||||
GL.MultiTexCoord(0, _uv0[2]);
|
||||
GL.MultiTexCoord(1, _uv1[2] - lightCamLocalPos);
|
||||
GL.Vertex(v2);
|
||||
|
||||
GL.MultiTexCoord(0, _uv0[3]);
|
||||
GL.MultiTexCoord(1, _uv1[3] - lightCamLocalPos);
|
||||
GL.Vertex(v3);
|
||||
|
||||
GL.MultiTexCoord(0, _uv0[1]);
|
||||
GL.MultiTexCoord(1, _uv1[1] - lightCamLocalPos);
|
||||
GL.Vertex(v4);
|
||||
|
||||
GL.End();
|
||||
}
|
||||
|
||||
public void DrawLightNormalsNow(Material material)
|
||||
{
|
||||
Vector2 size = Sprite.bounds.size;
|
||||
Vector2 center = _modelMatrix.MultiplyPoint3x4(((Vector2) LightOrigin).Mul(size));
|
||||
var lightPos = new Vector4(center.x, center.y, LightOrigin.z);
|
||||
|
||||
material.SetVector("_LightPos", lightPos);
|
||||
|
||||
if (!material.SetPass(0))
|
||||
return;
|
||||
|
||||
var v1 = _modelMatrix.MultiplyPoint3x4(_vertices[0]);
|
||||
var v2 = _modelMatrix.MultiplyPoint3x4(_vertices[2]);
|
||||
var v3 = _modelMatrix.MultiplyPoint3x4(_vertices[3]);
|
||||
var v4 = _modelMatrix.MultiplyPoint3x4(_vertices[1]);
|
||||
|
||||
GL.Begin(GL.QUADS);
|
||||
GL.Vertex(v1);
|
||||
GL.Vertex(v2);
|
||||
GL.Vertex(v3);
|
||||
GL.Vertex(v4);
|
||||
GL.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
Assets/Plugins/Light2D/Scripts/LightSprite.cs.meta
Normal file
8
Assets/Plugins/Light2D/Scripts/LightSprite.cs.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 61930e16e81db5c43a4ecc22422a0953
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 2
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
773
Assets/Plugins/Light2D/Scripts/LightingSystem.cs
Normal file
773
Assets/Plugins/Light2D/Scripts/LightingSystem.cs
Normal file
|
|
@ -0,0 +1,773 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Main script for lights. Should be attached to camera.
|
||||
/// Handles lighting operation like camera setup, shader setup, merging cameras output together, blurring and some others.
|
||||
/// </summary>
|
||||
[ExecuteInEditMode]
|
||||
[RequireComponent(typeof (Camera))]
|
||||
public class LightingSystem : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Size of lighting pixel in Unity meters. Controls resoultion of lighting textures.
|
||||
/// Smaller value - better quality, but lower performance.
|
||||
/// </summary>
|
||||
public float LightPixelSize = 0.05f;
|
||||
|
||||
/// <summary>
|
||||
/// Needed for off screen lights to work correctly. Set that value to radius of largest light.
|
||||
/// Used only when camera is in orthographic mode. Big values could cause a performance drop.
|
||||
/// </summary>
|
||||
public float LightCameraSizeAdd = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Needed for off screen lights to work correctly.
|
||||
/// Used only when camera is in perspective mode.
|
||||
/// </summary>
|
||||
public float LightCameraFovAdd = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Enable/disable ambient lights. Disable it to improve performance if you not using ambient light.
|
||||
/// </summary>
|
||||
public bool EnableAmbientLight = true;
|
||||
|
||||
/// <summary>
|
||||
/// LightSourcesBlurMaterial is applied to light sources texture if enabled. Disable to improve performance.
|
||||
/// </summary>
|
||||
public bool BlurLightSources = true;
|
||||
|
||||
/// <summary>
|
||||
/// AmbientLightBlurMaterial is applied to ambient light texture if enabled. Disable to improve performance.
|
||||
/// </summary>
|
||||
public bool BlurAmbientLight = true;
|
||||
|
||||
/// <summary>
|
||||
/// If true RGBHalf RenderTexture type will be used for light processing.
|
||||
/// That could improve smoothness of lights. Will be turned off if device is not supports it.
|
||||
/// </summary>
|
||||
public bool HDR = true;
|
||||
|
||||
/// <summary>
|
||||
/// If true light obstacles will be rendered in 2x resolution and then downsampled to 1x.
|
||||
/// </summary>
|
||||
public bool LightObstaclesAntialiasing = true;
|
||||
|
||||
/// <summary>
|
||||
/// Set it to distance from camera to plane with light obstacles. Used only when camera in perspective mode.
|
||||
/// </summary>
|
||||
public float LightObstaclesDistance = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Billinear for blurred lights, Point for pixelated lights.
|
||||
/// </summary>
|
||||
public FilterMode LightTexturesFilterMode = FilterMode.Bilinear;
|
||||
|
||||
/// <summary>
|
||||
/// Normal mapping. Not supported on mobiles.
|
||||
/// </summary>
|
||||
public bool EnableNormalMapping = false;
|
||||
|
||||
/// <summary>
|
||||
/// If true lighting won't be seen on contents of previous cameras.
|
||||
/// </summary>
|
||||
public bool AffectOnlyThisCamera;
|
||||
|
||||
public Material AmbientLightComputeMaterial;
|
||||
public Material LightOverlayMaterial;
|
||||
public Material LightSourcesBlurMaterial;
|
||||
public Material AmbientLightBlurMaterial;
|
||||
public Camera LightCamera;
|
||||
public int LightSourcesLayer;
|
||||
public int AmbientLightLayer;
|
||||
public int LightObstaclesLayer;
|
||||
public LayerMask LightObstaclesReplacementShaderLayer;
|
||||
|
||||
private RenderTexture _ambientEmissionTexture;
|
||||
private RenderTexture _ambientTexture;
|
||||
private RenderTexture _prevAmbientTexture;
|
||||
private RenderTexture _bluredLightTexture;
|
||||
private RenderTexture _obstaclesUpsampledTexture;
|
||||
private RenderTexture _lightSourcesTexture;
|
||||
private RenderTexture _obstaclesTexture;
|
||||
private RenderTexture _screenBlitTempTex;
|
||||
private RenderTexture _normalMapBuffer;
|
||||
private RenderTexture _singleLightSourceTexture;
|
||||
private RenderTexture _renderTargetTexture;
|
||||
private RenderTexture _oldActiveRenderTexture;
|
||||
|
||||
private Camera _camera;
|
||||
private ObstacleCameraPostPorcessor _obstaclesPostProcessor;
|
||||
private Point2 _extendedLightTextureSize;
|
||||
private Point2 _smallLightTextureSize;
|
||||
private Vector3 _oldPos;
|
||||
private Vector3 _currPos;
|
||||
private RenderTextureFormat _texFormat;
|
||||
private int _aditionalAmbientLightCycles = 0;
|
||||
private static LightingSystem _instance;
|
||||
private Shader _normalMapRenderShader;
|
||||
private Camera _normalMapCamera;
|
||||
private List<LightSprite> _lightSpritesCache = new List<LightSprite>();
|
||||
private Material _normalMappedLightMaterial;
|
||||
private Material _lightCombiningMaterial;
|
||||
private Material _alphaBlendedMaterial;
|
||||
private bool _halfTexelOffest;
|
||||
private Shader _lightBlockerReplacementShader;
|
||||
#if LIGHT2D_2DTK
|
||||
private tk2dCamera _tk2dCamera;
|
||||
#endif
|
||||
|
||||
private float LightPixelsPerUnityMeter
|
||||
{
|
||||
get { return 1/LightPixelSize; }
|
||||
}
|
||||
|
||||
public static LightingSystem Instance
|
||||
{
|
||||
get { return _instance != null ? _instance : (_instance = FindObjectOfType<LightingSystem>()); }
|
||||
}
|
||||
|
||||
[ContextMenu("Create Camera")]
|
||||
private void CreateCamera()
|
||||
{
|
||||
if (LightCamera == null)
|
||||
{
|
||||
var go = new GameObject("Ligt Camera",typeof(Camera));
|
||||
go.transform.SetParent(transform,false);
|
||||
LightCamera = go.GetComponent<Camera>();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_instance = this;
|
||||
_camera = GetComponent<Camera>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Shader.SetGlobalTexture("_ObstacleTex", Texture2D.whiteTexture);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (LightCamera == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
"Lighting Camera in LightingSystem is null. Please, select Lighting Camera camera for lighting to work.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
if (LightOverlayMaterial == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
"LightOverlayMaterial in LightingSystem is null. Please, select LightOverlayMaterial camera for lighting to work.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
if (AffectOnlyThisCamera && _camera.targetTexture != null)
|
||||
{
|
||||
Debug.LogError("\"Affect Only This Camera\" will not work if camera.targetTexture is set.");
|
||||
AffectOnlyThisCamera = false;
|
||||
}
|
||||
|
||||
_camera = GetComponent<Camera>();
|
||||
|
||||
if (EnableNormalMapping && !_camera.orthographic)
|
||||
{
|
||||
Debug.LogError("Normal mapping is not supported with perspective camera.");
|
||||
EnableNormalMapping = false;
|
||||
}
|
||||
|
||||
if (!SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf))
|
||||
HDR = false;
|
||||
_texFormat = HDR ? RenderTextureFormat.ARGBHalf : RenderTextureFormat.ARGB32;
|
||||
|
||||
var lightPixelsPerUnityMeter = LightPixelsPerUnityMeter;
|
||||
|
||||
_halfTexelOffest = SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 9");
|
||||
|
||||
InitTK2D();
|
||||
|
||||
if (_camera.orthographic)
|
||||
{
|
||||
var rawCamHeight = (_camera.orthographicSize + LightCameraSizeAdd)*2f;
|
||||
var rawCamWidth = (_camera.orthographicSize*_camera.aspect + LightCameraSizeAdd)*2f;
|
||||
|
||||
_extendedLightTextureSize = new Point2(
|
||||
Mathf.RoundToInt(rawCamWidth*lightPixelsPerUnityMeter),
|
||||
Mathf.RoundToInt(rawCamHeight*lightPixelsPerUnityMeter));
|
||||
|
||||
var rawSmallCamHeight = _camera.orthographicSize*2f*lightPixelsPerUnityMeter;
|
||||
_smallLightTextureSize = new Point2(
|
||||
Mathf.RoundToInt(rawSmallCamHeight*_camera.aspect),
|
||||
Mathf.RoundToInt(rawSmallCamHeight));
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
var lightCamHalfFov = (_camera.fieldOfView + LightCameraFovAdd)*Mathf.Deg2Rad/2f;
|
||||
var lightCamSize = Mathf.Tan(lightCamHalfFov)*LightObstaclesDistance*2;
|
||||
//var gameCamHalfFov = _camera.fieldOfView*Mathf.Deg2Rad/2f;
|
||||
var texHeight = Mathf.RoundToInt(lightCamSize/LightPixelSize);
|
||||
var texWidth = texHeight*_camera.aspect;
|
||||
_extendedLightTextureSize = Point2.Round(new Vector2(texWidth, texHeight));
|
||||
|
||||
}
|
||||
{
|
||||
var lightCamHalfFov = _camera.fieldOfView*Mathf.Deg2Rad/2f;
|
||||
var lightCamSize = Mathf.Tan(lightCamHalfFov)*LightObstaclesDistance*2;
|
||||
//LightCamera.orthographicSize = lightCamSize/2f;
|
||||
|
||||
var gameCamHalfFov = _camera.fieldOfView*Mathf.Deg2Rad/2f;
|
||||
var gameCamSize = Mathf.Tan(gameCamHalfFov)*LightObstaclesDistance*2;
|
||||
_camera.orthographicSize = gameCamSize/2f;
|
||||
|
||||
var texHeight = Mathf.RoundToInt(lightCamSize/LightPixelSize);
|
||||
var texWidth = texHeight*_camera.aspect;
|
||||
_smallLightTextureSize = Point2.Round(new Vector2(texWidth, texHeight));
|
||||
}
|
||||
}
|
||||
|
||||
if (_extendedLightTextureSize.x%2 != 0)
|
||||
_extendedLightTextureSize.x++;
|
||||
if (_extendedLightTextureSize.y%2 != 0)
|
||||
_extendedLightTextureSize.y++;
|
||||
|
||||
if (_extendedLightTextureSize.x > 1024 || _extendedLightTextureSize.y > 1024 ||
|
||||
_smallLightTextureSize.x > 1024 || _smallLightTextureSize.y > 1024)
|
||||
{
|
||||
Debug.LogError("LightPixelSize is too small. Turning off lighting system.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_extendedLightTextureSize.x < 4 || _extendedLightTextureSize.y < 4 ||
|
||||
_smallLightTextureSize.x < 4 || _smallLightTextureSize.y < 4)
|
||||
{
|
||||
Debug.LogError("LightPixelSize is too big. Turning off lighting system.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_screenBlitTempTex = new RenderTexture((int)_camera.pixelWidth, (int)_camera.pixelHeight, 0, _texFormat);
|
||||
_screenBlitTempTex.filterMode = FilterMode.Point;
|
||||
|
||||
LightCamera.orthographic = _camera.orthographic;
|
||||
|
||||
if (EnableNormalMapping)
|
||||
{
|
||||
_lightSourcesTexture = new RenderTexture((int)_camera.pixelWidth, (int)_camera.pixelHeight,
|
||||
0, _texFormat);
|
||||
_lightSourcesTexture.filterMode = FilterMode.Point;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lightSourcesTexture = new RenderTexture(_smallLightTextureSize.x, _smallLightTextureSize.y,
|
||||
0, _texFormat);
|
||||
_lightSourcesTexture.filterMode = LightTexturesFilterMode;
|
||||
}
|
||||
|
||||
_obstaclesTexture = new RenderTexture(_extendedLightTextureSize.x, _extendedLightTextureSize.y,
|
||||
0, _texFormat);
|
||||
_ambientTexture = new RenderTexture(_extendedLightTextureSize.x, _extendedLightTextureSize.y,
|
||||
0, _texFormat);
|
||||
|
||||
_ambientTexture.filterMode = LightTexturesFilterMode;
|
||||
|
||||
var upsampledObstacleSize = _extendedLightTextureSize * (LightObstaclesAntialiasing ? 2 : 1);
|
||||
_obstaclesUpsampledTexture = new RenderTexture(
|
||||
upsampledObstacleSize.x, upsampledObstacleSize.y, 0, _texFormat);
|
||||
|
||||
if (AffectOnlyThisCamera)
|
||||
{
|
||||
_renderTargetTexture = new RenderTexture((int)_camera.pixelWidth, (int)_camera.pixelHeight, 0, RenderTextureFormat.ARGB32);
|
||||
_renderTargetTexture.filterMode = FilterMode.Point;
|
||||
}
|
||||
|
||||
_obstaclesPostProcessor = new ObstacleCameraPostPorcessor();
|
||||
|
||||
_lightBlockerReplacementShader = Shader.Find(@"Light2D/Internal/LightBlockerReplacementShader");
|
||||
|
||||
LoopAmbientLight(100);
|
||||
}
|
||||
|
||||
private void OnRenderImage(RenderTexture src, RenderTexture dest)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying || Util.IsSceneViewFocused)
|
||||
{
|
||||
Shader.SetGlobalTexture("_ObstacleTex", Texture2D.whiteTexture);
|
||||
if (dest != null)
|
||||
dest.DiscardContents();
|
||||
Graphics.Blit(src, dest);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
Update2DTK();
|
||||
UpdateCamera();
|
||||
RenderObstacles();
|
||||
SetupShaders();
|
||||
RenderNormalBuffer();
|
||||
RenderLightSources();
|
||||
RenderLightSourcesBlur();
|
||||
RenderAmbientLight();
|
||||
RenderLightOverlay(src, dest);
|
||||
}
|
||||
|
||||
void OnPreRender()
|
||||
{
|
||||
if (Application.isPlaying && AffectOnlyThisCamera)
|
||||
{
|
||||
_oldActiveRenderTexture = RenderTexture.active;
|
||||
RenderTexture.active = _renderTargetTexture;
|
||||
GL.Clear(true, true, new Color(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void OnPostRender()
|
||||
{
|
||||
if (Application.isPlaying && AffectOnlyThisCamera)
|
||||
{
|
||||
RenderTexture.active = _oldActiveRenderTexture;
|
||||
//if (_alphaBlendedMaterial == null)
|
||||
// _alphaBlendedMaterial = new Material(Shader.Find("Unlit/Transparent"));
|
||||
//_alphaBlendedMaterial.SetTexture("_MainTex", _screenBlitTempTex);
|
||||
//Graphics.Blit(_screenBlitTempTex, _renderTargetTexture, _alphaBlendedMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
void InitTK2D()
|
||||
{
|
||||
#if LIGHT2D_2DTK
|
||||
_tk2dCamera = GetComponent<tk2dCamera>();
|
||||
if (_tk2dCamera != null && _tk2dCamera.CameraSettings.projection == tk2dCameraSettings.ProjectionType.Orthographic)
|
||||
{
|
||||
_camera.orthographic = true;
|
||||
_camera.orthographicSize = _tk2dCamera.ScreenExtents.yMax;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Update2DTK()
|
||||
{
|
||||
#if LIGHT2D_2DTK
|
||||
if (_tk2dCamera != null && _tk2dCamera.CameraSettings.projection == tk2dCameraSettings.ProjectionType.Orthographic)
|
||||
{
|
||||
_camera.orthographic = true;
|
||||
_camera.orthographicSize = _tk2dCamera.ScreenExtents.yMax;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying && LightCamera != null)
|
||||
{
|
||||
_camera = GetComponent<Camera>();
|
||||
if (_camera != null)
|
||||
{
|
||||
InitTK2D();
|
||||
LightCamera.orthographic = _camera.orthographic;
|
||||
if (_camera.orthographic)
|
||||
{
|
||||
LightCamera.orthographicSize = _camera.orthographicSize + LightCameraSizeAdd;
|
||||
}
|
||||
else
|
||||
{
|
||||
LightCamera.fieldOfView = _camera.fieldOfView + LightCameraFovAdd;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Application.isPlaying || Util.IsSceneViewFocused)
|
||||
{
|
||||
Shader.SetGlobalTexture("_ObstacleTex", Texture2D.whiteTexture);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void RenderObstacles()
|
||||
{
|
||||
ConfigLightCamera(true);
|
||||
|
||||
var oldColor = LightCamera.backgroundColor;
|
||||
var oldClearFlags = LightCamera.clearFlags;
|
||||
LightCamera.enabled = false;
|
||||
LightCamera.targetTexture = _obstaclesUpsampledTexture;
|
||||
|
||||
//main
|
||||
LightCamera.clearFlags = CameraClearFlags.SolidColor;
|
||||
LightCamera.cullingMask = 1 << LightObstaclesLayer;
|
||||
LightCamera.backgroundColor = new Color(1, 1, 1, 0);
|
||||
_obstaclesPostProcessor.DrawMesh(LightCamera, LightObstaclesAntialiasing ? 2 : 1);
|
||||
LightCamera.Render();
|
||||
|
||||
//replacement
|
||||
LightCamera.clearFlags = CameraClearFlags.Nothing;
|
||||
LightCamera.cullingMask = LightObstaclesReplacementShaderLayer;
|
||||
LightCamera.RenderWithShader(_lightBlockerReplacementShader, "RenderType");
|
||||
//LightCamera.Render();
|
||||
|
||||
//LightCamera.ResetReplacementShader();
|
||||
LightCamera.targetTexture = null;
|
||||
LightCamera.cullingMask = 0;
|
||||
LightCamera.backgroundColor = oldColor;
|
||||
LightCamera.clearFlags = oldClearFlags;
|
||||
|
||||
_obstaclesTexture.DiscardContents();
|
||||
Graphics.Blit(_obstaclesUpsampledTexture, _obstaclesTexture);
|
||||
}
|
||||
|
||||
private void SetupShaders()
|
||||
{
|
||||
var lightPixelsPerUnityMeter = LightPixelsPerUnityMeter;
|
||||
|
||||
if (HDR) Shader.EnableKeyword("HDR");
|
||||
else Shader.DisableKeyword("HDR");
|
||||
|
||||
if (_camera.orthographic) Shader.DisableKeyword("PERSPECTIVE_CAMERA");
|
||||
else Shader.EnableKeyword("PERSPECTIVE_CAMERA");
|
||||
|
||||
Shader.SetGlobalTexture("_ObstacleTex", _obstaclesTexture);
|
||||
Shader.SetGlobalFloat("_PixelsPerBlock", lightPixelsPerUnityMeter);
|
||||
Shader.SetGlobalVector("_ExtendedToSmallTextureScale", new Vector2(
|
||||
_smallLightTextureSize.x / (float)_extendedLightTextureSize.x,
|
||||
_smallLightTextureSize.y / (float)_extendedLightTextureSize.y));
|
||||
Shader.SetGlobalVector("_PosOffset", LightObstaclesAntialiasing
|
||||
? (EnableNormalMapping ? _obstaclesUpsampledTexture.texelSize * 0.75f : _obstaclesUpsampledTexture.texelSize * 0.25f)
|
||||
: (EnableNormalMapping ? _obstaclesTexture.texelSize : _obstaclesTexture.texelSize * 0.5f));
|
||||
}
|
||||
|
||||
private void RenderNormalBuffer()
|
||||
{
|
||||
if (!EnableNormalMapping)
|
||||
return;
|
||||
|
||||
if (_normalMapBuffer == null)
|
||||
{
|
||||
_normalMapBuffer = new RenderTexture(
|
||||
(int) _camera.pixelWidth, (int) _camera.pixelHeight, 0, RenderTextureFormat.ARGB32);
|
||||
_normalMapBuffer.filterMode = FilterMode.Point;
|
||||
}
|
||||
|
||||
if (_normalMapRenderShader == null)
|
||||
_normalMapRenderShader = Shader.Find("Light2D/Internal/Normal Map Drawer");
|
||||
|
||||
if (_normalMapCamera == null)
|
||||
{
|
||||
var camObj = new GameObject();
|
||||
camObj.name = "Normals Camera";
|
||||
camObj.transform.parent = _camera.transform;
|
||||
camObj.transform.localScale = Vector3.one;
|
||||
camObj.transform.localPosition = Vector3.zero;
|
||||
camObj.transform.localRotation = Quaternion.identity;
|
||||
_normalMapCamera = camObj.AddComponent<Camera>();
|
||||
_normalMapCamera.enabled = false;
|
||||
}
|
||||
|
||||
_normalMapBuffer.DiscardContents();
|
||||
_normalMapCamera.CopyFrom(_camera);
|
||||
_normalMapCamera.transform.position = LightCamera.transform.position;
|
||||
_normalMapCamera.clearFlags = CameraClearFlags.SolidColor;
|
||||
_normalMapCamera.targetTexture = _normalMapBuffer;
|
||||
_normalMapCamera.cullingMask = int.MaxValue;
|
||||
_normalMapCamera.backgroundColor = new Color(0.5f, 0.5f, 0, 1);
|
||||
_normalMapCamera.RenderWithShader(_normalMapRenderShader, "LightObstacle");
|
||||
|
||||
Shader.SetGlobalTexture("_NormalsBuffer", _normalMapBuffer);
|
||||
Shader.EnableKeyword("NORMAL_MAPPED_LIGHTS");
|
||||
}
|
||||
|
||||
private void RenderLightSources()
|
||||
{
|
||||
ConfigLightCamera(false);
|
||||
|
||||
if (EnableNormalMapping)
|
||||
{
|
||||
if(_singleLightSourceTexture == null)
|
||||
{
|
||||
_singleLightSourceTexture = new RenderTexture(
|
||||
_smallLightTextureSize.x, _smallLightTextureSize.y, 0, _texFormat);
|
||||
_singleLightSourceTexture.filterMode = LightTexturesFilterMode;
|
||||
}
|
||||
|
||||
if (_normalMappedLightMaterial == null)
|
||||
{
|
||||
_normalMappedLightMaterial = new Material(Shader.Find("Light2D/Internal/Normal Mapped Light"));
|
||||
_normalMappedLightMaterial.SetTexture("_MainTex", _singleLightSourceTexture);
|
||||
}
|
||||
|
||||
if (_lightCombiningMaterial == null)
|
||||
{
|
||||
_lightCombiningMaterial = new Material(Shader.Find("Light2D/Internal/Light Blender"));
|
||||
_lightCombiningMaterial.SetTexture("_MainTex", _singleLightSourceTexture);
|
||||
}
|
||||
|
||||
var cameraPlanes = GeometryUtility.CalculateFrustumPlanes(_camera);
|
||||
_lightSourcesTexture.DiscardContents();
|
||||
|
||||
var oldBackgroundColor = LightCamera.backgroundColor;
|
||||
var oldRt = RenderTexture.active;
|
||||
Graphics.SetRenderTarget(_lightSourcesTexture);
|
||||
GL.Clear(false, true, oldBackgroundColor);
|
||||
Graphics.SetRenderTarget(oldRt);
|
||||
|
||||
_lightSpritesCache.Clear();
|
||||
foreach (var lightSprite in LightSprite.AllLightSprites)
|
||||
{
|
||||
if (lightSprite.RendererEnabled &&
|
||||
GeometryUtility.TestPlanesAABB(cameraPlanes, lightSprite.Renderer.bounds))
|
||||
{
|
||||
_lightSpritesCache.Add(lightSprite);
|
||||
}
|
||||
}
|
||||
|
||||
var lightCamLocPos = LightCamera.transform.localPosition;
|
||||
LightCamera.targetTexture = _singleLightSourceTexture;
|
||||
LightCamera.cullingMask = 0;
|
||||
LightCamera.backgroundColor = new Color(0, 0, 0, 0);
|
||||
|
||||
foreach (var lightSprite in _lightSpritesCache)
|
||||
{
|
||||
// HACK: won't work for unknown reason without that line
|
||||
LightCamera.RenderWithShader(_normalMapRenderShader, "f84j");
|
||||
|
||||
Graphics.SetRenderTarget(_singleLightSourceTexture);
|
||||
lightSprite.DrawLightingNow(lightCamLocPos);
|
||||
Graphics.SetRenderTarget(_lightSourcesTexture);
|
||||
lightSprite.DrawLightNormalsNow(_normalMappedLightMaterial);
|
||||
}
|
||||
Graphics.SetRenderTarget(oldRt);
|
||||
|
||||
LightCamera.cullingMask = 1 << LightSourcesLayer;
|
||||
LightCamera.Render();
|
||||
Graphics.Blit(_singleLightSourceTexture, _lightSourcesTexture, _lightCombiningMaterial);
|
||||
|
||||
LightCamera.targetTexture = null;
|
||||
LightCamera.cullingMask = 0;
|
||||
LightCamera.backgroundColor = oldBackgroundColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
LightCamera.targetTexture = _lightSourcesTexture;
|
||||
LightCamera.cullingMask = 1 << LightSourcesLayer;
|
||||
//LightCamera.backgroundColor = new Color(0, 0, 0, 0);
|
||||
LightCamera.Render();
|
||||
LightCamera.targetTexture = null;
|
||||
LightCamera.cullingMask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderLightSourcesBlur()
|
||||
{
|
||||
if (BlurLightSources && LightSourcesBlurMaterial != null)
|
||||
{
|
||||
UnityEngine.Profiling.Profiler.BeginSample("LightingSystem.OnRenderImage Bluring Light Sources");
|
||||
|
||||
if (_bluredLightTexture == null)
|
||||
{
|
||||
var w = _lightSourcesTexture.width == _smallLightTextureSize.x
|
||||
? _lightSourcesTexture.width*2
|
||||
: _lightSourcesTexture.width;
|
||||
var h = _lightSourcesTexture.height == _smallLightTextureSize.y
|
||||
? _lightSourcesTexture.height*2
|
||||
: _lightSourcesTexture.height;
|
||||
_bluredLightTexture = new RenderTexture(w, h, 0, _texFormat);
|
||||
}
|
||||
|
||||
_bluredLightTexture.DiscardContents();
|
||||
_lightSourcesTexture.filterMode = FilterMode.Bilinear;
|
||||
LightSourcesBlurMaterial.mainTexture = _lightSourcesTexture;
|
||||
Graphics.Blit(null, _bluredLightTexture, LightSourcesBlurMaterial);
|
||||
|
||||
if (LightTexturesFilterMode == FilterMode.Point)
|
||||
{
|
||||
_lightSourcesTexture.filterMode = FilterMode.Point;
|
||||
_lightSourcesTexture.DiscardContents();
|
||||
Graphics.Blit(_bluredLightTexture, _lightSourcesTexture);
|
||||
}
|
||||
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderAmbientLight()
|
||||
{
|
||||
if (!EnableAmbientLight || AmbientLightComputeMaterial == null)
|
||||
return;
|
||||
|
||||
UnityEngine.Profiling.Profiler.BeginSample("LightingSystem.OnRenderImage Ambient Light");
|
||||
|
||||
ConfigLightCamera(true);
|
||||
|
||||
if (_ambientTexture == null)
|
||||
{
|
||||
_ambientTexture =
|
||||
new RenderTexture(_extendedLightTextureSize.x, _extendedLightTextureSize.y, 0, _texFormat);
|
||||
}
|
||||
if (_prevAmbientTexture == null)
|
||||
{
|
||||
_prevAmbientTexture =
|
||||
new RenderTexture(_extendedLightTextureSize.x, _extendedLightTextureSize.y, 0, _texFormat);
|
||||
}
|
||||
if (_ambientEmissionTexture == null)
|
||||
{
|
||||
_ambientEmissionTexture =
|
||||
new RenderTexture(_extendedLightTextureSize.x, _extendedLightTextureSize.y, 0, _texFormat);
|
||||
}
|
||||
|
||||
if (EnableAmbientLight)
|
||||
{
|
||||
var oldBackgroundColor = LightCamera.backgroundColor;
|
||||
LightCamera.targetTexture = _ambientEmissionTexture;
|
||||
LightCamera.cullingMask = 1 << AmbientLightLayer;
|
||||
LightCamera.backgroundColor = new Color(0, 0, 0, 0);
|
||||
LightCamera.Render();
|
||||
LightCamera.targetTexture = null;
|
||||
LightCamera.cullingMask = 0;
|
||||
LightCamera.backgroundColor = oldBackgroundColor;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _aditionalAmbientLightCycles + 1; i++)
|
||||
{
|
||||
var tmp = _prevAmbientTexture;
|
||||
_prevAmbientTexture = _ambientTexture;
|
||||
_ambientTexture = tmp;
|
||||
|
||||
var texSize = new Vector2(_ambientTexture.width, _ambientTexture.height);
|
||||
var posShift = ((Vector2) (_currPos - _oldPos)/LightPixelSize).Div(texSize);
|
||||
_oldPos = _currPos;
|
||||
|
||||
AmbientLightComputeMaterial.SetTexture("_LightSourcesTex", _ambientEmissionTexture);
|
||||
AmbientLightComputeMaterial.SetTexture("_MainTex", _prevAmbientTexture);
|
||||
AmbientLightComputeMaterial.SetVector("_Shift", posShift);
|
||||
|
||||
_ambientTexture.DiscardContents();
|
||||
Graphics.Blit(null, _ambientTexture, AmbientLightComputeMaterial);
|
||||
|
||||
if (BlurAmbientLight && AmbientLightBlurMaterial != null)
|
||||
{
|
||||
UnityEngine.Profiling.Profiler.BeginSample("LightingSystem.OnRenderImage Bluring Ambient Light");
|
||||
|
||||
_prevAmbientTexture.DiscardContents();
|
||||
AmbientLightBlurMaterial.mainTexture = _ambientTexture;
|
||||
Graphics.Blit(null, _prevAmbientTexture, AmbientLightBlurMaterial);
|
||||
|
||||
var tmpblur = _prevAmbientTexture;
|
||||
_prevAmbientTexture = _ambientTexture;
|
||||
_ambientTexture = tmpblur;
|
||||
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
|
||||
_aditionalAmbientLightCycles = 0;
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
}
|
||||
|
||||
private void RenderLightOverlay(RenderTexture src, RenderTexture dest)
|
||||
{
|
||||
UnityEngine.Profiling.Profiler.BeginSample("LightingSystem.OnRenderImage Light Overlay");
|
||||
|
||||
ConfigLightCamera(false);
|
||||
|
||||
Vector2 lightTexelSize = new Vector2(1f / _smallLightTextureSize.x, 1f / _smallLightTextureSize.y);
|
||||
float lightPixelsPerUnityMeter = LightPixelsPerUnityMeter;
|
||||
Vector2 worldOffset = Quaternion.Inverse(_camera.transform.rotation)*(LightCamera.transform.position - _camera.transform.position);
|
||||
Vector2 offset = Vector2.Scale(lightTexelSize, -worldOffset*lightPixelsPerUnityMeter);
|
||||
|
||||
var lightSourcesTex = BlurLightSources && LightSourcesBlurMaterial != null && LightTexturesFilterMode != FilterMode.Point
|
||||
? _bluredLightTexture
|
||||
: _lightSourcesTexture;
|
||||
float xDiff = _camera.aspect/LightCamera.aspect;
|
||||
|
||||
if (!_camera.orthographic)
|
||||
{
|
||||
var gameCamHalfFov = _camera.fieldOfView * Mathf.Deg2Rad / 2f;
|
||||
var gameCamSize = Mathf.Tan(gameCamHalfFov) * LightObstaclesDistance * 2;
|
||||
_camera.orthographicSize = gameCamSize / 2f;
|
||||
}
|
||||
|
||||
float scaleY = _camera.orthographicSize/LightCamera.orthographicSize;
|
||||
var scale = new Vector2(scaleY*xDiff, scaleY);
|
||||
|
||||
var oldAmbientFilterMode = _ambientTexture == null ? FilterMode.Point : _ambientTexture.filterMode;
|
||||
LightOverlayMaterial.SetTexture("_AmbientLightTex", EnableAmbientLight ? _ambientTexture : null);
|
||||
LightOverlayMaterial.SetTexture("_LightSourcesTex", lightSourcesTex);
|
||||
LightOverlayMaterial.SetTexture("_GameTex", src);
|
||||
LightOverlayMaterial.SetVector("_Offset", offset);
|
||||
LightOverlayMaterial.SetVector("_Scale", scale);
|
||||
|
||||
if (_screenBlitTempTex == null || _screenBlitTempTex.width != src.width ||
|
||||
_screenBlitTempTex.height != src.height)
|
||||
{
|
||||
if (_screenBlitTempTex != null)
|
||||
_screenBlitTempTex.Release();
|
||||
_screenBlitTempTex = new RenderTexture(src.width, src.height, 0, RenderTextureFormat.ARGB32);
|
||||
_screenBlitTempTex.filterMode = FilterMode.Point;
|
||||
}
|
||||
|
||||
_screenBlitTempTex.DiscardContents();
|
||||
Graphics.Blit(null, _screenBlitTempTex, LightOverlayMaterial);
|
||||
|
||||
if (_ambientTexture != null)
|
||||
_ambientTexture.filterMode = oldAmbientFilterMode;
|
||||
|
||||
if (!AffectOnlyThisCamera)
|
||||
Graphics.Blit(_screenBlitTempTex, dest);
|
||||
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
}
|
||||
|
||||
private void UpdateCamera()
|
||||
{
|
||||
LightPixelSize = _camera.orthographicSize*2f/_smallLightTextureSize.y;
|
||||
|
||||
var lightPixelsPerUnityMeter = LightPixelsPerUnityMeter;
|
||||
var mainPos = _camera.transform.position;
|
||||
var camRot = _camera.transform.rotation;
|
||||
var unrotMainPos = Quaternion.Inverse(camRot) * mainPos;
|
||||
var gridPos = new Vector2(
|
||||
Mathf.Round(unrotMainPos.x * lightPixelsPerUnityMeter) / lightPixelsPerUnityMeter,
|
||||
Mathf.Round(unrotMainPos.y * lightPixelsPerUnityMeter) / lightPixelsPerUnityMeter);
|
||||
Vector2 posDiff = gridPos - (Vector2)unrotMainPos;
|
||||
var pos = camRot*posDiff + mainPos;
|
||||
LightCamera.transform.position = pos;
|
||||
_currPos = pos;
|
||||
}
|
||||
|
||||
public void LoopAmbientLight(int cycles)
|
||||
{
|
||||
_aditionalAmbientLightCycles += cycles;
|
||||
}
|
||||
|
||||
void ConfigLightCamera(bool extended)
|
||||
{
|
||||
if (extended)
|
||||
{
|
||||
LightCamera.orthographicSize =
|
||||
_camera.orthographicSize*(_extendedLightTextureSize.y/(float)_smallLightTextureSize.y);// _extendedLightTextureSize.y/(2f*LightPixelsPerUnityMeter);
|
||||
LightCamera.fieldOfView = _camera.fieldOfView + LightCameraFovAdd;
|
||||
LightCamera.aspect = _extendedLightTextureSize.x/(float) _extendedLightTextureSize.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
LightCamera.orthographicSize = _camera.orthographicSize;// _smallLightTextureSize.y / (2f * LightPixelsPerUnityMeter);
|
||||
LightCamera.fieldOfView = _camera.fieldOfView;
|
||||
LightCamera.aspect = _smallLightTextureSize.x / (float)_smallLightTextureSize.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Assets/Plugins/Light2D/Scripts/LightingSystem.cs.meta
Normal file
8
Assets/Plugins/Light2D/Scripts/LightingSystem.cs.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d9b6871d3cdbba478825c4b041a7f90
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
18
Assets/Plugins/Light2D/Scripts/LightingSystemPrefabConfig.cs
Normal file
18
Assets/Plugins/Light2D/Scripts/LightingSystemPrefabConfig.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Some configuration for LightingSystem. Containd in lighting system prefab, destroyed after ininial setup.
|
||||
/// </summary>
|
||||
public class LightingSystemPrefabConfig : MonoBehaviour
|
||||
{
|
||||
public Material AmbientLightComputeMaterial;
|
||||
public Material LightOverlayMaterial;
|
||||
public Material BlurMaterial;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6a84973fb2c2f0449bd5d1b1fbb5b86d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// This class apply post processing effect to light obstacles texture.
|
||||
/// It is drawing one pixel wide white border on light obstacles texture.
|
||||
/// Whithout it light sources with off screen origin may not work.
|
||||
/// </summary>
|
||||
public class ObstacleCameraPostPorcessor
|
||||
{
|
||||
private Mesh _mesh;
|
||||
private Material _material;
|
||||
private Point2 _oldCameraSize;
|
||||
private List<Color32> _colors32 = new List<Color32>();
|
||||
private List<Vector3> _vertices = new List<Vector3>();
|
||||
private List<int> _indices = new List<int>();
|
||||
|
||||
public ObstacleCameraPostPorcessor()
|
||||
{
|
||||
if (_material == null)
|
||||
{
|
||||
_material = new Material(Shader.Find("Light2D/Obstacle Texture Post Porcessor"));
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawMesh(Camera camera, float pixelWidth)
|
||||
{
|
||||
var camSize = new Point2(Mathf.RoundToInt(camera.pixelWidth), Mathf.RoundToInt(camera.pixelHeight));
|
||||
if (_oldCameraSize != camSize || _mesh == null)
|
||||
{
|
||||
_oldCameraSize = camSize;
|
||||
CreateMesh(camera, pixelWidth);
|
||||
}
|
||||
|
||||
Graphics.DrawMesh(_mesh, camera.transform.position, camera.transform.rotation, _material,
|
||||
LightingSystem.Instance.LightObstaclesLayer, camera);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generating mesh with one pixel wide white border.
|
||||
/// </summary>
|
||||
private void CreateMesh(Camera camera, float pixelWidth)
|
||||
{
|
||||
var pixelSize = new Vector2(1f/camera.pixelWidth, 1f/camera.pixelHeight)*pixelWidth;
|
||||
|
||||
_vertices.Clear();
|
||||
_colors32.Clear();
|
||||
_indices.Clear();
|
||||
|
||||
CreateQuad(new Color32(0, 0, 0, 0), pixelSize, Vector2.one - pixelSize); // central
|
||||
CreateQuad(Color.white, Vector2.zero, new Vector2(pixelSize.x, 1)); // left
|
||||
CreateQuad(Color.white, new Vector2(1 - pixelSize.x, 0), Vector2.one); // right
|
||||
CreateQuad(Color.white, Vector2.zero, new Vector2(1, pixelSize.y)); // bottom
|
||||
CreateQuad(Color.white, new Vector2(0, 1 - pixelSize.y), Vector2.one); // top
|
||||
|
||||
if (_mesh == null)
|
||||
_mesh = new Mesh();
|
||||
|
||||
_mesh.Clear();
|
||||
_mesh.vertices = _vertices.ToArray();
|
||||
_mesh.triangles = _indices.ToArray();
|
||||
_mesh.colors32 = _colors32.ToArray();
|
||||
}
|
||||
|
||||
private void CreateQuad(Color32 color, Vector2 min, Vector2 max)
|
||||
{
|
||||
min = min*2 - Vector2.one;
|
||||
max = max*2 - Vector2.one;
|
||||
|
||||
int startVertex = _vertices.Count;
|
||||
|
||||
_indices.Add(0 + startVertex);
|
||||
_indices.Add(1 + startVertex);
|
||||
_indices.Add(3 + startVertex);
|
||||
_indices.Add(3 + startVertex);
|
||||
_indices.Add(1 + startVertex);
|
||||
_indices.Add(2 + startVertex);
|
||||
|
||||
_vertices.Add(new Vector3(min.x, min.y, 1));
|
||||
_vertices.Add(new Vector3(min.x, max.y, 1));
|
||||
_vertices.Add(new Vector3(max.x, max.y, 1));
|
||||
_vertices.Add(new Vector3(max.x, min.y, 1));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
_colors32.Add(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dc802f1bc103f85408e82da1905c7e32
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
137
Assets/Plugins/Light2D/Scripts/Point2.cs
Normal file
137
Assets/Plugins/Light2D/Scripts/Point2.cs
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Class is almost same as Vector2, but using int data type instead of float.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct Point2 : IEquatable<Point2>
|
||||
{
|
||||
public int x, y;
|
||||
|
||||
public Point2(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public bool Equals(Point2 other)
|
||||
{
|
||||
return x == other.x && y == other.y;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
return obj is Point2 && Equals((Point2)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (x * 397) ^ y;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator ==(Point2 left, Point2 right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Point2 left, Point2 right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public static implicit operator Vector2(Point2 p)
|
||||
{
|
||||
return new Vector2(p.x, p.y);
|
||||
}
|
||||
|
||||
public static implicit operator Vector3(Point2 p)
|
||||
{
|
||||
return new Vector2(p.x, p.y);
|
||||
}
|
||||
|
||||
public static Point2 Floor(Vector2 v)
|
||||
{
|
||||
return new Point2((int)v.x, (int)v.y);
|
||||
}
|
||||
|
||||
public static Point2 Round(Vector2 v)
|
||||
{
|
||||
return new Point2(Mathf.RoundToInt(v.x), Mathf.RoundToInt(v.y));
|
||||
}
|
||||
|
||||
public static Point2 Floor(float x, float y)
|
||||
{
|
||||
return new Point2((int)x, (int)y);
|
||||
}
|
||||
|
||||
public static Point2 Round(float x, float y)
|
||||
{
|
||||
return new Point2(Mathf.RoundToInt(x), Mathf.RoundToInt(y));
|
||||
}
|
||||
|
||||
public static Point2 operator +(Point2 first, Point2 second)
|
||||
{
|
||||
return new Point2(first.x + second.x, first.y + second.y);
|
||||
}
|
||||
|
||||
public static Point2 operator -(Point2 first, Point2 second)
|
||||
{
|
||||
return new Point2(first.x - second.x, first.y - second.y);
|
||||
}
|
||||
|
||||
public static Vector2 operator +(Point2 first, Vector2 second)
|
||||
{
|
||||
return new Vector2(first.x + second.x, first.y + second.y);
|
||||
}
|
||||
|
||||
public static Vector2 operator -(Point2 first, Vector2 second)
|
||||
{
|
||||
return new Vector2(first.x - second.x, first.y - second.y);
|
||||
}
|
||||
|
||||
public static Point2 operator *(Point2 p, int mul)
|
||||
{
|
||||
return new Point2(p.x * mul, p.y * mul);
|
||||
}
|
||||
|
||||
public static Point2 operator /(Point2 p, int div)
|
||||
{
|
||||
return new Point2(p.x / div, p.y / div);
|
||||
}
|
||||
|
||||
public static Vector2 operator *(Point2 p, float mul)
|
||||
{
|
||||
return new Vector2(p.x * mul, p.y * mul);
|
||||
}
|
||||
|
||||
public static Vector2 operator /(Point2 p, float div)
|
||||
{
|
||||
return new Vector2(p.x / div, p.y / div);
|
||||
}
|
||||
|
||||
public static Point2 one
|
||||
{
|
||||
get { return new Point2(1, 1); }
|
||||
}
|
||||
|
||||
public static Point2 zero
|
||||
{
|
||||
get { return new Point2(0, 0); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "(" + x + ", " + y + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Assets/Plugins/Light2D/Scripts/Point2.cs.meta
Normal file
8
Assets/Plugins/Light2D/Scripts/Point2.cs.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 569a4c0c227854345b2c9db3728899bc
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
633
Assets/Plugins/Light2D/Scripts/Util.cs
Normal file
633
Assets/Plugins/Light2D/Scripts/Util.cs
Normal file
|
|
@ -0,0 +1,633 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Light2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Bunch of utility functions that could be userful sometimes.
|
||||
/// </summary>
|
||||
public static class Util
|
||||
{
|
||||
#if UNITY_METRO && !UNITY_EDITOR
|
||||
static Windows.Devices.Input.TouchCapabilities touchCaps = new Windows.Devices.Input.TouchCapabilities();
|
||||
#endif
|
||||
|
||||
public static bool isTouchscreen
|
||||
{
|
||||
get
|
||||
{
|
||||
return
|
||||
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBPLAYER
|
||||
false;
|
||||
#elif UNITY_METRO
|
||||
touchCaps.TouchPresent != 0;
|
||||
#else
|
||||
true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static void SafeIterateBackward<T>(this IList<T> list, Action<T> action)
|
||||
{
|
||||
for (int i = list.Count - 1; i >= 0; i--)
|
||||
{
|
||||
action(list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SafeIterateBackward<T>(this IList<T> list, Action<T, int> action)
|
||||
{
|
||||
for (int i = list.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (i >= list.Count) continue;
|
||||
action(list[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SafeIterateBackward<T>(this IEnumerable<T> enumerable, Action<T> action)
|
||||
{
|
||||
var list = enumerable.ToArray();
|
||||
for (int i = list.Length - 1; i >= 0; i--)
|
||||
{
|
||||
action(list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SafeIterateBackward<T>(this IEnumerable<T> enumerable, Action<T, int> action)
|
||||
{
|
||||
var list = enumerable.ToArray();
|
||||
for (int i = list.Length - 1; i >= 0; i--)
|
||||
{
|
||||
action(list[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
|
||||
{
|
||||
foreach (var obj in enumerable)
|
||||
{
|
||||
action(obj);
|
||||
yield return obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T, int> action)
|
||||
{
|
||||
var i = 0;
|
||||
foreach (var obj in enumerable)
|
||||
{
|
||||
action(obj, i);
|
||||
yield return obj;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> GetComponentsInChildRecursive<T>(this GameObject root) where T : Component
|
||||
{
|
||||
return root.GetChildRecursive().SelectMany(go => go.GetComponents<T>());
|
||||
}
|
||||
|
||||
public static IEnumerable<GameObject> GetChildRecursive(this GameObject root)
|
||||
{
|
||||
foreach (Transform child in root.transform)
|
||||
{
|
||||
var cgo = child.gameObject;
|
||||
yield return cgo;
|
||||
foreach (var gameObject in cgo.GetChildRecursive())
|
||||
yield return gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
public static Rigidbody2D GetRigidbodyUnderCursor()
|
||||
{
|
||||
var mousePos = GetMousePosInUnits();
|
||||
var click = Physics2D.OverlapPoint(mousePos);
|
||||
return click != null ? click.attachedRigidbody : null;
|
||||
}
|
||||
|
||||
public static Vector2 GetMousePosInUnits()
|
||||
{
|
||||
var mouse = Input.mousePosition;
|
||||
var camera = Camera.main;
|
||||
var mouseWorld = camera.ScreenToWorldPoint(
|
||||
new Vector3(mouse.x, mouse.y, -camera.transform.position.z));
|
||||
return mouseWorld;
|
||||
}
|
||||
|
||||
public static Vector2 ScreenToWorld(Vector2 screen)
|
||||
{
|
||||
var camera = Camera.main;
|
||||
var mouseWorld = camera.ScreenToWorldPoint(
|
||||
new Vector3(screen.x, screen.y, -camera.transform.position.z));
|
||||
return mouseWorld;
|
||||
}
|
||||
|
||||
public static Vector2 WorldToScreen(Vector2 screen)
|
||||
{
|
||||
var camera = Camera.main;
|
||||
var mouseWorld = camera.WorldToScreenPoint(
|
||||
new Vector3(screen.x, screen.y, -camera.transform.position.z));
|
||||
return mouseWorld;
|
||||
}
|
||||
|
||||
public static GameObject Instantiate(GameObject prefab)
|
||||
{
|
||||
return (GameObject) Object.Instantiate(prefab);
|
||||
}
|
||||
|
||||
public static T Instantiate<T>(GameObject prefab) where T : Component
|
||||
{
|
||||
return (Instantiate(prefab)).GetComponent<T>();
|
||||
}
|
||||
|
||||
public static T Instantiate<T>(GameObject prefab, Vector3 position, Quaternion rotation)
|
||||
where T : Component
|
||||
{
|
||||
return ((GameObject) Object.Instantiate(prefab, position, rotation)).GetComponent<T>();
|
||||
}
|
||||
|
||||
public static float ClampAngle(float angle)
|
||||
{
|
||||
angle = Mathf.Repeat(angle, 360);
|
||||
if (angle > 180) angle -= 360;
|
||||
return angle;
|
||||
}
|
||||
|
||||
public static float AngleZ(this Vector2 angle)
|
||||
{
|
||||
if (angle == Vector2.zero) return 0;
|
||||
return Vector2.Angle(Vector2.up, angle)*Mathf.Sign(-angle.x);
|
||||
}
|
||||
|
||||
public static float AngleZ(this Vector3 angle)
|
||||
{
|
||||
if (angle == Vector3.zero) return 0;
|
||||
return Vector2.Angle(Vector2.up, angle)*Mathf.Sign(-angle.x);
|
||||
}
|
||||
|
||||
public static float Proj(Vector2 vector, Vector2 onNormal)
|
||||
{
|
||||
return Vector2.Dot(vector, onNormal)*onNormal.magnitude;
|
||||
}
|
||||
|
||||
public static float Cross(Vector2 lhs, Vector2 rhs)
|
||||
{
|
||||
return lhs.x*rhs.y - lhs.y*rhs.x;
|
||||
}
|
||||
|
||||
public static void Destroy(UnityEngine.Object obj)
|
||||
{
|
||||
if (obj == null) return;
|
||||
if (obj is GameObject)
|
||||
((GameObject) obj).transform.parent = null;
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
GameObject.DestroyImmediate(obj);
|
||||
else GameObject.Destroy(obj);
|
||||
#else
|
||||
GameObject.Destroy(obj);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static T RandomElement<T>(this IList<T> coll)
|
||||
{
|
||||
var index = Random.Range(0, coll.Count);
|
||||
return coll[index];
|
||||
}
|
||||
|
||||
public static T RandomElement<T>(this T[] coll)
|
||||
{
|
||||
var index = Random.Range(0, coll.Length);
|
||||
return coll[index];
|
||||
}
|
||||
|
||||
public static Vector2 RotateZ(this Vector2 v, float angle)
|
||||
{
|
||||
float sin = Mathf.Sin(angle*Mathf.Deg2Rad);
|
||||
float cos = Mathf.Cos(angle*Mathf.Deg2Rad);
|
||||
float tx = v.x;
|
||||
float ty = v.y;
|
||||
return new Vector2((cos*tx) - (sin*ty), (cos*ty) + (sin*tx));
|
||||
}
|
||||
|
||||
public static Vector3 RotateZ(this Vector3 v, float angle)
|
||||
{
|
||||
float sin = Mathf.Sin(angle);
|
||||
float cos = Mathf.Cos(angle);
|
||||
float tx = v.x;
|
||||
float ty = v.y;
|
||||
return new Vector3((cos*tx) - (sin*ty), (cos*ty) + (sin*tx), v.z);
|
||||
}
|
||||
|
||||
public static Vector2 Rotate90(this Vector2 v)
|
||||
{
|
||||
return new Vector2(-v.y, v.x);
|
||||
}
|
||||
|
||||
public static void Log(params object[] vals)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append(", ");
|
||||
sb.Append(vals[i]);
|
||||
}
|
||||
Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
public static void Log(UnityEngine.Object context, params object[] vals)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append(", ");
|
||||
sb.Append(vals[i]);
|
||||
}
|
||||
Debug.Log(sb.ToString(), context);
|
||||
}
|
||||
|
||||
public static void LogArray<T>(IEnumerable<T> enumerable)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var vals = enumerable.ToArray();
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
sb.Append(i);
|
||||
sb.Append(": ");
|
||||
sb.Append(vals[i]);
|
||||
sb.AppendLine(";");
|
||||
}
|
||||
Debug.Log(sb.ToString());
|
||||
}
|
||||
|
||||
public static Color Set(this Color color, int channel, float value)
|
||||
{
|
||||
color[channel] = value;
|
||||
return color;
|
||||
}
|
||||
|
||||
public static Color WithAlpha(this Color color, float value)
|
||||
{
|
||||
color.a = value;
|
||||
return color;
|
||||
}
|
||||
|
||||
public static Vector3 WithX(this Vector3 vec, float value)
|
||||
{
|
||||
vec.x = value;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector3 WithXY(this Vector3 vec, Vector2 xy)
|
||||
{
|
||||
vec.x = xy.x;
|
||||
vec.y = xy.y;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector3 WithXY(this Vector3 vec, float x, float y)
|
||||
{
|
||||
vec.x = x;
|
||||
vec.y = y;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector3 WithY(this Vector3 vec, float value)
|
||||
{
|
||||
vec.y = value;
|
||||
return vec;
|
||||
}
|
||||
|
||||
public static Vector3 WithZ(this Vector3 vec, float value)
|
||||
{
|
||||
vec.z = value;
|
||||
return vec;
|
||||
}
|
||||
|
||||
#if !UNITY_WINRT
|
||||
public static void Serialize<T>(string path, T obj) where T : class
|
||||
{
|
||||
using (var stream = File.Create(path))
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof (T));
|
||||
var xmlWriter = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
serializer.Serialize(xmlWriter, obj);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Serialize<T>(T obj)
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof (T));
|
||||
var xmlWriter = new XmlTextWriter(stream, Encoding.UTF8);
|
||||
serializer.Serialize(xmlWriter, obj);
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(string path) where T : class
|
||||
{
|
||||
using (var stream = File.OpenRead(path))
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof (T));
|
||||
var fromFile = serializer.Deserialize(stream) as T;
|
||||
return fromFile;
|
||||
}
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(byte[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stream = new MemoryStream(data))
|
||||
{
|
||||
var serializer = new XmlSerializer(typeof (T));
|
||||
var fromFile = (T) serializer.Deserialize(stream);
|
||||
return fromFile;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static int IndexOfMin<T>(this List<T> list, Func<T, float> pred)
|
||||
{
|
||||
int minId = -1;
|
||||
float minVal = float.MaxValue;
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
var obj = list[i];
|
||||
var val = pred(obj);
|
||||
if (val < minVal)
|
||||
{
|
||||
minId = i;
|
||||
minVal = val;
|
||||
}
|
||||
}
|
||||
return minId;
|
||||
}
|
||||
|
||||
public static T MinBy<T>(this IEnumerable<T> list, Func<T, float> pred)
|
||||
{
|
||||
T minObj = default(T);
|
||||
float minVal = float.MaxValue;
|
||||
bool isEmpty = true;
|
||||
foreach (var obj in list)
|
||||
{
|
||||
var val = pred(obj);
|
||||
if (val < minVal)
|
||||
{
|
||||
minObj = obj;
|
||||
minVal = val;
|
||||
}
|
||||
isEmpty = false;
|
||||
}
|
||||
if (isEmpty) throw new ArgumentException();
|
||||
return minObj;
|
||||
}
|
||||
|
||||
public static T MinByOrDefault<T>(this IEnumerable<T> list, Func<T, float> pred)
|
||||
{
|
||||
T minObj = default(T);
|
||||
float minVal = float.MaxValue;
|
||||
bool isEmpty = true;
|
||||
foreach (var obj in list)
|
||||
{
|
||||
var val = pred(obj);
|
||||
if (val < minVal)
|
||||
{
|
||||
minObj = obj;
|
||||
minVal = val;
|
||||
}
|
||||
isEmpty = false;
|
||||
}
|
||||
if (isEmpty) return default (T);
|
||||
return minObj;
|
||||
}
|
||||
|
||||
public static Vector2 NearestPointOnLine(this Vector2 c, Vector2 a, Vector2 b)
|
||||
{
|
||||
var v = (a - b).normalized;
|
||||
return b + v*Vector2.Dot(v, c - b);
|
||||
}
|
||||
|
||||
public static float DistToLine(this Vector2 c, Vector2 a, Vector2 b)
|
||||
{
|
||||
var n = new Vector2(b.y - a.y, a.x - b.x).normalized;
|
||||
var v = c - a;
|
||||
return Vector2.Dot(n, v);
|
||||
}
|
||||
|
||||
public static bool GetTouchByFingerId(int fingerId, out Touch resultTouch)
|
||||
{
|
||||
if (fingerId == -1)
|
||||
{
|
||||
resultTouch = new Touch();
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < Input.touchCount; i++)
|
||||
{
|
||||
var touch = Input.GetTouch(i);
|
||||
if (touch.fingerId == fingerId)
|
||||
{
|
||||
resultTouch = touch;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
resultTouch = new Touch();
|
||||
return false;
|
||||
}
|
||||
|
||||
public static float ClampAngle(float angle, float min, float max)
|
||||
{
|
||||
angle = Mathf.Repeat(angle, 360);
|
||||
min = Mathf.Repeat(min, 360);
|
||||
max = Mathf.Repeat(max, 360);
|
||||
|
||||
if (min > max)
|
||||
{
|
||||
if (angle > min || angle < max) return angle;
|
||||
return angle > (min + max)/2f ? min : max;
|
||||
}
|
||||
|
||||
if (angle > min && angle < max) return angle;
|
||||
return angle < min ? min : max;
|
||||
}
|
||||
|
||||
public static int Hash<T>(T v1, T v2, T v3, T v4)
|
||||
{
|
||||
int hash = 23;
|
||||
hash = hash*31 + v1.GetHashCode();
|
||||
hash = hash*31 + v2.GetHashCode();
|
||||
hash = hash*31 + v3.GetHashCode();
|
||||
hash = hash*31 + v4.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static int Hash<T>(T v1, T v2, T v3)
|
||||
{
|
||||
int hash = 23;
|
||||
hash = hash*31 + v1.GetHashCode();
|
||||
hash = hash*31 + v2.GetHashCode();
|
||||
hash = hash*31 + v3.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static int Hash<T>(T v1, T v2)
|
||||
{
|
||||
int hash = 23;
|
||||
hash = hash*31 + v1.GetHashCode();
|
||||
hash = hash*31 + v2.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static int Hash<T>(params T[] els)
|
||||
{
|
||||
int hash = 23;
|
||||
for (int i = 0; i < els.Length; i++)
|
||||
hash = hash*31 + els[i].GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public static Vector4 Div(this Vector4 vec, Vector4 div)
|
||||
{
|
||||
return new Vector4(vec.x/div.x, vec.y/div.y, vec.z/div.z, vec.w/div.w);
|
||||
}
|
||||
|
||||
public static Vector3 Div(this Vector3 vec, Vector3 div)
|
||||
{
|
||||
return new Vector3(vec.x/div.x, vec.y/div.y, vec.z/div.z);
|
||||
}
|
||||
|
||||
public static Vector2 Div(this Vector2 vec, Vector2 div)
|
||||
{
|
||||
return new Vector2(vec.x/div.x, vec.y/div.y);
|
||||
}
|
||||
|
||||
public static Vector4 Mul(this Vector4 v1, Vector4 v2)
|
||||
{
|
||||
return Vector4.Scale(v1, v2);
|
||||
}
|
||||
|
||||
public static Vector3 Mul(this Vector3 v1, Vector3 v2)
|
||||
{
|
||||
return Vector3.Scale(v1, v2);
|
||||
}
|
||||
|
||||
public static Vector2 Mul(this Vector2 v1, Vector2 v2)
|
||||
{
|
||||
return Vector2.Scale(v1, v2);
|
||||
}
|
||||
|
||||
public static float DecodeFloatRGBA(Vector3 enc)
|
||||
{
|
||||
enc = new Vector3((byte) (enc.x*254f), (byte) (enc.y*254f), (byte) (enc.z*254f))/255f;
|
||||
var kDecodeDot = new Vector4(1f, 1/255f, 1/65025f);
|
||||
var result = Vector3.Dot(enc, kDecodeDot);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Vector4 EncodeFloatRGBA(float v)
|
||||
{
|
||||
var kEncodeMul = new Vector3(1.0f, 255.0f, 65025.0f);
|
||||
var enc = kEncodeMul*v;
|
||||
enc = new Vector3(
|
||||
enc.x - Mathf.Floor(enc.x), enc.y - Mathf.Floor(enc.y),
|
||||
enc.z - Mathf.Floor(enc.z));
|
||||
return enc;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static bool IsSceneViewFocused
|
||||
{
|
||||
get
|
||||
{
|
||||
return SceneView.currentDrawingSceneView != null &&
|
||||
SceneView.currentDrawingSceneView == EditorWindow.focusedWindow;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool FastEquals(this Matrix4x4 m1, Matrix4x4 m2)
|
||||
{
|
||||
return m1.m00 == m2.m00 && m1.m01 == m2.m01 && m1.m02 == m2.m02 && m1.m03 == m2.m03 &&
|
||||
m1.m10 == m2.m10 && m1.m11 == m2.m11 && m1.m12 == m2.m12 && m1.m13 == m2.m13 &&
|
||||
m1.m20 == m2.m20 && m1.m21 == m2.m21 && m1.m22 == m2.m22 && m1.m23 == m2.m23 &&
|
||||
m1.m30 == m2.m30 && m1.m31 == m2.m31 && m1.m32 == m2.m32 && m1.m33 == m2.m33;
|
||||
}
|
||||
|
||||
public static bool Equals(this Color32 col1, Color32 col2)
|
||||
{
|
||||
return col1.r == col2.r && col1.g == col2.g && col1.b == col2.b && col1.a == col2.a;
|
||||
}
|
||||
}
|
||||
|
||||
internal class GenericEqualityComparer<T> : IEqualityComparer<T>
|
||||
{
|
||||
private Func<T, T, bool> distinct;
|
||||
private Func<T, int> hash;
|
||||
|
||||
public GenericEqualityComparer(Func<T, T, bool> distinct, Func<T, int> hash)
|
||||
{
|
||||
this.distinct = distinct;
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public bool Equals(T x, T y)
|
||||
{
|
||||
if (System.Object.ReferenceEquals(x, y))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (System.Object.ReferenceEquals(x, null) ||
|
||||
System.Object.ReferenceEquals(y, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return distinct(x, y);
|
||||
}
|
||||
|
||||
public int GetHashCode(T obj)
|
||||
{
|
||||
return hash(obj);
|
||||
}
|
||||
}
|
||||
|
||||
internal class GenericComparer<T> : IComparer<T>
|
||||
{
|
||||
private Func<T, T, int> comparer;
|
||||
|
||||
public GenericComparer(Func<T, T, int> comparer)
|
||||
{
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public int Compare(T x, T y)
|
||||
{
|
||||
return comparer(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public class ReadOnlyAttribute : PropertyAttribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
8
Assets/Plugins/Light2D/Scripts/Util.cs.meta
Normal file
8
Assets/Plugins/Light2D/Scripts/Util.cs.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5cec7f403e884314d99b1cd248d10843
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
Loading…
Add table
Add a link
Reference in a new issue