/* ____ _ _ __ __ _
* | _ \ _ __ ___ (_) ___ ___| |_ \ \ / /_ _ _ __ __| | ___ _ __
* | |_) | '__/ _ \| |/ _ \/ __| __| \ \ /\ / / _` | '_ \ / _` |/ _ \ '__|
* | __/| | | (_) | | __/ (__| |_ \ V V / (_| | | | | (_| | __/ |
* |_| |_| \___// |\___|\___|\__| \_/\_/ \__,_|_| |_|\__,_|\___|_|
* |__/
*
*
* ENJMIN - Hits PlayTime 2013
*
* This file is part of the Wander project,
* created and developped by :
* Louis Schnellbach
*
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class CameraPostProcess : MonoBehaviour
{
RenderTexture m_finalTex;
List<Source> m_list = new List<Source> ();
public Shader shader;
private Material m_materialPostProcess = null;
private Material m_materialInitTexture = null;
private int m_width;
private int m_height;
float CAMERA_NEAR;
float CAMERA_FAR;
float CAMERA_FOV;
float CAMERA_ASPECT_RATIO;
void Start ()
{
camera.depthTextureMode = DepthTextureMode.DepthNormals;
// Disable if we don't support image effects
if (!SystemInfo.supportsImageEffects) {
enabled = false;
return;
}
// Disable the image effect if the shader can't
// run on the users graphics card
if (!shader || !shader.isSupported)
enabled = false;
}
//Free texture
void OnDisable ()
{
m_list.Clear ();
DestroyImmediate (m_finalTex);
DestroyImmediate (m_materialPostProcess);
DestroyImmediate (m_materialInitTexture);
}
void OnEnable ()
{
if (m_materialPostProcess == null) {
m_materialPostProcess = new Material (shader);
m_materialPostProcess.hideFlags = HideFlags.HideAndDontSave;
}
if (m_materialInitTexture == null) {
m_materialInitTexture = new Material (Shader.Find ("Xleek/BlackTexture"));
m_materialInitTexture.hideFlags = HideFlags.HideAndDontSave;
}
m_list.Clear ();
camera.depthTextureMode = DepthTextureMode.DepthNormals;
m_finalTex = new RenderTexture ((int)camera.pixelWidth, (int)camera.pixelHeight, 0);
}
public void AddSource (Source obj)
{
m_list.Add (obj);
//Debug.Log ("Added Source. (" + m_list.Count.ToString () + ")");
}
public void RemoveSource (Source obj)
{
m_list.Remove (obj);
//Debug.Log ("Removed Source. (" + m_list.Count.ToString () + ")");
}
// Called by camera to apply image effect
void OnRenderImage (RenderTexture source, RenderTexture destination)
{
//Clear FinalTexture before each display
Graphics.Blit (null, m_finalTex, m_materialInitTexture);
// Setup the texture and floating point values in the shader
m_materialPostProcess.SetTexture ("_MainTex", source);
//Send to shader the frustum corner
m_materialPostProcess.SetMatrix ("_FrustumCornersWS", frustumCorner ());
//And the camera position (computed once)
m_materialPostProcess.SetVector ("_CameraWS", camera.transform.position);
//Start rendering each source
m_list.ForEach (delegate(Source src)
{
if (src != null) {
m_materialPostProcess.SetTexture ("_FinalTex", m_finalTex);
m_materialPostProcess.SetVector ("_Position", src.Position);
m_materialPostProcess.SetColor ("_SourceColor", src.SourceColor);
m_materialPostProcess.SetFloat ("_Radius", src.Radius);
m_materialPostProcess.SetFloat ("_MaxRadius", src.MaxRadius);
m_materialPostProcess.SetFloat ("_VisibleWidth", src.VisibleWidth);
m_materialPostProcess.SetFloat ("_HaloWidth", src.HaloWidth);
CustomGraphicBlit (source, m_finalTex, m_materialPostProcess);
}
});
//Final (at least !) blit
Graphics.Blit (m_finalTex, destination);
}
void CustomGraphicBlit (RenderTexture source, RenderTexture destination, Material material)
{
RenderTexture.active = destination;
GL.PushMatrix ();
GL.LoadOrtho ();
material.SetPass (0);
GL.Begin (GL.QUADS);
GL.MultiTexCoord2 (0, 0.0f, 0.0f);
GL.Vertex3 (0.0f, 0.0f, 3.0f); // BL
GL.MultiTexCoord2 (0, 1.0f, 0.0f);
GL.Vertex3 (1.0f, 0.0f, 2.0f); // BR
GL.MultiTexCoord2 (0, 1.0f, 1.0f);
GL.Vertex3 (1.0f, 1.0f, 1.0f); // TR
GL.MultiTexCoord2 (0, 0.0f, 1.0f);
GL.Vertex3 (0.0f, 1.0f, 0.0f); // TL
GL.End ();
GL.PopMatrix ();
}
//Avoid to write this in the render method
Matrix4x4 frustumCorner ()
{
Matrix4x4 frustumCorners = Matrix4x4.identity;
CAMERA_NEAR = camera.nearClipPlane;
CAMERA_FAR = camera.farClipPlane;
CAMERA_FOV = camera.fieldOfView;
CAMERA_ASPECT_RATIO = camera.aspect;
float fovWHalf = CAMERA_FOV * 0.5f;
Vector3 toRight = camera.transform.right * CAMERA_NEAR * Mathf.Tan (fovWHalf * Mathf.Deg2Rad) * CAMERA_ASPECT_RATIO;
Vector3 toTop = camera.transform.up * CAMERA_NEAR * Mathf.Tan (fovWHalf * Mathf.Deg2Rad);
Vector3 topLeft = (camera.transform.forward * CAMERA_NEAR - toRight + toTop);
float CAMERA_SCALE = topLeft.magnitude * CAMERA_FAR / CAMERA_NEAR;
topLeft.Normalize ();
topLeft *= CAMERA_SCALE;
Vector3 topRight = (camera.transform.forward * CAMERA_NEAR + toRight + toTop);
topRight.Normalize ();
topRight *= CAMERA_SCALE;
Vector3 bottomRight = (camera.transform.forward * CAMERA_NEAR + toRight - toTop);
bottomRight.Normalize ();
bottomRight *= CAMERA_SCALE;
Vector3 bottomLeft = (camera.transform.forward * CAMERA_NEAR - toRight - toTop);
bottomLeft.Normalize ();
bottomLeft *= CAMERA_SCALE;
frustumCorners.SetRow (0, topLeft);
frustumCorners.SetRow (1, topRight);
frustumCorners.SetRow (2, bottomRight);
frustumCorners.SetRow (3, bottomLeft);
return frustumCorners;
}
}