Created
March 7, 2017 16:21
-
-
Save rc1/fc8ffec73bea07ea4a327b42d2d6f7af to your computer and use it in GitHub Desktop.
Unity Point Lights as Image Effect
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
[ExecuteInEditMode] | |
public class PointLightsImageEffect : MonoBehaviour { | |
private Camera _camera; | |
public Material EffectMaterial; | |
public Transform pointLight; | |
void OnEnable() | |
{ | |
_camera = GetComponent<Camera>(); | |
_camera.depthTextureMode = DepthTextureMode.DepthNormals; | |
} | |
[ImageEffectOpaque] | |
void OnRenderImage(RenderTexture src, RenderTexture dst) | |
{ | |
// EffectMaterial.SetVector("_WorldSpaceScannerPos", ScannerOrigin.position); | |
// EffectMaterial.SetFloat("_ScanDistance", ScanDistance); | |
// Get the camera matrix to convert the view space normals to world normals | |
Matrix4x4 MV = _camera.cameraToWorldMatrix; | |
EffectMaterial.SetMatrix( "_CameraMV", MV); | |
// Update the point light | |
if ( pointLight != null ) { | |
EffectMaterial.SetVector( "_LightPosition", pointLight.position ); | |
} | |
RaycastCornerBlit(src, dst, EffectMaterial); | |
} | |
void RaycastCornerBlit(RenderTexture source, RenderTexture dest, Material mat) | |
{ | |
// Compute Frustum Corners | |
float camFar = _camera.farClipPlane; | |
float camFov = _camera.fieldOfView; | |
float camAspect = _camera.aspect; | |
float fovWHalf = camFov * 0.5f; | |
Vector3 toRight = _camera.transform.right * Mathf.Tan(fovWHalf * Mathf.Deg2Rad) * camAspect; | |
Vector3 toTop = _camera.transform.up * Mathf.Tan(fovWHalf * Mathf.Deg2Rad); | |
Vector3 topLeft = (_camera.transform.forward - toRight + toTop); | |
float camScale = topLeft.magnitude * camFar; | |
topLeft.Normalize(); | |
topLeft *= camScale; | |
Vector3 topRight = (_camera.transform.forward + toRight + toTop); | |
topRight.Normalize(); | |
topRight *= camScale; | |
Vector3 bottomRight = (_camera.transform.forward + toRight - toTop); | |
bottomRight.Normalize(); | |
bottomRight *= camScale; | |
Vector3 bottomLeft = (_camera.transform.forward - toRight - toTop); | |
bottomLeft.Normalize(); | |
bottomLeft *= camScale; | |
// Custom Blit, encoding Frustum Corners as additional Texture Coordinates | |
RenderTexture.active = dest; | |
mat.SetTexture("_MainTex", source); | |
GL.PushMatrix(); | |
GL.LoadOrtho(); | |
mat.SetPass(0); | |
GL.Begin(GL.QUADS); | |
GL.MultiTexCoord2(0, 0.0f, 0.0f); | |
GL.MultiTexCoord(1, bottomLeft); | |
GL.Vertex3(0.0f, 0.0f, 0.0f); | |
GL.MultiTexCoord2(0, 1.0f, 0.0f); | |
GL.MultiTexCoord(1, bottomRight); | |
GL.Vertex3(1.0f, 0.0f, 0.0f); | |
GL.MultiTexCoord2(0, 1.0f, 1.0f); | |
GL.MultiTexCoord(1, topRight); | |
GL.Vertex3(1.0f, 1.0f, 0.0f); | |
GL.MultiTexCoord2(0, 0.0f, 1.0f); | |
GL.MultiTexCoord(1, topLeft); | |
GL.Vertex3(0.0f, 1.0f, 0.0f); | |
GL.End(); | |
GL.PopMatrix(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Shader "PointLightsImageEffect" | |
{ | |
Properties | |
{ | |
_MainTex ("Texture", 2D) = "white" {} | |
_LightColor ("Light Color", Color) = ( 1.0, 1.0, 1.0 ) | |
_LightPosition ("Light Position", Vector) = ( 0.0, 0.0, 0.0 ) | |
_LightRange ("Light Range", Float) = 1.0 | |
} | |
SubShader | |
{ | |
// No culling or depth | |
Cull Off ZWrite Off ZTest Always | |
Pass | |
{ | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#include "UnityCG.cginc" | |
struct VertIn | |
{ | |
float4 vertex : POSITION; | |
float2 uv : TEXCOORD0; | |
float4 ray : TEXCOORD1; | |
}; | |
struct VertOut | |
{ | |
float2 uv : TEXCOORD0; | |
float4 vertex : SV_POSITION; | |
float2 uv_depth : TEXCOORD1; | |
float4 interpolatedRay : TEXCOORD2; | |
}; | |
VertOut vert (VertIn v) | |
{ | |
VertOut o; | |
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); | |
o.uv = v.uv; | |
o.uv_depth = v.uv.xy; | |
#if UNITY_UV_STARTS_AT_TOP | |
if (_MainTex_TexelSize.y < 0) | |
o.uv.y = 1 - o.uv.y; | |
#endif | |
o.interpolatedRay = v.ray; | |
return o; | |
} | |
sampler2D _MainTex; | |
// Provided by the camera | |
sampler2D_float _CameraDepthNormalsTexture; | |
// Provided by the material property | |
float4x4 _CameraMV; | |
float3 _LightPosition; | |
float4 _LightColor; | |
float _LightRange; | |
float3 lightDistanceNormalised ( float3 surfacePosition, float3 lightPosition, float lightRange ) { | |
float dis = distance( surfacePosition, lightPosition ); | |
return 1.0 - clamp( dis / lightRange, 0.0, 1.0 ); | |
} | |
fixed4 frag (VertOut i) : SV_Target | |
{ | |
float4 finalColor; | |
// Get the surface color | |
float4 surfaceColor = tex2D(_MainTex, i.uv); | |
// Get the depth & normal | |
float rawDepth = 1.0; | |
float3 viewSpaceNormal; | |
DecodeDepthNormal( tex2D(_CameraDepthNormalsTexture, i.uv_depth.xy), rawDepth, viewSpaceNormal ); | |
// Get the world position | |
float4 directionWorldSpace = rawDepth * i.interpolatedRay; | |
float3 surfaceWorldPosition = _WorldSpaceCameraPos + directionWorldSpace; | |
// Get the world normal | |
float3 surfaceWorldNormal = mul((float3x3)_CameraMV, viewSpaceNormal); | |
// Return the distance from the light | |
float distanceFromLight = clamp( 1.0 - distance( surfaceWorldPosition, _LightPosition ) / _LightRange, 0, 1 ); | |
// Get the vector from the surface to the light | |
float3 surfaceToLight = _LightPosition - surfaceWorldPosition; | |
// Get the brightness of the surface (cosine of the angle of incidence). 1 means it is facing the light. 0 means it's not | |
float brightness = dot(surfaceWorldNormal, surfaceToLight) / (length(surfaceToLight) * length(surfaceWorldNormal)); | |
brightness = clamp( brightness, 0, 1 ); | |
// Get the intensity of the light based on the distance and the direction | |
float intensity = lerp( 0, brightness, distanceFromLight ); | |
// Add the light to the surface color... there will be better ways | |
finalColor = surfaceColor + ( _LightColor * intensity ); | |
return finalColor; | |
} | |
ENDCG | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment