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 { /// /// Used to draw lights. Puts LightOrigin world position to UV1. /// Supports Point and Line light types. /// [ExecuteInEditMode] public class LightSprite : CustomSprite { public static List AllLightSprites = new List(); 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); } /// /// Update UV1 which is used for raytracking in shader. UV1 is set to world position of LightOrigin. /// 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(); } } }