/// ProFlares - v1.08 - Copyright 2014-2015 All rights reserved - ProFlares.com
///
/// ProFlareBatch.cs
/// Processes all the ProFlares in a scene, converts them into geometry that can be rendered.
///
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class FlareData {
public ProFlare flare;
public FlareOcclusion occlusion;
}
[System.Serializable]
public class FlareOcclusion {
public bool occluded = false;
public float occlusionScale = 1;
public CullingState _CullingState;
public float CullTimer = 0;
public float cullFader = 1;
public enum CullingState{
Visible,
CullCountDown,
CanCull,
Culled,
NeverCull
}
}
[ExecuteInEditMode]
[RequireComponent (typeof (MeshRenderer))]
[RequireComponent (typeof (MeshFilter))]
public class ProFlareBatch : MonoBehaviour {
public enum Mode{
Standard = 0,
SingleCamera = 1,
VR = 2
}
public bool debugMessages = true;
public Mode mode = Mode.Standard;
public ProFlareAtlas _atlas;
//List of flares
//public List Flares = new List();
public List FlaresList = new List();
//List of FlareElements
public List FlareElements = new List();
public ProFlareElement[] FlareElementsArray;
public Camera GameCamera;
public Transform GameCameraTrans;
//Camera that the flare geometry will be rendered from.
public Camera FlareCamera;
public Transform FlareCameraTrans;
//Cached Components
public MeshFilter meshFilter;
public Transform thisTransform;
public MeshRenderer meshRender;
public float zPos;
//Multiple meshes used for double buffering technique
private Mesh bufferMesh;
private Mesh meshA;
private Mesh meshB;
//Ping pong value for double Buffering
bool PingPong;
//Material used for the Flares, this is automatically created.
public Material mat;
//Geometry Arrays
Vector3[] vertices;
Vector2[] uv;
Color32[] colors;
int[] triangles;
public FlareOcclusion[] FlareOcclusionData;
//Debug Propertys
public bool useBrightnessThreshold = true;
public int BrightnessThreshold = 1;
public bool overdrawDebug;
//When set to true the Flarebatches' geomerty will be rebuilt.
public bool dirty = false;
public bool useCulling = true;
public int cullFlaresAfterTime = 5;
public int cullFlaresAfterCount = 5;
public bool culledFlaresNowVisiable = false;
private float reshowCulledFlaresTimer = 0;
public float reshowCulledFlaresAfter = 0.3f;
//HelperTransform used for FlarePositions calculations.
public Transform helperTransform;
public bool showAllConnectedFlares;
public bool VR_Mode = false;
public float VR_Depth = 0.2f;
public bool SingleCamera_Mode = false;
void Reset(){
if(helperTransform == null)
CreateHelperTransform();
mat = new Material(Shader.Find("ProFlares/Textured Flare Shader"));
if(meshFilter == null)
meshFilter = GetComponent();
if(meshFilter == null)
meshFilter = gameObject.AddComponent();
meshRender = gameObject.GetComponent();
if(meshRender == null)
meshRender = gameObject.AddComponent();
if(FlareCamera == null){
FlareCamera = transform.root.GetComponentInChildren();
}
meshRender.material = mat;
SetupMeshes();
dirty = true;
}
void Awake(){
PI_Div180 = Mathf.PI / 180;
Div180_PI = 180 / Mathf.PI;
ProFlare[] flares = GameObject.FindObjectsOfType(typeof(ProFlare)) as ProFlare[];
for(int i = 0; i < flares.Length; i++){
if(flares[i]._Atlas == _atlas)
this.AddFlare(flares[i]);
}
}
void Start () {
//Turn off overdraw debug mode.
if(Application.isPlaying){
overdrawDebug = false;
//dirty = true;
}
if(GameCamera == null){
GameObject GameCameraGo = GameObject.FindWithTag("MainCamera");
#if UNITY_5
if(GameCameraGo)
if(GameCameraGo.GetComponent())
GameCamera = GameCameraGo.GetComponent();
#else
if(GameCameraGo)
if(GameCameraGo.GetComponent())
GameCamera = GameCameraGo.GetComponent();
#endif
}
if(GameCamera)
GameCameraTrans = GameCamera.transform;
//Make sure we have the transform cached
thisTransform = transform;
SetupMeshes();
}
void CreateMat(){
// Debug.LogError("CreateMat");
mat = new Material(Shader.Find("ProFlares/Textured Flare Shader"));
meshRender.material = mat;
if(_atlas)
if(_atlas.texture)
mat.mainTexture = _atlas.texture;
}
//Call when you switch your main render.
public void SwitchCamera(Camera newCamera){
GameCamera = newCamera;
GameCameraTrans = newCamera.transform;
//Update Occlusion data on changing camera new in v1.03
FixedUpdate();
for(int F = 0; F < FlaresList.Count; F++){
if(FlaresList[F].occlusion != null){
if(FlaresList[F].occlusion.occluded)
FlaresList[F].occlusion.occlusionScale = 0;
}
}
}
void OnDestroy(){
//Remove the helper transform.
if(Application.isPlaying){
Destroy(helperTransform.gameObject);
Destroy(mat);
}
else{
DestroyImmediate(helperTransform.gameObject);
DestroyImmediate(mat);
}
}
public void RemoveFlare(ProFlare _flare){
bool found = false;
FlareData targetFlare = null;
for(int i = 0; i < FlaresList.Count; i++){
if(_flare == FlaresList[i].flare){
targetFlare = FlaresList[i];
found = true;
break;
}
}
if(found)
FlaresList.Remove(targetFlare);
}
//Called from ProFlare.cs
//First checks if the flare is already in the list, if not adds it and rebuils the Flarebatch Geometry
public void AddFlare(ProFlare _flare){
bool found = false;
for(int i = 0; i < FlaresList.Count; i++){
if(_flare == FlaresList[i].flare){
found = true;
break;
}
}
if(!found){
FlareData FlareData_ = new FlareData();
FlareData_.flare = _flare;
FlareOcclusion data = new FlareOcclusion();
if(_flare.neverCull)
data._CullingState = FlareOcclusion.CullingState.NeverCull;
FlareData_.occlusion = data;
FlaresList.Add(FlareData_);
dirty = true;
}
}
void CreateHelperTransform(){
GameObject HelpTransformGo = new GameObject("_HelperTransform");
helperTransform = HelpTransformGo.transform;
helperTransform.parent = transform;
helperTransform.localScale = Vector3.one;
helperTransform.localPosition = Vector3.zero;
}
void Update(){
if(thisTransform)
thisTransform.localPosition = Vector3.forward*zPos;
//Checks if you have deleted the helper transform. If its missing recreate it.....
if(helperTransform == null)
CreateHelperTransform();
if(meshRender){
if(meshRender.sharedMaterial == null)
CreateMat();
}else
meshRender = gameObject.GetComponent();
bool meshMissing = false;
if(meshA == null){
meshMissing = true;
// meshA = SetupSingleMesh();
// meshA.name = "MeshA";
// meshA.MarkDynamic();
}
if(meshB == null){
meshMissing = true;
// meshB = SetupSingleMesh();
// meshB.name = "MeshB";
// meshB.MarkDynamic();
}
if(meshMissing)
if(_atlas != null)
SetupMeshes();
if(dirty)
ReBuildGeometry();
}
//Late update
void LateUpdate () {
if(_atlas == null)
return;
UpdateFlares();
}
public void UpdateFlares(){
bufferMesh = PingPong ? meshA : meshB;
PingPong = !PingPong;
UpdateGeometry();
//Profiler.BeginSample("Set Arrays");
bufferMesh.vertices = vertices;
bufferMesh.colors32 = colors;
meshFilter.sharedMesh = bufferMesh;
//Profiler.EndSample();
}
public void ForceRefresh(){
FlaresList.Clear();
ProFlare[] flares = GameObject.FindObjectsOfType(typeof(ProFlare)) as ProFlare[];
for(int i = 0; i < flares.Length; i++){
if(flares[i]._Atlas == _atlas)
this.AddFlare(flares[i]);
}
dirty = true;
}
void ReBuildGeometry(){
#if UNITY_EDITOR
//See when the geometry is built, try and avoid triggering this in the middle of your game.
//This can be triggered by the new culling system, if your only using a few flares you may want to turn it off as the speed increase from culling will be more limited.
if(debugMessages)
Debug.Log("ProFlares - Rebuilding Geometry : "+ gameObject.name,gameObject);
#endif
FlareElements.Clear();
int flareElementsCount = 0;
bool missingFlare = false;
for(int i = 0; i < FlaresList.Count; i++){
if(FlaresList[i].flare == null){
missingFlare = true;
break;
}
for(int i2 = 0; i2 < FlaresList[i].flare.Elements.Count; i2++){
// FlareElements.Add(Flares[i].Elements[i2]);
if(FlaresList[i].occlusion._CullingState == FlareOcclusion.CullingState.CanCull){
FlaresList[i].occlusion._CullingState = FlareOcclusion.CullingState.Culled;
FlaresList[i].occlusion.cullFader = 0;
}
if(FlaresList[i].occlusion._CullingState != FlareOcclusion.CullingState.Culled){
flareElementsCount++;
}
}
}
FlareElementsArray = new ProFlareElement[flareElementsCount];
flareElementsCount = 0;
if(!missingFlare)
for(int i = 0; i < FlaresList.Count; i++){
for(int i2 = 0; i2 < FlaresList[i].flare.Elements.Count; i2++){
if(FlaresList[i].occlusion._CullingState != FlareOcclusion.CullingState.Culled){
FlareElementsArray[flareElementsCount] = (FlaresList[i].flare.Elements[i2]);
flareElementsCount++;
}
}
}
if(missingFlare){
ForceRefresh();
ReBuildGeometry();
missingFlare = false;
}
meshA = null;
meshB = null;
bufferMesh = null;
SetupMeshes();
dirty = false;
}
void SetupMeshes()
{
if(_atlas == null)
return;
if(FlareElementsArray == null)
return;
meshA = new Mesh();
meshB = new Mesh();
int vertSize = 0;
int uvSize = 0;
int colSize = 0;
int triCount = 0;
//Calculate how big each array needs to be based on the Flares
for(int i = 0; i < FlareElementsArray.Length; i++){
switch(FlareElementsArray[i].type){
case(ProFlareElement.Type.Single):
{
vertSize = vertSize+4;
uvSize = uvSize+4;
colSize = colSize+4;
triCount = triCount+6;
}
break;
case(ProFlareElement.Type.Multi):
{
int subCount = FlareElementsArray[i].subElements.Count;
vertSize = vertSize+(4*subCount);
uvSize = uvSize+(4*subCount);
colSize = colSize+(4*subCount);
triCount = triCount+(6*subCount);
}
break;
}
}
//Create Built in arrays
vertices = new Vector3[vertSize];
uv = new Vector2[uvSize];
colors = new Color32[colSize];
triangles = new int[triCount];
//Set Inital valuse for each vertex
for(int i = 0; i < vertices.Length/4; i++){
int extra = i * 4;
vertices[0+extra] = new Vector3(1,1,0); //((Vector3.right)+(Vector3.up));
vertices[1+extra] = new Vector3(1,-1,0);//((Vector3.right)+(Vector3.down));
vertices[2+extra] = new Vector3(-1,1,0);//((Vector3.left)+(Vector3.up));
vertices[3+extra] = new Vector3(-1,-1,0);//((Vector3.left)+(Vector3.down));
}
//Set UV coordinates for each vertex, this only needs to be done in the mesh rebuild.
int count = 0;
for(int i = 0; i < FlareElementsArray.Length; i++){
switch(FlareElementsArray[i].type){
case(ProFlareElement.Type.Single):
{
int extra = (count) * 4;
Rect final = _atlas.elementsList[FlareElementsArray[i].elementTextureID].UV;
uv[0+extra] = new Vector2(final.xMax,final.yMax);
uv[1+extra] = new Vector2(final.xMax,final.yMin);
uv[2+extra] = new Vector2(final.xMin,final.yMax);
uv[3+extra] = new Vector2(final.xMin,final.yMin);
count++;
}break;
case(ProFlareElement.Type.Multi):
{
for(int i2 = 0; i2 < FlareElementsArray[i].subElements.Count; i2++){
int extra2 = (count+i2) * 4;
Rect final = _atlas.elementsList[FlareElementsArray[i].elementTextureID].UV;
uv[0+extra2] = new Vector2(final.xMax,final.yMax);
uv[1+extra2] = new Vector2(final.xMax,final.yMin);
uv[2+extra2] = new Vector2(final.xMin,final.yMax);
uv[3+extra2] = new Vector2(final.xMin,final.yMin);
}
count = count+FlareElementsArray[i].subElements.Count;
}break;
}
}
Color32 newColor = new Color32(255,255,255,255);
//Set inital vertex colors.
for(int i = 0; i < colors.Length/4; i++){
int extra = i * 4;
colors[0+extra] = newColor;
colors[1+extra] = newColor;
colors[2+extra] = newColor;
colors[3+extra] = newColor;
}
//Set triangle array, this is only done in the mesh rebuild.
for(int i = 0; i < triangles.Length/6; i++){
int extra = i * 4;
int extra2 = i * 6;
triangles[0+extra2] = 0+extra;
triangles[1+extra2] = 1+extra;
triangles[2+extra2] = 2+extra;
triangles[3+extra2] = 2+extra;
triangles[4+extra2] = 1+extra;
triangles[5+extra2] = 3+extra;
}
meshA.vertices = vertices;
meshA.uv = uv;
meshA.triangles = triangles;
meshA.colors32 = colors;
meshA.bounds = new Bounds(Vector3.zero,Vector3.one*1000);
meshB.vertices = vertices;
meshB.uv = uv;
meshB.triangles = triangles;
meshB.colors32 = colors;
meshB.bounds = new Bounds(Vector3.zero,Vector3.one*1000);
}
Vector3[] verts;
Vector2 _scale;
Color32 _color;
float PI_Div180;
float Div180_PI;
int visibleFlares = 0;
/*
public Vector3 RotatePoint(Vector3 p, float d,float ct,float st) {
//float r = d * (Mathf.PI / 180);
//float ct = Mathf.Cos(r);
//float st = Mathf.Sin(r);
float x = (ct * p.x - st * p.y);
float y = (st * p.x + ct * p.y);
return new Vector3(x,y,0);
}*/
void FixedUpdate(){
if(!dirty)
for(int F = 0; F < FlaresList.Count; F++){
if(FlaresList[F].flare == null)
continue;
ProFlare flare_ = FlaresList[F].flare;
FlareOcclusion data = FlaresList[F].occlusion;
if(flare_.RaycastPhysics){
RaycastHit hit;
Vector3 direction = GameCameraTrans.position-flare_.thisTransform.position;
float distanceRay = Vector3.Distance(GameCameraTrans.position,flare_.thisTransform.position);
data.occluded = true;
if(flare_.isVisible){
Ray ray = new Ray(flare_.thisTransform.position,direction);
if (Physics.Raycast(ray, out hit,distanceRay,flare_.mask)){
//Flares[F].Occluded = true;
data.occluded = true;
#if UNITY_EDITOR
Debug.DrawRay(flare_.thisTransform.position,direction,Color.red);
flare_.OccludingObject = hit.collider.gameObject;
#endif
}else{
data.occluded = false;
#if UNITY_EDITOR
flare_.OccludingObject = null;
Debug.DrawRay(flare_.thisTransform.position,direction);
#endif
}
}
}
}
}
void UpdateGeometry(){
if(GameCamera == null){
meshRender.enabled = false;
return;
}
meshRender.enabled = true;
//Profiler.BeginSample("Update Pos");
visibleFlares = 0;
int canCullFlares = 0;
for(int F = 0; F < FlaresList.Count; F++){
//Profiler.BeginSample("Lens Pos");
ProFlare flare_ = FlaresList[F].flare;
FlareOcclusion data = FlaresList[F].occlusion;
if(flare_ == null)
continue;
// Debug.Log("UpdateGeometry");
flare_.LensPosition = GameCamera.WorldToViewportPoint(flare_.thisTransform.position);
Vector3 LensPosition = flare_.LensPosition;
//LensPosition = new Vector3(Random.Range(-1f,1f),Random.Range(-1f,1f),Random.Range(-1f,1f));
bool isVisible = (LensPosition.z > 0f && LensPosition.x+flare_.OffScreenFadeDist > 0f && LensPosition.x-flare_.OffScreenFadeDist < 1f && LensPosition.y+flare_.OffScreenFadeDist > 0f && LensPosition.y-flare_.OffScreenFadeDist < 1f);
flare_.isVisible = isVisible;
//Profiler.EndSample();
//Profiler.BeginSample("offScreen Fading");
//Off Screen fading
float offScreenFade = 1;
if(!(LensPosition.x > 0f && LensPosition.x < 1f && LensPosition.y > 0f && LensPosition.y < 1f)){
float offScreenNorm = 1f/flare_.OffScreenFadeDist;
float xPos = 0;
float yPos = 0;
if(!(LensPosition.x > 0f && LensPosition.x < 1f))
xPos = LensPosition.x > 0.5f ? LensPosition.x-1f : Mathf.Abs(LensPosition.x);
if(!(LensPosition.y > 0f && LensPosition.y < 1f))
yPos = LensPosition.y > 0.5f ? LensPosition.y-1f : Mathf.Abs(LensPosition.y);
offScreenFade = Mathf.Clamp01( offScreenFade - (Mathf.Max(xPos,yPos))*offScreenNorm);
}
//Profiler.EndSample();
//Profiler.BeginSample("Dynamic Triggering");
//Dynamic Triggering Center
float centerBoost = 0;
if(LensPosition.x > 0.5f-flare_.DynamicCenterRange && LensPosition.x < 0.5f+flare_.DynamicCenterRange && LensPosition.y > 0.5f-flare_.DynamicCenterRange && LensPosition.y < 0.5f+flare_.DynamicCenterRange){
if(flare_.DynamicCenterRange > 0){
float centerBoostNorm = 1/(flare_.DynamicCenterRange);
centerBoost = 1-Mathf.Max(Mathf.Abs(LensPosition.x-0.5f),Mathf.Abs(LensPosition.y-0.5f))*centerBoostNorm;
}
}
//Dynamic Triggering Edge
float DynamicEdgeAmount = 0;
bool isInEdgeZone1 = (
LensPosition.x > 0f+flare_.DynamicEdgeBias+(flare_.DynamicEdgeRange) &&
LensPosition.x < 1f-flare_.DynamicEdgeBias-(flare_.DynamicEdgeRange) &&
LensPosition.y > 0f+flare_.DynamicEdgeBias+(flare_.DynamicEdgeRange) &&
LensPosition.y < 1f-flare_.DynamicEdgeBias-(flare_.DynamicEdgeRange)
);
bool isInEdgeZone2 = (
LensPosition.x+(flare_.DynamicEdgeRange) > 0f+flare_.DynamicEdgeBias &&
LensPosition.x-(flare_.DynamicEdgeRange) < 1f-flare_.DynamicEdgeBias &&
LensPosition.y+(flare_.DynamicEdgeRange) > 0f+flare_.DynamicEdgeBias &&
LensPosition.y-(flare_.DynamicEdgeRange) < 1f-flare_.DynamicEdgeBias
);
if(!isInEdgeZone1&&isInEdgeZone2){
float DynamicEdgeNormalizeValue = 1/(flare_.DynamicEdgeRange);
float DynamicEdgeX = 0;
float DynamicEdgeY = 0;
bool isInEdgeZoneX1 = (LensPosition.x > 0f+flare_.DynamicEdgeBias+(flare_.DynamicEdgeRange) && LensPosition.x < 1f-flare_.DynamicEdgeBias-(flare_.DynamicEdgeRange));
bool isInEdgeZoneX2 = (LensPosition.x+(flare_.DynamicEdgeRange) > 0f+flare_.DynamicEdgeBias && LensPosition.x-(flare_.DynamicEdgeRange) < 1f-flare_.DynamicEdgeBias);
bool isInEdgeZoneY1 = (LensPosition.y > 0f+flare_.DynamicEdgeBias+(flare_.DynamicEdgeRange) && LensPosition.y < 1f-flare_.DynamicEdgeBias-(flare_.DynamicEdgeRange));
bool isInEdgeZoneY2 = (LensPosition.y+(flare_.DynamicEdgeRange) > 0f+flare_.DynamicEdgeBias && LensPosition.y-(flare_.DynamicEdgeRange) < 1f-flare_.DynamicEdgeBias);
if(!isInEdgeZoneX1&&isInEdgeZoneX2){
DynamicEdgeX = LensPosition.x > 0.5f ? (LensPosition.x - 1 +flare_.DynamicEdgeBias) + (flare_.DynamicEdgeRange) : Mathf.Abs(LensPosition.x -flare_.DynamicEdgeBias - (flare_.DynamicEdgeRange));
DynamicEdgeX = (DynamicEdgeX*DynamicEdgeNormalizeValue)*0.5f;
}
if(!isInEdgeZoneY1&&isInEdgeZoneY2){
DynamicEdgeY = LensPosition.y > 0.5f ? (LensPosition.y - 1 + flare_.DynamicEdgeBias) + (flare_.DynamicEdgeRange) : Mathf.Abs(LensPosition.y-flare_.DynamicEdgeBias - (flare_.DynamicEdgeRange));
DynamicEdgeY = (DynamicEdgeY*DynamicEdgeNormalizeValue)*0.5f;
}
DynamicEdgeAmount = Mathf.Max(DynamicEdgeX,DynamicEdgeY);
}
DynamicEdgeAmount = flare_.DynamicEdgeCurve.Evaluate(DynamicEdgeAmount);
//Profiler.EndSample();
//Profiler.BeginSample("Angle Fall Off");
/*
float AngleFallOff = 1;
if(flare_.UseAngleLimit){
Vector3 playerAngle = flare_.thisTransform.forward;
Vector3 cameraAngle = GameCameraTrans.forward;
float horizDiffAngle = Vector3.Angle(cameraAngle, playerAngle);
horizDiffAngle = Mathf.Abs( Mathf.Clamp(180-horizDiffAngle,-flare_.maxAngle,flare_.maxAngle));
AngleFallOff = 1f-(horizDiffAngle*(1f/(flare_.maxAngle*0.5f)));
if(flare_.UseAngleCurve)
AngleFallOff = flare_.AngleCurve.Evaluate(AngleFallOff);
}*/
float AngleFallOff = 1;
if(flare_.UseAngleLimit){
Vector3 playerAngle = flare_.thisTransform.forward;
//Vector3 cameraAngle = GameCameraTrans.forward;
//the direct vector from flare point to camera point
Vector3 camToPoint = GameCameraTrans.position - flare_.thisTransform.position;
float horizDiffAngle = Vector3.Angle(playerAngle, camToPoint);
horizDiffAngle = Mathf.Abs( Mathf.Clamp(horizDiffAngle,-flare_.maxAngle,flare_.maxAngle));
if (horizDiffAngle > flare_.maxAngle)
AngleFallOff = 0;
else
{
AngleFallOff = 1f - (horizDiffAngle * (1f / (flare_.maxAngle * 0.5f)));
if (flare_.UseAngleCurve)
AngleFallOff = flare_.AngleCurve.Evaluate(AngleFallOff);
}
}
//Profiler.EndSample();
//Profiler.BeginSample("Distance Check");
float distanceFalloff = 1f;
if(flare_.useMaxDistance){
Vector3 heading = flare_.thisTransform.position - GameCameraTrans.position;
float distance = Vector3.Dot(heading, GameCameraTrans.forward);
float distanceNormalised = 1f-(distance/flare_.GlobalMaxDistance);
distanceFalloff = 1f*distanceNormalised;
if(distanceFalloff < 0.001f)
flare_.isVisible = false;
}
//Profiler.EndSample();
//Profiler.BeginSample("Check Occlusion Data");
if(!dirty)
if(data != null)
if(data.occluded){
data.occlusionScale = Mathf.Lerp(data.occlusionScale,0,Time.deltaTime*16);
}else{
data.occlusionScale = Mathf.Lerp(data.occlusionScale,1,Time.deltaTime*16);
}
//Profiler.EndSample();
//Profiler.BeginSample("Final Lens Pos Set");
// Debug.Log("Visible = "+Flares[F].isVisible+" | offScreenFade "+offScreenFade);
// Debug.Log("distanceFalloff "+distanceFalloff);
if(!flare_.isVisible)
offScreenFade = 0;
float tempScale = 1;
if(FlareCamera)
helperTransform.position = FlareCamera.ViewportToWorldPoint(LensPosition);
LensPosition = helperTransform.localPosition;
//Profiler.EndSample();
if((!VR_Mode) && (!SingleCamera_Mode))
LensPosition.z = 0f;
float finalAlpha;
//Profiler.BeginSample("Elements Loo[");
for(int i = 0; i < flare_.Elements.Count; i++){
ProFlareElement _element = flare_.Elements[i];
Color GlobalColor = flare_.GlobalTintColor;
if(isVisible)
switch(_element.type){
case(ProFlareElement.Type.Single):
//Do the color stuff.
_element.ElementFinalColor.r = (_element.ElementTint.r * GlobalColor.r);
_element.ElementFinalColor.g = (_element.ElementTint.g * GlobalColor.g);
_element.ElementFinalColor.b = (_element.ElementTint.b * GlobalColor.b);
finalAlpha = _element.ElementTint.a * GlobalColor.a;
if(flare_.useDynamicEdgeBoost){
if(_element.OverrideDynamicEdgeBrightness)
finalAlpha = finalAlpha + (_element.DynamicEdgeBrightnessOverride*DynamicEdgeAmount);
else
finalAlpha = finalAlpha + (flare_.DynamicEdgeBrightness*DynamicEdgeAmount);
}
if(flare_.useDynamicCenterBoost){
if(_element.OverrideDynamicCenterBrightness)
finalAlpha += (_element.DynamicCenterBrightnessOverride*centerBoost);
else
finalAlpha += (flare_.DynamicCenterBrightness*centerBoost);
}
if(flare_.UseAngleBrightness)
finalAlpha *= AngleFallOff;
if(flare_.useDistanceFade)
finalAlpha *= distanceFalloff;
finalAlpha *= data.occlusionScale;
finalAlpha *= data.cullFader;
finalAlpha *= offScreenFade;
_element.ElementFinalColor.a = finalAlpha;
break;
case(ProFlareElement.Type.Multi):
//Profiler.BeginSample("Color Mutli Loop");
for(int i2 = 0; i2 < _element.subElements.Count; i2++){
//Do the color stuff.
SubElement _subElement = _element.subElements[i2];
_subElement.colorFinal.r = (_subElement.color.r * GlobalColor.r);
_subElement.colorFinal.g = (_subElement.color.g * GlobalColor.g);
_subElement.colorFinal.b = (_subElement.color.b * GlobalColor.b);
finalAlpha = _subElement.color.a * GlobalColor.a;
if(flare_.useDynamicEdgeBoost){
if(_element.OverrideDynamicEdgeBrightness)
finalAlpha = finalAlpha + (_element.DynamicEdgeBrightnessOverride*DynamicEdgeAmount);
else
finalAlpha = finalAlpha + (flare_.DynamicEdgeBrightness*DynamicEdgeAmount);
}
if(flare_.useDynamicCenterBoost){
if(_element.OverrideDynamicCenterBrightness)
finalAlpha += (_element.DynamicCenterBrightnessOverride*centerBoost);
else
finalAlpha += (flare_.DynamicCenterBrightness*centerBoost);
}
if(flare_.UseAngleBrightness)
finalAlpha *= AngleFallOff;
if(flare_.useDistanceFade)
finalAlpha *= distanceFalloff;
finalAlpha *= data.occlusionScale;
finalAlpha *= data.cullFader;
finalAlpha *= offScreenFade;
_subElement.colorFinal.a = finalAlpha;
}
//Profiler.EndSample();
break;
}
else{
switch(_element.type){
case(ProFlareElement.Type.Single):
// _element.ElementFinalColor = Color.black;
tempScale = 0;
break;
case(ProFlareElement.Type.Multi):
// for(int i2 = 0; i2 < _element.subElements.Count; i2++){
// _element.subElements[i2].colorFinal = Color.black;
// }
tempScale = 0;
break;
}
}
//Element Scale
float finalScale = tempScale;
if(flare_.useDynamicEdgeBoost){
if(_element.OverrideDynamicEdgeBoost)
finalScale = finalScale+((DynamicEdgeAmount)*_element.DynamicEdgeBoostOverride);
else
finalScale = finalScale+((DynamicEdgeAmount)*flare_.DynamicEdgeBoost);
}
if(flare_.useDynamicCenterBoost){
if(_element.OverrideDynamicCenterBoost)
finalScale = finalScale+(_element.DynamicCenterBoostOverride*centerBoost);
else
finalScale = finalScale+(flare_.DynamicCenterBoost*centerBoost);
}
if(finalScale < 0) finalScale = 0;
if(flare_.UseAngleScale)
finalScale *= AngleFallOff;
if(flare_.useDistanceScale)
finalScale *= distanceFalloff;
finalScale *= data.occlusionScale;
if(!_element.Visible)
finalScale = 0;
if(!isVisible)
finalScale = 0;
_element.ScaleFinal = finalScale;
//Apply final screen position.
if(isVisible)
switch(_element.type){
case(ProFlareElement.Type.Single):{
Vector3 pos = LensPosition*-_element.position;
float zpos = LensPosition.z;
if(VR_Mode){
float flarePos = (_element.position*-1)-1;
zpos = LensPosition.z *((flarePos*VR_Depth)+1);
}
Vector3 newVect = new Vector3(
Mathf.Lerp(pos.x,LensPosition.x,_element.Anamorphic.x),
Mathf.Lerp(pos.y,LensPosition.y,_element.Anamorphic.y),
zpos
);
newVect = newVect + _element.OffsetPostion;
_element.OffsetPosition = newVect;
}break;
case(ProFlareElement.Type.Multi):{
//Profiler.BeginSample("Scale Mutli Loop");
for(int i2 = 0; i2 < _element.subElements.Count; i2++){
SubElement _subElement = _element.subElements[i2];
if(_element.useRangeOffset){
Vector3 posM = LensPosition*-_subElement.position;
float zpos = LensPosition.z;
if(VR_Mode){
float flarePos = (_subElement.position*-1)-1;
zpos = LensPosition.z *((flarePos*VR_Depth)+1);
}
Vector3 newVectM = new Vector3(
Mathf.Lerp(posM.x,LensPosition.x,_element.Anamorphic.x),
Mathf.Lerp(posM.y,LensPosition.y,_element.Anamorphic.y),
zpos
);
newVectM = newVectM + _element.OffsetPostion;
_subElement.offset = newVectM;
}
else
_subElement.offset = LensPosition*-_element.position;
}
//Profiler.EndSample();
}break;
}
//Apply final element angle.
float angles = 0;
if(_element.rotateToFlare){
angles = (Div180_PI)*(Mathf.Atan2(LensPosition.y - 0,LensPosition.x - 0));
}
angles = angles + (LensPosition.x*_element.rotationSpeed);
angles = angles + (LensPosition.y*_element.rotationSpeed);
angles = angles + (Time.time*_element.rotationOverTime);
_element.FinalAngle = (_element.angle)+angles;
}
//Profiler.EndSample();
if((!flare_.neverCull)&&useCulling){
FlareOcclusion.CullingState _CullingState = data._CullingState;
if(flare_.isVisible){
visibleFlares++;
if(data.occluded){
if(_CullingState == FlareOcclusion.CullingState.Visible){
//Debug.Log("Culled via Occlusion");
data.CullTimer = cullFlaresAfterTime;
_CullingState = FlareOcclusion.CullingState.CullCountDown;
}
}else{
if(_CullingState == FlareOcclusion.CullingState.Culled){
//Debug.Log("Re show not occluded");
culledFlaresNowVisiable = true;
}
_CullingState = FlareOcclusion.CullingState.Visible;
}
}else{
if(_CullingState == FlareOcclusion.CullingState.Visible){
//Debug.Log("Culled via Not Vis");
data.CullTimer = cullFlaresAfterTime;
_CullingState = FlareOcclusion.CullingState.CullCountDown;
}
}
switch(_CullingState){
case(FlareOcclusion.CullingState.Visible):{
}break;
case(FlareOcclusion.CullingState.CullCountDown):{
data.CullTimer = data.CullTimer-Time.deltaTime;
if(data.CullTimer < 0)
_CullingState = FlareOcclusion.CullingState.CanCull;
}break;
}
if(_CullingState != FlareOcclusion.CullingState.Culled)
data.cullFader = Mathf.Clamp01(data.cullFader+(Time.deltaTime));
if(_CullingState == FlareOcclusion.CullingState.CanCull)
canCullFlares++;
data._CullingState = _CullingState;
}
reshowCulledFlaresTimer += Time.deltaTime;
if(reshowCulledFlaresTimer > reshowCulledFlaresAfter){
reshowCulledFlaresTimer = 0;
if(culledFlaresNowVisiable){
//Debug.Log("A culled flare has now become visiable");
dirty = true;
culledFlaresNowVisiable = false;
}
}
if(!dirty)
if(canCullFlares >= cullFlaresAfterCount){
Debug.Log("Culling Flares");dirty = true;
}
}
//Profiler.BeginSample("Rendering Bit");
//Rendering Bit
int count = 0;
if(FlareElementsArray != null)
for(int i = 0; i < FlareElementsArray.Length; i++){
float scaleMulti = 1;
ProFlare flare = FlareElementsArray[i].flare;
if(flare.MultiplyScaleByTransformScale)
scaleMulti = flare.thisTransform.localScale.x;
switch(FlareElementsArray[i].type){
case(ProFlareElement.Type.Single):
{
int extra = (count) * 4;
//Check for DisabledPlayMode, then scale to zero. then skip over the rest of the calculations
if(FlareElementsArray[i].flare.DisabledPlayMode){
vertices[0+extra] = Vector3.zero;
vertices[1+extra] = Vector3.zero;
vertices[2+extra] = Vector3.zero;
vertices[3+extra] = Vector3.zero;
}
_scale = (((FlareElementsArray[i].size*FlareElementsArray[i].Scale*0.01f)*flare.GlobalScale)*FlareElementsArray[i].ScaleFinal)*scaleMulti;
//Avoid Negative scaling
if((_scale.x < 0)||(_scale.y < 0))
_scale = Vector3.zero;
Vector3 offset = FlareElementsArray[i].OffsetPosition;
float angle = FlareElementsArray[i].FinalAngle;
_color = FlareElementsArray[i].ElementFinalColor;
if(useBrightnessThreshold){
if(_color.a < BrightnessThreshold){
_scale = Vector2.zero;
}else if(_color.r+_color.g+_color.b < BrightnessThreshold){
_scale = Vector2.zero;
}
}
if(overdrawDebug)
_color = new Color32(20,20,20,100);
if(!FlareElementsArray[i].flare.DisabledPlayMode){
//Precalculate some of the RotatePoint function to avoid repeat math.
float r = angle * (PI_Div180);
float ct = Mathf.Cos(r);
float st = Mathf.Sin(r);
vertices[0+extra] = new Vector3((ct * (1*_scale.x) - st * (1*_scale.y)),(st * (1*_scale.x) + ct * (1*_scale.y)),0)+offset;
vertices[1+extra] = new Vector3((ct * (1*_scale.x) - st * (-1*_scale.y)),(st * (1*_scale.x) + ct * (-1*_scale.y)),0)+offset;
vertices[2+extra] = new Vector3((ct * (-1*_scale.x) - st * (1*_scale.y)),(st * (-1*_scale.x) + ct * (1*_scale.y)),0)+offset;
vertices[3+extra] = new Vector3((ct * (-1*_scale.x) - st * (-1*_scale.y)),(st * (-1*_scale.x) + ct * (-1*_scale.y)),0)+offset;
}
Color32 _color32 = _color;
colors[0+extra] = _color32;
colors[1+extra] = _color32;
colors[2+extra] = _color32;
colors[3+extra] = _color32;
count++;
}
break;
case(ProFlareElement.Type.Multi):
{
for(int i2 = 0; i2 < FlareElementsArray[i].subElements.Count; i2++){
int extra2 = (count+i2) * 4;
//Check for DisabledPlayMode, then scale to zero. then skip over the rest of the calculations
if(FlareElementsArray[i].flare.DisabledPlayMode){
vertices[0+extra2] = Vector3.zero;
vertices[1+extra2] = Vector3.zero;
vertices[2+extra2] = Vector3.zero;
vertices[3+extra2] = Vector3.zero;
continue;
}
////Profiler.BeginSample("Calc Scale");
_scale = (((FlareElementsArray[i].size*FlareElementsArray[i].Scale*0.01f)*FlareElementsArray[i].flare.GlobalScale)*FlareElementsArray[i].subElements[i2].scale)*FlareElementsArray[i].ScaleFinal;
//Avoid Negative scaling
_scale = _scale*scaleMulti;
if((_scale.x < 0)||(_scale.y < 0))
_scale = Vector3.zero;
////Profiler.EndSample();
////Profiler.BeginSample("Calc Extras");
Vector3 offset = FlareElementsArray[i].subElements[i2].offset;
float angle = FlareElementsArray[i].FinalAngle;
angle += FlareElementsArray[i].subElements[i2].angle;
_color = FlareElementsArray[i].subElements[i2].colorFinal;
if(useBrightnessThreshold){
if(_color.a < BrightnessThreshold){
_scale = Vector2.zero;
}else if(_color.r+_color.g+_color.b < BrightnessThreshold){
_scale = Vector2.zero;
}
}
if(overdrawDebug)
_color = new Color32(20,20,20,100);
// //Profiler.EndSample();
////Profiler.BeginSample("Set Pos and Rot");
if(!FlareElementsArray[i].flare.DisabledPlayMode){
//Precalculate some of the RotatePoint function to avoid repeat math.
float r = angle * (PI_Div180);
float ct = Mathf.Cos(r);
float st = Mathf.Sin(r);
vertices[0+extra2] = new Vector3((ct * (1*_scale.x) - st * (1*_scale.y)),(st * (1*_scale.x) + ct * (1*_scale.y)),0)+offset;
vertices[1+extra2] = new Vector3((ct * (1*_scale.x) - st * (-1*_scale.y)),(st * (1*_scale.x) + ct * (-1*_scale.y)),0)+offset;
vertices[2+extra2] = new Vector3((ct * (-1*_scale.x) - st * (1*_scale.y)),(st * (-1*_scale.x) + ct * (1*_scale.y)),0)+offset;
vertices[3+extra2] = new Vector3((ct * (-1*_scale.x) - st * (-1*_scale.y)),(st * (-1*_scale.x) + ct * (-1*_scale.y)),0)+offset;
}
////Profiler.EndSample();
////Profiler.BeginSample("SetColors");
Color32 _color32 = _color;
colors[0+extra2] = _color32;
colors[1+extra2] = _color32;
colors[2+extra2] = _color32;
colors[3+extra2] = _color32;
////Profiler.EndSample();
}
count = count+FlareElementsArray[i].subElements.Count;
}
break;
}
}
//Profiler.EndSample();
// Debug.Log("updare Done");
}
}